Move isolatable bluetooth code to SettingsLib
Move the non-ui bluetooth control/tracking code to SettingsLib so that it can be shared with others. Mostly just move classes to frameworks/base/packages/SettingsLib, however a few things had to move around. - Dock handling had to move back to code still in settings - Local preference related code had to be moved back to settings - Added an error flow from SettingsLib to Settings Depends on I69fd888362c6dbb325f6113b32c4b15cc6a23a41 Bug: 19180466 Change-Id: Ie57fe26a27bbb0adc2ef69e042a05c7290c6a52a
This commit is contained in:
@@ -1,214 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.BluetoothA2dp;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.content.Context;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
final class A2dpProfile implements LocalBluetoothProfile {
|
||||
private static final String TAG = "A2dpProfile";
|
||||
private static boolean V = true;
|
||||
|
||||
private BluetoothA2dp mService;
|
||||
private boolean mIsProfileReady;
|
||||
|
||||
private final LocalBluetoothAdapter mLocalAdapter;
|
||||
private final CachedBluetoothDeviceManager mDeviceManager;
|
||||
|
||||
static final ParcelUuid[] SINK_UUIDS = {
|
||||
BluetoothUuid.AudioSink,
|
||||
BluetoothUuid.AdvAudioDist,
|
||||
};
|
||||
|
||||
static final String NAME = "A2DP";
|
||||
private final LocalBluetoothProfileManager mProfileManager;
|
||||
|
||||
// Order of this profile in device profiles list
|
||||
private static final int ORDINAL = 1;
|
||||
|
||||
// These callbacks run on the main thread.
|
||||
private final class A2dpServiceListener
|
||||
implements BluetoothProfile.ServiceListener {
|
||||
|
||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
if (V) Log.d(TAG,"Bluetooth service connected");
|
||||
mService = (BluetoothA2dp) proxy;
|
||||
// We just bound to the service, so refresh the UI for any connected A2DP devices.
|
||||
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||
while (!deviceList.isEmpty()) {
|
||||
BluetoothDevice nextDevice = deviceList.remove(0);
|
||||
CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
|
||||
// we may add a new device here, but generally this should not happen
|
||||
if (device == null) {
|
||||
Log.w(TAG, "A2dpProfile found new device: " + nextDevice);
|
||||
device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
|
||||
}
|
||||
device.onProfileStateChanged(A2dpProfile.this, BluetoothProfile.STATE_CONNECTED);
|
||||
device.refresh();
|
||||
}
|
||||
mIsProfileReady=true;
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(int profile) {
|
||||
if (V) Log.d(TAG,"Bluetooth service disconnected");
|
||||
mIsProfileReady=false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProfileReady() {
|
||||
return mIsProfileReady;
|
||||
}
|
||||
|
||||
A2dpProfile(Context context, LocalBluetoothAdapter adapter,
|
||||
CachedBluetoothDeviceManager deviceManager,
|
||||
LocalBluetoothProfileManager profileManager) {
|
||||
mLocalAdapter = adapter;
|
||||
mDeviceManager = deviceManager;
|
||||
mProfileManager = profileManager;
|
||||
mLocalAdapter.getProfileProxy(context, new A2dpServiceListener(),
|
||||
BluetoothProfile.A2DP);
|
||||
}
|
||||
|
||||
public boolean isConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAutoConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<BluetoothDevice> getConnectedDevices() {
|
||||
if (mService == null) return new ArrayList<BluetoothDevice>(0);
|
||||
return mService.getDevicesMatchingConnectionStates(
|
||||
new int[] {BluetoothProfile.STATE_CONNECTED,
|
||||
BluetoothProfile.STATE_CONNECTING,
|
||||
BluetoothProfile.STATE_DISCONNECTING});
|
||||
}
|
||||
|
||||
public boolean connect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
List<BluetoothDevice> sinks = getConnectedDevices();
|
||||
if (sinks != null) {
|
||||
for (BluetoothDevice sink : sinks) {
|
||||
mService.disconnect(sink);
|
||||
}
|
||||
}
|
||||
return mService.connect(device);
|
||||
}
|
||||
|
||||
public boolean disconnect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
// Downgrade priority as user is disconnecting the headset.
|
||||
if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
|
||||
}
|
||||
return mService.disconnect(device);
|
||||
}
|
||||
|
||||
public int getConnectionStatus(BluetoothDevice device) {
|
||||
if (mService == null) {
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
return mService.getConnectionState(device);
|
||||
}
|
||||
|
||||
public boolean isPreferred(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
|
||||
}
|
||||
|
||||
public int getPreferred(BluetoothDevice device) {
|
||||
if (mService == null) return BluetoothProfile.PRIORITY_OFF;
|
||||
return mService.getPriority(device);
|
||||
}
|
||||
|
||||
public void setPreferred(BluetoothDevice device, boolean preferred) {
|
||||
if (mService == null) return;
|
||||
if (preferred) {
|
||||
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
|
||||
}
|
||||
} else {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
|
||||
}
|
||||
}
|
||||
boolean isA2dpPlaying() {
|
||||
if (mService == null) return false;
|
||||
List<BluetoothDevice> sinks = mService.getConnectedDevices();
|
||||
if (!sinks.isEmpty()) {
|
||||
if (mService.isA2dpPlaying(sinks.get(0))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return ORDINAL;
|
||||
}
|
||||
|
||||
public int getNameResource(BluetoothDevice device) {
|
||||
return R.string.bluetooth_profile_a2dp;
|
||||
}
|
||||
|
||||
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
||||
int state = getConnectionStatus(device);
|
||||
switch (state) {
|
||||
case BluetoothProfile.STATE_DISCONNECTED:
|
||||
return R.string.bluetooth_a2dp_profile_summary_use_for;
|
||||
|
||||
case BluetoothProfile.STATE_CONNECTED:
|
||||
return R.string.bluetooth_a2dp_profile_summary_connected;
|
||||
|
||||
default:
|
||||
return Utils.getConnectionStateSummary(state);
|
||||
}
|
||||
}
|
||||
|
||||
public int getDrawableResource(BluetoothClass btClass) {
|
||||
return R.drawable.ic_bt_headphones_a2dp;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if (V) Log.d(TAG, "finalize()");
|
||||
if (mService != null) {
|
||||
try {
|
||||
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP,
|
||||
mService);
|
||||
mService = null;
|
||||
}catch (Throwable t) {
|
||||
Log.w(TAG, "Error cleaning up A2DP proxy", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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;
|
||||
|
||||
/**
|
||||
* BluetoothCallback provides a callback interface for the settings
|
||||
* UI to receive events from {@link BluetoothEventManager}.
|
||||
*/
|
||||
interface BluetoothCallback {
|
||||
void onBluetoothStateChanged(int bluetoothState);
|
||||
void onScanningStateChanged(boolean started);
|
||||
void onDeviceAdded(CachedBluetoothDevice cachedDevice);
|
||||
void onDeviceDeleted(CachedBluetoothDevice cachedDevice);
|
||||
void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState);
|
||||
}
|
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* BluetoothDeviceFilter contains a static method that returns a
|
||||
* Filter object that returns whether or not the BluetoothDevice
|
||||
* passed to it matches the specified filter type constant from
|
||||
* {@link android.bluetooth.BluetoothDevicePicker}.
|
||||
*/
|
||||
final class BluetoothDeviceFilter {
|
||||
private static final String TAG = "BluetoothDeviceFilter";
|
||||
|
||||
/** The filter interface to external classes. */
|
||||
interface Filter {
|
||||
boolean matches(BluetoothDevice device);
|
||||
}
|
||||
|
||||
/** All filter singleton (referenced directly). */
|
||||
static final Filter ALL_FILTER = new AllFilter();
|
||||
|
||||
/** Bonded devices only filter (referenced directly). */
|
||||
static final Filter BONDED_DEVICE_FILTER = new BondedDeviceFilter();
|
||||
|
||||
/** Unbonded devices only filter (referenced directly). */
|
||||
static final Filter UNBONDED_DEVICE_FILTER = new UnbondedDeviceFilter();
|
||||
|
||||
/** Table of singleton filter objects. */
|
||||
private static final Filter[] FILTERS = {
|
||||
ALL_FILTER, // FILTER_TYPE_ALL
|
||||
new AudioFilter(), // FILTER_TYPE_AUDIO
|
||||
new TransferFilter(), // FILTER_TYPE_TRANSFER
|
||||
new PanuFilter(), // FILTER_TYPE_PANU
|
||||
new NapFilter() // FILTER_TYPE_NAP
|
||||
};
|
||||
|
||||
/** Private constructor. */
|
||||
private BluetoothDeviceFilter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the singleton {@link Filter} object for the specified type,
|
||||
* or {@link #ALL_FILTER} if the type value is out of range.
|
||||
*
|
||||
* @param filterType a constant from BluetoothDevicePicker
|
||||
* @return a singleton object implementing the {@link Filter} interface.
|
||||
*/
|
||||
static Filter getFilter(int filterType) {
|
||||
if (filterType >= 0 && filterType < FILTERS.length) {
|
||||
return FILTERS[filterType];
|
||||
} else {
|
||||
Log.w(TAG, "Invalid filter type " + filterType + " for device picker");
|
||||
return ALL_FILTER;
|
||||
}
|
||||
}
|
||||
|
||||
/** Filter that matches all devices. */
|
||||
private static final class AllFilter implements Filter {
|
||||
public boolean matches(BluetoothDevice device) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Filter that matches only bonded devices. */
|
||||
private static final class BondedDeviceFilter implements Filter {
|
||||
public boolean matches(BluetoothDevice device) {
|
||||
return device.getBondState() == BluetoothDevice.BOND_BONDED;
|
||||
}
|
||||
}
|
||||
|
||||
/** Filter that matches only unbonded devices. */
|
||||
private static final class UnbondedDeviceFilter implements Filter {
|
||||
public boolean matches(BluetoothDevice device) {
|
||||
return device.getBondState() != BluetoothDevice.BOND_BONDED;
|
||||
}
|
||||
}
|
||||
|
||||
/** Parent class of filters based on UUID and/or Bluetooth class. */
|
||||
private abstract static class ClassUuidFilter implements Filter {
|
||||
abstract boolean matches(ParcelUuid[] uuids, BluetoothClass btClass);
|
||||
|
||||
public boolean matches(BluetoothDevice device) {
|
||||
return matches(device.getUuids(), device.getBluetoothClass());
|
||||
}
|
||||
}
|
||||
|
||||
/** Filter that matches devices that support AUDIO profiles. */
|
||||
private static final class AudioFilter extends ClassUuidFilter {
|
||||
@Override
|
||||
boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
|
||||
if (uuids != null) {
|
||||
if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS)) {
|
||||
return true;
|
||||
}
|
||||
if (BluetoothUuid.containsAnyUuid(uuids, HeadsetProfile.UUIDS)) {
|
||||
return true;
|
||||
}
|
||||
} else if (btClass != null) {
|
||||
if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) ||
|
||||
btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Filter that matches devices that support Object Transfer. */
|
||||
private static final class TransferFilter extends ClassUuidFilter {
|
||||
@Override
|
||||
boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
|
||||
if (uuids != null) {
|
||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return btClass != null
|
||||
&& btClass.doesClassMatch(BluetoothClass.PROFILE_OPP);
|
||||
}
|
||||
}
|
||||
|
||||
/** Filter that matches devices that support PAN User (PANU) profile. */
|
||||
private static final class PanuFilter extends ClassUuidFilter {
|
||||
@Override
|
||||
boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
|
||||
if (uuids != null) {
|
||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.PANU)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return btClass != null
|
||||
&& btClass.doesClassMatch(BluetoothClass.PROFILE_PANU);
|
||||
}
|
||||
}
|
||||
|
||||
/** Filter that matches devices that support NAP profile. */
|
||||
private static final class NapFilter extends ClassUuidFilter {
|
||||
@Override
|
||||
boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
|
||||
if (uuids != null) {
|
||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return btClass != null
|
||||
&& btClass.doesClassMatch(BluetoothClass.PROFILE_NAP);
|
||||
}
|
||||
}
|
||||
}
|
@@ -37,6 +37,11 @@ import android.widget.ImageView;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.search.Index;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.bluetooth.A2dpProfile;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.HeadsetProfile;
|
||||
import com.android.settingslib.bluetooth.HidProfile;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@@ -25,12 +25,11 @@ import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemProperties;
|
||||
import android.preference.Preference;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
import com.android.settingslib.bluetooth.BluetoothDiscoverableTimeoutReceiver;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
|
||||
/**
|
||||
* BluetoothDiscoverableEnabler is a helper to manage the "Discoverable"
|
||||
|
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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;
|
||||
|
||||
/* Required to handle timeout notification when phone is suspended */
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
public class BluetoothDiscoverableTimeoutReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = "BluetoothDiscoverableTimeoutReceiver";
|
||||
|
||||
private static final String INTENT_DISCOVERABLE_TIMEOUT =
|
||||
"android.bluetooth.intent.DISCOVERABLE_TIMEOUT";
|
||||
|
||||
static void setDiscoverableAlarm(Context context, long alarmTime) {
|
||||
Log.d(TAG, "setDiscoverableAlarm(): alarmTime = " + alarmTime);
|
||||
|
||||
Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT);
|
||||
intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class);
|
||||
PendingIntent pending = PendingIntent.getBroadcast(
|
||||
context, 0, intent, 0);
|
||||
AlarmManager alarmManager =
|
||||
(AlarmManager) context.getSystemService (Context.ALARM_SERVICE);
|
||||
|
||||
if (pending != null) {
|
||||
// Cancel any previous alarms that do the same thing.
|
||||
alarmManager.cancel(pending);
|
||||
Log.d(TAG, "setDiscoverableAlarm(): cancel prev alarm");
|
||||
}
|
||||
pending = PendingIntent.getBroadcast(
|
||||
context, 0, intent, 0);
|
||||
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, pending);
|
||||
}
|
||||
|
||||
static void cancelDiscoverableAlarm(Context context) {
|
||||
Log.d(TAG, "cancelDiscoverableAlarm(): Enter");
|
||||
|
||||
Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT);
|
||||
intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class);
|
||||
PendingIntent pending = PendingIntent.getBroadcast(
|
||||
context, 0, intent, PendingIntent.FLAG_NO_CREATE);
|
||||
if (pending != null) {
|
||||
// Cancel any previous alarms that do the same thing.
|
||||
AlarmManager alarmManager =
|
||||
(AlarmManager) context.getSystemService (Context.ALARM_SERVICE);
|
||||
|
||||
alarmManager.cancel(pending);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
LocalBluetoothAdapter localBluetoothAdapter = LocalBluetoothAdapter.getInstance();
|
||||
|
||||
if(localBluetoothAdapter != null &&
|
||||
localBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
|
||||
Log.d(TAG, "Disable discoverable...");
|
||||
|
||||
localBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
|
||||
} else {
|
||||
Log.e(TAG, "localBluetoothAdapter is NULL!!");
|
||||
}
|
||||
}
|
||||
};
|
@@ -22,6 +22,8 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
|
||||
/**
|
||||
* BluetoothDiscoveryReceiver updates a timestamp when the
|
||||
* Bluetooth adapter starts or finishes discovery mode. This
|
||||
|
@@ -31,6 +31,8 @@ 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
|
||||
@@ -77,7 +79,7 @@ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener
|
||||
mSwitch = switchBar.getSwitch();
|
||||
mValidListener = false;
|
||||
|
||||
LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context);
|
||||
LocalBluetoothManager manager = Utils.getLocalBtManager(context);
|
||||
if (manager == null) {
|
||||
// Bluetooth is not supported
|
||||
mLocalAdapter = null;
|
||||
|
@@ -1,390 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.android.settings.R;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* BluetoothEventManager receives broadcasts and callbacks from the Bluetooth
|
||||
* API and dispatches the event on the UI thread to the right class in the
|
||||
* Settings.
|
||||
*/
|
||||
final class BluetoothEventManager {
|
||||
private static final String TAG = "BluetoothEventManager";
|
||||
|
||||
private final LocalBluetoothAdapter mLocalAdapter;
|
||||
private final CachedBluetoothDeviceManager mDeviceManager;
|
||||
private LocalBluetoothProfileManager mProfileManager;
|
||||
private final IntentFilter mAdapterIntentFilter, mProfileIntentFilter;
|
||||
private final Map<String, Handler> mHandlerMap;
|
||||
private Context mContext;
|
||||
|
||||
private final Collection<BluetoothCallback> mCallbacks =
|
||||
new ArrayList<BluetoothCallback>();
|
||||
|
||||
interface Handler {
|
||||
void onReceive(Context context, Intent intent, BluetoothDevice device);
|
||||
}
|
||||
|
||||
void addHandler(String action, Handler handler) {
|
||||
mHandlerMap.put(action, handler);
|
||||
mAdapterIntentFilter.addAction(action);
|
||||
}
|
||||
|
||||
void addProfileHandler(String action, Handler handler) {
|
||||
mHandlerMap.put(action, handler);
|
||||
mProfileIntentFilter.addAction(action);
|
||||
}
|
||||
|
||||
// Set profile manager after construction due to circular dependency
|
||||
void setProfileManager(LocalBluetoothProfileManager manager) {
|
||||
mProfileManager = manager;
|
||||
}
|
||||
|
||||
BluetoothEventManager(LocalBluetoothAdapter adapter,
|
||||
CachedBluetoothDeviceManager deviceManager, Context context) {
|
||||
mLocalAdapter = adapter;
|
||||
mDeviceManager = deviceManager;
|
||||
mAdapterIntentFilter = new IntentFilter();
|
||||
mProfileIntentFilter = new IntentFilter();
|
||||
mHandlerMap = new HashMap<String, Handler>();
|
||||
mContext = context;
|
||||
|
||||
// Bluetooth on/off broadcasts
|
||||
addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
|
||||
|
||||
// Discovery broadcasts
|
||||
addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
|
||||
addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
|
||||
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
|
||||
addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
|
||||
addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
|
||||
|
||||
// Pairing broadcasts
|
||||
addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
|
||||
addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());
|
||||
|
||||
// Fine-grained state broadcasts
|
||||
addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
|
||||
addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
|
||||
|
||||
// Dock event broadcasts
|
||||
addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
|
||||
|
||||
mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);
|
||||
}
|
||||
|
||||
void registerProfileIntentReceiver() {
|
||||
mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter);
|
||||
}
|
||||
|
||||
/** Register to start receiving callbacks for Bluetooth events. */
|
||||
void registerCallback(BluetoothCallback callback) {
|
||||
synchronized (mCallbacks) {
|
||||
mCallbacks.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/** Unregister to stop receiving callbacks for Bluetooth events. */
|
||||
void unregisterCallback(BluetoothCallback callback) {
|
||||
synchronized (mCallbacks) {
|
||||
mCallbacks.remove(callback);
|
||||
}
|
||||
}
|
||||
|
||||
// This can't be called from a broadcast receiver where the filter is set in the Manifest.
|
||||
private static String getDockedDeviceAddress(Context context) {
|
||||
// This works only because these broadcast intents are "sticky"
|
||||
Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
|
||||
if (i != null) {
|
||||
int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
|
||||
if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
|
||||
BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
if (device != null) {
|
||||
return device.getAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
BluetoothDevice device = intent
|
||||
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
|
||||
Handler handler = mHandlerMap.get(action);
|
||||
if (handler != null) {
|
||||
handler.onReceive(context, intent, device);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private class AdapterStateChangedHandler implements Handler {
|
||||
public void onReceive(Context context, Intent intent,
|
||||
BluetoothDevice device) {
|
||||
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
|
||||
BluetoothAdapter.ERROR);
|
||||
// update local profiles and get paired devices
|
||||
mLocalAdapter.setBluetoothStateInt(state);
|
||||
// send callback to update UI and possibly start scanning
|
||||
synchronized (mCallbacks) {
|
||||
for (BluetoothCallback callback : mCallbacks) {
|
||||
callback.onBluetoothStateChanged(state);
|
||||
}
|
||||
}
|
||||
// Inform CachedDeviceManager that the adapter state has changed
|
||||
mDeviceManager.onBluetoothStateChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
private class ScanningStateChangedHandler implements Handler {
|
||||
private final boolean mStarted;
|
||||
|
||||
ScanningStateChangedHandler(boolean started) {
|
||||
mStarted = started;
|
||||
}
|
||||
public void onReceive(Context context, Intent intent,
|
||||
BluetoothDevice device) {
|
||||
synchronized (mCallbacks) {
|
||||
for (BluetoothCallback callback : mCallbacks) {
|
||||
callback.onScanningStateChanged(mStarted);
|
||||
}
|
||||
}
|
||||
mDeviceManager.onScanningStateChanged(mStarted);
|
||||
LocalBluetoothPreferences.persistDiscoveringTimestamp(context);
|
||||
}
|
||||
}
|
||||
|
||||
private class DeviceFoundHandler implements Handler {
|
||||
public void onReceive(Context context, Intent intent,
|
||||
BluetoothDevice device) {
|
||||
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
|
||||
BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
|
||||
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
|
||||
// TODO Pick up UUID. They should be available for 2.1 devices.
|
||||
// Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
|
||||
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
|
||||
if (cachedDevice == null) {
|
||||
cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
|
||||
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
|
||||
+ cachedDevice);
|
||||
// callback to UI to create Preference for new device
|
||||
dispatchDeviceAdded(cachedDevice);
|
||||
}
|
||||
cachedDevice.setRssi(rssi);
|
||||
cachedDevice.setBtClass(btClass);
|
||||
cachedDevice.setNewName(name);
|
||||
cachedDevice.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
|
||||
synchronized (mCallbacks) {
|
||||
for (BluetoothCallback callback : mCallbacks) {
|
||||
callback.onDeviceAdded(cachedDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DeviceDisappearedHandler implements Handler {
|
||||
public void onReceive(Context context, Intent intent,
|
||||
BluetoothDevice device) {
|
||||
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
|
||||
if (cachedDevice == null) {
|
||||
Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device);
|
||||
return;
|
||||
}
|
||||
if (CachedBluetoothDeviceManager.onDeviceDisappeared(cachedDevice)) {
|
||||
synchronized (mCallbacks) {
|
||||
for (BluetoothCallback callback : mCallbacks) {
|
||||
callback.onDeviceDeleted(cachedDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class NameChangedHandler implements Handler {
|
||||
public void onReceive(Context context, Intent intent,
|
||||
BluetoothDevice device) {
|
||||
mDeviceManager.onDeviceNameUpdated(device);
|
||||
}
|
||||
}
|
||||
|
||||
private class BondStateChangedHandler implements Handler {
|
||||
public void onReceive(Context context, Intent intent,
|
||||
BluetoothDevice device) {
|
||||
if (device == null) {
|
||||
Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE");
|
||||
return;
|
||||
}
|
||||
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
|
||||
BluetoothDevice.ERROR);
|
||||
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
|
||||
if (cachedDevice == null) {
|
||||
Log.w(TAG, "CachedBluetoothDevice for device " + device +
|
||||
" not found, calling readPairedDevices().");
|
||||
if (!readPairedDevices()) {
|
||||
Log.e(TAG, "Got bonding state changed for " + device +
|
||||
", but we have no record of that device.");
|
||||
return;
|
||||
}
|
||||
cachedDevice = mDeviceManager.findDevice(device);
|
||||
if (cachedDevice == null) {
|
||||
Log.e(TAG, "Got bonding state changed for " + device +
|
||||
", but device not added in cache.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mCallbacks) {
|
||||
for (BluetoothCallback callback : mCallbacks) {
|
||||
callback.onDeviceBondStateChanged(cachedDevice, bondState);
|
||||
}
|
||||
}
|
||||
cachedDevice.onBondingStateChanged(bondState);
|
||||
|
||||
if (bondState == BluetoothDevice.BOND_NONE) {
|
||||
if (device.isBluetoothDock()) {
|
||||
// After a dock is unpaired, we will forget the settings
|
||||
LocalBluetoothPreferences
|
||||
.removeDockAutoConnectSetting(context, device.getAddress());
|
||||
|
||||
// if the device is undocked, remove it from the list as well
|
||||
if (!device.getAddress().equals(getDockedDeviceAddress(context))) {
|
||||
cachedDevice.setVisible(false);
|
||||
}
|
||||
}
|
||||
int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
|
||||
BluetoothDevice.ERROR);
|
||||
|
||||
showUnbondMessage(context, cachedDevice.getName(), reason);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we have reached the unbonded state.
|
||||
*
|
||||
* @param reason one of the error reasons from
|
||||
* BluetoothDevice.UNBOND_REASON_*
|
||||
*/
|
||||
private void showUnbondMessage(Context context, String name, int reason) {
|
||||
int errorMsg;
|
||||
|
||||
switch(reason) {
|
||||
case BluetoothDevice.UNBOND_REASON_AUTH_FAILED:
|
||||
errorMsg = R.string.bluetooth_pairing_pin_error_message;
|
||||
break;
|
||||
case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED:
|
||||
errorMsg = R.string.bluetooth_pairing_rejected_error_message;
|
||||
break;
|
||||
case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN:
|
||||
errorMsg = R.string.bluetooth_pairing_device_down_error_message;
|
||||
break;
|
||||
case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS:
|
||||
case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT:
|
||||
case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS:
|
||||
case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED:
|
||||
errorMsg = R.string.bluetooth_pairing_error_message;
|
||||
break;
|
||||
default:
|
||||
Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason);
|
||||
return;
|
||||
}
|
||||
Utils.showError(context, name, errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassChangedHandler implements Handler {
|
||||
public void onReceive(Context context, Intent intent,
|
||||
BluetoothDevice device) {
|
||||
mDeviceManager.onBtClassChanged(device);
|
||||
}
|
||||
}
|
||||
|
||||
private class UuidChangedHandler implements Handler {
|
||||
public void onReceive(Context context, Intent intent,
|
||||
BluetoothDevice device) {
|
||||
mDeviceManager.onUuidChanged(device);
|
||||
}
|
||||
}
|
||||
|
||||
private class PairingCancelHandler implements Handler {
|
||||
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
|
||||
if (device == null) {
|
||||
Log.e(TAG, "ACTION_PAIRING_CANCEL with no EXTRA_DEVICE");
|
||||
return;
|
||||
}
|
||||
int errorMsg = R.string.bluetooth_pairing_error_message;
|
||||
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
|
||||
Utils.showError(context, cachedDevice.getName(), errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
private class DockEventHandler implements Handler {
|
||||
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
|
||||
// Remove if unpair device upon undocking
|
||||
int anythingButUnDocked = Intent.EXTRA_DOCK_STATE_UNDOCKED + 1;
|
||||
int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, anythingButUnDocked);
|
||||
if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
|
||||
if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) {
|
||||
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
|
||||
if (cachedDevice != null) {
|
||||
cachedDevice.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean readPairedDevices() {
|
||||
Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices();
|
||||
if (bondedDevices == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean deviceAdded = false;
|
||||
for (BluetoothDevice device : bondedDevices) {
|
||||
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
|
||||
if (cachedDevice == null) {
|
||||
cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
|
||||
dispatchDeviceAdded(cachedDevice);
|
||||
deviceAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
return deviceAdded;
|
||||
}
|
||||
}
|
@@ -40,6 +40,8 @@ import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
/**
|
||||
* Dialog fragment for renaming the local Bluetooth device.
|
||||
@@ -80,7 +82,7 @@ public final class BluetoothNameDialogFragment extends DialogFragment implements
|
||||
};
|
||||
|
||||
public BluetoothNameDialogFragment() {
|
||||
LocalBluetoothManager localManager = LocalBluetoothManager.getInstance(getActivity());
|
||||
LocalBluetoothManager localManager = Utils.getLocalBtManager(getActivity());
|
||||
mLocalAdapter = localManager.getBluetoothAdapter();
|
||||
}
|
||||
|
||||
|
@@ -43,6 +43,9 @@ import android.widget.TextView;
|
||||
import com.android.internal.app.AlertActivity;
|
||||
import com.android.internal.app.AlertController;
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import java.util.Locale;
|
||||
@@ -103,7 +106,7 @@ public final class BluetoothPairingDialog extends AlertActivity implements
|
||||
return;
|
||||
}
|
||||
|
||||
mBluetoothManager = LocalBluetoothManager.getInstance(this);
|
||||
mBluetoothManager = Utils.getLocalBtManager(this);
|
||||
if (mBluetoothManager == null) {
|
||||
Log.e(TAG, "Error: BluetoothAdapter not supported by system");
|
||||
finish();
|
||||
|
@@ -31,8 +31,10 @@ import android.widget.Button;
|
||||
|
||||
import com.android.internal.app.AlertActivity;
|
||||
import com.android.internal.app.AlertController;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
/**
|
||||
* BluetoothPermissionActivity shows a dialog for accepting incoming
|
||||
@@ -192,7 +194,7 @@ public class BluetoothPermissionActivity extends AlertActivity implements
|
||||
|
||||
boolean always = true;
|
||||
if (mRequestType == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS) {
|
||||
LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(this);
|
||||
LocalBluetoothManager bluetoothManager = Utils.getLocalBtManager(this);
|
||||
CachedBluetoothDeviceManager cachedDeviceManager =
|
||||
bluetoothManager.getCachedDeviceManager();
|
||||
CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice);
|
||||
|
@@ -28,6 +28,9 @@ import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
/**
|
||||
* BluetoothPermissionRequest is a receiver to receive Bluetooth connection
|
||||
@@ -200,7 +203,7 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver {
|
||||
return processed;
|
||||
}
|
||||
|
||||
LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(mContext);
|
||||
LocalBluetoothManager bluetoothManager = Utils.getLocalBtManager(mContext);
|
||||
CachedBluetoothDeviceManager cachedDeviceManager =
|
||||
bluetoothManager.getCachedDeviceManager();
|
||||
CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice);
|
||||
|
@@ -28,12 +28,9 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceCategory;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceGroup;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.util.Log;
|
||||
@@ -44,17 +41,18 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.Index;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settings.widget.SwitchBar;
|
||||
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -506,7 +504,7 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem
|
||||
result.add(data);
|
||||
|
||||
// Add cached paired BT devices
|
||||
LocalBluetoothManager lbtm = LocalBluetoothManager.getInstance(context);
|
||||
LocalBluetoothManager lbtm = Utils.getLocalBtManager(context);
|
||||
// LocalBluetoothManager.getInstance can return null if the device does not
|
||||
// support bluetooth (e.g. the emulator).
|
||||
if (lbtm != null) {
|
||||
|
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.InputFilter;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.android.internal.app.AlertController;
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* Dialog fragment for setting the discoverability timeout.
|
||||
*/
|
||||
public final class BluetoothVisibilityTimeoutFragment extends DialogFragment
|
||||
implements DialogInterface.OnClickListener {
|
||||
|
||||
private final BluetoothDiscoverableEnabler mDiscoverableEnabler;
|
||||
|
||||
public BluetoothVisibilityTimeoutFragment() {
|
||||
mDiscoverableEnabler = LocalBluetoothManager.getInstance(getActivity())
|
||||
.getDiscoverableEnabler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setTitle(R.string.bluetooth_visibility_timeout)
|
||||
.setSingleChoiceItems(R.array.bluetooth_visibility_timeout_entries,
|
||||
mDiscoverableEnabler.getDiscoverableTimeoutIndex(), this)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
mDiscoverableEnabler.setDiscoverableTimeout(which);
|
||||
dismiss();
|
||||
}
|
||||
}
|
@@ -1,787 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* CachedBluetoothDevice represents a remote Bluetooth device. It contains
|
||||
* attributes of the device (such as the address, name, RSSI, etc.) and
|
||||
* functionality that can be performed on the device (connect, pair, disconnect,
|
||||
* etc.).
|
||||
*/
|
||||
final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
|
||||
private static final String TAG = "CachedBluetoothDevice";
|
||||
private static final boolean DEBUG = Utils.V;
|
||||
|
||||
private final Context mContext;
|
||||
private final LocalBluetoothAdapter mLocalAdapter;
|
||||
private final LocalBluetoothProfileManager mProfileManager;
|
||||
private final BluetoothDevice mDevice;
|
||||
private String mName;
|
||||
private short mRssi;
|
||||
private BluetoothClass mBtClass;
|
||||
private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState;
|
||||
|
||||
private final List<LocalBluetoothProfile> mProfiles =
|
||||
new ArrayList<LocalBluetoothProfile>();
|
||||
|
||||
// List of profiles that were previously in mProfiles, but have been removed
|
||||
private final List<LocalBluetoothProfile> mRemovedProfiles =
|
||||
new ArrayList<LocalBluetoothProfile>();
|
||||
|
||||
// Device supports PANU but not NAP: remove PanProfile after device disconnects from NAP
|
||||
private boolean mLocalNapRoleConnected;
|
||||
|
||||
private boolean mVisible;
|
||||
|
||||
private int mPhonebookPermissionChoice;
|
||||
|
||||
private int mMessagePermissionChoice;
|
||||
|
||||
private int mMessageRejectionCount;
|
||||
|
||||
private final Collection<Callback> mCallbacks = new ArrayList<Callback>();
|
||||
|
||||
// Following constants indicate the user's choices of Phone book/message access settings
|
||||
// User hasn't made any choice or settings app has wiped out the memory
|
||||
public final static int ACCESS_UNKNOWN = 0;
|
||||
// User has accepted the connection and let Settings app remember the decision
|
||||
public final static int ACCESS_ALLOWED = 1;
|
||||
// User has rejected the connection and let Settings app remember the decision
|
||||
public final static int ACCESS_REJECTED = 2;
|
||||
|
||||
// How many times user should reject the connection to make the choice persist.
|
||||
private final static int MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST = 2;
|
||||
|
||||
private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject";
|
||||
|
||||
/**
|
||||
* When we connect to multiple profiles, we only want to display a single
|
||||
* error even if they all fail. This tracks that state.
|
||||
*/
|
||||
private boolean mIsConnectingErrorPossible;
|
||||
|
||||
/**
|
||||
* Last time a bt profile auto-connect was attempted.
|
||||
* If an ACTION_UUID intent comes in within
|
||||
* MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
|
||||
* again with the new UUIDs
|
||||
*/
|
||||
private long mConnectAttempted;
|
||||
|
||||
// See mConnectAttempted
|
||||
private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
|
||||
|
||||
/** Auto-connect after pairing only if locally initiated. */
|
||||
private boolean mConnectAfterPairing;
|
||||
|
||||
/**
|
||||
* Describes the current device and profile for logging.
|
||||
*
|
||||
* @param profile Profile to describe
|
||||
* @return Description of the device and profile
|
||||
*/
|
||||
private String describe(LocalBluetoothProfile profile) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Address:").append(mDevice);
|
||||
if (profile != null) {
|
||||
sb.append(" Profile:").append(profile);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
|
||||
if (Utils.D) {
|
||||
Log.d(TAG, "onProfileStateChanged: profile " + profile +
|
||||
" newProfileState " + newProfileState);
|
||||
}
|
||||
if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF)
|
||||
{
|
||||
if (Utils.D) Log.d(TAG, " BT Turninig Off...Profile conn state change ignored...");
|
||||
return;
|
||||
}
|
||||
mProfileConnectionState.put(profile, newProfileState);
|
||||
if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
|
||||
if (profile instanceof MapProfile) {
|
||||
profile.setPreferred(mDevice, true);
|
||||
} else if (!mProfiles.contains(profile)) {
|
||||
mRemovedProfiles.remove(profile);
|
||||
mProfiles.add(profile);
|
||||
if (profile instanceof PanProfile &&
|
||||
((PanProfile) profile).isLocalRoleNap(mDevice)) {
|
||||
// Device doesn't support NAP, so remove PanProfile on disconnect
|
||||
mLocalNapRoleConnected = true;
|
||||
}
|
||||
}
|
||||
} else if (profile instanceof MapProfile &&
|
||||
newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
profile.setPreferred(mDevice, false);
|
||||
} else if (mLocalNapRoleConnected && profile instanceof PanProfile &&
|
||||
((PanProfile) profile).isLocalRoleNap(mDevice) &&
|
||||
newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
Log.d(TAG, "Removing PanProfile from device after NAP disconnect");
|
||||
mProfiles.remove(profile);
|
||||
mRemovedProfiles.add(profile);
|
||||
mLocalNapRoleConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
CachedBluetoothDevice(Context context,
|
||||
LocalBluetoothAdapter adapter,
|
||||
LocalBluetoothProfileManager profileManager,
|
||||
BluetoothDevice device) {
|
||||
mContext = context;
|
||||
mLocalAdapter = adapter;
|
||||
mProfileManager = profileManager;
|
||||
mDevice = device;
|
||||
mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
|
||||
fillData();
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
for (LocalBluetoothProfile profile : mProfiles) {
|
||||
disconnect(profile);
|
||||
}
|
||||
// Disconnect PBAP server in case its connected
|
||||
// This is to ensure all the profiles are disconnected as some CK/Hs do not
|
||||
// disconnect PBAP connection when HF connection is brought down
|
||||
PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
|
||||
if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED)
|
||||
{
|
||||
PbapProfile.disconnect(mDevice);
|
||||
}
|
||||
}
|
||||
|
||||
void disconnect(LocalBluetoothProfile profile) {
|
||||
if (profile.disconnect(mDevice)) {
|
||||
if (Utils.D) {
|
||||
Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void connect(boolean connectAllProfiles) {
|
||||
if (!ensurePaired()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mConnectAttempted = SystemClock.elapsedRealtime();
|
||||
connectWithoutResettingTimer(connectAllProfiles);
|
||||
}
|
||||
|
||||
void onBondingDockConnect() {
|
||||
// Attempt to connect if UUIDs are available. Otherwise,
|
||||
// we will connect when the ACTION_UUID intent arrives.
|
||||
connect(false);
|
||||
}
|
||||
|
||||
private void connectWithoutResettingTimer(boolean connectAllProfiles) {
|
||||
// Try to initialize the profiles if they were not.
|
||||
if (mProfiles.isEmpty()) {
|
||||
// if mProfiles is empty, then do not invoke updateProfiles. This causes a race
|
||||
// condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated
|
||||
// from bluetooth stack but ACTION.uuid is not sent yet.
|
||||
// Eventually ACTION.uuid will be received which shall trigger the connection of the
|
||||
// various profiles
|
||||
// If UUIDs are not available yet, connect will be happen
|
||||
// upon arrival of the ACTION_UUID intent.
|
||||
Log.d(TAG, "No profiles. Maybe we will connect later");
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the only-show-one-error-dialog tracking variable
|
||||
mIsConnectingErrorPossible = true;
|
||||
|
||||
int preferredProfiles = 0;
|
||||
for (LocalBluetoothProfile profile : mProfiles) {
|
||||
if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
|
||||
if (profile.isPreferred(mDevice)) {
|
||||
++preferredProfiles;
|
||||
connectInt(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
|
||||
|
||||
if (preferredProfiles == 0) {
|
||||
connectAutoConnectableProfiles();
|
||||
}
|
||||
}
|
||||
|
||||
private void connectAutoConnectableProfiles() {
|
||||
if (!ensurePaired()) {
|
||||
return;
|
||||
}
|
||||
// Reset the only-show-one-error-dialog tracking variable
|
||||
mIsConnectingErrorPossible = true;
|
||||
|
||||
for (LocalBluetoothProfile profile : mProfiles) {
|
||||
if (profile.isAutoConnectable()) {
|
||||
profile.setPreferred(mDevice, true);
|
||||
connectInt(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect this device to the specified profile.
|
||||
*
|
||||
* @param profile the profile to use with the remote device
|
||||
*/
|
||||
void connectProfile(LocalBluetoothProfile profile) {
|
||||
mConnectAttempted = SystemClock.elapsedRealtime();
|
||||
// Reset the only-show-one-error-dialog tracking variable
|
||||
mIsConnectingErrorPossible = true;
|
||||
connectInt(profile);
|
||||
// Refresh the UI based on profile.connect() call
|
||||
refresh();
|
||||
}
|
||||
|
||||
synchronized void connectInt(LocalBluetoothProfile profile) {
|
||||
if (!ensurePaired()) {
|
||||
return;
|
||||
}
|
||||
if (profile.connect(mDevice)) {
|
||||
if (Utils.D) {
|
||||
Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
|
||||
}
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
|
||||
}
|
||||
|
||||
private boolean ensurePaired() {
|
||||
if (getBondState() == BluetoothDevice.BOND_NONE) {
|
||||
startPairing();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean startPairing() {
|
||||
// Pairing is unreliable while scanning, so cancel discovery
|
||||
if (mLocalAdapter.isDiscovering()) {
|
||||
mLocalAdapter.cancelDiscovery();
|
||||
}
|
||||
|
||||
if (!mDevice.createBond()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mConnectAfterPairing = true; // auto-connect after pairing
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if user initiated pairing on this device. The message text is
|
||||
* slightly different for local vs. remote initiated pairing dialogs.
|
||||
*/
|
||||
boolean isUserInitiatedPairing() {
|
||||
return mConnectAfterPairing;
|
||||
}
|
||||
|
||||
void unpair() {
|
||||
int state = getBondState();
|
||||
|
||||
if (state == BluetoothDevice.BOND_BONDING) {
|
||||
mDevice.cancelBondProcess();
|
||||
}
|
||||
|
||||
if (state != BluetoothDevice.BOND_NONE) {
|
||||
final BluetoothDevice dev = mDevice;
|
||||
if (dev != null) {
|
||||
final boolean successful = dev.removeBond();
|
||||
if (successful) {
|
||||
if (Utils.D) {
|
||||
Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
|
||||
}
|
||||
} else if (Utils.V) {
|
||||
Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
|
||||
describe(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getProfileConnectionState(LocalBluetoothProfile profile) {
|
||||
if (mProfileConnectionState == null ||
|
||||
mProfileConnectionState.get(profile) == null) {
|
||||
// If cache is empty make the binder call to get the state
|
||||
int state = profile.getConnectionStatus(mDevice);
|
||||
mProfileConnectionState.put(profile, state);
|
||||
}
|
||||
return mProfileConnectionState.get(profile);
|
||||
}
|
||||
|
||||
public void clearProfileConnectionState ()
|
||||
{
|
||||
if (Utils.D) {
|
||||
Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName());
|
||||
}
|
||||
for (LocalBluetoothProfile profile :getProfiles()) {
|
||||
mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do any of these need to run async on a background thread?
|
||||
private void fillData() {
|
||||
fetchName();
|
||||
fetchBtClass();
|
||||
updateProfiles();
|
||||
migratePhonebookPermissionChoice();
|
||||
migrateMessagePermissionChoice();
|
||||
fetchMessageRejectionCount();
|
||||
|
||||
mVisible = false;
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
|
||||
BluetoothDevice getDevice() {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate name from BluetoothDevice.ACTION_FOUND intent
|
||||
*/
|
||||
void setNewName(String name) {
|
||||
if (mName == null) {
|
||||
mName = name;
|
||||
if (mName == null || TextUtils.isEmpty(mName)) {
|
||||
mName = mDevice.getAddress();
|
||||
}
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* user changes the device name
|
||||
*/
|
||||
void setName(String name) {
|
||||
if (!mName.equals(name)) {
|
||||
mName = name;
|
||||
mDevice.setAlias(name);
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void refreshName() {
|
||||
fetchName();
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
|
||||
private void fetchName() {
|
||||
mName = mDevice.getAliasName();
|
||||
|
||||
if (TextUtils.isEmpty(mName)) {
|
||||
mName = mDevice.getAddress();
|
||||
if (DEBUG) Log.d(TAG, "Device has no name (yet), use address: " + mName);
|
||||
}
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
|
||||
boolean isVisible() {
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
void setVisible(boolean visible) {
|
||||
if (mVisible != visible) {
|
||||
mVisible = visible;
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int getBondState() {
|
||||
return mDevice.getBondState();
|
||||
}
|
||||
|
||||
void setRssi(short rssi) {
|
||||
if (mRssi != rssi) {
|
||||
mRssi = rssi;
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we are connected to this device (any profile counts).
|
||||
*
|
||||
* @return Whether it is connected.
|
||||
*/
|
||||
boolean isConnected() {
|
||||
for (LocalBluetoothProfile profile : mProfiles) {
|
||||
int status = getProfileConnectionState(profile);
|
||||
if (status == BluetoothProfile.STATE_CONNECTED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isConnectedProfile(LocalBluetoothProfile profile) {
|
||||
int status = getProfileConnectionState(profile);
|
||||
return status == BluetoothProfile.STATE_CONNECTED;
|
||||
|
||||
}
|
||||
|
||||
boolean isBusy() {
|
||||
for (LocalBluetoothProfile profile : mProfiles) {
|
||||
int status = getProfileConnectionState(profile);
|
||||
if (status == BluetoothProfile.STATE_CONNECTING
|
||||
|| status == BluetoothProfile.STATE_DISCONNECTING) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return getBondState() == BluetoothDevice.BOND_BONDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a new value for the cached BT class.
|
||||
*/
|
||||
private void fetchBtClass() {
|
||||
mBtClass = mDevice.getBluetoothClass();
|
||||
}
|
||||
|
||||
private boolean updateProfiles() {
|
||||
ParcelUuid[] uuids = mDevice.getUuids();
|
||||
if (uuids == null) return false;
|
||||
|
||||
ParcelUuid[] localUuids = mLocalAdapter.getUuids();
|
||||
if (localUuids == null) return false;
|
||||
|
||||
/**
|
||||
* Now we know if the device supports PBAP, update permissions...
|
||||
*/
|
||||
processPhonebookAccess();
|
||||
|
||||
mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles,
|
||||
mLocalNapRoleConnected, mDevice);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.e(TAG, "updating profiles for " + mDevice.getAliasName());
|
||||
BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
|
||||
|
||||
if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
|
||||
Log.v(TAG, "UUID:");
|
||||
for (ParcelUuid uuid : uuids) {
|
||||
Log.v(TAG, " " + uuid);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the UI for the BT class, including fetching the latest value
|
||||
* for the class.
|
||||
*/
|
||||
void refreshBtClass() {
|
||||
fetchBtClass();
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the UI when framework alerts us of a UUID change.
|
||||
*/
|
||||
void onUuidChanged() {
|
||||
updateProfiles();
|
||||
|
||||
if (DEBUG) {
|
||||
Log.e(TAG, "onUuidChanged: Time since last connect"
|
||||
+ (SystemClock.elapsedRealtime() - mConnectAttempted));
|
||||
}
|
||||
|
||||
/*
|
||||
* If a connect was attempted earlier without any UUID, we will do the
|
||||
* connect now.
|
||||
*/
|
||||
if (!mProfiles.isEmpty()
|
||||
&& (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
|
||||
.elapsedRealtime()) {
|
||||
connectWithoutResettingTimer(false);
|
||||
}
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
|
||||
void onBondingStateChanged(int bondState) {
|
||||
if (bondState == BluetoothDevice.BOND_NONE) {
|
||||
mProfiles.clear();
|
||||
mConnectAfterPairing = false; // cancel auto-connect
|
||||
setPhonebookPermissionChoice(ACCESS_UNKNOWN);
|
||||
setMessagePermissionChoice(ACCESS_UNKNOWN);
|
||||
mMessageRejectionCount = 0;
|
||||
saveMessageRejectionCount();
|
||||
}
|
||||
|
||||
refresh();
|
||||
|
||||
if (bondState == BluetoothDevice.BOND_BONDED) {
|
||||
if (mDevice.isBluetoothDock()) {
|
||||
onBondingDockConnect();
|
||||
} else if (mConnectAfterPairing) {
|
||||
connect(false);
|
||||
}
|
||||
mConnectAfterPairing = false;
|
||||
}
|
||||
}
|
||||
|
||||
void setBtClass(BluetoothClass btClass) {
|
||||
if (btClass != null && mBtClass != btClass) {
|
||||
mBtClass = btClass;
|
||||
dispatchAttributesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
BluetoothClass getBtClass() {
|
||||
return mBtClass;
|
||||
}
|
||||
|
||||
List<LocalBluetoothProfile> getProfiles() {
|
||||
return Collections.unmodifiableList(mProfiles);
|
||||
}
|
||||
|
||||
List<LocalBluetoothProfile> getConnectableProfiles() {
|
||||
List<LocalBluetoothProfile> connectableProfiles =
|
||||
new ArrayList<LocalBluetoothProfile>();
|
||||
for (LocalBluetoothProfile profile : mProfiles) {
|
||||
if (profile.isConnectable()) {
|
||||
connectableProfiles.add(profile);
|
||||
}
|
||||
}
|
||||
return connectableProfiles;
|
||||
}
|
||||
|
||||
List<LocalBluetoothProfile> getRemovedProfiles() {
|
||||
return mRemovedProfiles;
|
||||
}
|
||||
|
||||
void registerCallback(Callback callback) {
|
||||
synchronized (mCallbacks) {
|
||||
mCallbacks.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void unregisterCallback(Callback callback) {
|
||||
synchronized (mCallbacks) {
|
||||
mCallbacks.remove(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchAttributesChanged() {
|
||||
synchronized (mCallbacks) {
|
||||
for (Callback callback : mCallbacks) {
|
||||
callback.onDeviceAttributesChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mDevice.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ((o == null) || !(o instanceof CachedBluetoothDevice)) {
|
||||
return false;
|
||||
}
|
||||
return mDevice.equals(((CachedBluetoothDevice) o).mDevice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mDevice.getAddress().hashCode();
|
||||
}
|
||||
|
||||
// This comparison uses non-final fields so the sort order may change
|
||||
// when device attributes change (such as bonding state). Settings
|
||||
// will completely refresh the device list when this happens.
|
||||
public int compareTo(CachedBluetoothDevice another) {
|
||||
// Connected above not connected
|
||||
int comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
|
||||
if (comparison != 0) return comparison;
|
||||
|
||||
// Paired above not paired
|
||||
comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) -
|
||||
(getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
|
||||
if (comparison != 0) return comparison;
|
||||
|
||||
// Visible above not visible
|
||||
comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0);
|
||||
if (comparison != 0) return comparison;
|
||||
|
||||
// Stronger signal above weaker signal
|
||||
comparison = another.mRssi - mRssi;
|
||||
if (comparison != 0) return comparison;
|
||||
|
||||
// Fallback on name
|
||||
return mName.compareTo(another.mName);
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onDeviceAttributesChanged();
|
||||
}
|
||||
|
||||
int getPhonebookPermissionChoice() {
|
||||
int permission = mDevice.getPhonebookAccessPermission();
|
||||
if (permission == BluetoothDevice.ACCESS_ALLOWED) {
|
||||
return ACCESS_ALLOWED;
|
||||
} else if (permission == BluetoothDevice.ACCESS_REJECTED) {
|
||||
return ACCESS_REJECTED;
|
||||
}
|
||||
return ACCESS_UNKNOWN;
|
||||
}
|
||||
|
||||
void setPhonebookPermissionChoice(int permissionChoice) {
|
||||
int permission = BluetoothDevice.ACCESS_UNKNOWN;
|
||||
if (permissionChoice == ACCESS_ALLOWED) {
|
||||
permission = BluetoothDevice.ACCESS_ALLOWED;
|
||||
} else if (permissionChoice == ACCESS_REJECTED) {
|
||||
permission = BluetoothDevice.ACCESS_REJECTED;
|
||||
}
|
||||
mDevice.setPhonebookAccessPermission(permission);
|
||||
}
|
||||
|
||||
// Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth
|
||||
// app's shared preferences).
|
||||
private void migratePhonebookPermissionChoice() {
|
||||
SharedPreferences preferences = mContext.getSharedPreferences(
|
||||
"bluetooth_phonebook_permission", Context.MODE_PRIVATE);
|
||||
if (!preferences.contains(mDevice.getAddress())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
|
||||
int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN);
|
||||
if (oldPermission == ACCESS_ALLOWED) {
|
||||
mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
|
||||
} else if (oldPermission == ACCESS_REJECTED) {
|
||||
mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
|
||||
}
|
||||
}
|
||||
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.remove(mDevice.getAddress());
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
int getMessagePermissionChoice() {
|
||||
int permission = mDevice.getMessageAccessPermission();
|
||||
if (permission == BluetoothDevice.ACCESS_ALLOWED) {
|
||||
return ACCESS_ALLOWED;
|
||||
} else if (permission == BluetoothDevice.ACCESS_REJECTED) {
|
||||
return ACCESS_REJECTED;
|
||||
}
|
||||
return ACCESS_UNKNOWN;
|
||||
}
|
||||
|
||||
void setMessagePermissionChoice(int permissionChoice) {
|
||||
int permission = BluetoothDevice.ACCESS_UNKNOWN;
|
||||
if (permissionChoice == ACCESS_ALLOWED) {
|
||||
permission = BluetoothDevice.ACCESS_ALLOWED;
|
||||
} else if (permissionChoice == ACCESS_REJECTED) {
|
||||
permission = BluetoothDevice.ACCESS_REJECTED;
|
||||
}
|
||||
mDevice.setMessageAccessPermission(permission);
|
||||
}
|
||||
|
||||
// Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth
|
||||
// app's shared preferences).
|
||||
private void migrateMessagePermissionChoice() {
|
||||
SharedPreferences preferences = mContext.getSharedPreferences(
|
||||
"bluetooth_message_permission", Context.MODE_PRIVATE);
|
||||
if (!preferences.contains(mDevice.getAddress())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDevice.getMessageAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
|
||||
int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN);
|
||||
if (oldPermission == ACCESS_ALLOWED) {
|
||||
mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
|
||||
} else if (oldPermission == ACCESS_REJECTED) {
|
||||
mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
|
||||
}
|
||||
}
|
||||
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.remove(mDevice.getAddress());
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this rejection should persist.
|
||||
*/
|
||||
boolean checkAndIncreaseMessageRejectionCount() {
|
||||
if (mMessageRejectionCount < MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST) {
|
||||
mMessageRejectionCount++;
|
||||
saveMessageRejectionCount();
|
||||
}
|
||||
return mMessageRejectionCount >= MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST;
|
||||
}
|
||||
|
||||
private void fetchMessageRejectionCount() {
|
||||
SharedPreferences preference = mContext.getSharedPreferences(
|
||||
MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE);
|
||||
mMessageRejectionCount = preference.getInt(mDevice.getAddress(), 0);
|
||||
}
|
||||
|
||||
private void saveMessageRejectionCount() {
|
||||
SharedPreferences.Editor editor = mContext.getSharedPreferences(
|
||||
MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE).edit();
|
||||
if (mMessageRejectionCount == 0) {
|
||||
editor.remove(mDevice.getAddress());
|
||||
} else {
|
||||
editor.putInt(mDevice.getAddress(), mMessageRejectionCount);
|
||||
}
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
private void processPhonebookAccess() {
|
||||
if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) return;
|
||||
|
||||
ParcelUuid[] uuids = mDevice.getUuids();
|
||||
if (BluetoothUuid.containsAnyUuid(uuids, PbapServerProfile.PBAB_CLIENT_UUIDS)) {
|
||||
// The pairing dialog now warns of phone-book access for paired devices.
|
||||
// No separate prompt is displayed after pairing.
|
||||
setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
|
||||
*/
|
||||
final class CachedBluetoothDeviceManager {
|
||||
private static final String TAG = "CachedBluetoothDeviceManager";
|
||||
private static final boolean DEBUG = Utils.D;
|
||||
|
||||
private Context mContext;
|
||||
private final List<CachedBluetoothDevice> mCachedDevices =
|
||||
new ArrayList<CachedBluetoothDevice>();
|
||||
|
||||
CachedBluetoothDeviceManager(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
|
||||
return new ArrayList<CachedBluetoothDevice>(mCachedDevices);
|
||||
}
|
||||
|
||||
public static boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) {
|
||||
cachedDevice.setVisible(false);
|
||||
return cachedDevice.getBondState() == BluetoothDevice.BOND_NONE;
|
||||
}
|
||||
|
||||
public void onDeviceNameUpdated(BluetoothDevice device) {
|
||||
CachedBluetoothDevice cachedDevice = findDevice(device);
|
||||
if (cachedDevice != null) {
|
||||
cachedDevice.refreshName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for existing {@link CachedBluetoothDevice} or return null
|
||||
* if this device isn't in the cache. Use {@link #addDevice}
|
||||
* to create and return a new {@link CachedBluetoothDevice} for
|
||||
* a newly discovered {@link BluetoothDevice}.
|
||||
*
|
||||
* @param device the address of the Bluetooth device
|
||||
* @return the cached device object for this device, or null if it has
|
||||
* not been previously seen
|
||||
*/
|
||||
CachedBluetoothDevice findDevice(BluetoothDevice device) {
|
||||
for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
|
||||
if (cachedDevice.getDevice().equals(device)) {
|
||||
return cachedDevice;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new {@link CachedBluetoothDevice}. This assumes
|
||||
* that {@link #findDevice} has already been called and returned null.
|
||||
* @param device the address of the new Bluetooth device
|
||||
* @return the newly created CachedBluetoothDevice object
|
||||
*/
|
||||
CachedBluetoothDevice addDevice(LocalBluetoothAdapter adapter,
|
||||
LocalBluetoothProfileManager profileManager,
|
||||
BluetoothDevice device) {
|
||||
CachedBluetoothDevice newDevice = new CachedBluetoothDevice(mContext, adapter,
|
||||
profileManager, device);
|
||||
synchronized (mCachedDevices) {
|
||||
mCachedDevices.add(newDevice);
|
||||
}
|
||||
return newDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get the name of a remote device, otherwise returns the address.
|
||||
*
|
||||
* @param device The remote device.
|
||||
* @return The name, or if unavailable, the address.
|
||||
*/
|
||||
public String getName(BluetoothDevice device) {
|
||||
CachedBluetoothDevice cachedDevice = findDevice(device);
|
||||
if (cachedDevice != null) {
|
||||
return cachedDevice.getName();
|
||||
}
|
||||
|
||||
String name = device.getAliasName();
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
|
||||
return device.getAddress();
|
||||
}
|
||||
|
||||
public synchronized void clearNonBondedDevices() {
|
||||
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
|
||||
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
|
||||
if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
|
||||
mCachedDevices.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void onScanningStateChanged(boolean started) {
|
||||
if (!started) return;
|
||||
|
||||
// If starting a new scan, clear old visibility
|
||||
// Iterate in reverse order since devices may be removed.
|
||||
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
|
||||
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
|
||||
cachedDevice.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void onBtClassChanged(BluetoothDevice device) {
|
||||
CachedBluetoothDevice cachedDevice = findDevice(device);
|
||||
if (cachedDevice != null) {
|
||||
cachedDevice.refreshBtClass();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void onUuidChanged(BluetoothDevice device) {
|
||||
CachedBluetoothDevice cachedDevice = findDevice(device);
|
||||
if (cachedDevice != null) {
|
||||
cachedDevice.onUuidChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void onBluetoothStateChanged(int bluetoothState) {
|
||||
// When Bluetooth is turning off, we need to clear the non-bonded devices
|
||||
// Otherwise, they end up showing up on the next BT enable
|
||||
if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
|
||||
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
|
||||
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
|
||||
if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
|
||||
cachedDevice.setVisible(false);
|
||||
mCachedDevices.remove(i);
|
||||
} else {
|
||||
// For bonded devices, we need to clear the connection status so that
|
||||
// when BT is enabled next time, device connection status shall be retrieved
|
||||
// by making a binder call.
|
||||
cachedDevice.clearProfileConnectionState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void log(String msg) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, msg);
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,8 +16,12 @@
|
||||
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceCategory;
|
||||
@@ -26,6 +30,11 @@ import android.preference.PreferenceScreen;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.RestrictedSettingsFragment;
|
||||
import com.android.settingslib.bluetooth.BluetoothCallback;
|
||||
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.WeakHashMap;
|
||||
@@ -74,7 +83,7 @@ public abstract class DeviceListPreferenceFragment extends
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mLocalManager = LocalBluetoothManager.getInstance(getActivity());
|
||||
mLocalManager = Utils.getLocalBtManager(getActivity());
|
||||
if (mLocalManager == null) {
|
||||
Log.e(TAG, "Bluetooth is not supported on this device");
|
||||
return;
|
||||
@@ -164,7 +173,7 @@ public abstract class DeviceListPreferenceFragment extends
|
||||
if (mFilter.matches(cachedDevice.getDevice())) {
|
||||
createDevicePreference(cachedDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createDevicePreference(CachedBluetoothDevice cachedDevice) {
|
||||
if (mDeviceListGroup == null) {
|
||||
|
@@ -17,6 +17,7 @@
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothDevicePicker;
|
||||
@@ -29,6 +30,7 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
|
||||
/**
|
||||
* BluetoothSettings is the Settings screen for Bluetooth configuration and
|
||||
|
@@ -42,6 +42,13 @@ import com.android.settings.R;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.search.Index;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||
import com.android.settingslib.bluetooth.MapProfile;
|
||||
import com.android.settingslib.bluetooth.PbapServerProfile;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -80,7 +87,7 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
|
||||
mProfileContainer = (PreferenceGroup) findPreference(KEY_PROFILE_CONTAINER);
|
||||
mProfileContainer.setLayoutResource(R.layout.bluetooth_preference_category);
|
||||
|
||||
mManager = LocalBluetoothManager.getInstance(getActivity());
|
||||
mManager = Utils.getLocalBtManager(getActivity());
|
||||
CachedBluetoothDeviceManager deviceManager =
|
||||
mManager.getCachedDeviceManager();
|
||||
mProfileManager = mManager.getProfileManager();
|
||||
|
@@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.LocalBluetoothProfileManager.ServiceListener;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Notification;
|
||||
import android.app.Service;
|
||||
@@ -27,6 +24,7 @@ import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
@@ -44,6 +42,16 @@ import android.view.WindowManager;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.bluetooth.BluetoothCallback;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager.ServiceListener;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -126,7 +134,7 @@ public final class DockService extends Service implements ServiceListener {
|
||||
public void onCreate() {
|
||||
if (DEBUG) Log.d(TAG, "onCreate");
|
||||
|
||||
LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this);
|
||||
LocalBluetoothManager manager = Utils.getLocalBtManager(this);
|
||||
if (manager == null) {
|
||||
Log.e(TAG, "Can't get LocalBluetoothManager: exiting");
|
||||
return;
|
||||
@@ -918,4 +926,56 @@ public final class DockService extends Service implements ServiceListener {
|
||||
public void onServiceDisconnected() {
|
||||
// FIXME: shouldn't I do something on service disconnected too?
|
||||
}
|
||||
|
||||
public static class DockBluetoothCallback implements BluetoothCallback {
|
||||
private final Context mContext;
|
||||
|
||||
public DockBluetoothCallback(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void onBluetoothStateChanged(int bluetoothState) { }
|
||||
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) { }
|
||||
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { }
|
||||
|
||||
@Override
|
||||
public void onScanningStateChanged(boolean started) {
|
||||
// TODO: Find a more unified place for a persistent BluetoothCallback to live
|
||||
// as this is not exactly dock related.
|
||||
LocalBluetoothPreferences.persistDiscoveringTimestamp(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
|
||||
BluetoothDevice device = cachedDevice.getDevice();
|
||||
if (bondState == BluetoothDevice.BOND_NONE) {
|
||||
if (device.isBluetoothDock()) {
|
||||
// After a dock is unpaired, we will forget the settings
|
||||
LocalBluetoothPreferences
|
||||
.removeDockAutoConnectSetting(mContext, device.getAddress());
|
||||
|
||||
// if the device is undocked, remove it from the list as well
|
||||
if (!device.getAddress().equals(getDockedDeviceAddress(mContext))) {
|
||||
cachedDevice.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This can't be called from a broadcast receiver where the filter is set in the Manifest.
|
||||
private static String getDockedDeviceAddress(Context context) {
|
||||
// This works only because these broadcast intents are "sticky"
|
||||
Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
|
||||
if (i != null) {
|
||||
int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
|
||||
if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
|
||||
BluetoothDevice device = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
if (device != null) {
|
||||
return device.getAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.content.Context;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* HeadsetProfile handles Bluetooth HFP and Headset profiles.
|
||||
*/
|
||||
final class HeadsetProfile implements LocalBluetoothProfile {
|
||||
private static final String TAG = "HeadsetProfile";
|
||||
private static boolean V = true;
|
||||
|
||||
private BluetoothHeadset mService;
|
||||
private boolean mIsProfileReady;
|
||||
|
||||
private final LocalBluetoothAdapter mLocalAdapter;
|
||||
private final CachedBluetoothDeviceManager mDeviceManager;
|
||||
private final LocalBluetoothProfileManager mProfileManager;
|
||||
|
||||
static final ParcelUuid[] UUIDS = {
|
||||
BluetoothUuid.HSP,
|
||||
BluetoothUuid.Handsfree,
|
||||
};
|
||||
|
||||
static final String NAME = "HEADSET";
|
||||
|
||||
// Order of this profile in device profiles list
|
||||
private static final int ORDINAL = 0;
|
||||
|
||||
// These callbacks run on the main thread.
|
||||
private final class HeadsetServiceListener
|
||||
implements BluetoothProfile.ServiceListener {
|
||||
|
||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
if (V) Log.d(TAG,"Bluetooth service connected");
|
||||
mService = (BluetoothHeadset) proxy;
|
||||
// We just bound to the service, so refresh the UI for any connected HFP devices.
|
||||
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||
while (!deviceList.isEmpty()) {
|
||||
BluetoothDevice nextDevice = deviceList.remove(0);
|
||||
CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
|
||||
// we may add a new device here, but generally this should not happen
|
||||
if (device == null) {
|
||||
Log.w(TAG, "HeadsetProfile found new device: " + nextDevice);
|
||||
device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
|
||||
}
|
||||
device.onProfileStateChanged(HeadsetProfile.this,
|
||||
BluetoothProfile.STATE_CONNECTED);
|
||||
device.refresh();
|
||||
}
|
||||
|
||||
mProfileManager.callServiceConnectedListeners();
|
||||
mIsProfileReady=true;
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(int profile) {
|
||||
if (V) Log.d(TAG,"Bluetooth service disconnected");
|
||||
mProfileManager.callServiceDisconnectedListeners();
|
||||
mIsProfileReady=false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProfileReady() {
|
||||
return mIsProfileReady;
|
||||
}
|
||||
|
||||
HeadsetProfile(Context context, LocalBluetoothAdapter adapter,
|
||||
CachedBluetoothDeviceManager deviceManager,
|
||||
LocalBluetoothProfileManager profileManager) {
|
||||
mLocalAdapter = adapter;
|
||||
mDeviceManager = deviceManager;
|
||||
mProfileManager = profileManager;
|
||||
mLocalAdapter.getProfileProxy(context, new HeadsetServiceListener(),
|
||||
BluetoothProfile.HEADSET);
|
||||
}
|
||||
|
||||
public boolean isConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAutoConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean connect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
List<BluetoothDevice> sinks = mService.getConnectedDevices();
|
||||
if (sinks != null) {
|
||||
for (BluetoothDevice sink : sinks) {
|
||||
Log.d(TAG,"Not disconnecting device = " + sink);
|
||||
}
|
||||
}
|
||||
return mService.connect(device);
|
||||
}
|
||||
|
||||
public boolean disconnect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||
if (!deviceList.isEmpty()) {
|
||||
for (BluetoothDevice dev : deviceList) {
|
||||
if (dev.equals(device)) {
|
||||
if (V) Log.d(TAG,"Downgrade priority as user" +
|
||||
"is disconnecting the headset");
|
||||
// Downgrade priority as user is disconnecting the headset.
|
||||
if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
|
||||
}
|
||||
return mService.disconnect(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getConnectionStatus(BluetoothDevice device) {
|
||||
if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
|
||||
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||
if (!deviceList.isEmpty()){
|
||||
for (BluetoothDevice dev : deviceList) {
|
||||
if (dev.equals(device)) {
|
||||
return mService.getConnectionState(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
public boolean isPreferred(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
|
||||
}
|
||||
|
||||
public int getPreferred(BluetoothDevice device) {
|
||||
if (mService == null) return BluetoothProfile.PRIORITY_OFF;
|
||||
return mService.getPriority(device);
|
||||
}
|
||||
|
||||
public void setPreferred(BluetoothDevice device, boolean preferred) {
|
||||
if (mService == null) return;
|
||||
if (preferred) {
|
||||
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
|
||||
}
|
||||
} else {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
public List<BluetoothDevice> getConnectedDevices() {
|
||||
if (mService == null) return new ArrayList<BluetoothDevice>(0);
|
||||
return mService.getDevicesMatchingConnectionStates(
|
||||
new int[] {BluetoothProfile.STATE_CONNECTED,
|
||||
BluetoothProfile.STATE_CONNECTING,
|
||||
BluetoothProfile.STATE_DISCONNECTING});
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return ORDINAL;
|
||||
}
|
||||
|
||||
public int getNameResource(BluetoothDevice device) {
|
||||
return R.string.bluetooth_profile_headset;
|
||||
}
|
||||
|
||||
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
||||
int state = getConnectionStatus(device);
|
||||
switch (state) {
|
||||
case BluetoothProfile.STATE_DISCONNECTED:
|
||||
return R.string.bluetooth_headset_profile_summary_use_for;
|
||||
|
||||
case BluetoothProfile.STATE_CONNECTED:
|
||||
return R.string.bluetooth_headset_profile_summary_connected;
|
||||
|
||||
default:
|
||||
return Utils.getConnectionStateSummary(state);
|
||||
}
|
||||
}
|
||||
|
||||
public int getDrawableResource(BluetoothClass btClass) {
|
||||
return R.drawable.ic_bt_headset_hfp;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if (V) Log.d(TAG, "finalize()");
|
||||
if (mService != null) {
|
||||
try {
|
||||
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEADSET,
|
||||
mService);
|
||||
mService = null;
|
||||
}catch (Throwable t) {
|
||||
Log.w(TAG, "Error cleaning up HID proxy", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothInputDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* HidProfile handles Bluetooth HID profile.
|
||||
*/
|
||||
final class HidProfile implements LocalBluetoothProfile {
|
||||
private static final String TAG = "HidProfile";
|
||||
private static boolean V = true;
|
||||
|
||||
private BluetoothInputDevice mService;
|
||||
private boolean mIsProfileReady;
|
||||
|
||||
private final LocalBluetoothAdapter mLocalAdapter;
|
||||
private final CachedBluetoothDeviceManager mDeviceManager;
|
||||
private final LocalBluetoothProfileManager mProfileManager;
|
||||
|
||||
static final String NAME = "HID";
|
||||
|
||||
// Order of this profile in device profiles list
|
||||
private static final int ORDINAL = 3;
|
||||
|
||||
// These callbacks run on the main thread.
|
||||
private final class InputDeviceServiceListener
|
||||
implements BluetoothProfile.ServiceListener {
|
||||
|
||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
if (V) Log.d(TAG,"Bluetooth service connected");
|
||||
mService = (BluetoothInputDevice) proxy;
|
||||
// We just bound to the service, so refresh the UI for any connected HID devices.
|
||||
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||
while (!deviceList.isEmpty()) {
|
||||
BluetoothDevice nextDevice = deviceList.remove(0);
|
||||
CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
|
||||
// we may add a new device here, but generally this should not happen
|
||||
if (device == null) {
|
||||
Log.w(TAG, "HidProfile found new device: " + nextDevice);
|
||||
device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
|
||||
}
|
||||
device.onProfileStateChanged(HidProfile.this, BluetoothProfile.STATE_CONNECTED);
|
||||
device.refresh();
|
||||
}
|
||||
mIsProfileReady=true;
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(int profile) {
|
||||
if (V) Log.d(TAG,"Bluetooth service disconnected");
|
||||
mIsProfileReady=false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProfileReady() {
|
||||
return mIsProfileReady;
|
||||
}
|
||||
|
||||
HidProfile(Context context, LocalBluetoothAdapter adapter,
|
||||
CachedBluetoothDeviceManager deviceManager,
|
||||
LocalBluetoothProfileManager profileManager) {
|
||||
mLocalAdapter = adapter;
|
||||
mDeviceManager = deviceManager;
|
||||
mProfileManager = profileManager;
|
||||
adapter.getProfileProxy(context, new InputDeviceServiceListener(),
|
||||
BluetoothProfile.INPUT_DEVICE);
|
||||
}
|
||||
|
||||
public boolean isConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAutoConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean connect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
return mService.connect(device);
|
||||
}
|
||||
|
||||
public boolean disconnect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
return mService.disconnect(device);
|
||||
}
|
||||
|
||||
public int getConnectionStatus(BluetoothDevice device) {
|
||||
if (mService == null) {
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||
|
||||
return !deviceList.isEmpty() && deviceList.get(0).equals(device)
|
||||
? mService.getConnectionState(device)
|
||||
: BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
public boolean isPreferred(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
|
||||
}
|
||||
|
||||
public int getPreferred(BluetoothDevice device) {
|
||||
if (mService == null) return BluetoothProfile.PRIORITY_OFF;
|
||||
return mService.getPriority(device);
|
||||
}
|
||||
|
||||
public void setPreferred(BluetoothDevice device, boolean preferred) {
|
||||
if (mService == null) return;
|
||||
if (preferred) {
|
||||
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
|
||||
}
|
||||
} else {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return ORDINAL;
|
||||
}
|
||||
|
||||
public int getNameResource(BluetoothDevice device) {
|
||||
// TODO: distinguish between keyboard and mouse?
|
||||
return R.string.bluetooth_profile_hid;
|
||||
}
|
||||
|
||||
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
||||
int state = getConnectionStatus(device);
|
||||
switch (state) {
|
||||
case BluetoothProfile.STATE_DISCONNECTED:
|
||||
return R.string.bluetooth_hid_profile_summary_use_for;
|
||||
|
||||
case BluetoothProfile.STATE_CONNECTED:
|
||||
return R.string.bluetooth_hid_profile_summary_connected;
|
||||
|
||||
default:
|
||||
return Utils.getConnectionStateSummary(state);
|
||||
}
|
||||
}
|
||||
|
||||
public int getDrawableResource(BluetoothClass btClass) {
|
||||
if (btClass == null) {
|
||||
return R.drawable.ic_lockscreen_ime;
|
||||
}
|
||||
return getHidClassDrawable(btClass);
|
||||
}
|
||||
|
||||
static int getHidClassDrawable(BluetoothClass btClass) {
|
||||
switch (btClass.getDeviceClass()) {
|
||||
case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
|
||||
case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
|
||||
return R.drawable.ic_lockscreen_ime;
|
||||
case BluetoothClass.Device.PERIPHERAL_POINTING:
|
||||
return R.drawable.ic_bt_pointing_hid;
|
||||
default:
|
||||
return R.drawable.ic_bt_misc_hid;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if (V) Log.d(TAG, "finalize()");
|
||||
if (mService != null) {
|
||||
try {
|
||||
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.INPUT_DEVICE,
|
||||
mService);
|
||||
mService = null;
|
||||
}catch (Throwable t) {
|
||||
Log.w(TAG, "Error cleaning up HID proxy", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* LocalBluetoothAdapter provides an interface between the Settings app
|
||||
* and the functionality of the local {@link BluetoothAdapter}, specifically
|
||||
* those related to state transitions of the adapter itself.
|
||||
*
|
||||
* <p>Connection and bonding state changes affecting specific devices
|
||||
* are handled by {@link CachedBluetoothDeviceManager},
|
||||
* {@link BluetoothEventManager}, and {@link LocalBluetoothProfileManager}.
|
||||
*/
|
||||
public final class LocalBluetoothAdapter {
|
||||
private static final String TAG = "LocalBluetoothAdapter";
|
||||
|
||||
/** This class does not allow direct access to the BluetoothAdapter. */
|
||||
private final BluetoothAdapter mAdapter;
|
||||
|
||||
private LocalBluetoothProfileManager mProfileManager;
|
||||
|
||||
private static LocalBluetoothAdapter sInstance;
|
||||
|
||||
private int mState = BluetoothAdapter.ERROR;
|
||||
|
||||
private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins
|
||||
|
||||
private long mLastScan;
|
||||
|
||||
private LocalBluetoothAdapter(BluetoothAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
void setProfileManager(LocalBluetoothProfileManager manager) {
|
||||
mProfileManager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton instance of the LocalBluetoothAdapter. If this device
|
||||
* doesn't support Bluetooth, then null will be returned. Callers must be
|
||||
* prepared to handle a null return value.
|
||||
* @return the LocalBluetoothAdapter object, or null if not supported
|
||||
*/
|
||||
static synchronized LocalBluetoothAdapter getInstance() {
|
||||
if (sInstance == null) {
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (adapter != null) {
|
||||
sInstance = new LocalBluetoothAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
// Pass-through BluetoothAdapter methods that we can intercept if necessary
|
||||
|
||||
void cancelDiscovery() {
|
||||
mAdapter.cancelDiscovery();
|
||||
}
|
||||
|
||||
boolean enable() {
|
||||
return mAdapter.enable();
|
||||
}
|
||||
|
||||
boolean disable() {
|
||||
return mAdapter.disable();
|
||||
}
|
||||
|
||||
void getProfileProxy(Context context,
|
||||
BluetoothProfile.ServiceListener listener, int profile) {
|
||||
mAdapter.getProfileProxy(context, listener, profile);
|
||||
}
|
||||
|
||||
Set<BluetoothDevice> getBondedDevices() {
|
||||
return mAdapter.getBondedDevices();
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return mAdapter.getName();
|
||||
}
|
||||
|
||||
int getScanMode() {
|
||||
return mAdapter.getScanMode();
|
||||
}
|
||||
|
||||
int getState() {
|
||||
return mAdapter.getState();
|
||||
}
|
||||
|
||||
ParcelUuid[] getUuids() {
|
||||
return mAdapter.getUuids();
|
||||
}
|
||||
|
||||
boolean isDiscovering() {
|
||||
return mAdapter.isDiscovering();
|
||||
}
|
||||
|
||||
boolean isEnabled() {
|
||||
return mAdapter.isEnabled();
|
||||
}
|
||||
|
||||
void setDiscoverableTimeout(int timeout) {
|
||||
mAdapter.setDiscoverableTimeout(timeout);
|
||||
}
|
||||
|
||||
void setName(String name) {
|
||||
mAdapter.setName(name);
|
||||
}
|
||||
|
||||
void setScanMode(int mode) {
|
||||
mAdapter.setScanMode(mode);
|
||||
}
|
||||
|
||||
boolean setScanMode(int mode, int duration) {
|
||||
return mAdapter.setScanMode(mode, duration);
|
||||
}
|
||||
|
||||
void startScanning(boolean force) {
|
||||
// Only start if we're not already scanning
|
||||
if (!mAdapter.isDiscovering()) {
|
||||
if (!force) {
|
||||
// Don't scan more than frequently than SCAN_EXPIRATION_MS,
|
||||
// unless forced
|
||||
if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are playing music, don't scan unless forced.
|
||||
A2dpProfile a2dp = mProfileManager.getA2dpProfile();
|
||||
if (a2dp != null && a2dp.isA2dpPlaying()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mAdapter.startDiscovery()) {
|
||||
mLastScan = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stopScanning() {
|
||||
if (mAdapter.isDiscovering()) {
|
||||
mAdapter.cancelDiscovery();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized int getBluetoothState() {
|
||||
// Always sync state, in case it changed while paused
|
||||
syncBluetoothState();
|
||||
return mState;
|
||||
}
|
||||
|
||||
synchronized void setBluetoothStateInt(int state) {
|
||||
mState = state;
|
||||
|
||||
if (state == BluetoothAdapter.STATE_ON) {
|
||||
// if mProfileManager hasn't been constructed yet, it will
|
||||
// get the adapter UUIDs in its constructor when it is.
|
||||
if (mProfileManager != null) {
|
||||
mProfileManager.setBluetoothStateOn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the state changed; false otherwise.
|
||||
boolean syncBluetoothState() {
|
||||
int currentState = mAdapter.getState();
|
||||
if (currentState != mState) {
|
||||
setBluetoothStateInt(mAdapter.getState());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setBluetoothEnabled(boolean enabled) {
|
||||
boolean success = enabled
|
||||
? mAdapter.enable()
|
||||
: mAdapter.disable();
|
||||
|
||||
if (success) {
|
||||
setBluetoothStateInt(enabled
|
||||
? BluetoothAdapter.STATE_TURNING_ON
|
||||
: BluetoothAdapter.STATE_TURNING_OFF);
|
||||
} else {
|
||||
if (Utils.V) {
|
||||
Log.v(TAG, "setBluetoothEnabled call, manager didn't return " +
|
||||
"success for enabled: " + enabled);
|
||||
}
|
||||
|
||||
syncBluetoothState();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* LocalBluetoothManager provides a simplified interface on top of a subset of
|
||||
* the Bluetooth API. Note that {@link #getInstance} will return null
|
||||
* if there is no Bluetooth adapter on this device, and callers must be
|
||||
* prepared to handle this case.
|
||||
*/
|
||||
public final class LocalBluetoothManager {
|
||||
private static final String TAG = "LocalBluetoothManager";
|
||||
|
||||
/** Singleton instance. */
|
||||
private static LocalBluetoothManager sInstance;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
/** If a BT-related activity is in the foreground, this will be it. */
|
||||
private Context mForegroundActivity;
|
||||
|
||||
private BluetoothDiscoverableEnabler mDiscoverableEnabler;
|
||||
|
||||
private final LocalBluetoothAdapter mLocalAdapter;
|
||||
|
||||
private final CachedBluetoothDeviceManager mCachedDeviceManager;
|
||||
|
||||
/** The Bluetooth profile manager. */
|
||||
private final LocalBluetoothProfileManager mProfileManager;
|
||||
|
||||
/** The broadcast receiver event manager. */
|
||||
private final BluetoothEventManager mEventManager;
|
||||
|
||||
public static synchronized LocalBluetoothManager getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
|
||||
if (adapter == null) {
|
||||
return null;
|
||||
}
|
||||
// This will be around as long as this process is
|
||||
Context appContext = context.getApplicationContext();
|
||||
sInstance = new LocalBluetoothManager(adapter, appContext);
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public void setDiscoverableEnabler(BluetoothDiscoverableEnabler discoverableEnabler) {
|
||||
mDiscoverableEnabler = discoverableEnabler;
|
||||
}
|
||||
|
||||
public BluetoothDiscoverableEnabler getDiscoverableEnabler() {
|
||||
return mDiscoverableEnabler;
|
||||
}
|
||||
|
||||
private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {
|
||||
mContext = context;
|
||||
mLocalAdapter = adapter;
|
||||
|
||||
mCachedDeviceManager = new CachedBluetoothDeviceManager(context);
|
||||
mEventManager = new BluetoothEventManager(mLocalAdapter,
|
||||
mCachedDeviceManager, context);
|
||||
mProfileManager = new LocalBluetoothProfileManager(context,
|
||||
mLocalAdapter, mCachedDeviceManager, mEventManager);
|
||||
}
|
||||
|
||||
public LocalBluetoothAdapter getBluetoothAdapter() {
|
||||
return mLocalAdapter;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
public Context getForegroundActivity() {
|
||||
return mForegroundActivity;
|
||||
}
|
||||
|
||||
boolean isForegroundActivity() {
|
||||
return mForegroundActivity != null;
|
||||
}
|
||||
|
||||
synchronized void setForegroundActivity(Context context) {
|
||||
if (context != null) {
|
||||
Log.d(TAG, "setting foreground activity to non-null context");
|
||||
mForegroundActivity = context;
|
||||
} else {
|
||||
if (mForegroundActivity != null) {
|
||||
Log.d(TAG, "setting foreground activity to null");
|
||||
mForegroundActivity = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CachedBluetoothDeviceManager getCachedDeviceManager() {
|
||||
return mCachedDeviceManager;
|
||||
}
|
||||
|
||||
BluetoothEventManager getEventManager() {
|
||||
return mEventManager;
|
||||
}
|
||||
|
||||
LocalBluetoothProfileManager getProfileManager() {
|
||||
return mProfileManager;
|
||||
}
|
||||
}
|
@@ -22,6 +22,9 @@ import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
/**
|
||||
* LocalBluetoothPreferences provides an interface to the preferences
|
||||
* related to Bluetooth.
|
||||
@@ -60,7 +63,7 @@ final class LocalBluetoothPreferences {
|
||||
|
||||
static boolean shouldShowDialogInForeground(Context context,
|
||||
String deviceAddress) {
|
||||
LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context);
|
||||
LocalBluetoothManager manager = Utils.getLocalBtManager(context);
|
||||
if (manager == null) {
|
||||
if(DEBUG) Log.v(TAG, "manager == null - do not show dialog.");
|
||||
return false;
|
||||
|
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
|
||||
/**
|
||||
* LocalBluetoothProfile is an interface defining the basic
|
||||
* functionality related to a Bluetooth profile.
|
||||
*/
|
||||
interface LocalBluetoothProfile {
|
||||
|
||||
/**
|
||||
* Returns true if the user can initiate a connection, false otherwise.
|
||||
*/
|
||||
boolean isConnectable();
|
||||
|
||||
/**
|
||||
* Returns true if the user can enable auto connection for this profile.
|
||||
*/
|
||||
boolean isAutoConnectable();
|
||||
|
||||
boolean connect(BluetoothDevice device);
|
||||
|
||||
boolean disconnect(BluetoothDevice device);
|
||||
|
||||
int getConnectionStatus(BluetoothDevice device);
|
||||
|
||||
boolean isPreferred(BluetoothDevice device);
|
||||
|
||||
int getPreferred(BluetoothDevice device);
|
||||
|
||||
void setPreferred(BluetoothDevice device, boolean preferred);
|
||||
|
||||
boolean isProfileReady();
|
||||
|
||||
/** Display order for device profile settings. */
|
||||
int getOrdinal();
|
||||
|
||||
/**
|
||||
* Returns the string resource ID for the localized name for this profile.
|
||||
* @param device the Bluetooth device (to distinguish between PAN roles)
|
||||
*/
|
||||
int getNameResource(BluetoothDevice device);
|
||||
|
||||
/**
|
||||
* Returns the string resource ID for the summary text for this profile
|
||||
* for the specified device, e.g. "Use for media audio" or
|
||||
* "Connected to media audio".
|
||||
* @param device the device to query for profile connection status
|
||||
* @return a string resource ID for the profile summary text
|
||||
*/
|
||||
int getSummaryResourceForDevice(BluetoothDevice device);
|
||||
|
||||
int getDrawableResource(BluetoothClass btClass);
|
||||
}
|
@@ -1,383 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.BluetoothA2dp;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.bluetooth.BluetoothMap;
|
||||
import android.bluetooth.BluetoothInputDevice;
|
||||
import android.bluetooth.BluetoothPan;
|
||||
import android.bluetooth.BluetoothPbap;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
|
||||
* objects for the available Bluetooth profiles.
|
||||
*/
|
||||
final class LocalBluetoothProfileManager {
|
||||
private static final String TAG = "LocalBluetoothProfileManager";
|
||||
private static final boolean DEBUG = Utils.D;
|
||||
/** Singleton instance. */
|
||||
private static LocalBluetoothProfileManager sInstance;
|
||||
|
||||
/**
|
||||
* An interface for notifying BluetoothHeadset IPC clients when they have
|
||||
* been connected to the BluetoothHeadset service.
|
||||
* Only used by {@link DockService}.
|
||||
*/
|
||||
public interface ServiceListener {
|
||||
/**
|
||||
* Called to notify the client when this proxy object has been
|
||||
* connected to the BluetoothHeadset service. Clients must wait for
|
||||
* this callback before making IPC calls on the BluetoothHeadset
|
||||
* service.
|
||||
*/
|
||||
void onServiceConnected();
|
||||
|
||||
/**
|
||||
* Called to notify the client that this proxy object has been
|
||||
* disconnected from the BluetoothHeadset service. Clients must not
|
||||
* make IPC calls on the BluetoothHeadset service after this callback.
|
||||
* This callback will currently only occur if the application hosting
|
||||
* the BluetoothHeadset service, but may be called more often in future.
|
||||
*/
|
||||
void onServiceDisconnected();
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
private final LocalBluetoothAdapter mLocalAdapter;
|
||||
private final CachedBluetoothDeviceManager mDeviceManager;
|
||||
private final BluetoothEventManager mEventManager;
|
||||
|
||||
private A2dpProfile mA2dpProfile;
|
||||
private HeadsetProfile mHeadsetProfile;
|
||||
private MapProfile mMapProfile;
|
||||
private final HidProfile mHidProfile;
|
||||
private OppProfile mOppProfile;
|
||||
private final PanProfile mPanProfile;
|
||||
private final PbapServerProfile mPbapProfile;
|
||||
|
||||
/**
|
||||
* Mapping from profile name, e.g. "HEADSET" to profile object.
|
||||
*/
|
||||
private final Map<String, LocalBluetoothProfile>
|
||||
mProfileNameMap = new HashMap<String, LocalBluetoothProfile>();
|
||||
|
||||
LocalBluetoothProfileManager(Context context,
|
||||
LocalBluetoothAdapter adapter,
|
||||
CachedBluetoothDeviceManager deviceManager,
|
||||
BluetoothEventManager eventManager) {
|
||||
mContext = context;
|
||||
|
||||
mLocalAdapter = adapter;
|
||||
mDeviceManager = deviceManager;
|
||||
mEventManager = eventManager;
|
||||
// pass this reference to adapter and event manager (circular dependency)
|
||||
mLocalAdapter.setProfileManager(this);
|
||||
mEventManager.setProfileManager(this);
|
||||
|
||||
ParcelUuid[] uuids = adapter.getUuids();
|
||||
|
||||
// uuids may be null if Bluetooth is turned off
|
||||
if (uuids != null) {
|
||||
updateLocalProfiles(uuids);
|
||||
}
|
||||
|
||||
// Always add HID and PAN profiles
|
||||
mHidProfile = new HidProfile(context, mLocalAdapter, mDeviceManager, this);
|
||||
addProfile(mHidProfile, HidProfile.NAME,
|
||||
BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
|
||||
|
||||
mPanProfile = new PanProfile(context);
|
||||
addPanProfile(mPanProfile, PanProfile.NAME,
|
||||
BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
|
||||
|
||||
if(DEBUG) Log.d(TAG, "Adding local MAP profile");
|
||||
mMapProfile = new MapProfile(mContext, mLocalAdapter,
|
||||
mDeviceManager, this);
|
||||
addProfile(mMapProfile, MapProfile.NAME,
|
||||
BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
|
||||
|
||||
//Create PBAP server profile, but do not add it to list of profiles
|
||||
// as we do not need to monitor the profile as part of profile list
|
||||
mPbapProfile = new PbapServerProfile(context);
|
||||
|
||||
if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize or update the local profile objects. If a UUID was previously
|
||||
* present but has been removed, we print a warning but don't remove the
|
||||
* profile object as it might be referenced elsewhere, or the UUID might
|
||||
* come back and we don't want multiple copies of the profile objects.
|
||||
* @param uuids
|
||||
*/
|
||||
void updateLocalProfiles(ParcelUuid[] uuids) {
|
||||
// A2DP
|
||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
|
||||
if (mA2dpProfile == null) {
|
||||
if(DEBUG) Log.d(TAG, "Adding local A2DP profile");
|
||||
mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this);
|
||||
addProfile(mA2dpProfile, A2dpProfile.NAME,
|
||||
BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
|
||||
}
|
||||
} else if (mA2dpProfile != null) {
|
||||
Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
|
||||
}
|
||||
|
||||
// Headset / Handsfree
|
||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
|
||||
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
|
||||
if (mHeadsetProfile == null) {
|
||||
if (DEBUG) Log.d(TAG, "Adding local HEADSET profile");
|
||||
mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter,
|
||||
mDeviceManager, this);
|
||||
addProfile(mHeadsetProfile, HeadsetProfile.NAME,
|
||||
BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
|
||||
}
|
||||
} else if (mHeadsetProfile != null) {
|
||||
Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
|
||||
}
|
||||
|
||||
// OPP
|
||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
|
||||
if (mOppProfile == null) {
|
||||
if(DEBUG) Log.d(TAG, "Adding local OPP profile");
|
||||
mOppProfile = new OppProfile();
|
||||
// Note: no event handler for OPP, only name map.
|
||||
mProfileNameMap.put(OppProfile.NAME, mOppProfile);
|
||||
}
|
||||
} else if (mOppProfile != null) {
|
||||
Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
|
||||
}
|
||||
mEventManager.registerProfileIntentReceiver();
|
||||
|
||||
// There is no local SDP record for HID and Settings app doesn't control PBAP
|
||||
}
|
||||
|
||||
private final Collection<ServiceListener> mServiceListeners =
|
||||
new ArrayList<ServiceListener>();
|
||||
|
||||
private void addProfile(LocalBluetoothProfile profile,
|
||||
String profileName, String stateChangedAction) {
|
||||
mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile));
|
||||
mProfileNameMap.put(profileName, profile);
|
||||
}
|
||||
|
||||
private void addPanProfile(LocalBluetoothProfile profile,
|
||||
String profileName, String stateChangedAction) {
|
||||
mEventManager.addProfileHandler(stateChangedAction,
|
||||
new PanStateChangedHandler(profile));
|
||||
mProfileNameMap.put(profileName, profile);
|
||||
}
|
||||
|
||||
LocalBluetoothProfile getProfileByName(String name) {
|
||||
return mProfileNameMap.get(name);
|
||||
}
|
||||
|
||||
// Called from LocalBluetoothAdapter when state changes to ON
|
||||
void setBluetoothStateOn() {
|
||||
ParcelUuid[] uuids = mLocalAdapter.getUuids();
|
||||
if (uuids != null) {
|
||||
updateLocalProfiles(uuids);
|
||||
}
|
||||
mEventManager.readPairedDevices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic handler for connection state change events for the specified profile.
|
||||
*/
|
||||
private class StateChangedHandler implements BluetoothEventManager.Handler {
|
||||
final LocalBluetoothProfile mProfile;
|
||||
|
||||
StateChangedHandler(LocalBluetoothProfile profile) {
|
||||
mProfile = profile;
|
||||
}
|
||||
|
||||
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
|
||||
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
|
||||
if (cachedDevice == null) {
|
||||
Log.w(TAG, "StateChangedHandler found new device: " + device);
|
||||
cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
|
||||
LocalBluetoothProfileManager.this, device);
|
||||
}
|
||||
int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
|
||||
int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
|
||||
if (newState == BluetoothProfile.STATE_DISCONNECTED &&
|
||||
oldState == BluetoothProfile.STATE_CONNECTING) {
|
||||
Log.i(TAG, "Failed to connect " + mProfile + " device");
|
||||
}
|
||||
|
||||
cachedDevice.onProfileStateChanged(mProfile, newState);
|
||||
cachedDevice.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/** State change handler for NAP and PANU profiles. */
|
||||
private class PanStateChangedHandler extends StateChangedHandler {
|
||||
|
||||
PanStateChangedHandler(LocalBluetoothProfile profile) {
|
||||
super(profile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
|
||||
PanProfile panProfile = (PanProfile) mProfile;
|
||||
int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0);
|
||||
panProfile.setLocalRole(device, role);
|
||||
super.onReceive(context, intent, device);
|
||||
}
|
||||
}
|
||||
|
||||
// called from DockService
|
||||
void addServiceListener(ServiceListener l) {
|
||||
mServiceListeners.add(l);
|
||||
}
|
||||
|
||||
// called from DockService
|
||||
void removeServiceListener(ServiceListener l) {
|
||||
mServiceListeners.remove(l);
|
||||
}
|
||||
|
||||
// not synchronized: use only from UI thread! (TODO: verify)
|
||||
void callServiceConnectedListeners() {
|
||||
for (ServiceListener l : mServiceListeners) {
|
||||
l.onServiceConnected();
|
||||
}
|
||||
}
|
||||
|
||||
// not synchronized: use only from UI thread! (TODO: verify)
|
||||
void callServiceDisconnectedListeners() {
|
||||
for (ServiceListener listener : mServiceListeners) {
|
||||
listener.onServiceDisconnected();
|
||||
}
|
||||
}
|
||||
|
||||
// This is called by DockService, so check Headset and A2DP.
|
||||
public synchronized boolean isManagerReady() {
|
||||
// Getting just the headset profile is fine for now. Will need to deal with A2DP
|
||||
// and others if they aren't always in a ready state.
|
||||
LocalBluetoothProfile profile = mHeadsetProfile;
|
||||
if (profile != null) {
|
||||
return profile.isProfileReady();
|
||||
}
|
||||
profile = mA2dpProfile;
|
||||
if (profile != null) {
|
||||
return profile.isProfileReady();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
A2dpProfile getA2dpProfile() {
|
||||
return mA2dpProfile;
|
||||
}
|
||||
|
||||
HeadsetProfile getHeadsetProfile() {
|
||||
return mHeadsetProfile;
|
||||
}
|
||||
|
||||
PbapServerProfile getPbapProfile(){
|
||||
return mPbapProfile;
|
||||
}
|
||||
|
||||
MapProfile getMapProfile(){
|
||||
return mMapProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in a list of LocalBluetoothProfile objects that are supported by
|
||||
* the local device and the remote device.
|
||||
*
|
||||
* @param uuids of the remote device
|
||||
* @param localUuids UUIDs of the local device
|
||||
* @param profiles The list of profiles to fill
|
||||
* @param removedProfiles list of profiles that were removed
|
||||
*/
|
||||
synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
|
||||
Collection<LocalBluetoothProfile> profiles,
|
||||
Collection<LocalBluetoothProfile> removedProfiles,
|
||||
boolean isPanNapConnected, BluetoothDevice device) {
|
||||
// Copy previous profile list into removedProfiles
|
||||
removedProfiles.clear();
|
||||
removedProfiles.addAll(profiles);
|
||||
profiles.clear();
|
||||
|
||||
if (uuids == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHeadsetProfile != null) {
|
||||
if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
|
||||
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
|
||||
(BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
|
||||
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
|
||||
profiles.add(mHeadsetProfile);
|
||||
removedProfiles.remove(mHeadsetProfile);
|
||||
}
|
||||
}
|
||||
|
||||
if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
|
||||
mA2dpProfile != null) {
|
||||
profiles.add(mA2dpProfile);
|
||||
removedProfiles.remove(mA2dpProfile);
|
||||
}
|
||||
|
||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
|
||||
mOppProfile != null) {
|
||||
profiles.add(mOppProfile);
|
||||
removedProfiles.remove(mOppProfile);
|
||||
}
|
||||
|
||||
if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) ||
|
||||
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) &&
|
||||
mHidProfile != null) {
|
||||
profiles.add(mHidProfile);
|
||||
removedProfiles.remove(mHidProfile);
|
||||
}
|
||||
|
||||
if(isPanNapConnected)
|
||||
if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists.");
|
||||
if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
|
||||
mPanProfile != null) || isPanNapConnected) {
|
||||
profiles.add(mPanProfile);
|
||||
removedProfiles.remove(mPanProfile);
|
||||
}
|
||||
|
||||
if ((mMapProfile != null) &&
|
||||
(mMapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
|
||||
profiles.add(mMapProfile);
|
||||
removedProfiles.remove(mMapProfile);
|
||||
mMapProfile.setPreferred(device, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,213 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothMap;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.content.Context;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MapProfile handles Bluetooth MAP profile.
|
||||
*/
|
||||
final class MapProfile implements LocalBluetoothProfile {
|
||||
private static final String TAG = "MapProfile";
|
||||
private static boolean V = true;
|
||||
|
||||
private BluetoothMap mService;
|
||||
private boolean mIsProfileReady;
|
||||
|
||||
private final LocalBluetoothAdapter mLocalAdapter;
|
||||
private final CachedBluetoothDeviceManager mDeviceManager;
|
||||
private final LocalBluetoothProfileManager mProfileManager;
|
||||
|
||||
static final ParcelUuid[] UUIDS = {
|
||||
BluetoothUuid.MAP,
|
||||
BluetoothUuid.MNS,
|
||||
BluetoothUuid.MAS,
|
||||
};
|
||||
|
||||
static final String NAME = "MAP";
|
||||
|
||||
// Order of this profile in device profiles list
|
||||
|
||||
// These callbacks run on the main thread.
|
||||
private final class MapServiceListener
|
||||
implements BluetoothProfile.ServiceListener {
|
||||
|
||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
if (V) Log.d(TAG,"Bluetooth service connected");
|
||||
mService = (BluetoothMap) proxy;
|
||||
// We just bound to the service, so refresh the UI for any connected MAP devices.
|
||||
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||
while (!deviceList.isEmpty()) {
|
||||
BluetoothDevice nextDevice = deviceList.remove(0);
|
||||
CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
|
||||
// we may add a new device here, but generally this should not happen
|
||||
if (device == null) {
|
||||
Log.w(TAG, "MapProfile found new device: " + nextDevice);
|
||||
device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
|
||||
}
|
||||
device.onProfileStateChanged(MapProfile.this,
|
||||
BluetoothProfile.STATE_CONNECTED);
|
||||
device.refresh();
|
||||
}
|
||||
|
||||
mProfileManager.callServiceConnectedListeners();
|
||||
mIsProfileReady=true;
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(int profile) {
|
||||
if (V) Log.d(TAG,"Bluetooth service disconnected");
|
||||
mProfileManager.callServiceDisconnectedListeners();
|
||||
mIsProfileReady=false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProfileReady() {
|
||||
if(V) Log.d(TAG,"isProfileReady(): "+ mIsProfileReady);
|
||||
return mIsProfileReady;
|
||||
}
|
||||
|
||||
MapProfile(Context context, LocalBluetoothAdapter adapter,
|
||||
CachedBluetoothDeviceManager deviceManager,
|
||||
LocalBluetoothProfileManager profileManager) {
|
||||
mLocalAdapter = adapter;
|
||||
mDeviceManager = deviceManager;
|
||||
mProfileManager = profileManager;
|
||||
mLocalAdapter.getProfileProxy(context, new MapServiceListener(),
|
||||
BluetoothProfile.MAP);
|
||||
}
|
||||
|
||||
public boolean isConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAutoConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean connect(BluetoothDevice device) {
|
||||
if(V)Log.d(TAG,"connect() - should not get called");
|
||||
return false; // MAP never connects out
|
||||
}
|
||||
|
||||
public boolean disconnect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||
if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) {
|
||||
if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
|
||||
}
|
||||
return mService.disconnect(device);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int getConnectionStatus(BluetoothDevice device) {
|
||||
if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
|
||||
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||
if(V) Log.d(TAG,"getConnectionStatus: status is: "+ mService.getConnectionState(device));
|
||||
|
||||
return !deviceList.isEmpty() && deviceList.get(0).equals(device)
|
||||
? mService.getConnectionState(device)
|
||||
: BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
public boolean isPreferred(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
|
||||
}
|
||||
|
||||
public int getPreferred(BluetoothDevice device) {
|
||||
if (mService == null) return BluetoothProfile.PRIORITY_OFF;
|
||||
return mService.getPriority(device);
|
||||
}
|
||||
|
||||
public void setPreferred(BluetoothDevice device, boolean preferred) {
|
||||
if (mService == null) return;
|
||||
if (preferred) {
|
||||
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
|
||||
}
|
||||
} else {
|
||||
mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
public List<BluetoothDevice> getConnectedDevices() {
|
||||
if (mService == null) return new ArrayList<BluetoothDevice>(0);
|
||||
return mService.getDevicesMatchingConnectionStates(
|
||||
new int[] {BluetoothProfile.STATE_CONNECTED,
|
||||
BluetoothProfile.STATE_CONNECTING,
|
||||
BluetoothProfile.STATE_DISCONNECTING});
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return BluetoothProfile.MAP;
|
||||
}
|
||||
|
||||
public int getNameResource(BluetoothDevice device) {
|
||||
return R.string.bluetooth_profile_map;
|
||||
}
|
||||
|
||||
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
||||
int state = getConnectionStatus(device);
|
||||
switch (state) {
|
||||
case BluetoothProfile.STATE_DISCONNECTED:
|
||||
return R.string.bluetooth_map_profile_summary_use_for;
|
||||
|
||||
case BluetoothProfile.STATE_CONNECTED:
|
||||
return R.string.bluetooth_map_profile_summary_connected;
|
||||
|
||||
default:
|
||||
return Utils.getConnectionStateSummary(state);
|
||||
}
|
||||
}
|
||||
|
||||
public int getDrawableResource(BluetoothClass btClass) {
|
||||
return R.drawable.ic_bt_cellphone;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if (V) Log.d(TAG, "finalize()");
|
||||
if (mService != null) {
|
||||
try {
|
||||
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP,
|
||||
mService);
|
||||
mService = null;
|
||||
}catch (Throwable t) {
|
||||
Log.w(TAG, "Error cleaning up MAP proxy", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.android.settings.R;
|
||||
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
|
||||
/**
|
||||
* OppProfile handles Bluetooth OPP.
|
||||
*/
|
||||
final class OppProfile implements LocalBluetoothProfile {
|
||||
|
||||
static final String NAME = "OPP";
|
||||
|
||||
// Order of this profile in device profiles list
|
||||
private static final int ORDINAL = 2;
|
||||
|
||||
public boolean isConnectable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAutoConnectable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean connect(BluetoothDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean disconnect(BluetoothDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getConnectionStatus(BluetoothDevice device) {
|
||||
return BluetoothProfile.STATE_DISCONNECTED; // Settings app doesn't handle OPP
|
||||
}
|
||||
|
||||
public boolean isPreferred(BluetoothDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getPreferred(BluetoothDevice device) {
|
||||
return BluetoothProfile.PRIORITY_OFF; // Settings app doesn't handle OPP
|
||||
}
|
||||
|
||||
public void setPreferred(BluetoothDevice device, boolean preferred) {
|
||||
}
|
||||
|
||||
public boolean isProfileReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return ORDINAL;
|
||||
}
|
||||
|
||||
public int getNameResource(BluetoothDevice device) {
|
||||
return R.string.bluetooth_profile_opp;
|
||||
}
|
||||
|
||||
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
||||
return 0; // OPP profile not displayed in UI
|
||||
}
|
||||
|
||||
public int getDrawableResource(BluetoothClass btClass) {
|
||||
return 0; // no icon for OPP
|
||||
}
|
||||
}
|
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothPan;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* PanProfile handles Bluetooth PAN profile (NAP and PANU).
|
||||
*/
|
||||
final class PanProfile implements LocalBluetoothProfile {
|
||||
private static final String TAG = "PanProfile";
|
||||
private static boolean V = true;
|
||||
|
||||
private BluetoothPan mService;
|
||||
private boolean mIsProfileReady;
|
||||
|
||||
// Tethering direction for each device
|
||||
private final HashMap<BluetoothDevice, Integer> mDeviceRoleMap =
|
||||
new HashMap<BluetoothDevice, Integer>();
|
||||
|
||||
static final String NAME = "PAN";
|
||||
|
||||
// Order of this profile in device profiles list
|
||||
private static final int ORDINAL = 4;
|
||||
|
||||
// These callbacks run on the main thread.
|
||||
private final class PanServiceListener
|
||||
implements BluetoothProfile.ServiceListener {
|
||||
|
||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
if (V) Log.d(TAG,"Bluetooth service connected");
|
||||
mService = (BluetoothPan) proxy;
|
||||
mIsProfileReady=true;
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(int profile) {
|
||||
if (V) Log.d(TAG,"Bluetooth service disconnected");
|
||||
mIsProfileReady=false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProfileReady() {
|
||||
return mIsProfileReady;
|
||||
}
|
||||
|
||||
PanProfile(Context context) {
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
adapter.getProfileProxy(context, new PanServiceListener(),
|
||||
BluetoothProfile.PAN);
|
||||
}
|
||||
|
||||
public boolean isConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAutoConnectable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean connect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
List<BluetoothDevice> sinks = mService.getConnectedDevices();
|
||||
if (sinks != null) {
|
||||
for (BluetoothDevice sink : sinks) {
|
||||
mService.disconnect(sink);
|
||||
}
|
||||
}
|
||||
return mService.connect(device);
|
||||
}
|
||||
|
||||
public boolean disconnect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
return mService.disconnect(device);
|
||||
}
|
||||
|
||||
public int getConnectionStatus(BluetoothDevice device) {
|
||||
if (mService == null) {
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
return mService.getConnectionState(device);
|
||||
}
|
||||
|
||||
public boolean isPreferred(BluetoothDevice device) {
|
||||
// return current connection status so profile checkbox is set correctly
|
||||
return getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED;
|
||||
}
|
||||
|
||||
public int getPreferred(BluetoothDevice device) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void setPreferred(BluetoothDevice device, boolean preferred) {
|
||||
// ignore: isPreferred is always true for PAN
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return ORDINAL;
|
||||
}
|
||||
|
||||
public int getNameResource(BluetoothDevice device) {
|
||||
if (isLocalRoleNap(device)) {
|
||||
return R.string.bluetooth_profile_pan_nap;
|
||||
} else {
|
||||
return R.string.bluetooth_profile_pan;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
||||
int state = getConnectionStatus(device);
|
||||
switch (state) {
|
||||
case BluetoothProfile.STATE_DISCONNECTED:
|
||||
return R.string.bluetooth_pan_profile_summary_use_for;
|
||||
|
||||
case BluetoothProfile.STATE_CONNECTED:
|
||||
if (isLocalRoleNap(device)) {
|
||||
return R.string.bluetooth_pan_nap_profile_summary_connected;
|
||||
} else {
|
||||
return R.string.bluetooth_pan_user_profile_summary_connected;
|
||||
}
|
||||
|
||||
default:
|
||||
return Utils.getConnectionStateSummary(state);
|
||||
}
|
||||
}
|
||||
|
||||
public int getDrawableResource(BluetoothClass btClass) {
|
||||
return R.drawable.ic_bt_network_pan;
|
||||
}
|
||||
|
||||
// Tethering direction determines UI strings.
|
||||
void setLocalRole(BluetoothDevice device, int role) {
|
||||
mDeviceRoleMap.put(device, role);
|
||||
}
|
||||
|
||||
boolean isLocalRoleNap(BluetoothDevice device) {
|
||||
if (mDeviceRoleMap.containsKey(device)) {
|
||||
return mDeviceRoleMap.get(device) == BluetoothPan.LOCAL_NAP_ROLE;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if (V) Log.d(TAG, "finalize()");
|
||||
if (mService != null) {
|
||||
try {
|
||||
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.PAN, mService);
|
||||
mService = null;
|
||||
}catch (Throwable t) {
|
||||
Log.w(TAG, "Error cleaning up PAN proxy", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothPbap;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.content.Context;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* PBAPServer Profile
|
||||
*/
|
||||
final class PbapServerProfile implements LocalBluetoothProfile {
|
||||
private static final String TAG = "PbapServerProfile";
|
||||
private static boolean V = true;
|
||||
|
||||
private BluetoothPbap mService;
|
||||
private boolean mIsProfileReady;
|
||||
|
||||
static final String NAME = "PBAP Server";
|
||||
|
||||
// Order of this profile in device profiles list
|
||||
private static final int ORDINAL = 6;
|
||||
|
||||
// The UUIDs indicate that remote device might access pbap server
|
||||
static final ParcelUuid[] PBAB_CLIENT_UUIDS = {
|
||||
BluetoothUuid.HSP,
|
||||
BluetoothUuid.Handsfree,
|
||||
BluetoothUuid.PBAP_PCE
|
||||
};
|
||||
|
||||
// These callbacks run on the main thread.
|
||||
private final class PbapServiceListener
|
||||
implements BluetoothPbap.ServiceListener {
|
||||
|
||||
public void onServiceConnected(BluetoothPbap proxy) {
|
||||
if (V) Log.d(TAG,"Bluetooth service connected");
|
||||
mService = (BluetoothPbap) proxy;
|
||||
mIsProfileReady=true;
|
||||
}
|
||||
|
||||
public void onServiceDisconnected() {
|
||||
if (V) Log.d(TAG,"Bluetooth service disconnected");
|
||||
mIsProfileReady=false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProfileReady() {
|
||||
return mIsProfileReady;
|
||||
}
|
||||
|
||||
PbapServerProfile(Context context) {
|
||||
BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener());
|
||||
}
|
||||
|
||||
public boolean isConnectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAutoConnectable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean connect(BluetoothDevice device) {
|
||||
/*Can't connect from server */
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public boolean disconnect(BluetoothDevice device) {
|
||||
if (mService == null) return false;
|
||||
return mService.disconnect();
|
||||
}
|
||||
|
||||
public int getConnectionStatus(BluetoothDevice device) {
|
||||
if (mService == null) {
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
if (mService.isConnected(device))
|
||||
return BluetoothProfile.STATE_CONNECTED;
|
||||
else
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
public boolean isPreferred(BluetoothDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getPreferred(BluetoothDevice device) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void setPreferred(BluetoothDevice device, boolean preferred) {
|
||||
// ignore: isPreferred is always true for PBAP
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return ORDINAL;
|
||||
}
|
||||
|
||||
public int getNameResource(BluetoothDevice device) {
|
||||
return R.string.bluetooth_profile_pbap;
|
||||
}
|
||||
|
||||
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
||||
return R.string.bluetooth_profile_pbap_summary;
|
||||
}
|
||||
|
||||
public int getDrawableResource(BluetoothClass btClass) {
|
||||
return R.drawable.ic_bt_cellphone;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if (V) Log.d(TAG, "finalize()");
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.close();
|
||||
mService = null;
|
||||
}catch (Throwable t) {
|
||||
Log.w(TAG, "Error cleaning up PBAP proxy", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
@@ -30,6 +28,11 @@ import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.bluetooth.BluetoothDiscoverableTimeoutReceiver;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
/**
|
||||
* RequestPermissionActivity asks the user whether to enable discovery. This is
|
||||
* usually started by an application wanted to start bluetooth and or discovery
|
||||
@@ -275,7 +278,7 @@ public class RequestPermissionActivity extends Activity implements
|
||||
return true;
|
||||
}
|
||||
|
||||
LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this);
|
||||
LocalBluetoothManager manager = Utils.getLocalBtManager(this);
|
||||
if (manager == null) {
|
||||
Log.e(TAG, "Error: there's a problem starting Bluetooth");
|
||||
setResult(RESULT_CANCELED);
|
||||
|
@@ -19,6 +19,8 @@ package com.android.settings.bluetooth;
|
||||
import com.android.internal.app.AlertActivity;
|
||||
import com.android.internal.app.AlertController;
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
@@ -146,7 +148,7 @@ public class RequestPermissionHelperActivity extends AlertActivity implements
|
||||
return true;
|
||||
}
|
||||
|
||||
LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this);
|
||||
LocalBluetoothManager manager = Utils.getLocalBtManager(this);
|
||||
if (manager == null) {
|
||||
Log.e(TAG, "Error: there's a problem starting Bluetooth");
|
||||
setResult(RESULT_CANCELED);
|
||||
|
@@ -17,24 +17,27 @@
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.DockService.DockBluetoothCallback;
|
||||
import com.android.settings.search.Index;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
|
||||
import com.android.settingslib.bluetooth.Utils.ErrorListener;
|
||||
|
||||
/**
|
||||
* Utils is a helper class that contains constants for various
|
||||
* Android resource IDs, debug logging flags, and static methods
|
||||
* for creating dialogs.
|
||||
*/
|
||||
final class Utils {
|
||||
static final boolean V = false; // verbose logging
|
||||
static final boolean D = true; // regular logging
|
||||
public final class Utils {
|
||||
static final boolean V = com.android.settingslib.bluetooth.Utils.V; // verbose logging
|
||||
static final boolean D = com.android.settingslib.bluetooth.Utils.D; // regular logging
|
||||
|
||||
private Utils() {
|
||||
}
|
||||
@@ -91,7 +94,7 @@ final class Utils {
|
||||
|
||||
static void showError(Context context, String name, int messageResId) {
|
||||
String message = context.getString(messageResId, name);
|
||||
LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context);
|
||||
LocalBluetoothManager manager = getLocalBtManager(context);
|
||||
Context activity = manager.getForegroundActivity();
|
||||
if(manager.isForegroundActivity()) {
|
||||
new AlertDialog.Builder(activity)
|
||||
@@ -118,4 +121,25 @@ final class Utils {
|
||||
|
||||
Index.getInstance(context).updateFromSearchIndexableData(data);
|
||||
}
|
||||
|
||||
public static LocalBluetoothManager getLocalBtManager(Context context) {
|
||||
return LocalBluetoothManager.getInstance(context, mOnInitCallback);
|
||||
}
|
||||
|
||||
private static final ErrorListener mErrorListener = new ErrorListener() {
|
||||
@Override
|
||||
public void onShowError(Context context, String name, int messageResId) {
|
||||
showError(context, name, messageResId);
|
||||
}
|
||||
};
|
||||
|
||||
private static final BluetoothManagerCallback mOnInitCallback = new BluetoothManagerCallback() {
|
||||
@Override
|
||||
public void onBluetoothManagerInitialized(Context appContext,
|
||||
LocalBluetoothManager bluetoothManager) {
|
||||
bluetoothManager.getEventManager().registerCallback(
|
||||
new DockBluetoothCallback(appContext));
|
||||
com.android.settingslib.bluetooth.Utils.setErrorListener(mErrorListener);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user