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