diff options
| -rw-r--r-- | compiled-classes-phone | 1 | ||||
| -rw-r--r-- | core/java/android/bluetooth/BluetoothA2dp.java | 69 | ||||
| -rw-r--r-- | core/java/android/bluetooth/BluetoothCodecConfig.aidl | 19 | ||||
| -rw-r--r-- | core/java/android/bluetooth/BluetoothCodecConfig.java | 287 | ||||
| -rw-r--r-- | core/java/android/bluetooth/IBluetoothA2dp.aidl | 3 | ||||
| -rw-r--r-- | core/jni/android_media_AudioSystem.cpp | 13 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 2 | ||||
| -rw-r--r-- | media/java/android/media/AudioManager.java | 14 | ||||
| -rw-r--r-- | media/java/android/media/AudioSystem.java | 3 | ||||
| -rw-r--r-- | media/java/android/media/IAudioService.aidl | 2 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioService.java | 67 | 
11 files changed, 468 insertions, 12 deletions
diff --git a/compiled-classes-phone b/compiled-classes-phone index 221d68739366..ec3371e45711 100644 --- a/compiled-classes-phone +++ b/compiled-classes-phone @@ -632,6 +632,7 @@ android.bluetooth.BluetoothAdapter$LeScanCallback  android.bluetooth.BluetoothAudioConfig  android.bluetooth.BluetoothClass  android.bluetooth.BluetoothClass$1 +android.bluetooth.BluetoothCodecConfig  android.bluetooth.BluetoothDevice  android.bluetooth.BluetoothDevice$1  android.bluetooth.BluetoothDevice$2 diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 353c6400ffd7..1165fce3ce0a 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -102,6 +102,27 @@ public final class BluetoothA2dp implements BluetoothProfile {          "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";      /** +     * Intent used to broadcast the change in the Audio Codec state of the +     * A2DP Source profile. +     * +     * <p>This intent will have 3 extras: +     * <ul> +     *   <li> {@link #EXTRA_CODEC_CONFIG} - The current codec configuration. </li> +     *   <li> {@link #EXTRA_PREVIOUS_CODEC_CONFIG} - The previous codec configuration. </li> +     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently +     *   connected, otherwise it is not included.</li> +     * </ul> +     * +     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to +     * receive. +     * +     * @hide +     */ +    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) +    public static final String ACTION_CODEC_CONFIG_CHANGED = +        "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED"; + +    /**       * A2DP sink device is streaming music. This state can be one of       * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of       * {@link #ACTION_PLAYING_STATE_CHANGED} intent. @@ -543,6 +564,54 @@ public final class BluetoothA2dp implements BluetoothProfile {      }      /** +     * Gets the current codec configuration. +     * +     * @return the current codec configuration +     * @hide +     */ +    public BluetoothCodecConfig getCodecConfig() { +        if (DBG) Log.d(TAG, "getCodecConfig"); +        try { +            mServiceLock.readLock().lock(); +            if (mService != null && isEnabled()) { +                return mService.getCodecConfig(); +            } +            if (mService == null) { +                Log.w(TAG, "Proxy not attached to service"); +            } +            return null; +        } catch (RemoteException e) { +            Log.e(TAG, "Error talking to BT service in getCodecConfig()", e); +            return null; +        } finally { +            mServiceLock.readLock().unlock(); +        } +    } + +    /** +     * Sets the codec configuration preference. +     * +     * @param codecConfig the codec configuration preference +     * @hide +     */ +    public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) { +        if (DBG) Log.d(TAG, "setCodecConfigPreference"); +        try { +            mServiceLock.readLock().lock(); +            if (mService != null && isEnabled()) { +                mService.setCodecConfigPreference(codecConfig); +            } +            if (mService == null) Log.w(TAG, "Proxy not attached to service"); +            return; +        } catch (RemoteException e) { +            Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e); +            return; +        } finally { +            mServiceLock.readLock().unlock(); +        } +    } + +    /**       * Helper for converting a state to a string.       *       * For debug use only - strings are not internationalized. diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.aidl b/core/java/android/bluetooth/BluetoothCodecConfig.aidl new file mode 100644 index 000000000000..553e66e1dac5 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothCodecConfig.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2016 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 android.bluetooth; + +parcelable BluetoothCodecConfig; diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java new file mode 100644 index 000000000000..5cc127766e83 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothCodecConfig.java @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2016 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 android.bluetooth; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Represents the codec configuration for a Bluetooth A2DP source device. + * + * {@see BluetoothA2dp} + * + * {@hide} + */ +public final class BluetoothCodecConfig implements Parcelable { + +    /** +     * Extra for the codec configuration intents of the individual profiles. +     * +     * This extra represents the current codec configuration of the A2DP +     * profile. +     */ +    public static final String EXTRA_CODEC_CONFIG = "android.bluetooth.codec.extra.CODEC_CONFIG"; + +    /** +     * Extra for the codec configuration intents of the individual profiles. +     * +     * This extra represents the previous codec configuration of the A2DP +     * profile. +     */ +    public static final String EXTRA_PREVIOUS_CODEC_CONFIG = +        "android.bluetooth.codec.extra.PREVIOUS_CODEC_CONFIG"; + +    public static final int SOURCE_CODEC_TYPE_SBC     = 0; +    public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000; + +    public static final int CODEC_PRIORITY_DEFAULT = 0; +    public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000; + +    public static final int SAMPLE_RATE_NONE   = 0; +    public static final int SAMPLE_RATE_44100  = 0x1 << 0; +    public static final int SAMPLE_RATE_48000  = 0x1 << 1; +    public static final int SAMPLE_RATE_88200  = 0x1 << 2; +    public static final int SAMPLE_RATE_96000  = 0x1 << 3; +    public static final int SAMPLE_RATE_176400 = 0x1 << 4; +    public static final int SAMPLE_RATE_192000 = 0x1 << 5; + +    public static final int BITS_PER_SAMPLE_NONE = 0; +    public static final int BITS_PER_SAMPLE_16   = 0x1 << 0; +    public static final int BITS_PER_SAMPLE_24   = 0x1 << 1; +    public static final int BITS_PER_SAMPLE_32   = 0x1 << 2; + +    public static final int CHANNEL_MODE_NONE   = 0; +    public static final int CHANNEL_MODE_MONO   = 0x1 << 0; +    public static final int CHANNEL_MODE_STEREO = 0x1 << 1; + +    private final int mCodecType; +    private final int mCodecPriority; +    private final int mSampleRate; +    private final int mBitsPerSample; +    private final int mChannelMode; +    private final long mCodecSpecific1; +    private final long mCodecSpecific2; +    private final long mCodecSpecific3; +    private final long mCodecSpecific4; + +    public BluetoothCodecConfig(int codecType, int codecPriority, +                                int sampleRate, int bitsPerSample, +                                int channelMode,long codecSpecific1, +                                long codecSpecific2, long codecSpecific3, +                                long codecSpecific4) { +        mCodecType = codecType; +        mCodecPriority = codecPriority; +        mSampleRate = sampleRate; +        mBitsPerSample = bitsPerSample; +        mChannelMode = channelMode; +        mCodecSpecific1 = codecSpecific1; +        mCodecSpecific2 = codecSpecific2; +        mCodecSpecific3 = codecSpecific3; +        mCodecSpecific4 = codecSpecific4; +    } + +    @Override +    public boolean equals(Object o) { +        if (o instanceof BluetoothCodecConfig) { +            BluetoothCodecConfig other = (BluetoothCodecConfig)o; +            return (other.mCodecType == mCodecType && +                    other.mCodecPriority == mCodecPriority && +                    other.mSampleRate == mSampleRate && +                    other.mBitsPerSample == mBitsPerSample && +                    other.mChannelMode == mChannelMode && +                    other.mCodecSpecific1 == mCodecSpecific1 && +                    other.mCodecSpecific2 == mCodecSpecific2 && +                    other.mCodecSpecific3 == mCodecSpecific3 && +                    other.mCodecSpecific4 == mCodecSpecific4); +        } +        return false; +    } + +    @Override +    public int hashCode() { +        return Objects.hash(mCodecType, mCodecPriority, mSampleRate, +                            mBitsPerSample, mChannelMode, mCodecSpecific1, +                            mCodecSpecific2, mCodecSpecific3, mCodecSpecific4); +    } + +    @Override +    public String toString() { +        return "{mCodecType:" + mCodecType + +            ",mCodecPriority:" + mCodecPriority + +            ",mSampleRate:" + String.format("0x%x", mSampleRate) + +            ",mBitsPerSample:" + String.format("0x%x", mBitsPerSample) + +            ",mChannelMode:" + String.format("0x%x", mChannelMode) + +            ",mCodecSpecific1:" + mCodecSpecific1 + +            ",mCodecSpecific2:" + mCodecSpecific2 + +            ",mCodecSpecific3:" + mCodecSpecific3 + +            ",mCodecSpecific4:" + mCodecSpecific4 + "}"; +    } + +    public int describeContents() { +        return 0; +    } + +    public static final Parcelable.Creator<BluetoothCodecConfig> CREATOR = +            new Parcelable.Creator<BluetoothCodecConfig>() { +        public BluetoothCodecConfig createFromParcel(Parcel in) { +            final int codecType = in.readInt(); +            final int codecPriority = in.readInt(); +            final int sampleRate = in.readInt(); +            final int bitsPerSample = in.readInt(); +            final int channelMode = in.readInt(); +            final long codecSpecific1 = in.readLong(); +            final long codecSpecific2 = in.readLong(); +            final long codecSpecific3 = in.readLong(); +            final long codecSpecific4 = in.readLong(); +            return new BluetoothCodecConfig(codecType, codecPriority, +                                            sampleRate, bitsPerSample, +                                            channelMode, codecSpecific1, +                                            codecSpecific2, codecSpecific3, +                                            codecSpecific4); +        } +        public BluetoothCodecConfig[] newArray(int size) { +            return new BluetoothCodecConfig[size]; +        } +    }; + +    public void writeToParcel(Parcel out, int flags) { +        out.writeInt(mCodecType); +        out.writeInt(mCodecPriority); +        out.writeInt(mSampleRate); +        out.writeInt(mBitsPerSample); +        out.writeInt(mChannelMode); +        out.writeLong(mCodecSpecific1); +        out.writeLong(mCodecSpecific2); +        out.writeLong(mCodecSpecific3); +        out.writeLong(mCodecSpecific4); +    } + +    /** +     * Returns the codec type. +     * See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}. +     * +     * @return the codec type +     */ +    public int getCodecType() { +        return mCodecType; +    } + +    /** +     * Returns the codec selection priority. +     * The codec selection priority is relative to other codecs: larger value +     * means higher priority. If 0, reset to default. +     * +     * @return the codec priority +     */ +    public int getCodecPriority() { +        return mCodecPriority; +    } + +    /** +     * Returns the codec sample rate. The value can be a bitmask with all +     * supported sample rates: +     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or +     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or +     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_48000} or +     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_88200} or +     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_96000} or +     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_176400} or +     * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_192000} +     * +     * @return the codec sample rate +     */ +    public int getSampleRate() { +        return mSampleRate; +    } + +    /** +     * Returns the codec bits per sample. The value can be a bitmask with all +     * bits per sample supported: +     * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or +     * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or +     * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_24} or +     * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_32} +     * +     * @return the codec bits per sample +     */ +    public int getBitsPerSample() { +        return mBitsPerSample; +    } + +    /** +     * Returns the codec channel mode. The value can be a bitmask with all +     * supported channel modes: +     * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or +     * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or +     * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO} +     * +     * @return the codec channel mode +     */ +    public int getChannelMode() { +        return mChannelMode; +    } + +    /** +     * Returns a codec specific value1. +     * +     * @return a codec specific value1. +     */ +    public long getCodecSpecific1() { +        return mCodecSpecific1; +    } + +    /** +     * Returns a codec specific value2. +     * +     * @return a codec specific value2 +     */ +    public long getCodecSpecific2() { +        return mCodecSpecific2; +    } + +    /** +     * Returns a codec specific value3. +     * +     * @return a codec specific value3 +     */ +    public long getCodecSpecific3() { +        return mCodecSpecific3; +    } + +    /** +     * Returns a codec specific value4. +     * +     * @return a codec specific value4 +     */ +    public long getCodecSpecific4() { +        return mCodecSpecific4; +    } + +    /** +     * Checks whether the audio feeding parameters are same. +     * +     * @param other the codec config to compare against +     * @return true if the audio feeding parameters are same, otherwise false +     */ +    public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) { +        return (other != null && other.mSampleRate == mSampleRate && +                other.mBitsPerSample == mBitsPerSample && +                other.mChannelMode == mChannelMode); +    } +} diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl index 26ff9e274c39..5b524eb18a5e 100644 --- a/core/java/android/bluetooth/IBluetoothA2dp.aidl +++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl @@ -16,6 +16,7 @@  package android.bluetooth; +import android.bluetooth.BluetoothCodecConfig;  import android.bluetooth.BluetoothDevice;  /** @@ -36,4 +37,6 @@ interface IBluetoothA2dp {      oneway void adjustAvrcpAbsoluteVolume(int direction);      oneway void setAvrcpAbsoluteVolume(int volume);      boolean isA2dpPlaying(in BluetoothDevice device); +    BluetoothCodecConfig getCodecConfig(); +    oneway void setCodecConfigPreference(in BluetoothCodecConfig codecConfig);  } diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 497600212095..d30e6eba48e7 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -457,6 +457,18 @@ android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, ji  }  static jint +android_media_AudioSystem_handleDeviceConfigChange(JNIEnv *env, jobject thiz, jint device, jstring device_address, jstring device_name) +{ +    const char *c_address = env->GetStringUTFChars(device_address, NULL); +    const char *c_name = env->GetStringUTFChars(device_name, NULL); +    int status = check_AudioSystem_Command(AudioSystem::handleDeviceConfigChange(static_cast <audio_devices_t>(device), +                                          c_address, c_name)); +    env->ReleaseStringUTFChars(device_address, c_address); +    env->ReleaseStringUTFChars(device_name, c_name); +    return (jint) status; +} + +static jint  android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)  {      return (jint) check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state)); @@ -1757,6 +1769,7 @@ static const JNINativeMethod gMethods[] = {      {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},      {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},      {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState}, +    {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},      {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},      {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},      {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse}, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 60cf8109edf1..3bd0acc49646 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -167,6 +167,8 @@      <protected-broadcast          android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />      <protected-broadcast +        android:name="android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED" /> +    <protected-broadcast          android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />      <protected-broadcast          android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" /> diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 33c1c3f6acc0..ce75bb4957f5 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3278,6 +3278,20 @@ public class AudioManager {          return delay;      } +     /** +     * Indicate A2DP device configuration has changed. +     * @param device Bluetooth device whose configuration has changed. +     * {@hide} +     */ +    public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) { +        IAudioService service = getService(); +        try { +            service.handleBluetoothA2dpDeviceConfigChange(device); +        } catch (RemoteException e) { +            throw e.rethrowFromSystemServer(); +        } +    } +      /** {@hide} */      public IRingtonePlayer getRingtonePlayer() {          try { diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index f597440ccbb3..8a2825500670 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -678,6 +678,9 @@ public class AudioSystem      public static native int setDeviceConnectionState(int device, int state,                                                        String device_address, String device_name);      public static native int getDeviceConnectionState(int device, String device_address); +    public static native int handleDeviceConfigChange(int device, +                                                      String device_address, +                                                      String device_name);      public static native int setPhoneState(int state);      public static native int setForceUse(int usage, int config);      public static native int getForceUse(int usage); diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index c7931fcd297b..9e5ac7231925 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -133,6 +133,8 @@ interface IAudioService {      int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile); +    void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device); +      AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);      boolean isCameraSoundForced(); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 7fe6c3e0a332..5d619c11ba44 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -225,6 +225,7 @@ public class AudioService extends IAudioService.Stub {      private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;      private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;      private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102; +    private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;      // end of messages handled under wakelock      private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; @@ -3146,7 +3147,7 @@ public class AudioService extends IAudioService.Stub {                              queueMsgUnderWakeLock(mAudioHandler,                                      MSG_SET_A2DP_SINK_CONNECTION_STATE,                                      state, -                                    0, +                                    0 /* arg2 unused */,                                      btDevice,                                      delay);                          } @@ -3163,7 +3164,7 @@ public class AudioService extends IAudioService.Stub {                          queueMsgUnderWakeLock(mAudioHandler,                                  MSG_SET_A2DP_SRC_CONNECTION_STATE,                                  state, -                                0, +                                0 /* arg2 unused */,                                  btDevice,                                  0 /* delay */);                      } @@ -3809,8 +3810,8 @@ public class AudioService extends IAudioService.Stub {              int delay = checkSendBecomingNoisyIntent(type, state);              queueMsgUnderWakeLock(mAudioHandler,                      MSG_SET_WIRED_DEVICE_CONNECTION_STATE, -                    0, -                    0, +                    0 /* arg1 unused */, +                    0 /* arg2 unused */,                      new WiredDeviceConnectionState(type, state, address, name, caller),                      delay);          } @@ -3833,13 +3834,25 @@ public class AudioService extends IAudioService.Stub {                      (profile == BluetoothProfile.A2DP ?                          MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),                      state, -                    0, +                    0 /* arg2 unused */,                      device,                      delay);          }          return delay;      } +    public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) +    { +        synchronized (mConnectedDevices) { +            queueMsgUnderWakeLock(mAudioHandler, +                    MSG_A2DP_DEVICE_CONFIG_CHANGE, +                    0 /* arg1 unused */, +                    0 /* arg1 unused */, +                    device, +                    0 /* delay */); +        } +    } +      ///////////////////////////////////////////////////////////////////////////      // Inner classes      /////////////////////////////////////////////////////////////////////////// @@ -4644,6 +4657,11 @@ public class AudioService extends IAudioService.Stub {                      mAudioEventWakeLock.release();                      break; +                case MSG_A2DP_DEVICE_CONFIG_CHANGE: +                    onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj); +                    mAudioEventWakeLock.release(); +                    break; +                  case MSG_REPORT_NEW_ROUTES: {                      int N = mRoutesObservers.beginBroadcast();                      if (N > 0) { @@ -4866,7 +4884,7 @@ public class AudioService extends IAudioService.Stub {      private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)      {          if (DEBUG_VOL) { -            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state); +            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);          }          if (btDevice == null) {              return; @@ -4877,9 +4895,9 @@ public class AudioService extends IAudioService.Stub {          }          synchronized (mConnectedDevices) { -            String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, -                                           btDevice.getAddress()); -            DeviceListSpec deviceSpec = mConnectedDevices.get(key); +            final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, +                                                 btDevice.getAddress()); +            final DeviceListSpec deviceSpec = mConnectedDevices.get(key);              boolean isConnected = deviceSpec != null;              if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { @@ -4930,7 +4948,7 @@ public class AudioService extends IAudioService.Stub {      private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)      {          if (DEBUG_VOL) { -            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state); +            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);          }          if (btDevice == null) {              return; @@ -4941,8 +4959,8 @@ public class AudioService extends IAudioService.Stub {          }          synchronized (mConnectedDevices) { -            String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address); -            DeviceListSpec deviceSpec = mConnectedDevices.get(key); +            final String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address); +            final DeviceListSpec deviceSpec = mConnectedDevices.get(key);              boolean isConnected = deviceSpec != null;              if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { @@ -4953,6 +4971,31 @@ public class AudioService extends IAudioService.Stub {          }      } +    private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice) +    { +        if (DEBUG_VOL) { +            Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice); +        } +        if (btDevice == null) { +            return; +        } +        String address = btDevice.getAddress(); +        if (!BluetoothAdapter.checkBluetoothAddress(address)) { +            address = ""; +        } + +        int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; +        synchronized (mConnectedDevices) { +            final String key = makeDeviceListKey(device, address); +            final DeviceListSpec deviceSpec = mConnectedDevices.get(key); +            if (deviceSpec != null) { +                // Device is connected +                AudioSystem.handleDeviceConfigChange(device, address, +                        btDevice.getName()); +            } +        } +    } +      public void avrcpSupportsAbsoluteVolume(String address, boolean support) {          // address is not used for now, but may be used when multiple a2dp devices are supported          synchronized (mA2dpAvrcpLock) {  |