BluetoothDiscoverableEnabler.java revision ca564d6bdaa56fba60f499e092e1024fff5d1aba
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.BluetoothError; 23import android.bluetooth.BluetoothIntent; 24import android.content.BroadcastReceiver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.content.SharedPreferences; 29import android.os.Handler; 30import android.os.SystemProperties; 31import android.preference.Preference; 32import android.preference.CheckBoxPreference; 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 42 private static final String SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT = 43 "debug.bt.discoverable_time"; 44 private static final int DISCOVERABLE_TIMEOUT = 120; 45 46 private static final String SHARED_PREFERENCES_KEY_DISCOVERABLE_END_TIMESTAMP = 47 "discoverable_end_timestamp"; 48 49 private final Context mContext; 50 private final Handler mUiHandler; 51 private final CheckBoxPreference mCheckBoxPreference; 52 53 private final LocalBluetoothManager mLocalManager; 54 55 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 56 @Override 57 public void onReceive(Context context, Intent intent) { 58 if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) { 59 int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothError.ERROR); 60 if (mode != BluetoothError.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