2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.bluetooth;
19 import android.bluetooth.BluetoothAdapter;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.os.UserManager;
25 import android.provider.Settings;
26 import android.widget.Toast;
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.settings.R;
30 import com.android.settings.widget.SwitchWidgetController;
31 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
32 import com.android.settingslib.WirelessUtils;
33 import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
34 import com.android.settingslib.bluetooth.LocalBluetoothManager;
35 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
38 * BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox
39 * preference. It turns on/off Bluetooth and ensures the summary of the
40 * preference reflects the current state.
42 public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchChangeListener {
43 private final SwitchWidgetController mSwitchController;
44 private final MetricsFeatureProvider mMetricsFeatureProvider;
45 private Context mContext;
46 private boolean mValidListener;
47 private final LocalBluetoothAdapter mLocalAdapter;
48 private final IntentFilter mIntentFilter;
49 private final RestrictionUtils mRestrictionUtils;
50 private SwitchWidgetController.OnSwitchChangeListener mCallback;
52 private static final String EVENT_DATA_IS_BT_ON = "is_bluetooth_on";
53 private static final int EVENT_UPDATE_INDEX = 0;
54 private final int mMetricsEvent;
56 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
58 public void onReceive(Context context, Intent intent) {
59 // Broadcast receiver is always running on the UI thread here,
60 // so we don't need consider thread synchronization.
61 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
62 handleStateChanged(state);
66 public BluetoothEnabler(Context context, SwitchWidgetController switchController,
67 MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager,
69 this(context, switchController, metricsFeatureProvider, manager, metricsEvent,
70 new RestrictionUtils());
73 public BluetoothEnabler(Context context, SwitchWidgetController switchController,
74 MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager,
75 int metricsEvent, RestrictionUtils restrictionUtils) {
77 mMetricsFeatureProvider = metricsFeatureProvider;
78 mSwitchController = switchController;
79 mSwitchController.setListener(this);
80 mValidListener = false;
81 mMetricsEvent = metricsEvent;
83 if (manager == null) {
84 // Bluetooth is not supported
86 mSwitchController.setEnabled(false);
88 mLocalAdapter = manager.getBluetoothAdapter();
90 mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
91 mRestrictionUtils = restrictionUtils;
94 public void setupSwitchController() {
95 mSwitchController.setupView();
98 public void teardownSwitchController() {
99 mSwitchController.teardownView();
102 public void resume(Context context) {
103 if (mContext != context) {
107 final boolean restricted = maybeEnforceRestrictions();
109 if (mLocalAdapter == null) {
110 mSwitchController.setEnabled(false);
114 // Bluetooth state is not sticky, so set it manually
116 handleStateChanged(mLocalAdapter.getBluetoothState());
119 mSwitchController.startListening();
120 mContext.registerReceiver(mReceiver, mIntentFilter);
121 mValidListener = true;
124 public void pause() {
125 if (mLocalAdapter == null) {
128 if (mValidListener) {
129 mSwitchController.stopListening();
130 mContext.unregisterReceiver(mReceiver);
131 mValidListener = false;
135 void handleStateChanged(int state) {
137 case BluetoothAdapter.STATE_TURNING_ON:
138 mSwitchController.setEnabled(false);
140 case BluetoothAdapter.STATE_ON:
142 mSwitchController.setEnabled(true);
144 case BluetoothAdapter.STATE_TURNING_OFF:
145 mSwitchController.setEnabled(false);
147 case BluetoothAdapter.STATE_OFF:
149 mSwitchController.setEnabled(true);
153 mSwitchController.setEnabled(true);
157 private void setChecked(boolean isChecked) {
158 if (isChecked != mSwitchController.isChecked()) {
159 // set listener to null, so onCheckedChanged won't be called
160 // if the checked status on Switch isn't changed by user click
161 if (mValidListener) {
162 mSwitchController.stopListening();
164 mSwitchController.setChecked(isChecked);
165 if (mValidListener) {
166 mSwitchController.startListening();
172 public boolean onSwitchToggled(boolean isChecked) {
173 if (maybeEnforceRestrictions()) {
174 triggerParentPreferenceCallback(isChecked);
178 // Show toast message if Bluetooth is not allowed in airplane mode
180 !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
181 Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
182 // Reset switch to off
183 mSwitchController.setChecked(false);
184 triggerParentPreferenceCallback(false);
188 mMetricsFeatureProvider.action(mContext, mMetricsEvent, isChecked);
190 if (mLocalAdapter != null) {
191 boolean status = mLocalAdapter.setBluetoothEnabled(isChecked);
192 // If we cannot toggle it ON then reset the UI assets:
193 // a) The switch should be OFF but it should still be togglable (enabled = True)
194 // b) The switch bar should have OFF text.
195 if (isChecked && !status) {
196 mSwitchController.setChecked(false);
197 mSwitchController.setEnabled(true);
198 mSwitchController.updateTitle(false);
199 triggerParentPreferenceCallback(false);
203 mSwitchController.setEnabled(false);
204 triggerParentPreferenceCallback(isChecked);
209 * Sets a callback back that this enabler will trigger in case the preference using the enabler
210 * still needed the callback on the SwitchController (which we now use).
211 * @param listener The listener with a callback to trigger.
213 public void setToggleCallback(SwitchWidgetController.OnSwitchChangeListener listener) {
214 mCallback = listener;
218 * Enforces user restrictions disallowing Bluetooth (or its configuration) if there are any.
220 * @return if there was any user restriction to enforce.
223 boolean maybeEnforceRestrictions() {
224 EnforcedAdmin admin = getEnforcedAdmin(mRestrictionUtils, mContext);
225 mSwitchController.setDisabledByAdmin(admin);
227 mSwitchController.setChecked(false);
228 mSwitchController.setEnabled(false);
230 return admin != null;
233 public static EnforcedAdmin getEnforcedAdmin(RestrictionUtils mRestrictionUtils,
235 EnforcedAdmin admin = mRestrictionUtils.checkIfRestrictionEnforced(
236 mContext, UserManager.DISALLOW_BLUETOOTH);
238 admin = mRestrictionUtils.checkIfRestrictionEnforced(
239 mContext, UserManager.DISALLOW_CONFIG_BLUETOOTH);
244 // This triggers the callback which was manually set for this enabler since the enabler will
245 // take over the switch controller callback
246 private void triggerParentPreferenceCallback(boolean isChecked) {
247 if (mCallback != null) {
248 mCallback.onSwitchToggled(isChecked);