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

Commit 0d3a2e93 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "AudioService: strengthen A2DP device detection" into ics-mr1

parents bfb3dec2 6bc7f2cd
Loading
Loading
Loading
Loading
+239 −159
Original line number Diff line number Diff line
@@ -1576,11 +1576,24 @@ public class AudioService extends IAudioService.Stub {
    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
        new BluetoothProfile.ServiceListener() {
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            BluetoothDevice btDevice;
            List<BluetoothDevice> deviceList;
            switch(profile) {
            case BluetoothProfile.A2DP:
                BluetoothA2dp a2dp = (BluetoothA2dp) proxy;
                deviceList = a2dp.getConnectedDevices();
                if (deviceList.size() > 0) {
                    btDevice = deviceList.get(0);
                    handleA2dpConnectionStateChange(btDevice, a2dp.getConnectionState(btDevice));
                }
                break;

            case BluetoothProfile.HEADSET:
                synchronized (mScoClients) {
                    // Discard timeout message
                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
                    mBluetoothHeadset = (BluetoothHeadset) proxy;
                List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
                    deviceList = mBluetoothHeadset.getConnectedDevices();
                    if (deviceList.size() > 0) {
                        mBluetoothHeadsetDevice = deviceList.get(0);
                    } else {
@@ -1615,11 +1628,32 @@ public class AudioService extends IAudioService.Stub {
                        }
                    }
                }
                break;

            default:
                break;
            }
        }
        public void onServiceDisconnected(int profile) {
            switch(profile) {
            case BluetoothProfile.A2DP:
                synchronized (mConnectedDevices) {
                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
                        makeA2dpDeviceUnavailableNow(
                                mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
                    }
                }
                break;

            case BluetoothProfile.HEADSET:
                synchronized (mScoClients) {
                    mBluetoothHeadset = null;
                }
                break;

            default:
                break;
            }
        }
    };

@@ -2197,15 +2231,17 @@ public class AudioService extends IAudioService.Stub {
                    AudioSystem.setParameters("restarting=true");

                    // Restore device connection states
                    synchronized (mConnectedDevices) {
                        Set set = mConnectedDevices.entrySet();
                        Iterator i = set.iterator();
                        while(i.hasNext()){
                            Map.Entry device = (Map.Entry)i.next();
                        AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(),
                            AudioSystem.setDeviceConnectionState(
                                                            ((Integer)device.getKey()).intValue(),
                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
                                                            (String)device.getValue());
                        }

                    }
                    // Restore call state
                    AudioSystem.setPhoneState(mMode);

@@ -2244,7 +2280,9 @@ public class AudioService extends IAudioService.Stub {

                case MSG_BTA2DP_DOCK_TIMEOUT:
                    // msg.obj  == address of BTA2DP device
                    synchronized (mConnectedDevices) {
                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
                    }
                    break;

                case MSG_SET_FORCE_USE:
@@ -2304,6 +2342,7 @@ public class AudioService extends IAudioService.Stub {
        }
    }

    // must be called synchronized on mConnectedDevices
    private void makeA2dpDeviceAvailable(String address) {
        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                AudioSystem.DEVICE_STATE_AVAILABLE,
@@ -2314,6 +2353,7 @@ public class AudioService extends IAudioService.Stub {
                address);
    }

    // must be called synchronized on mConnectedDevices
    private void makeA2dpDeviceUnavailableNow(String address) {
        Intent noisyIntent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
        mContext.sendBroadcast(noisyIntent);
@@ -2323,6 +2363,7 @@ public class AudioService extends IAudioService.Stub {
        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
    }

    // must be called synchronized on mConnectedDevices
    private void makeA2dpDeviceUnavailableLater(String address) {
        // prevent any activity on the A2DP audio output to avoid unwanted
        // reconnection of the sink.
@@ -2335,51 +2376,18 @@ public class AudioService extends IAudioService.Stub {

    }

    // must be called synchronized on mConnectedDevices
    private void cancelA2dpDeviceTimeout() {
        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
    }

    // must be called synchronized on mConnectedDevices
    private boolean hasScheduledA2dpDockTimeout() {
        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
    }

    /* cache of the address of the last dock the device was connected to */
    private String mDockAddress;

    /**
     * Receiver for misc intent broadcasts the Phone app cares about.
     */
    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
                int config;
                switch (dockState) {
                    case Intent.EXTRA_DOCK_STATE_DESK:
                        config = AudioSystem.FORCE_BT_DESK_DOCK;
                        break;
                    case Intent.EXTRA_DOCK_STATE_CAR:
                        config = AudioSystem.FORCE_BT_CAR_DOCK;
                        break;
                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
                        config = AudioSystem.FORCE_ANALOG_DOCK;
                        break;
                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
                        config = AudioSystem.FORCE_DIGITAL_DOCK;
                        break;
                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
                    default:
                        config = AudioSystem.FORCE_NONE;
                }
                AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
            } else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                                               BluetoothProfile.STATE_DISCONNECTED);
                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
    private void handleA2dpConnectionStateChange(BluetoothDevice btDevice, int state)
    {
        if (btDevice == null) {
            return;
        }
@@ -2387,6 +2395,7 @@ public class AudioService extends IAudioService.Stub {
        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
            address = "";
        }
        synchronized (mConnectedDevices) {
            boolean isConnected =
                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
@@ -2418,6 +2427,48 @@ public class AudioService extends IAudioService.Stub {
                }
                makeA2dpDeviceAvailable(address);
            }
        }
    }

    /* cache of the address of the last dock the device was connected to */
    private String mDockAddress;

    /**
     * Receiver for misc intent broadcasts the Phone app cares about.
     */
    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
                int config;
                switch (dockState) {
                    case Intent.EXTRA_DOCK_STATE_DESK:
                        config = AudioSystem.FORCE_BT_DESK_DOCK;
                        break;
                    case Intent.EXTRA_DOCK_STATE_CAR:
                        config = AudioSystem.FORCE_BT_CAR_DOCK;
                        break;
                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
                        config = AudioSystem.FORCE_ANALOG_DOCK;
                        break;
                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
                        config = AudioSystem.FORCE_DIGITAL_DOCK;
                        break;
                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
                    default:
                        config = AudioSystem.FORCE_NONE;
                }
                AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
            } else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                                               BluetoothProfile.STATE_DISCONNECTED);
                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                handleA2dpConnectionStateChange(btDevice, state);
            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                                               BluetoothProfile.STATE_DISCONNECTED);
