BluetoothDiscoverableEnabler.java revision f4779354b39353a48d0bec6cc5c71fd73e3f369a
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.R;
20
21import android.bluetooth.BluetoothAdapter;
22import android.bluetooth.BluetoothIntent;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.SharedPreferences;
28import android.os.Handler;
29import android.os.SystemProperties;
30import android.preference.Preference;
31import android.preference.CheckBoxPreference;
32
33/**
34 * BluetoothDiscoverableEnabler is a helper to manage the "Discoverable"
35 * checkbox. It sets/unsets discoverability and keeps track of how much time
36 * until the the discoverability is automatically turned off.
37 */
38public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChangeListener {
39    private static final String TAG = "BluetoothDiscoverableEnabler";
40
41    private static final String SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT =
42            "debug.bt.discoverable_time";
43    private static final int DISCOVERABLE_TIMEOUT = 120;
44
45    private static final String SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP =
46            "discoverable_end_timestamp";
47
48    private final Context mContext;
49    private final Handler mUiHandler;
50    private final CheckBoxPreference mCheckBoxPreference;
51
52    private final LocalBluetoothManager mLocalManager;
53
54    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
55        @Override
56        public void onReceive(Context context, Intent intent) {
57            if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
58                int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
59                        BluetoothAdapter.ERROR);
60                if (mode != BluetoothAdapter.ERROR) {
61                    handleModeChanged(mode);
62                }
63            }
64        }
65    };
66
67    private final Runnable mUpdateCountdownSummaryRunnable = new Runnable() {
68        public void run() {
69            updateCountdownSummary();
70        }
71    };
72
73    public BluetoothDiscoverableEnabler(Context context, CheckBoxPreference checkBoxPreference) {
74        mContext = context;
75        mUiHandler = new Handler();
76        mCheckBoxPreference = checkBoxPreference;
77
78        checkBoxPreference.setPersistent(false);
79
80        mLocalManager = LocalBluetoothManager.getInstance(context);
81        if (mLocalManager == null) {
82            // Bluetooth not supported
83            checkBoxPreference.setEnabled(false);
84        }
85    }
86
87    public void resume() {
88        if (mLocalManager == null) {
89            return;
90        }
91
92        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
93        mContext.registerReceiver(mReceiver, filter);
94        mCheckBoxPreference.setOnPreferenceChangeListener(this);
95
96        handleModeChanged(mLocalManager.getBluetoothAdapter().getScanMode());
97    }
98
99    public void pause() {
100        if (mLocalManager == null) {
101            return;
102        }
103
104        mUiHandler.removeCallbacks(mUpdateCountdownSummaryRunnable);
105        mCheckBoxPreference.setOnPreferenceChangeListener(null);
106        mContext.unregisterReceiver(mReceiver);
107    }
108
109    public boolean onPreferenceChange(Preference preference, Object value) {
110        // Turn on/off BT discoverability
111        setEnabled((Boolean) value);
112
113        return true;
114    }
115
116    private void setEnabled(final boolean enable) {
117        BluetoothAdapter manager = mLocalManager.getBluetoothAdapter();
118
119        if (enable) {
120
121            int timeout = getDiscoverableTimeout();
122            manager.setDiscoverableTimeout(timeout);
123
124            mCheckBoxPreference.setSummaryOn(
125                    mContext.getResources().getString(R.string.bluetooth_is_discoverable, timeout));
126
127            long endTimestamp = System.currentTimeMillis() + timeout * 1000;
128            persistDiscoverableEndTimestamp(endTimestamp);
129
130            manager.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
131        } else {
132            manager.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
133        }
134    }
135
136    private int getDiscoverableTimeout() {
137        int timeout = SystemProperties.getInt(SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT, -1);
138        if (timeout <= 0) {
139            timeout = DISCOVERABLE_TIMEOUT;
140        }
141
142        return timeout;
143    }
144
145    private void persistDiscoverableEndTimestamp(long endTimestamp) {
146        SharedPreferences.Editor editor = mLocalManager.getSharedPreferences().edit();
147        editor.putLong(SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP, endTimestamp);
148        editor.commit();
149    }
150
151    private void handleModeChanged(int mode) {
152        if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
153            mCheckBoxPreference.setChecked(true);
154            updateCountdownSummary();
155
156        } else {
157            mCheckBoxPreference.setChecked(false);
158        }
159    }
160
161    private void updateCountdownSummary() {
162        int mode = mLocalManager.getBluetoothAdapter().getScanMode();
163        if (mode != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
164            return;
165        }
166
167        long currentTimestamp = System.currentTimeMillis();
168        long endTimestamp = mLocalManager.getSharedPreferences().getLong(
169                SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP, 0);
170
171        if (currentTimestamp > endTimestamp) {
172            // We're still in discoverable mode, but maybe there isn't a timeout.
173            mCheckBoxPreference.setSummaryOn(null);
174            return;
175        }
176
177        String formattedTimeLeft = String.valueOf((endTimestamp - currentTimestamp) / 1000);
178
179        mCheckBoxPreference.setSummaryOn(
180                mContext.getResources().getString(R.string.bluetooth_is_discoverable,
181                        formattedTimeLeft));
182
183        synchronized (this) {
184            mUiHandler.removeCallbacks(mUpdateCountdownSummaryRunnable);
185            mUiHandler.postDelayed(mUpdateCountdownSummaryRunnable, 1000);
186        }
187    }
188
189
190}
191