Skip to content

Commit 632ca41

Browse files
author
Dianne Hackborn
committed
Add new callback for MediaRouter to found out about device changes.
The AudioService now has an API to call to get the currently connected devices, and later reports of changes in connection state. The information includes the name of the bluetooth device if one is connected for display to the user, and states for all of the pluggable devices. No longer requires a Bluetooth permission to keep the routes updated. Change-Id: I81ca421c60592fbc1592477d59bf1c9d1b64954a
1 parent 17b9cec commit 632ca41

File tree

7 files changed

+268
-83
lines changed

7 files changed

+268
-83
lines changed

Android.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ LOCAL_SRC_FILES += \
193193
location/java/android/location/INetInitiatedListener.aidl \
194194
media/java/android/media/IAudioService.aidl \
195195
media/java/android/media/IAudioFocusDispatcher.aidl \
196+
media/java/android/media/IAudioRoutesObserver.aidl \
196197
media/java/android/media/IMediaScannerListener.aidl \
197198
media/java/android/media/IMediaScannerService.aidl \
198199
media/java/android/media/IRemoteControlClient.aidl \
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* Copyright 2012, The Android Open Source Project
2+
**
3+
** Licensed under the Apache License, Version 2.0 (the "License");
4+
** you may not use this file except in compliance with the License.
5+
** You may obtain a copy of the License at
6+
**
7+
** http://www.apache.org/licenses/LICENSE-2.0
8+
**
9+
** Unless required by applicable law or agreed to in writing, software
10+
** distributed under the License is distributed on an "AS IS" BASIS,
11+
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
** See the License for the specific language governing permissions and
13+
** limitations under the License.
14+
*/
15+
16+
package android.media;
17+
18+
parcelable AudioRoutesInfo;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (C) 2012 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.media;
18+
19+
import android.os.Parcel;
20+
import android.os.Parcelable;
21+
import android.text.TextUtils;
22+
23+
/**
24+
* Information available from AudioService about the current routes.
25+
* @hide
26+
*/
27+
public class AudioRoutesInfo implements Parcelable {
28+
static final int MAIN_SPEAKER = 0;
29+
static final int MAIN_HEADSET = 1<<0;
30+
static final int MAIN_HEADPHONES = 1<<1;
31+
static final int MAIN_DOCK_SPEAKERS = 1<<2;
32+
static final int MAIN_HDMI = 1<<3;
33+
34+
CharSequence mBluetoothName;
35+
int mMainType = MAIN_SPEAKER;
36+
37+
public AudioRoutesInfo() {
38+
}
39+
40+
public AudioRoutesInfo(AudioRoutesInfo o) {
41+
mBluetoothName = o.mBluetoothName;
42+
mMainType = o.mMainType;
43+
}
44+
45+
AudioRoutesInfo(Parcel src) {
46+
mBluetoothName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
47+
mMainType = src.readInt();
48+
}
49+
50+
@Override
51+
public int describeContents() {
52+
return 0;
53+
}
54+
55+
@Override
56+
public void writeToParcel(Parcel dest, int flags) {
57+
TextUtils.writeToParcel(mBluetoothName, dest, flags);
58+
dest.writeInt(mMainType);
59+
}
60+
61+
public static final Parcelable.Creator<AudioRoutesInfo> CREATOR
62+
= new Parcelable.Creator<AudioRoutesInfo>() {
63+
public AudioRoutesInfo createFromParcel(Parcel in) {
64+
return new AudioRoutesInfo(in);
65+
}
66+
67+
public AudioRoutesInfo[] newArray(int size) {
68+
return new AudioRoutesInfo[size];
69+
}
70+
};
71+
}

media/java/android/media/AudioService.java

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import android.os.Looper;
5454
import android.os.Message;
5555
import android.os.PowerManager;
56+
import android.os.RemoteCallbackList;
5657
import android.os.RemoteException;
5758
import android.os.ServiceManager;
5859
import android.os.SystemProperties;
@@ -62,6 +63,7 @@
6263
import android.speech.RecognizerIntent;
6364
import android.telephony.PhoneStateListener;
6465
import android.telephony.TelephonyManager;
66+
import android.text.TextUtils;
6567
import android.util.Log;
6668
import android.view.KeyEvent;
6769
import android.view.VolumePanel;
@@ -135,10 +137,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
135137
private static final int MSG_RCDISPLAY_UPDATE = 13;
136138
private static final int MSG_SET_ALL_VOLUMES = 14;
137139
private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15;
140+
private static final int MSG_REPORT_NEW_ROUTES = 16;
138141
// messages handled under wakelock, can only be queued, i.e. sent with queueMsgUnderWakeLock(),
139142
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
140-
private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 16;
141-
private static final int MSG_SET_A2DP_CONNECTION_STATE = 17;
143+
private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 17;
144+
private static final int MSG_SET_A2DP_CONNECTION_STATE = 18;
142145

143146

