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