OSDN Git Service

Prevent overlay drawing on top of Bluetooth discovery request dialog
[android-x86/packages-apps-Settings.git] / src / com / android / settings / bluetooth / BluetoothEnabler.java
1 /*
2  * Copyright (C) 2010 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.bluetooth;
18
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;
27
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;
36
37 /**
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.
41  */
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;
51
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;
55
56     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
57         @Override
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);
63         }
64     };
65
66     public BluetoothEnabler(Context context, SwitchWidgetController switchController,
67             MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager,
68             int metricsEvent) {
69         this(context, switchController, metricsFeatureProvider, manager, metricsEvent,
70                 new RestrictionUtils());
71     }
72
73     public BluetoothEnabler(Context context, SwitchWidgetController switchController,
74             MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager,
75             int metricsEvent, RestrictionUtils restrictionUtils) {
76         mContext = context;
77         mMetricsFeatureProvider = metricsFeatureProvider;
78         mSwitchController = switchController;
79         mSwitchController.setListener(this);
80         mValidListener = false;
81         mMetricsEvent = metricsEvent;
82
83         if (manager == null) {
84             // Bluetooth is not supported
85             mLocalAdapter = null;
86             mSwitchController.setEnabled(false);
87         } else {
88             mLocalAdapter = manager.getBluetoothAdapter();
89         }
90         mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
91         mRestrictionUtils = restrictionUtils;
92     }
93
94     public void setupSwitchController() {
95         mSwitchController.setupView();
96     }
97
98     public void teardownSwitchController() {
99         mSwitchController.teardownView();
100     }
101
102     public void resume(Context context) {
103         if (mContext != context) {
104             mContext = context;
105         }
106
107         final boolean restricted = maybeEnforceRestrictions();
108
109         if (mLocalAdapter == null) {
110             mSwitchController.setEnabled(false);
111             return;
112         }
113
114         // Bluetooth state is not sticky, so set it manually
115         if (!restricted) {
116             handleStateChanged(mLocalAdapter.getBluetoothState());
117         }
118
119         mSwitchController.startListening();
120         mContext.registerReceiver(mReceiver, mIntentFilter);
121         mValidListener = true;
122     }
123
124     public void pause() {
125         if (mLocalAdapter == null) {
126             return;
127         }
128         if (mValidListener) {
129             mSwitchController.stopListening();
130             mContext.unregisterReceiver(mReceiver);
131             mValidListener = false;
132         }
133     }
134
135     void handleStateChanged(int state) {
136         switch (state) {
137             case BluetoothAdapter.STATE_TURNING_ON:
138                 mSwitchController.setEnabled(false);
139                 break;
140             case BluetoothAdapter.STATE_ON:
141                 setChecked(true);
142                 mSwitchController.setEnabled(true);
143                 break;
144             case BluetoothAdapter.STATE_TURNING_OFF:
145                 mSwitchController.setEnabled(false);
146                 break;
147             case BluetoothAdapter.STATE_OFF:
148                 setChecked(false);
149                 mSwitchController.setEnabled(true);
150                 break;
151             default:
152                 setChecked(false);
153                 mSwitchController.setEnabled(true);
154         }
155     }
156
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();
163             }
164             mSwitchController.setChecked(isChecked);
165             if (mValidListener) {
166                 mSwitchController.startListening();
167             }
168         }
169     }
170
171     @Override
172     public boolean onSwitchToggled(boolean isChecked) {
173         if (maybeEnforceRestrictions()) {
174             triggerParentPreferenceCallback(isChecked);
175             return true;
176         }
177
178         // Show toast message if Bluetooth is not allowed in airplane mode
179         if (isChecked &&
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);
185             return false;
186         }
187
188         mMetricsFeatureProvider.action(mContext, mMetricsEvent, isChecked);
189
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);
200                 return false;
201             }
202         }
203         mSwitchController.setEnabled(false);
204         triggerParentPreferenceCallback(isChecked);
205         return true;
206     }
207
208     /**
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.
212      */
213     public void setToggleCallback(SwitchWidgetController.OnSwitchChangeListener listener) {
214         mCallback = listener;
215     }
216
217     /**
218      * Enforces user restrictions disallowing Bluetooth (or its configuration) if there are any.
219      *
220      * @return if there was any user restriction to enforce.
221      */
222     @VisibleForTesting
223     boolean maybeEnforceRestrictions() {
224         EnforcedAdmin admin = getEnforcedAdmin(mRestrictionUtils, mContext);
225         mSwitchController.setDisabledByAdmin(admin);
226         if (admin != null) {
227             mSwitchController.setChecked(false);
228             mSwitchController.setEnabled(false);
229         }
230         return admin != null;
231     }
232
233     public static EnforcedAdmin getEnforcedAdmin(RestrictionUtils mRestrictionUtils,
234             Context mContext) {
235         EnforcedAdmin admin = mRestrictionUtils.checkIfRestrictionEnforced(
236                 mContext, UserManager.DISALLOW_BLUETOOTH);
237         if (admin == null) {
238             admin = mRestrictionUtils.checkIfRestrictionEnforced(
239                     mContext, UserManager.DISALLOW_CONFIG_BLUETOOTH);
240         }
241         return admin;
242     }
243
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);
249         }
250     }
251 }