1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.accessibility;
18 
19 import android.content.ContentResolver;
20 import android.database.ContentObserver;
21 import android.net.Uri;
22 import android.os.Handler;
23 import android.provider.Settings;
24 import android.util.Log;
25 
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 
31 class AccessibilitySettingsContentObserver extends ContentObserver {
32 
33     private static final String TAG = "AccessibilitySettingsContentObserver";
34 
35     public interface ContentObserverCallback {
onChange(String key)36         void onChange(String key);
37     }
38 
39     // Key: Preference key's uri, Value: Preference key
40     private final Map<Uri, String> mUriToKey = new HashMap<>(2);
41 
42     // Key: Collection of preference keys, Value: onChange callback for keys
43     private final Map<List<String>, ContentObserverCallback> mUrisToCallback = new HashMap<>();
44 
AccessibilitySettingsContentObserver(Handler handler)45     AccessibilitySettingsContentObserver(Handler handler) {
46         super(handler);
47 
48         // default key to be observed
49         addDefaultKeysToMap();
50     }
51 
register(ContentResolver contentResolver)52     public void register(ContentResolver contentResolver) {
53         for (Uri uri : mUriToKey.keySet()) {
54             contentResolver.registerContentObserver(uri, false, this);
55         }
56     }
57 
unregister(ContentResolver contentResolver)58     public void unregister(ContentResolver contentResolver) {
59         contentResolver.unregisterContentObserver(this);
60     }
61 
addDefaultKeysToMap()62     private void addDefaultKeysToMap() {
63         addKeyToMap(Settings.Secure.ACCESSIBILITY_ENABLED);
64         addKeyToMap(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
65     }
66 
isDefaultKey(String key)67     private boolean isDefaultKey(String key) {
68         return Settings.Secure.ACCESSIBILITY_ENABLED.equals(key)
69                 || Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(key);
70     }
71 
addKeyToMap(String key)72     private void addKeyToMap(String key) {
73         mUriToKey.put(Settings.Secure.getUriFor(key), key);
74     }
75 
76     /**
77      * {@link ContentObserverCallback} is added to {@link ContentObserver} to handle the
78      * onChange event triggered by the key collection of {@code keysToObserve} and the default
79      * keys.
80      *
81      * Note: The following key are default to be observed.
82      *      {@link Settings.Secure.ACCESSIBILITY_ENABLED}
83      *      {@link Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES}
84      *
85      * @param keysToObserve A collection of keys which are going to be observed.
86      * @param observerCallback A callback which is used to handle the onChange event triggered
87      *                         by the key collection of {@code keysToObserve}.
88      */
registerKeysToObserverCallback(List<String> keysToObserve, ContentObserverCallback observerCallback)89     public void registerKeysToObserverCallback(List<String> keysToObserve,
90             ContentObserverCallback observerCallback) {
91 
92         for (String key: keysToObserve) {
93             addKeyToMap(key);
94         }
95 
96         mUrisToCallback.put(keysToObserve, observerCallback);
97     }
98 
99     /**
100      * {@link ContentObserverCallback} is added to {@link ContentObserver} to handle the
101      * onChange event triggered by the default keys.
102      *
103      * Note: The following key are default to be observed.
104      *      {@link Settings.Secure.ACCESSIBILITY_ENABLED}
105      *      {@link Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES}
106      *
107      * @param observerCallback A callback which is used to handle the onChange event triggered
108      *      *                         by the key collection of {@code keysToObserve}.
109      */
registerObserverCallback(ContentObserverCallback observerCallback)110     public void registerObserverCallback(ContentObserverCallback observerCallback) {
111         mUrisToCallback.put(Collections.emptyList(), observerCallback);
112     }
113 
114     @Override
onChange(boolean selfChange, Uri uri)115     public final void onChange(boolean selfChange, Uri uri) {
116 
117         final String key = mUriToKey.get(uri);
118 
119         if (key == null) {
120             Log.w(TAG, "AccessibilitySettingsContentObserver can not find the key for "
121                     + "uri: " + uri);
122             return;
123         }
124 
125         for (List<String> keys : mUrisToCallback.keySet()) {
126             final boolean isDefaultKey = isDefaultKey(key);
127             if (isDefaultKey || keys.contains(key)) {
128                 mUrisToCallback.get(keys).onChange(key);
129             }
130         }
131     }
132 }
133