Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b73802a authored by Ugo Yu's avatar Ugo Yu
Browse files

Implementation for Bluetooth silence mode

Policies of silence mode:
1) If an active device (for A2DP or HFP) enters silence mode,
   the active device for that profile will be set to null.
2) If a device exits silence mode while the A2DP or HFP active
   device is null, the device will be set as the active device
   for that profile.
3) If a device is disconnected, it exits silence mode.
4) If a device is set as the active device for A2DP or HFP,
   while silence mode is enabled, then the device will exit
   silence mode.
5) If a device is in silence mode, AVRCP position change event
   and HFP AG indicators will be disabled.
6) If a device is not connected with A2DP or HFP, it cannot
   enter silence mode.

Bug: 112323989
Test: Manual, runtest bluetooth
Change-Id: I16d8460fb6713f8196914dd7cc2f6b4476fd8c9d
parent 55083170
Loading
Loading
Loading
Loading
+31 −0
Original line number Original line Diff line number Diff line
@@ -390,6 +390,33 @@ static jboolean disconnectA2dpNative(JNIEnv* env, jobject object,
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
}


static jboolean setSilenceDeviceNative(JNIEnv* env, jobject object,
                                       jbyteArray address, jboolean silence) {
  ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
  std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
  if (!sBluetoothA2dpInterface) {
    ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
    return JNI_FALSE;
  }

  jbyte* addr = env->GetByteArrayElements(address, nullptr);

  RawAddress bd_addr = RawAddress::kEmpty;
  if (addr) {
    bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
  }
  if (bd_addr == RawAddress::kEmpty) {
    return JNI_FALSE;
  }
  bt_status_t status =
      sBluetoothA2dpInterface->set_silence_device(bd_addr, silence);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("%s: Failed A2DP set_silence_device, status: %d", __func__, status);
  }
  env->ReleaseByteArrayElements(address, addr, 0);
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean setActiveDeviceNative(JNIEnv* env, jobject object,
static jboolean setActiveDeviceNative(JNIEnv* env, jobject object,
                                      jbyteArray address) {
                                      jbyteArray address) {
  ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
  ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
@@ -405,6 +432,9 @@ static jboolean setActiveDeviceNative(JNIEnv* env, jobject object,
  if (addr) {
  if (addr) {
    bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
    bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
  }
  }
  if (bd_addr == RawAddress::kEmpty) {
    return JNI_FALSE;
  }
  bt_status_t status = sBluetoothA2dpInterface->set_active_device(bd_addr);
  bt_status_t status = sBluetoothA2dpInterface->set_active_device(bd_addr);
  if (status != BT_STATUS_SUCCESS) {
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("%s: Failed A2DP set_active_device, status: %d", __func__, status);
    ALOGE("%s: Failed A2DP set_active_device, status: %d", __func__, status);
@@ -450,6 +480,7 @@ static JNINativeMethod sMethods[] = {
    {"cleanupNative", "()V", (void*)cleanupNative},
    {"cleanupNative", "()V", (void*)cleanupNative},
    {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative},
    {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative},
    {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative},
    {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative},
    {"setSilenceDeviceNative", "([BZ)Z", (void*)setSilenceDeviceNative},
    {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative},
    {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative},
    {"setCodecConfigPreferenceNative",
    {"setCodecConfigPreferenceNative",
     "([B[Landroid/bluetooth/BluetoothCodecConfig;)Z",
     "([B[Landroid/bluetooth/BluetoothCodecConfig;)Z",
+11 −0
Original line number Original line Diff line number Diff line
@@ -106,6 +106,16 @@ public class A2dpNativeInterface {
        return disconnectA2dpNative(getByteAddress(device));
        return disconnectA2dpNative(getByteAddress(device));
    }
    }


    /**
     * Sets a connected A2DP remote device to silence mode.
     *
     * @param device the remote device
     * @return true on success, otherwise false.
     */
    public boolean setSilenceDevice(BluetoothDevice device, boolean silence) {
        return setSilenceDeviceNative(getByteAddress(device), silence);
    }

    /**
    /**
     * Sets a connected A2DP remote device as active.
     * Sets a connected A2DP remote device as active.
     *
     *
@@ -199,6 +209,7 @@ public class A2dpNativeInterface {
    private native void cleanupNative();
    private native void cleanupNative();
    private native boolean connectA2dpNative(byte[] address);
    private native boolean connectA2dpNative(byte[] address);
    private native boolean disconnectA2dpNative(byte[] address);
    private native boolean disconnectA2dpNative(byte[] address);
    private native boolean setSilenceDeviceNative(byte[] address, boolean silence);
    private native boolean setActiveDeviceNative(byte[] address);
    private native boolean setActiveDeviceNative(byte[] address);
    private native boolean setCodecConfigPreferenceNative(byte[] address,
    private native boolean setCodecConfigPreferenceNative(byte[] address,
                BluetoothCodecConfig[] codecConfigArray);
                BluetoothCodecConfig[] codecConfigArray);
+28 −0
Original line number Original line Diff line number Diff line
@@ -466,6 +466,34 @@ public class A2dpService extends ProfileService {
        }
        }
    }
    }


    /**
     * Process a change in the silence mode for a {@link BluetoothDevice}.
     *
     * @param device the device to change silence mode
     * @param silence true to enable silence mode, false to disable.
     * @return true on success, false on error
     */
    @VisibleForTesting
    public boolean setSilenceMode(BluetoothDevice device, boolean silence) {
        if (DBG) {
            Log.d(TAG, "setSilenceMode(" + device + "): " + silence);
        }
        if (silence && Objects.equals(mActiveDevice, device)) {
            if (mActiveDevice != null && AvrcpTargetService.get() != null) {
                AvrcpTargetService.get().storeVolumeForDevice(mActiveDevice);
            }
            removeActiveDevice(true);
        } else if (!silence && mActiveDevice == null) {
            // Set the device as the active device if currently no active device.
            setActiveDevice(device);
        }
        if (!mA2dpNativeInterface.setSilenceDevice(device, silence)) {
            Log.e(TAG, "Cannot set " + device + " silence mode " + silence + " in native layer");
            return false;
        }
        return true;
    }

    /**
    /**
     * Set the active device.
     * Set the active device.
     *
     *
+49 −1
Original line number Original line Diff line number Diff line
@@ -189,6 +189,7 @@ public class AdapterService extends Service {
    private PhonePolicy mPhonePolicy;
    private PhonePolicy mPhonePolicy;
    private ActiveDeviceManager mActiveDeviceManager;
    private ActiveDeviceManager mActiveDeviceManager;
    private DatabaseManager mDatabaseManager;
    private DatabaseManager mDatabaseManager;
    private SilenceDeviceManager mSilenceDeviceManager;
    private AppOpsManager mAppOps;
    private AppOpsManager mAppOps;


    /**
    /**
@@ -423,6 +424,9 @@ public class AdapterService extends Service {
                MetadataDatabase.class, MetadataDatabase.DATABASE_NAME).build();
                MetadataDatabase.class, MetadataDatabase.DATABASE_NAME).build();
        mDatabaseManager.start(database);
        mDatabaseManager.start(database);


        mSilenceDeviceManager = new SilenceDeviceManager(this, new ServiceFactory(),
                Looper.getMainLooper());
        mSilenceDeviceManager.start();


        setAdapterService(this);
        setAdapterService(this);


@@ -704,6 +708,10 @@ public class AdapterService extends Service {
            mPhonePolicy.cleanup();
            mPhonePolicy.cleanup();
        }
        }


        if (mSilenceDeviceManager != null) {
            mSilenceDeviceManager.cleanup();
        }

        if (mActiveDeviceManager != null) {
        if (mActiveDeviceManager != null) {
            mActiveDeviceManager.cleanup();
            mActiveDeviceManager.cleanup();
        }
        }
@@ -1363,6 +1371,34 @@ public class AdapterService extends Service {
            return service.getPhonebookAccessPermission(device);
            return service.getPhonebookAccessPermission(device);
        }
        }


        @Override
        public boolean setSilenceMode(BluetoothDevice device, boolean silence) {
            if (!Utils.checkCaller()) {
                Log.w(TAG, "setSilenceMode() - Not allowed for non-active user");
                return false;
            }

            AdapterService service = getService();
            if (service == null) {
                return false;
            }
            return service.setSilenceMode(device, silence);
        }

        @Override
        public boolean getSilenceMode(BluetoothDevice device) {
            if (!Utils.checkCaller()) {
                Log.w(TAG, "getSilenceMode() - Not allowed for non-active user");
                return false;
            }

            AdapterService service = getService();
            if (service == null) {
                return false;
            }
            return service.getSilenceMode(device);
        }

        @Override
        @Override
        public boolean setPhonebookAccessPermission(BluetoothDevice device, int value) {
        public boolean setPhonebookAccessPermission(BluetoothDevice device, int value) {
            if (!Utils.checkCaller()) {
            if (!Utils.checkCaller()) {
@@ -2180,9 +2216,20 @@ public class AdapterService extends Service {
                : BluetoothDevice.ACCESS_REJECTED;
                : BluetoothDevice.ACCESS_REJECTED;
    }
    }


    boolean setPhonebookAccessPermission(BluetoothDevice device, int value) {
    boolean setSilenceMode(BluetoothDevice device, boolean silence) {
        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
                "Need BLUETOOTH PRIVILEGED permission");
                "Need BLUETOOTH PRIVILEGED permission");
        mSilenceDeviceManager.setSilenceMode(device, silence);
        return true;
    }

    boolean getSilenceMode(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
                "Need BLUETOOTH PRIVILEGED permission");
        return mSilenceDeviceManager.getSilenceMode(device);
    }

    boolean setPhonebookAccessPermission(BluetoothDevice device, int value) {
        SharedPreferences pref = getSharedPreferences(PHONEBOOK_ACCESS_PERMISSION_PREFERENCE_FILE,
        SharedPreferences pref = getSharedPreferences(PHONEBOOK_ACCESS_PERMISSION_PREFERENCE_FILE,
                Context.MODE_PRIVATE);
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = pref.edit();
        SharedPreferences.Editor editor = pref.edit();
@@ -2672,6 +2719,7 @@ public class AdapterService extends Service {
        for (ProfileService profile : mRegisteredProfiles) {
        for (ProfileService profile : mRegisteredProfiles) {
            profile.dump(sb);
            profile.dump(sb);
        }
        }
        mSilenceDeviceManager.dump(fd, writer, args);


        writer.write(sb.toString());
        writer.write(sb.toString());
        writer.flush();
        writer.flush();
+355 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2019 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.btservice;

import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
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.UserHandle;
import android.util.Log;

import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.internal.annotations.VisibleForTesting;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The silence device manager controls silence mode for A2DP, HFP, and AVRCP.
 *
 * 1) If an active device (for A2DP or HFP) enters silence mode, the active device
 *    for that profile will be set to null.
 * 2) If a device exits silence mode while the A2DP or HFP active device is null,
 *    the device will be set as the active device for that profile.
 * 3) If a device is disconnected, it exits silence mode.
 * 4) If a device is set as the active device for A2DP or HFP, while silence mode
 *    is enabled, then the device will exit silence mode.
 * 5) If a device is in silence mode, AVRCP position change event and HFP AG indicators
 *    will be disabled.
 * 6) If a device is not connected with A2DP or HFP, it cannot enter silence mode.
 */
public class SilenceDeviceManager {
    private static final boolean DBG = true;
    private static final boolean VERBOSE = false;
    private static final String TAG = "SilenceDeviceManager";

    private final AdapterService mAdapterService;
    private final ServiceFactory mFactory;
    private Handler mHandler = null;
    private Looper mLooper = null;
    private A2dpService mA2dpService = null;
    private HeadsetService mHeadsetService = null;

    private final Map<BluetoothDevice, Boolean> mSilenceDevices = new HashMap<>();
    private final List<BluetoothDevice> mA2dpConnectedDevices = new ArrayList<>();
    private final List<BluetoothDevice> mHfpConnectedDevices = new ArrayList<>();

    private static final int MSG_SILENCE_DEVICE_STATE_CHANGED = 1;
    private static final int MSG_A2DP_CONNECTION_STATE_CHANGED = 10;
    private static final int MSG_HFP_CONNECTION_STATE_CHANGED = 11;
    private static final int MSG_A2DP_ACTIVE_DEIVCE_CHANGED = 20;
    private static final int MSG_HFP_ACTIVE_DEVICE_CHANGED = 21;
    private static final int ENABLE_SILENCE = 0;
    private static final int DISABLE_SILENCE = 1;

    // Broadcast receiver for all changes
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action == null) {
                Log.e(TAG, "Received intent with null action");
                return;
            }
            switch (action) {
                case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
                    mHandler.obtainMessage(MSG_A2DP_CONNECTION_STATE_CHANGED,
                                           intent).sendToTarget();
                    break;
                case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
                    mHandler.obtainMessage(MSG_HFP_CONNECTION_STATE_CHANGED,
                                           intent).sendToTarget();
                    break;
                case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
                    mHandler.obtainMessage(MSG_A2DP_ACTIVE_DEIVCE_CHANGED,
                                           intent).sendToTarget();
                    break;
                case BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED:
                    mHandler.obtainMessage(MSG_HFP_ACTIVE_DEVICE_CHANGED,
                        intent).sendToTarget();
                    break;
                default:
                    Log.e(TAG, "Received unexpected intent, action=" + action);
                    break;
            }
        }
    };

    class SilenceDeviceManagerHandler extends Handler {
        SilenceDeviceManagerHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            if (VERBOSE) {
                Log.d(TAG, "handleMessage: " + msg.what);
            }
            switch (msg.what) {
                case MSG_SILENCE_DEVICE_STATE_CHANGED: {
                    BluetoothDevice device = (BluetoothDevice) msg.obj;
                    boolean state = (msg.arg1 == ENABLE_SILENCE);
                    handleSilenceDeviceStateChanged(device, state);
                }
                break;

                case MSG_A2DP_CONNECTION_STATE_CHANGED: {
                    Intent intent = (Intent) msg.obj;
                    BluetoothDevice device =
                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
                    int nextState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);

                    if (nextState == BluetoothProfile.STATE_CONNECTED) {
                        // enter connected state
                        addConnectedDevice(device, BluetoothProfile.A2DP);
                        if (!mSilenceDevices.containsKey(device)) {
                            mSilenceDevices.put(device, false);
                        }
                    } else if (prevState == BluetoothProfile.STATE_CONNECTED) {
                        // exiting from connected state
                        removeConnectedDevice(device, BluetoothProfile.A2DP);
                        if (!isBluetoothAudioConnected(device)) {
                            handleSilenceDeviceStateChanged(device, false);
                            mSilenceDevices.remove(device);
                        }
                    }
                }
                break;

                case MSG_HFP_CONNECTION_STATE_CHANGED: {
                    Intent intent = (Intent) msg.obj;
                    BluetoothDevice device =
                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
                    int nextState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);

                    if (nextState == BluetoothProfile.STATE_CONNECTED) {
                        // enter connected state
                        addConnectedDevice(device, BluetoothProfile.HEADSET);
                        if (!mSilenceDevices.containsKey(device)) {
                            mSilenceDevices.put(device, false);
                        }
                    } else if (prevState == BluetoothProfile.STATE_CONNECTED) {
                        // exiting from connected state
                        removeConnectedDevice(device, BluetoothProfile.HEADSET);
                        if (!isBluetoothAudioConnected(device)) {
                            handleSilenceDeviceStateChanged(device, false);
                            mSilenceDevices.remove(device);
                        }
                    }
                }
                break;

                case MSG_A2DP_ACTIVE_DEIVCE_CHANGED: {
                    Intent intent = (Intent) msg.obj;
                    BluetoothDevice a2dpActiveDevice =
                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    if (getSilenceMode(a2dpActiveDevice)) {
                        // Resume the device from silence mode.
                        setSilenceMode(a2dpActiveDevice, false);
                    }
                }
                break;

                case MSG_HFP_ACTIVE_DEVICE_CHANGED: {
                    Intent intent = (Intent) msg.obj;
                    BluetoothDevice hfpActiveDevice =
                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    if (getSilenceMode(hfpActiveDevice)) {
                        // Resume the device from silence mode.
                        setSilenceMode(hfpActiveDevice, false);
                    }
                }
                break;

                default: {
                    Log.e(TAG, "Unknown message: " + msg.what);
                }
                break;
            }
        }
    };

    SilenceDeviceManager(AdapterService service, ServiceFactory factory, Looper looper) {
        mAdapterService = service;
        mFactory = factory;
        mLooper = looper;
    }

    void start() {
        if (VERBOSE) {
            Log.v(TAG, "start()");
        }
        mHandler = new SilenceDeviceManagerHandler(mLooper);
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
        filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED);
        mAdapterService.registerReceiver(mReceiver, filter);
        mA2dpService = mFactory.getA2dpService();
        mHeadsetService = mFactory.getHeadsetService();
    }

    void cleanup() {
        if (VERBOSE) {
            Log.v(TAG, "cleanup()");
        }
        mSilenceDevices.clear();
        mA2dpService = null;
        mHeadsetService = null;
        mAdapterService.unregisterReceiver(mReceiver);
    }

    @VisibleForTesting
    boolean setSilenceMode(BluetoothDevice device, boolean silence) {
        if (mHandler == null) {
            Log.e(TAG, "setSilenceMode() mHandler is null!");
            return false;
        }
        Log.d(TAG, "setSilenceMode: " + device.getAddress() + ", " + silence);
        Message message = mHandler.obtainMessage(MSG_SILENCE_DEVICE_STATE_CHANGED,
                silence ? ENABLE_SILENCE : DISABLE_SILENCE, 0, device);
        mHandler.sendMessage(message);
        return true;
    }

    void handleSilenceDeviceStateChanged(BluetoothDevice device, boolean state) {
        boolean oldState = getSilenceMode(device);
        if (oldState == state) {
            return;
        }
        if (!isBluetoothAudioConnected(device)) {
            if (oldState) {
                // Device is disconnected, resume all silenced profiles.
                state = false;
            } else {
                Log.d(TAG, "Deivce is not connected to any Bluetooth audio.");
                return;
            }
        }
        mSilenceDevices.replace(device, state);

        if (mA2dpService == null) {
            Log.d(TAG, "A2dpService is null!");
            return;
        }
        if (mHeadsetService == null) {
            Log.d(TAG, "HeadsetService is null!");
            return;
        }
        mA2dpService.setSilenceMode(device, state);
        mHeadsetService.setSilenceMode(device, state);
        Log.i(TAG, "Silence mode change " + device.getAddress() + ": " + oldState + " -> "
                + state);
        broadcastSilenceStateChange(device, state);
    }

    void broadcastSilenceStateChange(BluetoothDevice device, boolean state) {
        Intent intent = new Intent(BluetoothDevice.ACTION_SILENCE_MODE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.putExtra(BluetoothDevice.EXTRA_SILENCE_ENABLED, state);
        mAdapterService.sendBroadcastAsUser(intent, UserHandle.ALL, AdapterService.BLUETOOTH_PERM);

    }

    @VisibleForTesting
    boolean getSilenceMode(BluetoothDevice device) {
        boolean state = false;
        if (mSilenceDevices.containsKey(device)) {
            state = mSilenceDevices.get(device);
        }
        return state;
    }

    void addConnectedDevice(BluetoothDevice device, int profile) {
        if (VERBOSE) {
            Log.d(TAG, "addConnectedDevice: " + device.getAddress() + ", profile:" + profile);
        }
        switch (profile) {
            case BluetoothProfile.A2DP:
                if (!mA2dpConnectedDevices.contains(device)) {
                    mA2dpConnectedDevices.add(device);
                }
                break;
            case BluetoothProfile.HEADSET:
                if (!mHfpConnectedDevices.contains(device)) {
                    mHfpConnectedDevices.add(device);
                }
                break;
        }
    }

    void removeConnectedDevice(BluetoothDevice device, int profile) {
        if (VERBOSE) {
            Log.d(TAG, "removeConnectedDevice: " + device.getAddress() + ", profile:" + profile);
        }
        switch (profile) {
            case BluetoothProfile.A2DP:
                if (mA2dpConnectedDevices.contains(device)) {
                    mA2dpConnectedDevices.remove(device);
                }
                break;
            case BluetoothProfile.HEADSET:
                if (mHfpConnectedDevices.contains(device)) {
                    mHfpConnectedDevices.remove(device);
                }
                break;
        }
    }

    boolean isBluetoothAudioConnected(BluetoothDevice device) {
        return (mA2dpConnectedDevices.contains(device) || mHfpConnectedDevices.contains(device));
    }

    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
        writer.println("\nSilenceDeviceManager:");
        writer.println("  Address            | Is silenced?");
        for (BluetoothDevice device : mSilenceDevices.keySet()) {
            writer.println("  " + device.getAddress() + "  | " + getSilenceMode(device));
        }
    }

    @VisibleForTesting
    BroadcastReceiver getBroadcastReceiver() {
        return mReceiver;
    }
}
Loading