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

Commit 272369cc authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Perform all start/stop A2dpService operations in start() and stop() methods"

parents f089b225 1a5c8be4
Loading
Loading
Loading
Loading
+85 −65
Original line number Diff line number Diff line
@@ -41,9 +41,7 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -82,103 +80,125 @@ public class A2dpService extends ProfileService {
    private BroadcastReceiver mBondStateChangedReceiver;
    private BroadcastReceiver mConnectionStateChangedReceiver;

    public A2dpService() {
        mA2dpNativeInterface = A2dpNativeInterface.getInstance();
    }

    @Override
    protected IProfileServiceBinder initBinder() {
        return new BluetoothA2dpBinder(this);
    }

    @Override
    protected void create() {
        Log.i(TAG, "create()");
    }

    @Override
    protected boolean start() {
        if (DBG) {
            Log.d(TAG, "start()");
        Log.i(TAG, "start()");
        if (sA2dpService != null) {
            throw new IllegalStateException("start() called twice");
        }

        // Step 1: Get BluetoothAdapter, AdapterService, A2dpNativeInterface, AudioManager.
        // None of them can be null.
        mAdapter = Objects.requireNonNull(BluetoothAdapter.getDefaultAdapter(),
                "BluetoothAdapter cannot be null when A2dpService starts");
        mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
                "AdapterService cannot be null when A2dpService starts");
        mA2dpNativeInterface = Objects.requireNonNull(A2dpNativeInterface.getInstance(),
                "A2dpNativeInterface cannot be null when A2dpService starts");
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        Objects.requireNonNull(mAudioManager,
                               "AudioManager cannot be null when A2dpService starts");

        // Step 2: Get maximum number of connected audio devices
        mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices();
        if (DBG) {
            Log.d(TAG, "Max connected audio devices set to " + mMaxConnectedAudioDevices);
        }
        Log.i(TAG, "Max connected audio devices set to " + mMaxConnectedAudioDevices);

        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        // Step 3: Start handler thread for state machines
        mStateMachines.clear();
        mStateMachinesThread = new HandlerThread("A2dpService.StateMachines");
        mStateMachinesThread.start();

        // Step 4: Setup codec config and clear active device
        mA2dpCodecConfig = new A2dpCodecConfig(this, mA2dpNativeInterface);
        mActiveDevice = null;

        // Step 5: Setup AVRCP
        mAvrcp = Avrcp.make(this);
        setA2dpService(this);

        mA2dpCodecConfig = new A2dpCodecConfig(this, mA2dpNativeInterface);
        // Step 6: Initialize native interface
        mA2dpNativeInterface.init(mA2dpCodecConfig.codecConfigPriorities());
        mActiveDevice = null;

        if (mBondStateChangedReceiver == null) {
        // Step 7: Setup broadcast receivers
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        mBondStateChangedReceiver = new BondStateChangedReceiver();
        registerReceiver(mBondStateChangedReceiver, filter);
        }
        if (mConnectionStateChangedReceiver == null) {
            IntentFilter filter = new IntentFilter();
        filter = new IntentFilter();
        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
        mConnectionStateChangedReceiver = new ConnectionStateChangedReceiver();
        registerReceiver(mConnectionStateChangedReceiver, filter);
        }

        // Step 8: Mark service as started
        setA2dpService(this);

        return true;
    }

    @Override
    protected boolean stop() {
        if (DBG) {
            Log.d(TAG, "stop()");
        }

        for (A2dpStateMachine sm : mStateMachines.values()) {
            sm.doQuit();
        }
        if (mAvrcp != null) {
            mAvrcp.doQuit();
        }
        if (mStateMachinesThread != null) {
            mStateMachinesThread.quit();
            mStateMachinesThread = null;
        }
        Log.i(TAG, "stop()");
        if (sA2dpService == null) {
            Log.w(TAG, "stop() called before start()");
            return true;
        }

    @Override
    protected void cleanup() {
        if (DBG) {
            Log.d(TAG, "cleanup()");
        }
        // Step 8: Mark service as stopped
        setA2dpService(null);

        if (mConnectionStateChangedReceiver != null) {
        // Step 7: Unregister broadcast receivers
        unregisterReceiver(mConnectionStateChangedReceiver);
        mConnectionStateChangedReceiver = null;
        }
        if (mBondStateChangedReceiver != null) {
        unregisterReceiver(mBondStateChangedReceiver);
        mBondStateChangedReceiver = null;
        }
        for (Iterator<Map.Entry<BluetoothDevice, A2dpStateMachine>> it =
                 mStateMachines.entrySet().iterator(); it.hasNext(); ) {
            A2dpStateMachine sm = it.next().getValue();
            sm.cleanup();
            it.remove();
        }

        // Step 6: Cleanup native interface
        mA2dpNativeInterface.cleanup();
        mA2dpNativeInterface = null;

        if (mAvrcp != null) {
        // Step 5: Cleanup AVRCP
        mAvrcp.cleanup();
        mAvrcp = null;

        // Step 4: Clear codec config and active device
        mA2dpCodecConfig = null;
        mActiveDevice = null;

        // Step 3: Destroy state machines and stop handler thread
        synchronized (mStateMachines) {
            for (A2dpStateMachine sm : mStateMachines.values()) {
                sm.doQuit();
                sm.cleanup();
            }
        // TODO(b/72948646): should be moved to stop()
        setA2dpService(null);
            mStateMachines.clear();
        }
        mStateMachinesThread.quitSafely();
        mStateMachinesThread = null;

        // Step 2: Reset maximum number of connected audio devices
        mMaxConnectedAudioDevices = 1;

        // Step 1: Clear BluetoothAdapter, AdapterService, A2dpNativeInterface, AudioManager
        mAudioManager = null;
        mA2dpNativeInterface = null;
        mAdapterService = null;
        mAdapter = null;

        return true;
    }

    @Override
    protected void cleanup() {
        Log.i(TAG, "cleanup()");
    }

    public static synchronized A2dpService getA2dpService() {