| /* |
| * 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.systemui.statusbar.policy; |
| |
| import static android.bluetooth.BluetoothAdapter.ERROR; |
| import static com.android.systemui.statusbar.policy.BluetoothUtil.connectionStateToString; |
| import static com.android.systemui.statusbar.policy.BluetoothUtil.deviceToString; |
| import static com.android.systemui.statusbar.policy.BluetoothUtil.profileToString; |
| import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidToProfile; |
| import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidToString; |
| import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidsToString; |
| |
| import android.bluetooth.BluetoothA2dp; |
| import android.bluetooth.BluetoothA2dpSink; |
| import android.bluetooth.BluetoothAdapter; |
| import android.bluetooth.BluetoothDevice; |
| import android.bluetooth.BluetoothHeadset; |
| import android.bluetooth.BluetoothHeadsetClient; |
| import android.bluetooth.BluetoothInputDevice; |
| import android.bluetooth.BluetoothManager; |
| import android.bluetooth.BluetoothMap; |
| import android.bluetooth.BluetoothPan; |
| import android.bluetooth.BluetoothProfile; |
| import android.bluetooth.BluetoothProfile.ServiceListener; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.os.ParcelUuid; |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.Log; |
| import android.util.SparseArray; |
| |
| import com.android.systemui.statusbar.policy.BluetoothUtil.Profile; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.Set; |
| |
| public class BluetoothControllerImpl implements BluetoothController { |
| private static final String TAG = "BluetoothController"; |
| private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); |
| // This controls the order in which we check the states. Since a device can only have |
| // one state on screen, but can have multiple profiles, the later states override the |
| // value of earlier states. So if a device has a profile in CONNECTING and one in |
| // CONNECTED, it will show as CONNECTED, theoretically this shouldn't really happen often, |
| // but seemed worth noting. |
| private static final int[] CONNECTION_STATES = { |
| BluetoothProfile.STATE_DISCONNECTED, |
| BluetoothProfile.STATE_DISCONNECTING, |
| BluetoothProfile.STATE_CONNECTING, |
| BluetoothProfile.STATE_CONNECTED, |
| }; |
| // Update all the BT device states. |
| private static final int MSG_UPDATE_CONNECTION_STATES = 1; |
| // Update just one BT device. |
| private static final int MSG_UPDATE_SINGLE_CONNECTION_STATE = 2; |
| // Update whether devices are bonded or not. |
| private static final int MSG_UPDATE_BONDED_DEVICES = 3; |
| |
| private static final int MSG_ADD_PROFILE = 4; |
| private static final int MSG_REM_PROFILE = 5; |
| |
| private final Context mContext; |
| private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); |
| private final BluetoothAdapter mAdapter; |
| private final Receiver mReceiver = new Receiver(); |
| private final ArrayMap<BluetoothDevice, DeviceInfo> mDeviceInfo = new ArrayMap<>(); |
| private final SparseArray<BluetoothProfile> mProfiles = new SparseArray<>(); |
| |
| private final H mHandler; |
| |
| private boolean mEnabled; |
| private boolean mConnecting; |
| private BluetoothDevice mLastDevice; |
| |
| public BluetoothControllerImpl(Context context, Looper bgLooper) { |
| mContext = context; |
| mHandler = new H(bgLooper); |
| |
| final BluetoothManager bluetoothManager = |
| (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); |
| mAdapter = bluetoothManager.getAdapter(); |
| if (mAdapter == null) { |
| Log.w(TAG, "Default BT adapter not found"); |
| return; |
| } |
| |
| mReceiver.register(); |
| setAdapterState(mAdapter.getState()); |
| updateBondedDevices(); |
| bindAllProfiles(); |
| } |
| |
| public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| pw.println("BluetoothController state:"); |
| pw.print(" mAdapter="); pw.println(mAdapter); |
| pw.print(" mEnabled="); pw.println(mEnabled); |
| pw.print(" mConnecting="); pw.println(mConnecting); |
| pw.print(" mLastDevice="); pw.println(mLastDevice); |
| pw.print(" mCallbacks.size="); pw.println(mCallbacks.size()); |
| pw.print(" mProfiles="); pw.println(profilesToString(mProfiles)); |
| pw.print(" mDeviceInfo.size="); pw.println(mDeviceInfo.size()); |
| for (int i = 0; i < mDeviceInfo.size(); i++) { |
| final BluetoothDevice device = mDeviceInfo.keyAt(i); |
| final DeviceInfo info = mDeviceInfo.valueAt(i); |
| pw.print(" "); pw.print(deviceToString(device)); |
| pw.print('('); pw.print(uuidsToString(device)); pw.print(')'); |
| pw.print(" "); pw.println(infoToString(info)); |
| } |
| } |
| |
| private static String infoToString(DeviceInfo info) { |
| return info == null ? null : ("connectionState=" + |
| connectionStateToString(CONNECTION_STATES[info.connectionStateIndex]) |
| + ",bonded=" + info.bonded + ",profiles=" |
| + profilesToString(info.connectedProfiles)); |
| } |
| |
| private static String profilesToString(SparseArray<?> profiles) { |
| final int N = profiles.size(); |
| final StringBuffer buffer = new StringBuffer(); |
| buffer.append('['); |
| for (int i = 0; i < N; i++) { |
| if (i != 0) { |
| buffer.append(','); |
| } |
| buffer.append(BluetoothUtil.profileToString(profiles.keyAt(i))); |
| } |
| buffer.append(']'); |
| return buffer.toString(); |
| } |
| |
| public void addStateChangedCallback(Callback cb) { |
| mCallbacks.add(cb); |
| fireStateChange(cb); |
| } |
| |
| @Override |
| public void removeStateChangedCallback(Callback cb) { |
| mCallbacks.remove(cb); |
| } |
| |
| @Override |
| public boolean isBluetoothEnabled() { |
| return mAdapter != null && mAdapter.isEnabled(); |
| } |
| |
| @Override |
| public boolean isBluetoothConnected() { |
| return mAdapter != null |
| && mAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED; |
| } |
| |
| @Override |
| public boolean isBluetoothConnecting() { |
| return mAdapter != null |
| && mAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTING; |
| } |
| |
| @Override |
| public void setBluetoothEnabled(boolean enabled) { |
| if (mAdapter != null) { |
| if (enabled) { |
| mAdapter.enable(); |
| } else { |
| mAdapter.disable(); |
| } |
| } |
| } |
| |
| @Override |
| public boolean isBluetoothSupported() { |
| return mAdapter != null; |
| } |
| |
| @Override |
| public ArraySet<PairedDevice> getPairedDevices() { |
| final ArraySet<PairedDevice> rt = new ArraySet<>(); |
| for (int i = 0; i < mDeviceInfo.size(); i++) { |
| final BluetoothDevice device = mDeviceInfo.keyAt(i); |
| final DeviceInfo info = mDeviceInfo.valueAt(i); |
| if (!info.bonded) continue; |
| final PairedDevice paired = new PairedDevice(); |
| paired.id = device.getAddress(); |
| paired.tag = device; |
| paired.name = device.getAliasName(); |
| paired.state = connectionStateToPairedDeviceState(info.connectionStateIndex); |
| rt.add(paired); |
| } |
| return rt; |
| } |
| |
| private static int connectionStateToPairedDeviceState(int index) { |
| int state = CONNECTION_STATES[index]; |
| if (state == BluetoothAdapter.STATE_CONNECTED) return PairedDevice.STATE_CONNECTED; |
| if (state == BluetoothAdapter.STATE_CONNECTING) return PairedDevice.STATE_CONNECTING; |
| if (state == BluetoothAdapter.STATE_DISCONNECTING) return PairedDevice.STATE_DISCONNECTING; |
| return PairedDevice.STATE_DISCONNECTED; |
| } |
| |
| @Override |
| public void connect(final PairedDevice pd) { |
| connect(pd, true); |
| } |
| |
| @Override |
| public void disconnect(PairedDevice pd) { |
| connect(pd, false); |
| } |
| |
| private void connect(PairedDevice pd, final boolean connect) { |
| if (mAdapter == null || pd == null || pd.tag == null) return; |
| final BluetoothDevice device = (BluetoothDevice) pd.tag; |
| final DeviceInfo info = mDeviceInfo.get(device); |
| final String action = connect ? "connect" : "disconnect"; |
| if (DEBUG) Log.d(TAG, action + " " + deviceToString(device)); |
| final ParcelUuid[] uuids = device.getUuids(); |
| if (uuids == null) { |
| Log.w(TAG, "No uuids returned, aborting " + action + " for " + deviceToString(device)); |
| return; |
| } |
| SparseArray<Boolean> profiles = new SparseArray<>(); |
| if (connect) { |
| // When connecting add every profile we can recognize by uuid. |
| for (ParcelUuid uuid : uuids) { |
| final int profile = uuidToProfile(uuid); |
| if (profile == 0) { |
| Log.w(TAG, "Device " + deviceToString(device) + " has an unsupported uuid: " |
| + uuidToString(uuid)); |
| continue; |
| } |
| final boolean connected = info.connectedProfiles.get(profile, false); |
| if (!connected) { |
| profiles.put(profile, true); |
| } |
| } |
| } else { |
| // When disconnecting, just add every profile we know they are connected to. |
| profiles = info.connectedProfiles; |
| } |
| for (int i = 0; i < profiles.size(); i++) { |
| final int profile = profiles.keyAt(i); |
| if (mProfiles.indexOfKey(profile) >= 0) { |
| final Profile p = BluetoothUtil.getProfile(mProfiles.get(profile)); |
| final boolean ok = connect ? p.connect(device) : p.disconnect(device); |
| if (DEBUG) Log.d(TAG, action + " " + profileToString(profile) + " " |
| + (ok ? "succeeded" : "failed")); |
| } else { |
| Log.w(TAG, "Unable get get Profile for " + profileToString(profile)); |
| } |
| } |
| } |
| |
| @Override |
| public String getLastDeviceName() { |
| return mLastDevice != null ? mLastDevice.getAliasName() : null; |
| } |
| |
| private void updateBondedDevices() { |
| mHandler.removeMessages(MSG_UPDATE_BONDED_DEVICES); |
| mHandler.sendEmptyMessage(MSG_UPDATE_BONDED_DEVICES); |
| } |
| |
| private void updateConnectionStates() { |
| mHandler.removeMessages(MSG_UPDATE_CONNECTION_STATES); |
| mHandler.removeMessages(MSG_UPDATE_SINGLE_CONNECTION_STATE); |
| mHandler.sendEmptyMessage(MSG_UPDATE_CONNECTION_STATES); |
| } |
| |
| private void updateConnectionState(BluetoothDevice device, int profile, int state) { |
| if (mHandler.hasMessages(MSG_UPDATE_CONNECTION_STATES)) { |
| // If we are about to update all the devices, then we don't need to update this one. |
| return; |
| } |
| mHandler.obtainMessage(MSG_UPDATE_SINGLE_CONNECTION_STATE, profile, state, device) |
| .sendToTarget(); |
| } |
| |
| private void handleUpdateBondedDevices() { |
| if (mAdapter == null) return; |
| final Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); |
| for (DeviceInfo info : mDeviceInfo.values()) { |
| info.bonded = false; |
| } |
| int bondedCount = 0; |
| BluetoothDevice lastBonded = null; |
| if (bondedDevices != null) { |
| for (BluetoothDevice bondedDevice : bondedDevices) { |
| final boolean bonded = bondedDevice.getBondState() != BluetoothDevice.BOND_NONE; |
| updateInfo(bondedDevice).bonded = bonded; |
| if (bonded) { |
| bondedCount++; |
| lastBonded = bondedDevice; |
| } |
| } |
| } |
| if (mLastDevice == null && bondedCount == 1) { |
| mLastDevice = lastBonded; |
| } |
| updateConnectionStates(); |
| firePairedDevicesChanged(); |
| } |
| |
| private void handleUpdateConnectionStates() { |
| final int N = mDeviceInfo.size(); |
| for (int i = 0; i < N; i++) { |
| BluetoothDevice device = mDeviceInfo.keyAt(i); |
| DeviceInfo info = updateInfo(device); |
| info.connectionStateIndex = 0; |
| info.connectedProfiles.clear(); |
| for (int j = 0; j < mProfiles.size(); j++) { |
| int state = mProfiles.valueAt(j).getConnectionState(device); |
| handleUpdateConnectionState(device, mProfiles.keyAt(j), state); |
| } |
| } |
| handleConnectionChange(); |
| firePairedDevicesChanged(); |
| } |
| |
| private void handleUpdateConnectionState(BluetoothDevice device, int profile, int state) { |
| if (DEBUG) Log.d(TAG, "updateConnectionState " + BluetoothUtil.deviceToString(device) |
| + " " + BluetoothUtil.profileToString(profile) |
| + " " + BluetoothUtil.connectionStateToString(state)); |
| DeviceInfo info = updateInfo(device); |
| int stateIndex = 0; |
| for (int i = 0; i < CONNECTION_STATES.length; i++) { |
| if (CONNECTION_STATES[i] == state) { |
| stateIndex = i; |
| break; |
| } |
| } |
| info.profileStates.put(profile, stateIndex); |
| |
| info.connectionStateIndex = 0; |
| final int N = info.profileStates.size(); |
| for (int i = 0; i < N; i++) { |
| if (info.profileStates.valueAt(i) > info.connectionStateIndex) { |
| info.connectionStateIndex = info.profileStates.valueAt(i); |
| } |
| } |
| if (state == BluetoothProfile.STATE_CONNECTED) { |
| info.connectedProfiles.put(profile, true); |
| } else { |
| info.connectedProfiles.remove(profile); |
| } |
| } |
| |
| private void handleConnectionChange() { |
| // If we are no longer connected to the current device, see if we are connected to |
| // something else, so we don't display a name we aren't connected to. |
| if (mLastDevice != null && |
| CONNECTION_STATES[mDeviceInfo.get(mLastDevice).connectionStateIndex] |
| != BluetoothProfile.STATE_CONNECTED) { |
| // Make sure we don't keep this device while it isn't connected. |
| mLastDevice = null; |
| // Look for anything else connected. |
| final int size = mDeviceInfo.size(); |
| for (int i = 0; i < size; i++) { |
| BluetoothDevice device = mDeviceInfo.keyAt(i); |
| DeviceInfo info = mDeviceInfo.valueAt(i); |
| if (CONNECTION_STATES[info.connectionStateIndex] |
| == BluetoothProfile.STATE_CONNECTED) { |
| mLastDevice = device; |
| break; |
| } |
| } |
| } |
| } |
| |
| private void bindAllProfiles() { |
| // Note: This needs to contain all of the types that can be returned by BluetoothUtil |
| // otherwise we can't find the profiles we need when we connect/disconnect. |
| mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP); |
| mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP_SINK); |
| mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.AVRCP_CONTROLLER); |
| mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET); |
| mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET_CLIENT); |
| mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.INPUT_DEVICE); |
| mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.MAP); |
| mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.PAN); |
| // Note Health is not in this list because health devices aren't 'connected'. |
| // If profiles are expanded to use more than just connection state and connect/disconnect |
| // then it should be added. |
| } |
| |
| private void firePairedDevicesChanged() { |
| for (Callback cb : mCallbacks) { |
| cb.onBluetoothPairedDevicesChanged(); |
| } |
| } |
| |
| private void setAdapterState(int adapterState) { |
| final boolean enabled = adapterState == BluetoothAdapter.STATE_ON; |
| if (mEnabled == enabled) return; |
| mEnabled = enabled; |
| fireStateChange(); |
| } |
| |
| private void setConnecting(boolean connecting) { |
| if (mConnecting == connecting) return; |
| mConnecting = connecting; |
| fireStateChange(); |
| } |
| |
| private void fireStateChange() { |
| for (Callback cb : mCallbacks) { |
| fireStateChange(cb); |
| } |
| } |
| |
| private void fireStateChange(Callback cb) { |
| cb.onBluetoothStateChange(mEnabled, mConnecting); |
| } |
| |
| private static int getProfileFromAction(String action) { |
| if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { |
| return BluetoothProfile.A2DP; |
| } else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { |
| return BluetoothProfile.HEADSET; |
| } else if (BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { |
| return BluetoothProfile.A2DP_SINK; |
| } else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { |
| return BluetoothProfile.HEADSET_CLIENT; |
| } else if (BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { |
| return BluetoothProfile.INPUT_DEVICE; |
| } else if (BluetoothMap.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { |
| return BluetoothProfile.MAP; |
| } else if (BluetoothPan.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { |
| return BluetoothProfile.PAN; |
| } |
| if (DEBUG) Log.d(TAG, "Unknown action " + action); |
| return -1; |
| } |
| |
| private final ServiceListener mProfileListener = new ServiceListener() { |
| @Override |
| public void onServiceDisconnected(int profile) { |
| if (DEBUG) Log.d(TAG, "Disconnected from " + BluetoothUtil.profileToString(profile)); |
| // We lost a profile, don't do any updates until it gets removed. |
| mHandler.removeMessages(MSG_UPDATE_CONNECTION_STATES); |
| mHandler.removeMessages(MSG_UPDATE_SINGLE_CONNECTION_STATE); |
| mHandler.obtainMessage(MSG_REM_PROFILE, profile, 0).sendToTarget(); |
| } |
| |
| @Override |
| public void onServiceConnected(int profile, BluetoothProfile proxy) { |
| if (DEBUG) Log.d(TAG, "Connected to " + BluetoothUtil.profileToString(profile)); |
| mHandler.obtainMessage(MSG_ADD_PROFILE, profile, 0, proxy).sendToTarget(); |
| } |
| }; |
| |
| private final class Receiver extends BroadcastReceiver { |
| public void register() { |
| final IntentFilter filter = new IntentFilter(); |
| filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); |
| filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); |
| filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); |
| filter.addAction(BluetoothDevice.ACTION_ALIAS_CHANGED); |
| filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); |
| filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); |
| filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED); |
| filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED); |
| filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); |
| filter.addAction(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED); |
| filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); |
| mContext.registerReceiver(this, filter); |
| } |
| |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| final String action = intent.getAction(); |
| final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); |
| |
| if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { |
| setAdapterState(intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, ERROR)); |
| updateBondedDevices(); |
| if (DEBUG) Log.d(TAG, "ACTION_STATE_CHANGED " + mEnabled); |
| } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { |
| updateInfo(device); |
| final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, |
| ERROR); |
| mLastDevice = device; |
| if (DEBUG) Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED " |
| + connectionStateToString(state) + " " + deviceToString(device)); |
| setConnecting(state == BluetoothAdapter.STATE_CONNECTING); |
| } else if (action.equals(BluetoothDevice.ACTION_ALIAS_CHANGED)) { |
| updateInfo(device); |
| mLastDevice = device; |
| } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) { |
| if (DEBUG) Log.d(TAG, "ACTION_BOND_STATE_CHANGED " + device); |
| updateBondedDevices(); |
| } else { |
| int profile = getProfileFromAction(intent.getAction()); |
| int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); |
| if (DEBUG) Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGE " |
| + BluetoothUtil.profileToString(profile) |
| + " " + BluetoothUtil.connectionStateToString(state)); |
| if ((profile != -1) && (state != -1)) { |
| updateConnectionState(device, profile, state); |
| } |
| } |
| } |
| } |
| |
| private DeviceInfo updateInfo(BluetoothDevice device) { |
| DeviceInfo info = mDeviceInfo.get(device); |
| info = info != null ? info : new DeviceInfo(); |
| mDeviceInfo.put(device, info); |
| return info; |
| } |
| |
| private class H extends Handler { |
| public H(Looper l) { |
| super(l); |
| } |
| |
| public void handleMessage(Message msg) { |
| switch (msg.what) { |
| case MSG_UPDATE_CONNECTION_STATES: |
| handleUpdateConnectionStates(); |
| firePairedDevicesChanged(); |
| break; |
| case MSG_UPDATE_SINGLE_CONNECTION_STATE: |
| handleUpdateConnectionState((BluetoothDevice) msg.obj, msg.arg1, msg.arg2); |
| handleConnectionChange(); |
| firePairedDevicesChanged(); |
| break; |
| case MSG_UPDATE_BONDED_DEVICES: |
| handleUpdateBondedDevices(); |
| firePairedDevicesChanged(); |
| break; |
| case MSG_ADD_PROFILE: |
| mProfiles.put(msg.arg1, (BluetoothProfile) msg.obj); |
| handleUpdateConnectionStates(); |
| firePairedDevicesChanged(); |
| break; |
| case MSG_REM_PROFILE: |
| mProfiles.remove(msg.arg1); |
| handleUpdateConnectionStates(); |
| firePairedDevicesChanged(); |
| break; |
| } |
| }; |
| }; |
| |
| private static class DeviceInfo { |
| int connectionStateIndex = 0; |
| boolean bonded; // per getBondedDevices |
| SparseArray<Boolean> connectedProfiles = new SparseArray<>(); |
| SparseArray<Integer> profileStates = new SparseArray<>(); |
| } |
| } |