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