1 /* 2 * Copyright (C) 2010 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 android.bluetooth.BluetoothAdapter; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.os.Handler; 25 import android.os.Message; 26 import android.provider.Settings; 27 import android.widget.Switch; 28 import android.widget.Toast; 29 30 import com.android.internal.logging.MetricsLogger; 31 import com.android.settings.R; 32 import com.android.settings.search.Index; 33 import com.android.settings.widget.SwitchBar; 34 import com.android.settingslib.WirelessUtils; 35 import com.android.settingslib.bluetooth.LocalBluetoothAdapter; 36 import com.android.settingslib.bluetooth.LocalBluetoothManager; 37 38 /** 39 * BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox 40 * preference. It turns on/off Bluetooth and ensures the summary of the 41 * preference reflects the current state. 42 */ 43 public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener { 44 private Context mContext; 45 private Switch mSwitch; 46 private SwitchBar mSwitchBar; 47 private boolean mValidListener; 48 private final LocalBluetoothAdapter mLocalAdapter; 49 private final IntentFilter mIntentFilter; 50 51 private static final String EVENT_DATA_IS_BT_ON = "is_bluetooth_on"; 52 private static final int EVENT_UPDATE_INDEX = 0; 53 54 private Handler mHandler = new Handler() { 55 @Override 56 public void handleMessage(Message msg) { 57 switch (msg.what) { 58 case EVENT_UPDATE_INDEX: 59 final boolean isBluetoothOn = msg.getData().getBoolean(EVENT_DATA_IS_BT_ON); 60 Index.getInstance(mContext).updateFromClassNameResource( 61 BluetoothSettings.class.getName(), true, isBluetoothOn); 62 break; 63 } 64 } 65 }; 66 67 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 68 @Override 69 public void onReceive(Context context, Intent intent) { 70 // Broadcast receiver is always running on the UI thread here, 71 // so we don't need consider thread synchronization. 72 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 73 handleStateChanged(state); 74 } 75 }; 76 77 public BluetoothEnabler(Context context, SwitchBar switchBar) { 78 mContext = context; 79 mSwitchBar = switchBar; 80 mSwitch = switchBar.getSwitch(); 81 mValidListener = false; 82 83 LocalBluetoothManager manager = Utils.getLocalBtManager(context); 84 if (manager == null) { 85 // Bluetooth is not supported 86 mLocalAdapter = null; 87 mSwitch.setEnabled(false); 88 } else { 89 mLocalAdapter = manager.getBluetoothAdapter(); 90 } 91 mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 92 } 93 94 public void setupSwitchBar() { 95 mSwitchBar.show(); 96 } 97 98 public void teardownSwitchBar() { 99 mSwitchBar.hide(); 100 } 101 102 public void resume(Context context) { 103 if (mLocalAdapter == null) { 104 mSwitch.setEnabled(false); 105 return; 106 } 107 108 if (mContext != context) { 109 mContext = context; 110 } 111 112 // Bluetooth state is not sticky, so set it manually 113 handleStateChanged(mLocalAdapter.getBluetoothState()); 114 115 mSwitchBar.addOnSwitchChangeListener(this); 116 mContext.registerReceiver(mReceiver, mIntentFilter); 117 mValidListener = true; 118 } 119 120 public void pause() { 121 if (mLocalAdapter == null) { 122 return; 123 } 124 125 mSwitchBar.removeOnSwitchChangeListener(this); 126 mContext.unregisterReceiver(mReceiver); 127 mValidListener = false; 128 } 129 130 void handleStateChanged(int state) { 131 switch (state) { 132 case BluetoothAdapter.STATE_TURNING_ON: 133 mSwitch.setEnabled(false); 134 break; 135 case BluetoothAdapter.STATE_ON: 136 setChecked(true); 137 mSwitch.setEnabled(true); 138 updateSearchIndex(true); 139 break; 140 case BluetoothAdapter.STATE_TURNING_OFF: 141 mSwitch.setEnabled(false); 142 break; 143 case BluetoothAdapter.STATE_OFF: 144 setChecked(false); 145 mSwitch.setEnabled(true); 146 updateSearchIndex(false); 147 break; 148 default: 149 setChecked(false); 150 mSwitch.setEnabled(true); 151 updateSearchIndex(false); 152 } 153 } 154 155 private void setChecked(boolean isChecked) { 156 if (isChecked != mSwitch.isChecked()) { 157 // set listener to null, so onCheckedChanged won't be called 158 // if the checked status on Switch isn't changed by user click 159 if (mValidListener) { 160 mSwitchBar.removeOnSwitchChangeListener(this); 161 } 162 mSwitch.setChecked(isChecked); 163 if (mValidListener) { 164 mSwitchBar.addOnSwitchChangeListener(this); 165 } 166 } 167 } 168 169 private void updateSearchIndex(boolean isBluetoothOn) { 170 mHandler.removeMessages(EVENT_UPDATE_INDEX); 171 172 Message msg = new Message(); 173 msg.what = EVENT_UPDATE_INDEX; 174 msg.getData().putBoolean(EVENT_DATA_IS_BT_ON, isBluetoothOn); 175 mHandler.sendMessage(msg); 176 } 177 178 @Override 179 public void onSwitchChanged(Switch switchView, boolean isChecked) { 180 // Show toast message if Bluetooth is not allowed in airplane mode 181 if (isChecked && 182 !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) { 183 Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show(); 184 // Reset switch to off 185 switchView.setChecked(false); 186 } 187 188 MetricsLogger.action(mContext, MetricsLogger.ACTION_BLUETOOTH_TOGGLE, isChecked); 189 190 if (mLocalAdapter != null) { 191 mLocalAdapter.setBluetoothEnabled(isChecked); 192 } 193 mSwitch.setEnabled(false); 194 } 195 } 196