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