The root cause is normally when change the airplane mode, the bluetooth setting UI will not be foreground. No listener is setup for bluetooth setting UI when it is in background. So the onCheckedChanged won't be called and mLocalAdapter.setBluetoothEnabled won't be called. But for manta, airplane mode setting and bluetooth setting UI both will show on the foreground due to bigger screen size. When we turn ariplane mode on, bluetooth manager service will disable bluetooth without changing the persist bluetooth setting. But bluetooth setting UI will listen to the bluetooth state change intent, it will receive bluetooth state turn-off intent then it will call mSwitch.setChecked(false) in handleStateChanged, which cause checked status changed from true to false to trigger the listener (onCheckedChanged) being called. The listener will call mAdapter.disable() which will call mManagerService.disable(true) to change bluetooth persist state to OFF. So when we turn back airplane more to OFF, due to the bluetooth persist state is OFF, we won't turn back bluetooth to ON. Don't need to consider thread synchronization, because everything is running on the main thread. bug 7366814 Change-Id: I138d1904df6cb17c7828295caa51a7d80abf99f2
159 lines
5.5 KiB
Java
159 lines
5.5 KiB
Java
/*
|
|
* 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.provider.Settings;
|
|
import android.widget.CompoundButton;
|
|
import android.widget.Switch;
|
|
import android.widget.Toast;
|
|
|
|
import com.android.settings.R;
|
|
import com.android.settings.WirelessSettings;
|
|
|
|
/**
|
|
* 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 CompoundButton.OnCheckedChangeListener {
|
|
private final Context mContext;
|
|
private Switch mSwitch;
|
|
private boolean mValidListener;
|
|
private final LocalBluetoothAdapter mLocalAdapter;
|
|
private final IntentFilter mIntentFilter;
|
|
|
|
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, Switch switch_) {
|
|
mContext = context;
|
|
mSwitch = switch_;
|
|
mValidListener = false;
|
|
|
|
LocalBluetoothManager manager = LocalBluetoothManager.getInstance(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 resume() {
|
|
if (mLocalAdapter == null) {
|
|
mSwitch.setEnabled(false);
|
|
return;
|
|
}
|
|
|
|
// Bluetooth state is not sticky, so set it manually
|
|
handleStateChanged(mLocalAdapter.getBluetoothState());
|
|
|
|
mContext.registerReceiver(mReceiver, mIntentFilter);
|
|
mSwitch.setOnCheckedChangeListener(this);
|
|
mValidListener = true;
|
|
}
|
|
|
|
public void pause() {
|
|
if (mLocalAdapter == null) {
|
|
return;
|
|
}
|
|
|
|
mContext.unregisterReceiver(mReceiver);
|
|
mSwitch.setOnCheckedChangeListener(null);
|
|
mValidListener = false;
|
|
}
|
|
|
|
public void setSwitch(Switch switch_) {
|
|
if (mSwitch == switch_) return;
|
|
mSwitch.setOnCheckedChangeListener(null);
|
|
mSwitch = switch_;
|
|
mSwitch.setOnCheckedChangeListener(mValidListener ? this : null);
|
|
|
|
int bluetoothState = BluetoothAdapter.STATE_OFF;
|
|
if (mLocalAdapter != null) bluetoothState = mLocalAdapter.getBluetoothState();
|
|
boolean isOn = bluetoothState == BluetoothAdapter.STATE_ON;
|
|
boolean isOff = bluetoothState == BluetoothAdapter.STATE_OFF;
|
|
setChecked(isOn);
|
|
mSwitch.setEnabled(isOn || isOff);
|
|
}
|
|
|
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
// Show toast message if Bluetooth is not allowed in airplane mode
|
|
if (isChecked &&
|
|
!WirelessSettings.isRadioAllowed(mContext, Settings.System.RADIO_BLUETOOTH)) {
|
|
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
|
|
// Reset switch to off
|
|
buttonView.setChecked(false);
|
|
}
|
|
|
|
if (mLocalAdapter != null) {
|
|
mLocalAdapter.setBluetoothEnabled(isChecked);
|
|
}
|
|
mSwitch.setEnabled(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);
|
|
break;
|
|
case BluetoothAdapter.STATE_TURNING_OFF:
|
|
mSwitch.setEnabled(false);
|
|
break;
|
|
case BluetoothAdapter.STATE_OFF:
|
|
setChecked(false);
|
|
mSwitch.setEnabled(true);
|
|
break;
|
|
default:
|
|
setChecked(false);
|
|
mSwitch.setEnabled(true);
|
|
}
|
|
}
|
|
|
|
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) {
|
|
mSwitch.setOnCheckedChangeListener(null);
|
|
}
|
|
mSwitch.setChecked(isChecked);
|
|
if (mValidListener) {
|
|
mSwitch.setOnCheckedChangeListener(this);
|
|
}
|
|
}
|
|
}
|
|
}
|