• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.slices;
18 
19 import static com.android.settings.bluetooth.BluetoothSliceBuilder.ACTION_BLUETOOTH_SLICE_CHANGED;
20 import static com.android.settings.network.telephony.Enhanced4gLteSliceHelper.ACTION_ENHANCED_4G_LTE_CHANGED;
21 import static com.android.settings.notification.ZenModeSliceBuilder.ACTION_ZEN_MODE_SLICE_CHANGED;
22 import static com.android.settings.slices.SettingsSliceProvider.ACTION_COPY;
23 import static com.android.settings.slices.SettingsSliceProvider.ACTION_SLIDER_CHANGED;
24 import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CHANGED;
25 import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
26 import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED;
27 import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED;
28 import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED;
29 import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY;
30 import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED;
31 
32 import android.app.settings.SettingsEnums;
33 import android.app.slice.Slice;
34 import android.content.BroadcastReceiver;
35 import android.content.ContentResolver;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.net.Uri;
39 import android.provider.SettingsSlicesContract;
40 import android.text.TextUtils;
41 import android.util.Log;
42 
43 import com.android.settings.bluetooth.BluetoothSliceBuilder;
44 import com.android.settings.core.BasePreferenceController;
45 import com.android.settings.core.SliderPreferenceController;
46 import com.android.settings.core.TogglePreferenceController;
47 import com.android.settings.notification.ZenModeSliceBuilder;
48 import com.android.settings.overlay.FeatureFactory;
49 
50 /**
51  * Responds to actions performed on slices and notifies slices of updates in state changes.
52  */
53 public class SliceBroadcastReceiver extends BroadcastReceiver {
54 
55     private static String TAG = "SettSliceBroadcastRec";
56 
57     @Override
onReceive(Context context, Intent intent)58     public void onReceive(Context context, Intent intent) {
59         final String action = intent.getAction();
60         final String key = intent.getStringExtra(EXTRA_SLICE_KEY);
61         final boolean isPlatformSlice = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED,
62                 false /* default */);
63 
64         if (CustomSliceRegistry.isValidAction(action)) {
65             final CustomSliceable sliceable =
66                     CustomSliceable.createInstance(context,
67                             CustomSliceRegistry.getSliceClassByUri(Uri.parse(action)));
68             sliceable.onNotifyChange(intent);
69             return;
70         }
71 
72         switch (action) {
73             case ACTION_TOGGLE_CHANGED:
74                 final boolean isChecked = intent.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE, false);
75                 handleToggleAction(context, key, isChecked, isPlatformSlice);
76                 break;
77             case ACTION_SLIDER_CHANGED:
78                 final int newPosition = intent.getIntExtra(Slice.EXTRA_RANGE_VALUE, -1);
79                 handleSliderAction(context, key, newPosition, isPlatformSlice);
80                 break;
81             case ACTION_BLUETOOTH_SLICE_CHANGED:
82                 BluetoothSliceBuilder.handleUriChange(context, intent);
83                 break;
84             case ACTION_WIFI_CALLING_CHANGED:
85                 FeatureFactory.getFactory(context)
86                         .getSlicesFeatureProvider()
87                         .getNewWifiCallingSliceHelper(context)
88                         .handleWifiCallingChanged(intent);
89                 break;
90             case ACTION_ZEN_MODE_SLICE_CHANGED:
91                 ZenModeSliceBuilder.handleUriChange(context, intent);
92                 break;
93             case ACTION_ENHANCED_4G_LTE_CHANGED:
94                 FeatureFactory.getFactory(context)
95                         .getSlicesFeatureProvider()
96                         .getNewEnhanced4gLteSliceHelper(context)
97                         .handleEnhanced4gLteChanged(intent);
98                 break;
99             case ACTION_WIFI_CALLING_PREFERENCE_WIFI_ONLY:
100             case ACTION_WIFI_CALLING_PREFERENCE_WIFI_PREFERRED:
101             case ACTION_WIFI_CALLING_PREFERENCE_CELLULAR_PREFERRED:
102                 FeatureFactory.getFactory(context)
103                         .getSlicesFeatureProvider()
104                         .getNewWifiCallingSliceHelper(context)
105                         .handleWifiCallingPreferenceChanged(intent);
106                 break;
107             case ACTION_COPY:
108                 handleCopyAction(context, key, isPlatformSlice);
109                 break;
110         }
111     }
112 
handleToggleAction(Context context, String key, boolean isChecked, boolean isPlatformSlice)113     private void handleToggleAction(Context context, String key, boolean isChecked,
114             boolean isPlatformSlice) {
115         if (TextUtils.isEmpty(key)) {
116             throw new IllegalStateException("No key passed to Intent for toggle controller");
117         }
118 
119         final BasePreferenceController controller = getPreferenceController(context, key);
120 
121         if (!(controller instanceof TogglePreferenceController)) {
122             throw new IllegalStateException("Toggle action passed for a non-toggle key: " + key);
123         }
124 
125         if (!controller.isAvailable()) {
126             Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
127             if (!controller.hasAsyncUpdate()) {
128                 updateUri(context, key, isPlatformSlice);
129             }
130             return;
131         }
132 
133         // TODO post context.getContentResolver().notifyChanged(uri, null) in the Toggle controller
134         // so that it's automatically broadcast to any slice.
135         final TogglePreferenceController toggleController = (TogglePreferenceController) controller;
136         toggleController.setChecked(isChecked);
137         logSliceValueChange(context, key, isChecked ? 1 : 0);
138         if (!controller.hasAsyncUpdate()) {
139             updateUri(context, key, isPlatformSlice);
140         }
141     }
142 
handleSliderAction(Context context, String key, int newPosition, boolean isPlatformSlice)143     private void handleSliderAction(Context context, String key, int newPosition,
144             boolean isPlatformSlice) {
145         if (TextUtils.isEmpty(key)) {
146             throw new IllegalArgumentException(
147                     "No key passed to Intent for slider controller. Use extra: " + EXTRA_SLICE_KEY);
148         }
149 
150         if (newPosition == -1) {
151             throw new IllegalArgumentException("Invalid position passed to Slider controller");
152         }
153 
154         final BasePreferenceController controller = getPreferenceController(context, key);
155 
156         if (!(controller instanceof SliderPreferenceController)) {
157             throw new IllegalArgumentException("Slider action passed for a non-slider key: " + key);
158         }
159 
160         if (!controller.isAvailable()) {
161             Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
162             updateUri(context, key, isPlatformSlice);
163             return;
164         }
165 
166         final SliderPreferenceController sliderController = (SliderPreferenceController) controller;
167         final int minValue = sliderController.getMin();
168         final int maxValue = sliderController.getMax();
169         if (newPosition < minValue || newPosition > maxValue) {
170             throw new IllegalArgumentException(
171                     "Invalid position passed to Slider controller. Expected between " + minValue
172                             + " and " + maxValue + " but found " + newPosition);
173         }
174 
175         sliderController.setSliderPosition(newPosition);
176         logSliceValueChange(context, key, newPosition);
177         updateUri(context, key, isPlatformSlice);
178     }
179 
handleCopyAction(Context context, String key, boolean isPlatformSlice)180     private void handleCopyAction(Context context, String key, boolean isPlatformSlice) {
181         if (TextUtils.isEmpty(key)) {
182             throw new IllegalArgumentException("No key passed to Intent for controller");
183         }
184 
185         final BasePreferenceController controller = getPreferenceController(context, key);
186 
187         if (!(controller instanceof Sliceable)) {
188             throw new IllegalArgumentException(
189                     "Copyable action passed for a non-copyable key:" + key);
190         }
191 
192         if (!controller.isAvailable()) {
193             Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
194             if (!controller.hasAsyncUpdate()) {
195                 updateUri(context, key, isPlatformSlice);
196             }
197             return;
198         }
199 
200         controller.copy();
201     }
202 
203     /**
204      * Log Slice value update events into MetricsFeatureProvider. The logging schema generally
205      * follows the pattern in SharedPreferenceLogger.
206      */
logSliceValueChange(Context context, String sliceKey, int newValue)207     private void logSliceValueChange(Context context, String sliceKey, int newValue) {
208         FeatureFactory.getFactory(context).getMetricsFeatureProvider()
209                 .action(SettingsEnums.PAGE_UNKNOWN,
210                         SettingsEnums.ACTION_SETTINGS_SLICE_CHANGED,
211                         SettingsEnums.PAGE_UNKNOWN,
212                         sliceKey, newValue);
213     }
214 
getPreferenceController(Context context, String key)215     private BasePreferenceController getPreferenceController(Context context, String key) {
216         final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(context);
217         final SliceData sliceData = accessor.getSliceDataFromKey(key);
218         return SliceBuilderUtils.getPreferenceController(context, sliceData);
219     }
220 
updateUri(Context context, String key, boolean isPlatformDefined)221     private void updateUri(Context context, String key, boolean isPlatformDefined) {
222         final String authority = isPlatformDefined
223                 ? SettingsSlicesContract.AUTHORITY
224                 : SettingsSliceProvider.SLICE_AUTHORITY;
225         final Uri uri = new Uri.Builder()
226                 .scheme(ContentResolver.SCHEME_CONTENT)
227                 .authority(authority)
228                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
229                 .appendPath(key)
230                 .build();
231         context.getContentResolver().notifyChange(uri, null /* observer */);
232     }
233 }
234