/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.bluetooth; import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.Message; import android.provider.Settings; import android.util.Log; import android.widget.Switch; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.search.Index; import com.android.settings.widget.SwitchBar; import com.android.settingslib.WirelessUtils; import com.android.settingslib.bluetooth.LocalBluetoothAdapter; import com.android.settingslib.bluetooth.LocalBluetoothManager; /** * BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox * preference. It turns on/off Bluetooth and ensures the summary of the * preference reflects the current state. */ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener { private Context mContext; private Switch mSwitch; private SwitchBar mSwitchBar; private boolean mValidListener; private final LocalBluetoothAdapter mLocalAdapter; private final IntentFilter mIntentFilter; private static final String EVENT_DATA_IS_BT_ON = "is_bluetooth_on"; private static final int EVENT_UPDATE_INDEX = 0; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_UPDATE_INDEX: final boolean isBluetoothOn = msg.getData().getBoolean(EVENT_DATA_IS_BT_ON); Index.getInstance(mContext).updateFromClassNameResource( BluetoothSettings.class.getName(), true, isBluetoothOn); break; } } }; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Broadcast receiver is always running on the UI thread here, // so we don't need consider thread synchronization. int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); handleStateChanged(state); } }; public BluetoothEnabler(Context context, SwitchBar switchBar) { mContext = context; mSwitchBar = switchBar; mSwitch = switchBar.getSwitch(); mValidListener = false; LocalBluetoothManager manager = Utils.getLocalBtManager(context); if (manager == null) { // Bluetooth is not supported mLocalAdapter = null; mSwitch.setEnabled(false); } else { mLocalAdapter = manager.getBluetoothAdapter(); } mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); } public void setupSwitchBar() { mSwitchBar.show(); } public void teardownSwitchBar() { mSwitchBar.hide(); } public void resume(Context context) { if (mLocalAdapter == null) { mSwitch.setEnabled(false); return; } if (mContext != context) { mContext = context; } // Bluetooth state is not sticky, so set it manually handleStateChanged(mLocalAdapter.getBluetoothState()); mSwitchBar.addOnSwitchChangeListener(this); mContext.registerReceiver(mReceiver, mIntentFilter); mValidListener = true; } public void pause() { if (mLocalAdapter == null) { return; } mSwitchBar.removeOnSwitchChangeListener(this); mContext.unregisterReceiver(mReceiver); mValidListener = false; } void handleStateChanged(int state) { switch (state) { case BluetoothAdapter.STATE_TURNING_ON: mSwitch.setEnabled(false); break; case BluetoothAdapter.STATE_ON: setChecked(true); mSwitch.setEnabled(true); updateSearchIndex(true); break; case BluetoothAdapter.STATE_TURNING_OFF: mSwitch.setEnabled(false); break; case BluetoothAdapter.STATE_OFF: setChecked(false); mSwitch.setEnabled(true); updateSearchIndex(false); break; default: setChecked(false); mSwitch.setEnabled(true); updateSearchIndex(false); } } private void setChecked(boolean isChecked) { if (isChecked != mSwitch.isChecked()) { // set listener to null, so onCheckedChanged won't be called // if the checked status on Switch isn't changed by user click if (mValidListener) { mSwitchBar.removeOnSwitchChangeListener(this); } mSwitch.setChecked(isChecked); if (mValidListener) { mSwitchBar.addOnSwitchChangeListener(this); } } } private void updateSearchIndex(boolean isBluetoothOn) { mHandler.removeMessages(EVENT_UPDATE_INDEX); Message msg = new Message(); msg.what = EVENT_UPDATE_INDEX; msg.getData().putBoolean(EVENT_DATA_IS_BT_ON, isBluetoothOn); mHandler.sendMessage(msg); } @Override public void onSwitchChanged(Switch switchView, boolean isChecked) { // Show toast message if Bluetooth is not allowed in airplane mode if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) { Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show(); // Reset switch to off switchView.setChecked(false); } MetricsLogger.action(mContext, MetricsEvent.ACTION_BLUETOOTH_TOGGLE, isChecked); if (mLocalAdapter != null) { boolean status = mLocalAdapter.setBluetoothEnabled(isChecked); // If we cannot toggle it ON then reset the UI assets: // a) The switch should be OFF but it should still be togglable (enabled = True) // b) The switch bar should have OFF text. if (isChecked && !status) { switchView.setChecked(false); mSwitch.setEnabled(true); mSwitchBar.setTextViewLabel(false); return; } } mSwitch.setEnabled(false); } }