144147
// flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be
@@ -397,6 +400,11 @@ public void onError(int error) {
397400
private boolean mBluetoothA2dpEnabled;
398401
private final Object mBluetoothA2dpEnabledLock = new Object();
399402

403+
// Monitoring of audio routes. Protected by mCurAudioRoutes.
404+
final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
405+
final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
406+
= new RemoteCallbackList<IAudioRoutesObserver>();
407+
400408
///////////////////////////////////////////////////////////////////////////
401409
// Construction
402410
///////////////////////////////////////////////////////////////////////////
@@ -3011,6 +3019,26 @@ public void handleMessage(Message msg) {
30113019
onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1);
30123020
mMediaEventWakeLock.release();
30133021
break;
3022+
3023+
case MSG_REPORT_NEW_ROUTES: {
3024+
int N = mRoutesObservers.beginBroadcast();
3025+
if (N > 0) {
3026+
AudioRoutesInfo routes;
3027+
synchronized (mCurAudioRoutes) {
3028+
routes = new AudioRoutesInfo(mCurAudioRoutes);
3029+
}
3030+
while (N > 0) {
3031+
N--;
3032+
IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3033+
try {
3034+
obs.dispatchAudioRoutesChanged(routes);
3035+
} catch (RemoteException e) {
3036+
}
3037+
}
3038+
}
3039+
mRoutesObservers.finishBroadcast();
3040+
break;
3041+
}
30143042
}
30153043
}
30163044
}
@@ -3127,6 +3155,13 @@ private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
31273155
} else {
31283156
makeA2dpDeviceUnavailableNow(address);
31293157
}
3158+
synchronized (mCurAudioRoutes) {
3159+
if (mCurAudioRoutes.mBluetoothName != null) {
3160+
mCurAudioRoutes.mBluetoothName = null;
3161+
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3162+
SENDMSG_NOOP, 0, 0, null, 0);
3163+
}
3164+
}
31303165
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
31313166
if (btDevice.isBluetoothDock()) {
31323167
// this could be a reconnection after a transient disconnection
@@ -3141,6 +3176,14 @@ private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
31413176
}
31423177
}
31433178
makeA2dpDeviceAvailable(address);
3179+
synchronized (mCurAudioRoutes) {
3180+
String name = btDevice.getAliasName();
3181+
if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3182+
mCurAudioRoutes.mBluetoothName = name;
3183+
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3184+
SENDMSG_NOOP, 0, 0, null, 0);
3185+
}
3186+
}
31443187
}
31453188
}
31463189
}
@@ -3204,20 +3247,43 @@ private void sendDeviceConnectionIntent(int device, int state, String name)
32043247
intent.putExtra("name", name);
32053248
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
32063249

3250+
int connType = 0;
3251+
32073252
if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
3253+
connType = AudioRoutesInfo.MAIN_HEADSET;
32083254
intent.setAction(Intent.ACTION_HEADSET_PLUG);
32093255
intent.putExtra("microphone", 1);
32103256
} else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
3257+
connType = AudioRoutesInfo.MAIN_HEADPHONES;
32113258
intent.setAction(Intent.ACTION_HEADSET_PLUG);
32123259
intent.putExtra("microphone", 0);
32133260
} else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
3261+
connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
32143262
intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
32153263
} else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
3264+
connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
32163265
intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
32173266
} else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
3267+
connType = AudioRoutesInfo.MAIN_HDMI;
32183268
intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
32193269
}
32203270

3271+
synchronized (mCurAudioRoutes) {
3272+
if (connType != 0) {
3273+
int newConn = mCurAudioRoutes.mMainType;
3274+
if (state != 0) {
3275+
newConn |= connType;
3276+
} else {
3277+
newConn &= ~connType;
3278+
}
3279+
if (newConn != mCurAudioRoutes.mMainType) {
3280+
mCurAudioRoutes.mMainType = newConn;
3281+
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3282+
SENDMSG_NOOP, 0, 0, null, 0);
3283+
}
3284+
}
3285+
}
3286+
32213287
ActivityManagerNative.broadcastStickyIntent(intent, null);
32223288
}
32233289

@@ -4795,6 +4861,15 @@ public IRingtonePlayer getRingtonePlayer() {
47954861
return mRingtonePlayer;
47964862
}
47974863

4864+
@Override
4865+
public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4866+
synchronized (mCurAudioRoutes) {
4867+
AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4868+
mRoutesObservers.register(observer);
4869+
return routes;
4870+
}
4871+
}
4872+
47984873
@Override
47994874
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
48004875
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
@@ -4803,5 +4878,8 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
48034878
dumpFocusStack(pw);
48044879
dumpRCStack(pw);
48054880
dumpStreamStates(pw);
4881+
pw.println("\nAudio routes:");
4882+
pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
4883+
pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
48064884
}
48074885
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (C) 2012 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.media;
18+
19+
import android.media.AudioRoutesInfo;
20+
21+
/**
22+
* AIDL for the AudioService to report changes in available audio routes.
23+
* @hide
24+
*/
25+
oneway interface IAudioRoutesObserver {
26+
void dispatchAudioRoutesChanged(in AudioRoutesInfo newRoutes);
27+
}

media/java/android/media/IAudioService.aidl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ package android.media;
1919
import android.app.PendingIntent;
2020
import android.bluetooth.BluetoothDevice;
2121
import android.content.ComponentName;
22+
import android.media.AudioRoutesInfo;
2223
import android.media.IAudioFocusDispatcher;
24+
import android.media.IAudioRoutesObserver;
2325
import android.media.IRemoteControlClient;
2426
import android.media.IRemoteControlDisplay;
2527
import android.media.IRingtonePlayer;
@@ -137,4 +139,6 @@ interface IAudioService {
137139

138140
void setWiredDeviceConnectionState(int device, int state, String name);
139141
int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state);
142+
143+
AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
140144
}

0 commit comments

Comments
 (0)