blob: 0901f98618174fa449682348ec2906c97b7ce646 [file] [log] [blame]
/******************************************************************************
*
* Copyright 2021 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.bluetooth.apm;
import android.content.SharedPreferences;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothUuid;
import android.os.ParcelUuid;
import android.os.Parcelable;
import android.os.SystemProperties;
import android.util.Log;
import android.content.Context;
import com.android.internal.util.ArrayUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
import java.util.ArrayList;
import java.lang.Integer;
import java.lang.Boolean;
import java.util.Objects;
public class DeviceProfileMap {
Map<BluetoothDevice, Integer> mSupportedProfileMap = new HashMap();
Map<BluetoothDevice, int []> mActiveProfileMap = new HashMap();
Map<BluetoothDevice, Integer> mConnectedProfileMap = new HashMap();
private Context mContext;
private static DeviceProfileMap DPMSingleInstance = null;
public static int [] mPreferredProfileList = new int[ApmConst.AudioFeatures.MAX_AUDIO_FEATURES];
public static final String SUPPORTED_PROFILE_MAP = "bluetooth_supported_profile_map";
public final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
public final String ACTION_POWER_OFF = "android.intent.action.QUICKBOOT_POWEROFF";
private final Object mLock = new Object();
private static final int LeMediaProfiles = ApmConst.AudioProfiles.BAP_MEDIA
| ApmConst.AudioProfiles.TMAP_MEDIA
| ApmConst.AudioProfiles.BAP_GCP
| ApmConst.AudioProfiles.BAP_RECORDING;
private static final int LeCallProfiles = ApmConst.AudioProfiles.BAP_CALL
| ApmConst.AudioProfiles.TMAP_CALL;
// private constructor restricted to this class itself
private DeviceProfileMap() {
Log.w(LOGTAG, "DeviceProfileMap object creation");
}
// static method to create instance of Singleton class
public static DeviceProfileMap getDeviceProfileMapInstance() {
if (DPMSingleInstance == null) {
DPMSingleInstance = new DeviceProfileMap();
DeviceProfileMapIntf.init(DPMSingleInstance);
}
return DPMSingleInstance;
}
private static final String LOGTAG = "DeviceProfileMap";
private SharedPreferences getSupportedProfileMap() {
return mContext.getSharedPreferences(SUPPORTED_PROFILE_MAP, Context.MODE_PRIVATE);
}
/**
* Initialize the device profile map
*/
public synchronized boolean init(Context context) {
Log.d(LOGTAG, "init: ");
// populate the supported profile list.
mContext = context;
Map<String, ?> allKeys = getSupportedProfileMap().getAll();
SharedPreferences.Editor mSupportedProfileMapEditor = getSupportedProfileMap().edit();
for (Map.Entry<String, ?> entry : allKeys.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
BluetoothDevice mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().
getRemoteDevice(key);
if (value instanceof Integer && mBluetoothDevice.getBondState()
== BluetoothDevice.BOND_BONDED) {
mSupportedProfileMap.put(mBluetoothDevice, (Integer) value);
Log.d(LOGTAG, "address " + key + " from the Supported Profile Map: " + value);
} else {
Log.d(LOGTAG, "Removing " + key + " from the Supported Profile map");
mSupportedProfileMapEditor.remove(key);
}
}
mSupportedProfileMapEditor.apply();
//intialize the preferred profile list
int mPreferredProfileVal =
SystemProperties.getInt("persist.vendor.qcom.bluetooth.default_profiles", 0);
Log.d(LOGTAG, "init: Preferred Profile = " + mPreferredProfileVal);
int mfeature = 0;
while (mfeature < ApmConst.AudioFeatures.MAX_AUDIO_FEATURES) {
switch(mfeature) {
case ApmConst.AudioFeatures.CALL_AUDIO:
/* default preferred profile for call */
mPreferredProfileList[mfeature] = ApmConst.AudioProfiles.HFP;
if((mPreferredProfileVal &
ApmConst.AudioProfiles.TMAP_CALL) != 0) {
mPreferredProfileList[mfeature] = ApmConst.AudioProfiles.TMAP_CALL;
} else if((mPreferredProfileVal &
ApmConst.AudioProfiles.BAP_CALL) != 0) {
mPreferredProfileList[mfeature] = ApmConst.AudioProfiles.BAP_CALL;
}
break;
case ApmConst.AudioFeatures.MEDIA_AUDIO:
mPreferredProfileList[mfeature] = ApmConst.AudioProfiles.A2DP;
if((mPreferredProfileVal &
ApmConst.AudioProfiles.TMAP_MEDIA) != 0) {
mPreferredProfileList[mfeature] = ApmConst.AudioProfiles.TMAP_MEDIA;
} else if((mPreferredProfileVal &
ApmConst.AudioProfiles.BAP_RECORDING) != 0) {
mPreferredProfileList[mfeature] = ApmConst.AudioProfiles.BAP_RECORDING;
} else if((mPreferredProfileVal &
ApmConst.AudioProfiles.BAP_MEDIA) != 0) {
mPreferredProfileList[mfeature] = ApmConst.AudioProfiles.BAP_MEDIA;
}
break;
case ApmConst.AudioFeatures.CALL_CONTROL:
mPreferredProfileList[mfeature] = ((mPreferredProfileVal &
ApmConst.AudioProfiles.CCP) != 0) ?
ApmConst.AudioProfiles.CCP : ApmConst.AudioProfiles.HFP;
break;
case ApmConst.AudioFeatures.MEDIA_CONTROL:
mPreferredProfileList[mfeature] = ((mPreferredProfileVal &
ApmConst.AudioProfiles.AVRCP) != 0) ?
ApmConst.AudioProfiles.AVRCP : ApmConst.AudioProfiles.MCP;
break;
case ApmConst.AudioFeatures.CALL_VOLUME_CONTROL:
mPreferredProfileList[mfeature] = ((mPreferredProfileVal &
(ApmConst.AudioProfiles.BAP_CALL | ApmConst.AudioProfiles.TMAP_CALL)) != 0) ?
ApmConst.AudioProfiles.VCP : ApmConst.AudioProfiles.HFP;
break;
case ApmConst.AudioFeatures.MEDIA_VOLUME_CONTROL:
mPreferredProfileList[mfeature] = ((mPreferredProfileVal &
ApmConst.AudioProfiles.AVRCP) != 0) ?
ApmConst.AudioProfiles.AVRCP : ApmConst.AudioProfiles.VCP;
break;
case ApmConst.AudioFeatures.HEARING_AID:
mPreferredProfileList[mfeature] = ((mPreferredProfileVal &
ApmConst.AudioProfiles.HAP_BREDR) != 0) ?
ApmConst.AudioProfiles.HAP_BREDR : ApmConst.AudioProfiles.HAP_LE;
break;
case ApmConst.AudioFeatures.BROADCAST_AUDIO:
mPreferredProfileList[mfeature] = ((mPreferredProfileVal &
ApmConst.AudioProfiles.BROADCAST_BREDR) != 0) ?
ApmConst.AudioProfiles.BROADCAST_BREDR : ApmConst.AudioProfiles.BROADCAST_LE;
break;
default :
break;
}
Log.w(LOGTAG, "init: Preferred Profile = " + mPreferredProfileList[mfeature] +
" for audio feature " + mfeature);
mfeature++;
}
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_UUID);
filter.addAction(ACTION_SHUTDOWN);
filter.addAction(ACTION_POWER_OFF);
mContext.registerReceiver(mDeviceProfileMapReceiver, filter);
return true;
}
private final BroadcastReceiver mDeviceProfileMapReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
Log.w(LOGTAG, "mDeviceProfileMapReceiver, action is null");
return;
}
switch (action) {
case BluetoothDevice.ACTION_UUID: {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
handleDeviceUuidEvent(device, uuids);
break;
}
case ACTION_SHUTDOWN:
case ACTION_POWER_OFF:
handleDeviceShutdown();
break;
default:
Log.w(LOGTAG, "Unknown action " + action);
}
}
};
private void handleDeviceUuidEvent(BluetoothDevice device, Parcelable[] uuids) {
Log.d(LOGTAG, "UUIDs found, device: " + device);
if (uuids != null) {
ParcelUuid[] uuidsToSend = new ParcelUuid[uuids.length];
for (int i = 0; i < uuidsToSend.length; i++) {
uuidsToSend[i] = (ParcelUuid) uuids[i];
Log.d(LOGTAG,"index=" + i + "uuid=" + uuidsToSend[i]);
}
checkIfProfileSupported(device, uuidsToSend);
}
}
private void checkIfProfileSupported(BluetoothDevice device, ParcelUuid[] remoteDeviceUuids) {
ParcelUuid ADV_AUDIO_T_MEDIA =
ParcelUuid.fromString("00006AD0-0000-1000-8000-00805F9B34FB");
ParcelUuid HEARINGAID_ADV_AUDIO =
ParcelUuid.fromString("00006AD2-0000-1000-8000-00805F9B34FB");
ParcelUuid ADV_AUDIO_P_MEDIA =
ParcelUuid.fromString("00006AD1-0000-1000-8000-00805F9B34FB");
ParcelUuid ADV_AUDIO_P_VOICE =
ParcelUuid.fromString("00006AD4-0000-1000-8000-00805F9B34FB");
ParcelUuid ADV_AUDIO_T_VOICE =
ParcelUuid.fromString("00006AD5-0000-1000-8000-00805F9B34FB");
ParcelUuid ADV_AUDIO_G_MEDIA =
ParcelUuid.fromString("12994B7E-6d47-4215-8C9E-AAE9A1095BA3");
ParcelUuid ADV_AUDIO_W_RECORDING =
ParcelUuid.fromString("2587DB3C-CE70-4FC9-935F-777AB4188FD7");
if (ArrayUtils.contains(remoteDeviceUuids, BluetoothUuid.HFP)) {
updateSupportedProfileMap(device, ApmConst.AudioProfiles.HFP);
}
if (ArrayUtils.contains(remoteDeviceUuids, BluetoothUuid.A2DP_SINK)) {
updateSupportedProfileMap(device, ApmConst.AudioProfiles.A2DP);
}
if (ArrayUtils.contains(remoteDeviceUuids, BluetoothUuid.HEARING_AID)) {
updateSupportedProfileMap(device, ApmConst.AudioProfiles.HAP_BREDR);
}
if (ArrayUtils.contains(remoteDeviceUuids, BluetoothUuid.AVRCP_CONTROLLER)) {
updateSupportedProfileMap(device, ApmConst.AudioProfiles.AVRCP);
}
if (ArrayUtils.contains(remoteDeviceUuids, ADV_AUDIO_T_MEDIA)) {
updateSupportedProfileMap(device, ApmConst.AudioProfiles.TMAP_MEDIA);
}
if (ArrayUtils.contains(remoteDeviceUuids, ADV_AUDIO_T_VOICE)) {
updateSupportedProfileMap(device, ApmConst.AudioProfiles.TMAP_CALL);
}
if (ArrayUtils.contains(remoteDeviceUuids, ADV_AUDIO_P_MEDIA)) {
updateSupportedProfileMap(device, ApmConst.AudioProfiles.BAP_MEDIA);
}
if (ArrayUtils.contains(remoteDeviceUuids, ADV_AUDIO_P_VOICE)) {
updateSupportedProfileMap(device, ApmConst.AudioProfiles.BAP_CALL);
}
if (ArrayUtils.contains(remoteDeviceUuids, ADV_AUDIO_W_RECORDING)) {
updateSupportedProfileMap(device, ApmConst.AudioProfiles.BAP_RECORDING);
}
}
private void updateSupportedProfileMap(BluetoothDevice device, int mProfile) {
synchronized (mLock) {
int mSupportedProfileBitMap = 0;
if(!mSupportedProfileMap.containsKey(device)) {
//device is not added in supported map, add to it
Log.d(LOGTAG, "updateSupportedProfileMap: device " + device +
"is not added in supported map, add it");
mSupportedProfileMap.put(device, mSupportedProfileBitMap);
} else {
mSupportedProfileBitMap = mSupportedProfileMap.get(device);
}
Log.d(LOGTAG, "updateSupportedProfileMap: device " + device + " for profile "
+ mProfile + " mSupportedProfileBitMap " + mSupportedProfileBitMap);
mSupportedProfileBitMap = mSupportedProfileBitMap | mProfile;
mSupportedProfileMap.put(device, mSupportedProfileBitMap);
Log.d(LOGTAG, "updateSupportedProfileMap: device " + device + " for profile "
+ mProfile + " mSupportedProfileBitMap " + mSupportedProfileBitMap);
}
}
public int getAllSupportedProfile(BluetoothDevice device) {
int mSupportedProfileBitMap = 0;
synchronized (mLock) {
if(!mSupportedProfileMap.containsKey(device)) {
Log.d(LOGTAG, "No Supported Profile found for the device " + device);
} else {
mSupportedProfileBitMap = mSupportedProfileMap.get(device);
}
Log.d(LOGTAG, "getAllSupportedProfile: Supported Profile for the device "
+ device + " mSupportedProfileBitMap " + Integer.toHexString(mSupportedProfileBitMap));
}
return mSupportedProfileBitMap;
}
public int getProfile(BluetoothDevice device, Integer mAudioFeature) {
int profileMap = getSupportedProfile(device, mAudioFeature);
int preferredProfile = profileMap;
int [] mAciveProfileArray = mActiveProfileMap.get(device);
if(profileMap == ApmConst.AudioProfiles.NONE)
return ApmConst.AudioProfiles.NONE;
switch(mAudioFeature) {
case ApmConst.AudioFeatures.CALL_AUDIO:
int mActiveProfileForCallAudio = mAciveProfileArray[mAudioFeature];
if(mActiveProfileForCallAudio != ApmConst.AudioProfiles.NONE) {
//active profile is set
preferredProfile = mActiveProfileForCallAudio;
return preferredProfile;
}
if(profileMap == ApmConst.AudioProfiles.HAP_BREDR ||
profileMap == ApmConst.AudioProfiles.HAP_LE) {
preferredProfile = profileMap;
return preferredProfile;
}
int mHFP = profileMap & ApmConst.AudioProfiles.HFP;
int mLeCall = profileMap & ApmConst.AudioProfiles.TMAP_CALL;
if(mLeCall == ApmConst.AudioProfiles.NONE)
mLeCall = profileMap & ApmConst.AudioProfiles.BAP_CALL;
if(mHFP != ApmConst.AudioProfiles.NONE &&
mLeCall != ApmConst.AudioProfiles.NONE) {
preferredProfile = mPreferredProfileList[mAudioFeature];
} else if(mHFP != ApmConst.AudioProfiles.NONE) {
preferredProfile = mHFP;
} else {
preferredProfile = mLeCall;
}
Log.d(LOGTAG, "getProfile: device " + device + " preferredProfile: "
+ preferredProfile + " for CALL_AUDIO");
break;
case ApmConst.AudioFeatures.MEDIA_AUDIO:
int mActiveProfileForMediaAudio = mAciveProfileArray[mAudioFeature];
if(mActiveProfileForMediaAudio != ApmConst.AudioProfiles.NONE) {
//active profile is set
preferredProfile = mActiveProfileForMediaAudio;
Log.d(LOGTAG, "getProfile: device " + device + " Active Profile: "
+ preferredProfile + " for MEDIA_AUDIO");
return preferredProfile;
}
if(profileMap == ApmConst.AudioProfiles.HAP_BREDR ||
profileMap == ApmConst.AudioProfiles.HAP_LE) {
preferredProfile = profileMap;
return preferredProfile;
}
int mA2dp = profileMap & ApmConst.AudioProfiles.A2DP;
int mLeMedia = profileMap & ApmConst.AudioProfiles.TMAP_MEDIA;
if(mLeMedia == ApmConst.AudioProfiles.NONE)
mLeMedia = profileMap & ApmConst.AudioProfiles.BAP_MEDIA;
if(mA2dp != ApmConst.AudioProfiles.NONE &&
mLeMedia != ApmConst.AudioProfiles.NONE) {
preferredProfile = mPreferredProfileList[mAudioFeature];
} else if(mA2dp != ApmConst.AudioProfiles.NONE) {
preferredProfile = mA2dp;
} else {
if((preferredProfile & ApmConst.AudioProfiles.BAP_RECORDING)
!= ApmConst.AudioProfiles.NONE)
preferredProfile = mPreferredProfileList[mAudioFeature];
else
preferredProfile = mLeMedia;
}
Log.d(LOGTAG, "getProfile: device " + device + " preferredProfile: "
+ preferredProfile + " for MEDIA_AUDIO");
break;
}
return preferredProfile;
}
public int getSupportedProfile(BluetoothDevice device, Integer mAudioFeature) {
int [] mAciveProfileArray;
Log.d(LOGTAG, "getSupportedProfile: for the device " + device + " AudioFeature " + mAudioFeature);
if(!mActiveProfileMap.containsKey(device)) {
// intialize the active profile but map for the device
Log.d(LOGTAG, "getSupportedProfile: intialize the active profile map for the device " + device);
mAciveProfileArray = new int[ApmConst.AudioFeatures.MAX_AUDIO_FEATURES];
Arrays.fill(mAciveProfileArray, ApmConst.AudioProfiles.NONE);
mActiveProfileMap.put(device, mAciveProfileArray);
} else {
mAciveProfileArray = mActiveProfileMap.get(device);
}
//get the supprted profile list
int mSupportedProfileBitMap = 0;
if(!mSupportedProfileMap.containsKey(device)) {
//device is not added in supported map, add to it
Log.d(LOGTAG, "getSupportedProfile: device " + device + " is not added in supported map, add it");
mSupportedProfileMap.put(device, mSupportedProfileBitMap);
} else {
mSupportedProfileBitMap = mSupportedProfileMap.get(device);
}
Log.d(LOGTAG, "getSupportedProfile: supported Profiles for the device " + device
+ " val = " + Integer.toHexString(mSupportedProfileBitMap));
switch(mAudioFeature) {
case ApmConst.AudioFeatures.CALL_AUDIO:
{
int mIsHapBREDRSupported = mSupportedProfileBitMap & ApmConst.AudioProfiles.HAP_BREDR;
int mIsHapLESupported = mSupportedProfileBitMap & ApmConst.AudioProfiles.HAP_LE;
if(mIsHapBREDRSupported != ApmConst.AudioProfiles.NONE) {
return ApmConst.AudioProfiles.HAP_BREDR;
} else if (mIsHapLESupported != ApmConst.AudioProfiles.NONE) {
return ApmConst.AudioProfiles.HAP_LE;
}
int mCallAudioProfile = mSupportedProfileBitMap & ( ApmConst.AudioProfiles.HFP
| ApmConst.AudioProfiles.BAP_CALL
| ApmConst.AudioProfiles.TMAP_CALL);
Log.d(LOGTAG, "getSupportedProfile: device " + device + " supports: "
+ mCallAudioProfile + " for CALL_AUDIO");
return mCallAudioProfile;
}
case ApmConst.AudioFeatures.MEDIA_AUDIO:
{
int mIsHapBREDRSupported = mSupportedProfileBitMap & ApmConst.AudioProfiles.HAP_BREDR;
int mIsHapLESupported = mSupportedProfileBitMap & ApmConst.AudioProfiles.HAP_LE;
if(mIsHapBREDRSupported != ApmConst.AudioProfiles.NONE) {
return ApmConst.AudioProfiles.HAP_BREDR;
} else if (mIsHapLESupported != ApmConst.AudioProfiles.NONE) {
return ApmConst.AudioProfiles.HAP_LE;
}
int mMediaAudioProfile = mSupportedProfileBitMap & ( ApmConst.AudioProfiles.A2DP
| ApmConst.AudioProfiles.BAP_MEDIA
| ApmConst.AudioProfiles.TMAP_MEDIA
| ApmConst.AudioProfiles.BAP_RECORDING);
Log.d(LOGTAG, "getSupportedProfile: device " + device + " supports: "
+ mMediaAudioProfile + " for MEDIA_AUDIO");
return mMediaAudioProfile;
}
case ApmConst.AudioFeatures.MEDIA_CONTROL:
{
int mActiveProfileForMediaControl = mAciveProfileArray
[ApmConst.AudioFeatures.MEDIA_CONTROL];
Log.d(LOGTAG, "getSupportedProfile: device " + device + " ActiveProfile For MediaControl " +
mActiveProfileForMediaControl);
return mActiveProfileForMediaControl;
}
case ApmConst.AudioFeatures.CALL_CONTROL:
{
int mActiveProfileForCallControl = mAciveProfileArray
[ApmConst.AudioFeatures.CALL_CONTROL];
Log.d(LOGTAG, "getSupportedProfile: device " + device + " ActiveProfile For Call Control " +
mActiveProfileForCallControl);
return mActiveProfileForCallControl;
}
case ApmConst.AudioFeatures.MEDIA_VOLUME_CONTROL:
{
int mActiveProfileForMediaVolControl = mAciveProfileArray
[ApmConst.AudioFeatures.MEDIA_VOLUME_CONTROL];
Log.d(LOGTAG, "getSupportedProfile: device " + device +
" ActiveProfile For Media Volume Control " + mActiveProfileForMediaVolControl);
return mActiveProfileForMediaVolControl;
}
case ApmConst.AudioFeatures.CALL_VOLUME_CONTROL:
{
int mActiveProfileForCallVolControl = mAciveProfileArray
[ApmConst.AudioFeatures.CALL_VOLUME_CONTROL];
Log.d(LOGTAG, "getSupportedProfile: device " + device +
" ActiveProfile For call Volume Control " + mActiveProfileForCallVolControl);
return mActiveProfileForCallVolControl;
}
case ApmConst.AudioFeatures.BROADCAST_AUDIO:
{
int mActiveProfileForBroadCastAudio = mAciveProfileArray
[ApmConst.AudioFeatures.BROADCAST_AUDIO];
if(mActiveProfileForBroadCastAudio != ApmConst.AudioProfiles.NONE) {
//active profile is set
return mActiveProfileForBroadCastAudio;
}
int mIsBroadCastBREDRSupported = mSupportedProfileBitMap &
ApmConst.AudioProfiles.BROADCAST_BREDR;
int mIsBroadCastLESupported =
mSupportedProfileBitMap & ApmConst.AudioProfiles.BROADCAST_LE;
Log.d(LOGTAG, "getSupportedProfile: device " + device + " mIsBroadCastBREDRSupported "
+ mIsBroadCastBREDRSupported + " mIsBroadCastLESupported "
+ mIsBroadCastLESupported);
if((mIsBroadCastBREDRSupported != 0) && (mIsBroadCastLESupported != 0)) {
return mPreferredProfileList[ApmConst.AudioFeatures.BROADCAST_AUDIO];
} else if (mIsBroadCastBREDRSupported != 0) {
return ApmConst.AudioProfiles.BROADCAST_BREDR;
} else if(mIsBroadCastLESupported != 0) {
return ApmConst.AudioProfiles.BROADCAST_LE;
}
break;
}
case ApmConst.AudioFeatures.HEARING_AID:
{
int mActiveProfileForHearingAid = mAciveProfileArray
[ApmConst.AudioFeatures.HEARING_AID];
if(mActiveProfileForHearingAid != ApmConst.AudioProfiles.NONE) {
//active profile is set
return mActiveProfileForHearingAid;
}
int mIsHAPBREDRSupported = mSupportedProfileBitMap & ApmConst.AudioProfiles.HAP_BREDR;
int mIsHAPLESupported = mSupportedProfileBitMap & ApmConst.AudioProfiles.HAP_LE;
Log.d(LOGTAG, "getSupportedProfile: device " + device + " mIsHAPBREDRSupported "
+ mIsHAPBREDRSupported + " mIsHAPLESupported " + mIsHAPLESupported);
if((mIsHAPBREDRSupported != 0) && (mIsHAPLESupported !=0)) {
return mPreferredProfileList[ApmConst.AudioFeatures.HEARING_AID];
} else if (mIsHAPBREDRSupported != 0) {
return ApmConst.AudioProfiles.HAP_BREDR;
} else if(mIsHAPLESupported != 0) {
return ApmConst.AudioProfiles.HAP_LE;
}
break;
}
default :
{
Log.w(LOGTAG, "getSupportedProfile: no profile supported for" +
mAudioFeature + " device " + device);
return ApmConst.AudioProfiles.NONE;
}
}
return ApmConst.AudioProfiles.NONE;
}
public void profileDescoveryUpdate (BluetoothDevice device, Integer mAudioProfile) {
int mSupportedProfileBitMap = 0;
if(mSupportedProfileMap.containsKey(device)) {
mSupportedProfileBitMap = mSupportedProfileMap.get(device);
}
mSupportedProfileBitMap = mSupportedProfileBitMap | mAudioProfile;
mSupportedProfileMap.put(device, mSupportedProfileBitMap);
}
public void profileConnectionUpdate(BluetoothDevice device, Integer mAudioFeature,
Integer mAudioProfile, Boolean mProfileStatus) {
int mSupportedProfileBitMap = 0;
int mConnectedProfileBitMap = 0;
int [] mAciveProfileArray;
Log.d(LOGTAG, "profileConnectionUpdate: device : " + device + " AudioProfile "
+ mAudioProfile + " ProfileStatus " + mProfileStatus);
synchronized (mLock) {
// get the Connected profile list
if(mConnectedProfileMap.containsKey(device)) {
mConnectedProfileBitMap = mConnectedProfileMap.get(device);
}
// get the Supported profile list
if(mSupportedProfileMap.containsKey(device)) {
mSupportedProfileBitMap = mSupportedProfileMap.get(device);
}
if(!mActiveProfileMap.containsKey(device)) {
// intialize the active profile but map for the device
Log.d(LOGTAG, "profileConnectionUpdate: intialize the active " +
" profile map for the device " + device);
mAciveProfileArray = new int[ApmConst.AudioFeatures.MAX_AUDIO_FEATURES];
Arrays.fill(mAciveProfileArray, ApmConst.AudioProfiles.NONE);
mActiveProfileMap.put(device, mAciveProfileArray);
} else {
mAciveProfileArray = mActiveProfileMap.get(device);
}
// update the Audio profile connection in list
if (mProfileStatus) {
mSupportedProfileBitMap = mSupportedProfileBitMap | mAudioProfile;
mConnectedProfileBitMap = mConnectedProfileBitMap | mAudioProfile;
//update the active profile list
if(mAciveProfileArray[mAudioFeature] == ApmConst.AudioProfiles.NONE) {
mAciveProfileArray[mAudioFeature] = mAudioProfile;
} else if(mAciveProfileArray[mAudioFeature] != mAudioProfile) {
// diffrent profile connected for the same mAudioFeature need to update the active list.
int mPreferredProfile = mPreferredProfileList[mAudioFeature];
Log.d(LOGTAG, "profileConnectionUpdate: PreferredProfile for audio feature " +
mAudioFeature + " is " + mPreferredProfile + " device " + device);
if((mPreferredProfile != ApmConst.AudioProfiles.NONE)
&& (mConnectedProfileBitMap & mPreferredProfile) != 0) {
mAciveProfileArray[mAudioFeature] = mPreferredProfile;
}
}
} else {
mConnectedProfileBitMap = mConnectedProfileBitMap & ~mAudioProfile;
// profile disconnect for active profile
if(mAciveProfileArray[mAudioFeature] == mAudioProfile) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
// do we need to update the active profile with other connected profile for that audio feature.
switch(mAudioFeature) {
case ApmConst.AudioFeatures.CALL_AUDIO:
if(mAudioProfile == ApmConst.AudioProfiles.HFP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.TMAP_CALL) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.TMAP_CALL;
} else if ((mConnectedProfileBitMap & ApmConst.AudioProfiles.BAP_CALL) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.BAP_CALL;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
} else if (mAudioProfile == ApmConst.AudioProfiles.TMAP_CALL
|| mAudioProfile == ApmConst.AudioProfiles.BAP_CALL) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.HFP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.HFP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
}
break;
case ApmConst.AudioFeatures.MEDIA_AUDIO:
if(mAudioProfile == ApmConst.AudioProfiles.A2DP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.TMAP_MEDIA) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.TMAP_MEDIA;
} else if ((mConnectedProfileBitMap & ApmConst.AudioProfiles.BAP_MEDIA) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.BAP_MEDIA;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
} else if (mAudioProfile == ApmConst.AudioProfiles.TMAP_MEDIA
|| mAudioProfile == ApmConst.AudioProfiles.BAP_MEDIA) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.A2DP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.A2DP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
}
break;
case ApmConst.AudioFeatures.CALL_CONTROL:
if(mAudioProfile == ApmConst.AudioProfiles.HFP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.CCP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.CCP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
} else if (mAudioProfile == ApmConst.AudioProfiles.CCP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.HFP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.HFP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
}
break;
case ApmConst.AudioFeatures.MEDIA_CONTROL:
if(mAudioProfile == ApmConst.AudioProfiles.AVRCP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.MCP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.MCP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
} else if (mAudioProfile == ApmConst.AudioProfiles.MCP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.AVRCP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.AVRCP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
}
break;
case ApmConst.AudioFeatures.MEDIA_VOLUME_CONTROL:
if(mAudioProfile == ApmConst.AudioProfiles.AVRCP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.VCP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.VCP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
} else if (mAudioProfile == ApmConst.AudioProfiles.VCP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.AVRCP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.AVRCP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
}
break;
case ApmConst.AudioFeatures.CALL_VOLUME_CONTROL:
if(mAudioProfile == ApmConst.AudioProfiles.HFP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.VCP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.VCP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
} else if (mAudioProfile == ApmConst.AudioProfiles.VCP) {
if((mConnectedProfileBitMap & ApmConst.AudioProfiles.HFP) > 0) {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.HFP;
} else {
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
}
break;
default:
mAciveProfileArray[mAudioFeature] = ApmConst.AudioProfiles.NONE;
}
}
}
mActiveProfileMap.put(device, mAciveProfileArray);
Log.d(LOGTAG, "profileConnectionUpdate: supported Profiles for the device " + device
+ " val " + Integer.toHexString(mSupportedProfileBitMap));
Log.d(LOGTAG, "profileConnectionUpdate: connected Profiles for the device " + device
+ " val " + Integer.toHexString(mConnectedProfileBitMap));
mConnectedProfileMap.put(device, mConnectedProfileBitMap);
mSupportedProfileMap.put(device, mSupportedProfileBitMap);
}
}
public boolean isProfileConnected(BluetoothDevice device, Integer mAudioProfile) {
if (device == null) return false;
int mConnectedProfileBitMap = mConnectedProfileMap.get(device);
Log.d(LOGTAG, "isProfileConnected: device: " + device
+ " mAudioProfile: " + mAudioProfile + " mConnectedProfileMap: " + mConnectedProfileBitMap);
return ((mConnectedProfileBitMap & mAudioProfile) == mAudioProfile);
}
public void setActiveProfile(BluetoothDevice device, Integer mAudioFeature, Integer mAudioProfile) {
int [] mAciveProfileArray;
Log.d(LOGTAG, "setActiveProfile: device : " + device + " AudioProfile "
+ mAudioProfile + " AudioFeature " + mAudioFeature);
synchronized (mLock) {
if(!mActiveProfileMap.containsKey(device)) {
Log.d(LOGTAG, "setActiveProfile: intialize the active profile map for the device "
+ device);
mAciveProfileArray = new int[ApmConst.AudioFeatures.MAX_AUDIO_FEATURES];
Arrays.fill(mAciveProfileArray, ApmConst.AudioProfiles.NONE);
mActiveProfileMap.put(device, mAciveProfileArray);
} else {
mAciveProfileArray = mActiveProfileMap.get(device);
}
mAciveProfileArray[mAudioFeature] = mAudioProfile;
mActiveProfileMap.put(device, mAciveProfileArray);
}
}
static int getLeMediaProfiles() {
return LeMediaProfiles;
}
static int getLeCallProfiles() {
return LeCallProfiles;
}
public synchronized void handleDeviceShutdown() {
Log.d(LOGTAG, "handleDeviceShutdown: started");
//store the supported profiles for the bonded devices
SharedPreferences.Editor pref = getSupportedProfileMap().edit();
for (BluetoothDevice mBluetoothDevice : mSupportedProfileMap.keySet()) {
int mSupportedProfilesVal = mSupportedProfileMap.get(mBluetoothDevice);
Log.d(LOGTAG, "cleanup: supported Profiles for the device " + mBluetoothDevice
+ " val = " + Integer.toHexString(mSupportedProfilesVal));
if(mBluetoothDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
pref.putInt(mBluetoothDevice.getAddress(), mSupportedProfilesVal);
}
}
pref.apply();
mSupportedProfileMap.clear();
mActiveProfileMap.clear();
mConnectedProfileMap.clear();
Log.d(LOGTAG, "handleDeviceShutdown: Done");
}
public synchronized void cleanup () {
if(DPMSingleInstance == null) {
Log.w(LOGTAG, "cleanup called without initialization, Returning");
return;
}
Log.d(LOGTAG, "cleanup: started");
//store the supported profiles for the bonded devices
SharedPreferences.Editor pref = getSupportedProfileMap().edit();
for (BluetoothDevice mBluetoothDevice : mSupportedProfileMap.keySet()) {
int mSupportedProfilesVal = mSupportedProfileMap.get(mBluetoothDevice);
Log.d(LOGTAG, "cleanup: supported Profiles for the device " + mBluetoothDevice
+ " val = " + Integer.toHexString(mSupportedProfilesVal));
if(mBluetoothDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
pref.putInt(mBluetoothDevice.getAddress(), mSupportedProfilesVal);
}
}
pref.apply();
mSupportedProfileMap.clear();
mActiveProfileMap.clear();
mConnectedProfileMap.clear();
DPMSingleInstance = null;
mContext.unregisterReceiver(mDeviceProfileMapReceiver);
Log.d(LOGTAG, "cleanup: Done");
}
}