BluetoothEnabler.java revision 1c4e96864f054f0d3d754d21eb4803fe0df6d89f
1/*
2 * Copyright (C) 2008 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
17package com.android.settings.bluetooth;
18
19import com.android.settings.AirplaneModeEnabler;
20import com.android.settings.R;
21
22import android.bluetooth.BluetoothAdapter;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.preference.Preference;
28import android.preference.CheckBoxPreference;
29import android.provider.Settings;
30import android.text.TextUtils;
31import android.util.Config;
32
33/**
34 * BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox
35 * preference. It is turns on/off Bluetooth and ensures the summary of the
36 * preference reflects the current state.
37 */
38public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
39
40    private static final boolean LOCAL_LOGD = Config.LOGD || false;
41    private static final String TAG = "BluetoothEnabler";
42
43    private final Context mContext;
44    private final CheckBoxPreference mCheckBoxPreference;
45    private final CharSequence mOriginalSummary;
46
47    private final LocalBluetoothManager mLocalManager;
48
49    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
50        @Override
51        public void onReceive(Context context, Intent intent) {
52            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
53            handleStateChanged(state);
54        }
55    };
56
57    public BluetoothEnabler(Context context, CheckBoxPreference checkBoxPreference) {
58        mContext = context;
59        mCheckBoxPreference = checkBoxPreference;
60
61        mOriginalSummary = checkBoxPreference.getSummary();
62        checkBoxPreference.setPersistent(false);
63
64        mLocalManager = LocalBluetoothManager.getInstance(context);
65        if (mLocalManager == null) {
66            // Bluetooth not supported
67            checkBoxPreference.setEnabled(false);
68        }
69    }
70
71    public void resume() {
72        if (mLocalManager == null) {
73            return;
74        }
75
76        int state = mLocalManager.getBluetoothState();
77        // This is the widget enabled state, not the preference toggled state
78        mCheckBoxPreference.setEnabled(state == BluetoothAdapter.STATE_ON ||
79                state == BluetoothAdapter.STATE_OFF);
80        // BT state is not a sticky broadcast, so set it manually
81        handleStateChanged(state);
82
83        mContext.registerReceiver(mReceiver,
84                new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
85        mCheckBoxPreference.setOnPreferenceChangeListener(this);
86    }
87
88    public void pause() {
89        if (mLocalManager == null) {
90            return;
91        }
92
93        mContext.unregisterReceiver(mReceiver);
94        mCheckBoxPreference.setOnPreferenceChangeListener(null);
95    }
96
97    public boolean onPreferenceChange(Preference preference, Object value) {
98        // Turn on/off BT
99        setEnabled((Boolean) value);
100
101        // Don't update UI to opposite state until we're sure
102        return false;
103    }
104
105    private void setEnabled(final boolean enable) {
106        // Disable preference
107        mCheckBoxPreference.setEnabled(false);
108
109        mLocalManager.setBluetoothEnabled(enable);
110    }
111
112    private void handleStateChanged(int state) {
113
114        if (state == BluetoothAdapter.STATE_OFF ||
115                state == BluetoothAdapter.STATE_ON) {
116            mCheckBoxPreference.setChecked(state == BluetoothAdapter.STATE_ON);
117            mCheckBoxPreference.setSummary(state == BluetoothAdapter.STATE_OFF ?
118                                           mOriginalSummary :
119                                           null);
120
121            final boolean hasDependency = !TextUtils.isEmpty(mCheckBoxPreference.getDependency());
122            final boolean bluetoothAllowed = isBluetoothAllowed(mContext);
123
124            // Avoid disabling when dependencies have been manually set,
125            // workaround for framework bug http://b/2053751
126            if (bluetoothAllowed) {
127                mCheckBoxPreference.setEnabled(true);
128            } else if (!hasDependency) {
129                mCheckBoxPreference.setEnabled(false);
130            }
131
132        } else if (state == BluetoothAdapter.STATE_TURNING_ON ||
133                state == BluetoothAdapter.STATE_TURNING_OFF) {
134            mCheckBoxPreference.setSummary(state == BluetoothAdapter.STATE_TURNING_ON
135                    ? R.string.wifi_starting
136                    : R.string.wifi_stopping);
137
138        } else {
139            mCheckBoxPreference.setChecked(false);
140            mCheckBoxPreference.setSummary(R.string.wifi_error);
141            mCheckBoxPreference.setEnabled(true);
142        }
143    }
144
145    private static boolean isBluetoothAllowed(Context context) {
146        // allowed if we are not in airplane mode
147        if (!AirplaneModeEnabler.isAirplaneModeOn(context)) {
148            return true;
149        }
150        // allowed if bluetooth is not in AIRPLANE_MODE_RADIOS
151        String radios = Settings.System.getString(context.getContentResolver(),
152                Settings.System.AIRPLANE_MODE_RADIOS);
153        if (radios == null || !radios.contains(Settings.System.RADIO_BLUETOOTH)) {
154            return true;
155        }
156        // allowed if bluetooth is in AIRPLANE_MODE_TOGGLEABLE_RADIOS
157        radios = Settings.System.getString(context.getContentResolver(),
158                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
159        return (radios != null && radios.contains(Settings.System.RADIO_BLUETOOTH));
160    }
161
162}
163