• 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.notification.ZenModeSliceBuilder.ACTION_ZEN_MODE_SLICE_CHANGED;
21 import static com.android.settings.slices.SettingsSliceProvider.ACTION_SLIDER_CHANGED;
22 import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CHANGED;
23 import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
24 import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED;
25 import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED;
26 import static com.android.settings.wifi.WifiSliceBuilder.ACTION_WIFI_SLICE_CHANGED;
27 
28 import android.app.slice.Slice;
29 import android.content.BroadcastReceiver;
30 import android.content.ContentResolver;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.net.Uri;
34 import android.provider.SettingsSlicesContract;
35 import android.text.TextUtils;
36 import android.util.Log;
37 import android.util.Pair;
38 
39 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
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.ZenModeSliceBuilder;
45 import com.android.settings.overlay.FeatureFactory;
46 import com.android.settings.wifi.WifiSliceBuilder;
47 
48 /**
49  * Responds to actions performed on slices and notifies slices of updates in state changes.
50  */
51 public class SliceBroadcastReceiver extends BroadcastReceiver {
52 
53     private static String TAG = "SettSliceBroadcastRec";
54 
55     @Override
onReceive(Context context, Intent intent)56     public void onReceive(Context context, Intent intent) {
57         final String action = intent.getAction();
58         final String key = intent.getStringExtra(EXTRA_SLICE_KEY);
59         final boolean isPlatformSlice = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED,
60                 false /* default */);
61 
62         switch (action) {
63             case ACTION_TOGGLE_CHANGED:
64                 final boolean isChecked = intent.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE, false);
65                 handleToggleAction(context, key, isChecked, isPlatformSlice);
66                 break;
67             case ACTION_SLIDER_CHANGED:
68                 final int newPosition = intent.getIntExtra(Slice.EXTRA_RANGE_VALUE, -1);
69                 handleSliderAction(context, key, newPosition, isPlatformSlice);
70                 break;
71             case ACTION_BLUETOOTH_SLICE_CHANGED:
72                 BluetoothSliceBuilder.handleUriChange(context, intent);
73                 break;
74             case ACTION_WIFI_SLICE_CHANGED:
75                 WifiSliceBuilder.handleUriChange(context, intent);
76                 break;
77             case ACTION_WIFI_CALLING_CHANGED:
78                 FeatureFactory.getFactory(context)
79                         .getSlicesFeatureProvider()
80                         .getNewWifiCallingSliceHelper(context)
81                         .handleWifiCallingChanged(intent);
82                 break;
83             case ACTION_ZEN_MODE_SLICE_CHANGED:
84                 ZenModeSliceBuilder.handleUriChange(context, intent);
85                 break;
86         }
87     }
88 
handleToggleAction(Context context, String key, boolean isChecked, boolean isPlatformSlice)89     private void handleToggleAction(Context context, String key, boolean isChecked,
90             boolean isPlatformSlice) {
91         if (TextUtils.isEmpty(key)) {
92             throw new IllegalStateException("No key passed to Intent for toggle controller");
93         }
94 
95         final BasePreferenceController controller = getPreferenceController(context, key);
96 
97         if (!(controller instanceof TogglePreferenceController)) {
98             throw new IllegalStateException("Toggle action passed for a non-toggle key: " + key);
99         }
100 
101         if (!controller.isAvailable()) {
102             Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
103             if (!controller.hasAsyncUpdate()) {
104                 updateUri(context, key, isPlatformSlice);
105             }
106             return;
107         }
108 
109         // TODO post context.getContentResolver().notifyChanged(uri, null) in the Toggle controller
110         // so that it's automatically broadcast to any slice.
111         final TogglePreferenceController toggleController = (TogglePreferenceController) controller;
112         toggleController.setChecked(isChecked);
113         logSliceValueChange(context, key, isChecked ? 1 : 0);
114         if (!controller.hasAsyncUpdate()) {
115             updateUri(context, key, isPlatformSlice);
116         }
117     }
118 
handleSliderAction(Context context, String key, int newPosition, boolean isPlatformSlice)119     private void handleSliderAction(Context context, String key, int newPosition,
120             boolean isPlatformSlice) {
121         if (TextUtils.isEmpty(key)) {
122             throw new IllegalArgumentException(
123                     "No key passed to Intent for slider controller. Use extra: " + EXTRA_SLICE_KEY);
124         }
125 
126         if (newPosition == -1) {
127             throw new IllegalArgumentException("Invalid position passed to Slider controller");
128         }
129 
130         final BasePreferenceController controller = getPreferenceController(context, key);
131 
132         if (!(controller instanceof SliderPreferenceController)) {
133             throw new IllegalArgumentException("Slider action passed for a non-slider key: " + key);
134         }
135 
136         if (!controller.isAvailable()) {
137             Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
138             updateUri(context, key, isPlatformSlice);
139             return;
140         }
141 
142         final SliderPreferenceController sliderController = (SliderPreferenceController) controller;
143         final int maxSteps = sliderController.getMaxSteps();
144         if (newPosition < 0 || newPosition > maxSteps) {
145             throw new IllegalArgumentException(
146                     "Invalid position passed to Slider controller. Expected between 0 and "
147                             + maxSteps + " but found " + newPosition);
148         }
149 
150         sliderController.setSliderPosition(newPosition);
151         logSliceValueChange(context, key, newPosition);
152         updateUri(context, key, isPlatformSlice);
153     }
154 
155     /**
156      * Log Slice value update events into MetricsFeatureProvider. The logging schema generally
157      * follows the pattern in SharedPreferenceLogger.
158      */
logSliceValueChange(Context context, String sliceKey, int newValue)159     private void logSliceValueChange(Context context, String sliceKey, int newValue) {
160         final Pair<Integer, Object> namePair = Pair.create(
161                 MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, sliceKey);
162         final Pair<Integer, Object> valuePair = Pair.create(
163                 MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, newValue);
164         FeatureFactory.getFactory(context).getMetricsFeatureProvider()
165                 .action(context, MetricsEvent.ACTION_SETTINGS_SLICE_CHANGED, namePair, valuePair);
166     }
167 
getPreferenceController(Context context, String key)168     private BasePreferenceController getPreferenceController(Context context, String key) {
169         final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(context);
170         final SliceData sliceData = accessor.getSliceDataFromKey(key);
171         return SliceBuilderUtils.getPreferenceController(context, sliceData);
172     }
173 
updateUri(Context context, String key, boolean isPlatformDefined)174     private void updateUri(Context context, String key, boolean isPlatformDefined) {
175         final String authority = isPlatformDefined
176                 ? SettingsSlicesContract.AUTHORITY
177                 : SettingsSliceProvider.SLICE_AUTHORITY;
178         final Uri uri = new Uri.Builder()
179                 .scheme(ContentResolver.SCHEME_CONTENT)
180                 .authority(authority)
181                 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
182                 .appendPath(key)
183                 .build();
184         context.getContentResolver().notifyChange(uri, null /* observer */);
185     }
186 }
187