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