diff options
3 files changed, 215 insertions, 3 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java new file mode 100644 index 000000000000..941964a57eb4 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2017 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.settingslib.bluetooth; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothClass; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHidDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.util.Log; + +import com.android.settingslib.R; + +import java.util.Collection; +import java.util.List; + +/** + * HidProfile handles Bluetooth HID profile. + */ +public class HidDeviceProfile implements LocalBluetoothProfile { + private static final String TAG = "HidDeviceProfile"; + // Order of this profile in device profiles list + private static final int ORDINAL = 18; + // HID Device Profile is always preferred. + private static final int PREFERRED_VALUE = -1; + private static final boolean DEBUG = true; + + private final LocalBluetoothAdapter mLocalAdapter; + private final CachedBluetoothDeviceManager mDeviceManager; + private final LocalBluetoothProfileManager mProfileManager; + static final String NAME = "HID DEVICE"; + + private BluetoothHidDevice mService; + private boolean mIsProfileReady; + + HidDeviceProfile(Context context, LocalBluetoothAdapter adapter, + CachedBluetoothDeviceManager deviceManager, + LocalBluetoothProfileManager profileManager) { + mLocalAdapter = adapter; + mDeviceManager = deviceManager; + mProfileManager = profileManager; + adapter.getProfileProxy(context, new HidDeviceServiceListener(), + BluetoothProfile.HID_DEVICE); + } + + // These callbacks run on the main thread. + private final class HidDeviceServiceListener + implements BluetoothProfile.ServiceListener { + + public void onServiceConnected(int profile, BluetoothProfile proxy) { + if (DEBUG) { + Log.d(TAG,"Bluetooth service connected :-)"); + } + mService = (BluetoothHidDevice) proxy; + // We just bound to the service, so refresh the UI for any connected HID devices. + List<BluetoothDevice> deviceList = mService.getConnectedDevices(); + for (BluetoothDevice nextDevice : deviceList) { + 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); + } + Log.d(TAG, "Connection status changed: " + device); + device.onProfileStateChanged(HidDeviceProfile.this, + BluetoothProfile.STATE_CONNECTED); + device.refresh(); + } + mIsProfileReady = true; + } + + public void onServiceDisconnected(int profile) { + if (DEBUG) { + Log.d(TAG, "Bluetooth service disconnected"); + } + mIsProfileReady = false; + } + } + + @Override + public boolean isProfileReady() { + return mIsProfileReady; + } + + @Override + public boolean isConnectable() { + return true; + } + + @Override + public boolean isAutoConnectable() { + return false; + } + + @Override + public boolean connect(BluetoothDevice device) { + return false; + } + + @Override + public boolean disconnect(BluetoothDevice device) { + if (mService == null) { + return false; + } + return mService.disconnect(device); + } + + @Override + public int getConnectionStatus(BluetoothDevice device) { + if (mService == null) { + return BluetoothProfile.STATE_DISCONNECTED; + } + List<BluetoothDevice> deviceList = mService.getConnectedDevices(); + + return !deviceList.isEmpty() && deviceList.contains(device) + ? mService.getConnectionState(device) + : BluetoothProfile.STATE_DISCONNECTED; + } + + @Override + public boolean isPreferred(BluetoothDevice device) { + return getConnectionStatus(device) != BluetoothProfile.STATE_DISCONNECTED; + } + + @Override + public int getPreferred(BluetoothDevice device) { + return PREFERRED_VALUE; + } + + @Override + public void setPreferred(BluetoothDevice device, boolean preferred) { + // if set preferred to false, then disconnect to the current device + if (!preferred) { + mService.disconnect(device); + } + } + + @Override + public String toString() { + return NAME; + } + + @Override + public int getOrdinal() { + return ORDINAL; + } + + @Override + public int getNameResource(BluetoothDevice device) { + return R.string.bluetooth_profile_hid; + } + + @Override + public int getSummaryResourceForDevice(BluetoothDevice device) { + final 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); + } + } + + @Override + public int getDrawableResource(BluetoothClass btClass) { + return R.drawable.ic_bt_misc_hid; + } + + protected void finalize() { + if (DEBUG) { + Log.d(TAG, "finalize()"); + } + if (mService != null) { + try { + BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HID_DEVICE, + mService); + mService = null; + } catch (Throwable t) { + Log.w(TAG, "Error cleaning up HID proxy", t); + } + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java index 213002fb9726..93c4017fdaf8 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java @@ -48,7 +48,7 @@ public class HidProfile implements LocalBluetoothProfile { private static final int ORDINAL = 3; // These callbacks run on the main thread. - private final class InputDeviceServiceListener + private final class HidHostServiceListener implements BluetoothProfile.ServiceListener { public void onServiceConnected(int profile, BluetoothProfile proxy) { @@ -86,7 +86,7 @@ public class HidProfile implements LocalBluetoothProfile { mLocalAdapter = adapter; mDeviceManager = deviceManager; mProfileManager = profileManager; - adapter.getProfileProxy(context, new InputDeviceServiceListener(), + adapter.getProfileProxy(context, new HidHostServiceListener(), BluetoothProfile.HID_HOST); } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index 34a099cb7ea0..5b202dc58579 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -22,6 +22,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothHidDevice; import android.bluetooth.BluetoothHidHost; import android.bluetooth.BluetoothMap; import android.bluetooth.BluetoothMapClient; @@ -86,6 +87,7 @@ public class LocalBluetoothProfileManager { private MapProfile mMapProfile; private MapClientProfile mMapClientProfile; private final HidProfile mHidProfile; + private HidDeviceProfile mHidDeviceProfile; private OppProfile mOppProfile; private final PanProfile mPanProfile; private PbapClientProfile mPbapClientProfile; @@ -123,7 +125,7 @@ public class LocalBluetoothProfileManager { updateLocalProfiles(uuids); } - // Always add HID and PAN profiles + // Always add HID host, HID device, and PAN profiles mHidProfile = new HidProfile(context, mLocalAdapter, mDeviceManager, this); addProfile(mHidProfile, HidProfile.NAME, BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED); @@ -132,6 +134,10 @@ public class LocalBluetoothProfileManager { addPanProfile(mPanProfile, PanProfile.NAME, BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); + mHidDeviceProfile = new HidDeviceProfile(context, mLocalAdapter, mDeviceManager, this); + addProfile(mHidDeviceProfile, HidDeviceProfile.NAME, + BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED); + if(DEBUG) Log.d(TAG, "Adding local MAP profile"); if (mUseMapClient) { mMapClientProfile = new MapClientProfile(mContext, mLocalAdapter, mDeviceManager, this); @@ -505,6 +511,12 @@ public class LocalBluetoothProfileManager { removedProfiles.remove(mHidProfile); } + if (mHidProfile != null && mHidDeviceProfile.getConnectionStatus(device) + != BluetoothProfile.STATE_DISCONNECTED) { + profiles.add(mHidDeviceProfile); + removedProfiles.remove(mHidDeviceProfile); + } + if(isPanNapConnected) if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists."); if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) && |