@@ -2446,6 +2497,8 @@ public class AudioService extends IAudioService.Stub {
                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
                    address = "";
                }

                synchronized (mConnectedDevices) {
                    boolean isConnected = (mConnectedDevices.containsKey(device) &&
                                           mConnectedDevices.get(device).equals(address));

@@ -2465,10 +2518,12 @@ public class AudioService extends IAudioService.Stub {
                            mBluetoothHeadsetDevice = btDevice;
                        }
                    }
                }
            } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
                int state = intent.getIntExtra("state", 0);
                int microphone = intent.getIntExtra("microphone", 0);

                synchronized (mConnectedDevices) {
                    if (microphone != 0) {
                        boolean isConnected =
                            mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
@@ -2488,62 +2543,81 @@ public class AudioService extends IAudioService.Stub {
                        boolean isConnected =
                            mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
                        if (state == 0 && isConnected) {
                        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
                            AudioSystem.setDeviceConnectionState(
                                    AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
                                    AudioSystem.DEVICE_STATE_UNAVAILABLE,
                                    "");
                            mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
                        } else if (state == 1 && !isConnected)  {
                        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
                            AudioSystem.setDeviceConnectionState(
                                    AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
                                    AudioSystem.DEVICE_STATE_AVAILABLE,
                                    "");
                            mConnectedDevices.put(
                                    new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), "");
                        }
                    }
                }
            } else if (action.equals(Intent.ACTION_USB_ANLG_HEADSET_PLUG)) {
                int state = intent.getIntExtra("state", 0);
                Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_ANLG_HEADSET_PLUG, state = "+state);
                synchronized (mConnectedDevices) {
                    boolean isConnected =
                        mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
                    if (state == 0 && isConnected) {
                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
                                                         AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
                        AudioSystem.setDeviceConnectionState(
                                                        AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
                                                        AudioSystem.DEVICE_STATE_UNAVAILABLE,
                                                        "");
                        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
                    } else if (state == 1 && !isConnected)  {
                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
                                                         AudioSystem.DEVICE_STATE_AVAILABLE, "");
                        AudioSystem.setDeviceConnectionState(
                                                        AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
                                                        AudioSystem.DEVICE_STATE_AVAILABLE,
                                                        "");
                        mConnectedDevices.put(
                                new Integer(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET), "");
                    }
                }
            } else if (action.equals(Intent.ACTION_HDMI_AUDIO_PLUG)) {
                int state = intent.getIntExtra("state", 0);
                Log.v(TAG, "Broadcast Receiver: Got ACTION_HDMI_AUDIO_PLUG, state = "+state);
                synchronized (mConnectedDevices) {
                    boolean isConnected =
                        mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_AUX_DIGITAL);
                    if (state == 0 && isConnected) {
                        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL,
                                                         AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
                                                             AudioSystem.DEVICE_STATE_UNAVAILABLE,
                                                             "");
                        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_AUX_DIGITAL);
                    } else if (state == 1 && !isConnected)  {
                        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL,
                                                         AudioSystem.DEVICE_STATE_AVAILABLE, "");
                                                             AudioSystem.DEVICE_STATE_AVAILABLE,
                                                             "");
                        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_AUX_DIGITAL), "");
                    }
                }
            } else if (action.equals(Intent.ACTION_USB_DGTL_HEADSET_PLUG)) {
                int state = intent.getIntExtra("state", 0);
                Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_DGTL_HEADSET_PLUG, state = "+state);
                synchronized (mConnectedDevices) {
                    boolean isConnected =
                        mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
                    if (state == 0 && isConnected) {
                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
                                                         AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
                        AudioSystem.setDeviceConnectionState(
                                                         AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
                                                         AudioSystem.DEVICE_STATE_UNAVAILABLE,
                                                         "");
                        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
                    } else if (state == 1 && !isConnected)  {
                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
                                                         AudioSystem.DEVICE_STATE_AVAILABLE, "");
                        AudioSystem.setDeviceConnectionState(
                                                         AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
                                                         AudioSystem.DEVICE_STATE_AVAILABLE,
                                                         "");
                        mConnectedDevices.put(
                                new Integer(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET), "");
                    }
                }
            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
                boolean broadcast = false;
                int state = AudioManager.SCO_AUDIO_STATE_ERROR;
@@ -2606,6 +2680,12 @@ public class AudioService extends IAudioService.Stub {
                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
                mContext.sendStickyBroadcast(newIntent);

                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
                if (adapter != null) {
                    adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
                                            BluetoothProfile.A2DP);
                }
            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                    // a package is being removed, not replaced