summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kyunglyul Hyun <klhyun@google.com> 2019-11-19 07:16:23 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-11-19 07:16:23 +0000
commitbff5f30f0431ebb2040cf4fa2871f2a82540319e (patch)
tree54f55c0dcd9d753616ffab19d7149c7cb57f710b
parentdb32920931b5bc903282efbc62cc75f1f890452c (diff)
parentcfa8f9ab6181d4c9c32da4d1ea769f1be6655072 (diff)
Merge "MediaRouter: Add SystemMediaRoute2Provider to publish default route"
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java43
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2Provider.java82
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java49
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java25
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider.java202
5 files changed, 335 insertions, 66 deletions
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 240e7d1b6357..d0f7c780ceb2 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -82,6 +82,11 @@ public class MediaRouterManagerTest {
public static final String CATEGORY_SPECIAL =
"com.android.mediarouteprovider.CATEGORY_SPECIAL";
+ // system routes
+ private static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE";
+ private static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
+ private static final String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO";
+
private static final int TIMEOUT_MS = 5000;
private Context mContext;
@@ -90,13 +95,17 @@ public class MediaRouterManagerTest {
private Executor mExecutor;
private String mPackageName;
- private static final List<String> CONTROL_CATEGORIES_ALL = new ArrayList();
- private static final List<String> CONTROL_CATEGORIES_SPECIAL = new ArrayList();
+ private static final List<String> CATEGORIES_ALL = new ArrayList();
+ private static final List<String> CATEGORIES_SPECIAL = new ArrayList();
+ private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>();
static {
- CONTROL_CATEGORIES_ALL.add(CATEGORY_SAMPLE);
- CONTROL_CATEGORIES_ALL.add(CATEGORY_SPECIAL);
+ CATEGORIES_ALL.add(CATEGORY_SAMPLE);
+ CATEGORIES_ALL.add(CATEGORY_SPECIAL);
+ CATEGORIES_ALL.add(CATEGORY_LIVE_AUDIO);
+
+ CATEGORIES_SPECIAL.add(CATEGORY_SPECIAL);
- CONTROL_CATEGORIES_SPECIAL.add(CATEGORY_SPECIAL);
+ CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO);
}
@Before
@@ -153,7 +162,7 @@ public class MediaRouterManagerTest {
mRouter2.registerCallback(mExecutor, routerCallback);
Map<String, MediaRoute2Info> routes =
- waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL);
+ waitAndGetRoutesWithManager(CATEGORIES_ALL);
CountDownLatch latch = new CountDownLatch(1);
MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
@@ -187,7 +196,7 @@ public class MediaRouterManagerTest {
mManager.registerCallback(mExecutor, mockCallback);
Map<String, MediaRoute2Info> routes =
- waitAndGetRoutesWithManager(CONTROL_CATEGORIES_SPECIAL);
+ waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
Assert.assertEquals(1, routes.size());
Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
@@ -203,7 +212,7 @@ public class MediaRouterManagerTest {
MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
mRouter2.registerCallback(mExecutor, mockCallback);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CONTROL_CATEGORIES_SPECIAL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
Assert.assertEquals(1, routes.size());
Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
@@ -219,7 +228,7 @@ public class MediaRouterManagerTest {
mManager.registerCallback(mExecutor, managerCallback);
mRouter2.registerCallback(mExecutor, routerCallback);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
assertNotNull(routeToSelect);
@@ -242,7 +251,7 @@ public class MediaRouterManagerTest {
mRouter2.registerCallback(mExecutor, routerCallback);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
awaitOnRouteChangedManager(
() -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)),
@@ -264,7 +273,7 @@ public class MediaRouterManagerTest {
@Test
public void testControlVolumeWithRouter() throws Exception {
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CONTROL_CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
int originalVolume = volRoute.getVolume();
@@ -286,7 +295,7 @@ public class MediaRouterManagerTest {
MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
mRouter2.registerCallback(mExecutor, mockCallback);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
int originalVolume = volRoute.getVolume();
@@ -309,7 +318,7 @@ public class MediaRouterManagerTest {
public void testVolumeHandling() throws Exception {
MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
mRouter2.registerCallback(mExecutor, mockCallback);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CONTROL_CATEGORIES_ALL);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
@@ -321,6 +330,13 @@ public class MediaRouterManagerTest {
mRouter2.unregisterCallback(mockCallback);
}
+ @Test
+ public void testDefaultRoute() throws Exception {
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_LIVE_AUDIO);
+
+ assertNotNull(routes.get(DEFAULT_ROUTE_ID));
+ }
+
Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> controlCategories) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
MediaRouter2.Callback callback = new MediaRouter2.Callback() {
@@ -417,6 +433,7 @@ public class MediaRouterManagerTest {
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
for (MediaRoute2Info route : routes) {
+ // intentionally not route.getUniqueId() for convenience.
routeMap.put(route.getId(), route);
}
return routeMap;
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
new file mode 100644
index 000000000000..91c9253269a3
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -0,0 +1,82 @@
+/*
+ * 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.server.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.media.MediaRoute2Info;
+import android.media.MediaRoute2ProviderInfo;
+
+import java.util.Objects;
+
+abstract class MediaRoute2Provider {
+ final ComponentName mComponentName;
+ final String mUniqueId;
+
+ private Callback mCallback;
+ private MediaRoute2ProviderInfo mProviderInfo;
+
+ MediaRoute2Provider(@NonNull ComponentName componentName) {
+ mComponentName = Objects.requireNonNull(componentName, "Component name must not be null.");
+ mUniqueId = componentName.flattenToShortString();
+ }
+
+ public void setCallback(MediaRoute2ProviderProxy.Callback callback) {
+ mCallback = callback;
+ }
+
+ public abstract void requestSelectRoute(String packageName, String routeId, int seq);
+ public abstract void unselectRoute(String packageName, String routeId);
+ public abstract void sendControlRequest(MediaRoute2Info route, Intent request);
+ public abstract void requestSetVolume(MediaRoute2Info route, int volume);
+ public abstract void requestUpdateVolume(MediaRoute2Info route, int delta);
+
+ @NonNull
+ public String getUniqueId() {
+ return mUniqueId;
+ }
+
+ @Nullable
+ public MediaRoute2ProviderInfo getProviderInfo() {
+ return mProviderInfo;
+ }
+
+ void setAndNotifyProviderInfo(MediaRoute2ProviderInfo info) {
+ //TODO: check if info is not updated
+ if (info == null) {
+ mProviderInfo = null;
+ } else {
+ mProviderInfo = new MediaRoute2ProviderInfo.Builder(info)
+ .setUniqueId(mUniqueId)
+ .build();
+ }
+ if (mCallback != null) {
+ mCallback.onProviderStateChanged(this);
+ }
+ }
+
+ public boolean hasComponentName(String packageName, String className) {
+ return mComponentName.getPackageName().equals(packageName)
+ && mComponentName.getClassName().equals(className);
+ }
+
+ public interface Callback {
+ void onProviderStateChanged(MediaRoute2Provider provider);
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 51a0df33bc65..3b6580ad7357 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -17,7 +17,6 @@
package com.android.server.media;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -42,20 +41,14 @@ import java.util.Objects;
/**
* Maintains a connection to a particular media route provider service.
*/
-final class MediaRoute2ProviderProxy implements ServiceConnection {
+final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements ServiceConnection {
private static final String TAG = "MR2ProviderProxy";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
- private final ComponentName mComponentName;
- private final String mUniqueId;
private final int mUserId;
private final Handler mHandler;
- private Callback mCallback;
-
- private MediaRoute2ProviderInfo mProviderInfo;
-
// Connection state
private boolean mRunning;
private boolean mBound;
@@ -64,9 +57,8 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
MediaRoute2ProviderProxy(@NonNull Context context, @NonNull ComponentName componentName,
int userId) {
+ super(componentName);
mContext = Objects.requireNonNull(context, "Context must not be null.");
- mComponentName = Objects.requireNonNull(componentName, "Component name must not be null.");
- mUniqueId = componentName.flattenToShortString();
mUserId = userId;
mHandler = new Handler();
}
@@ -80,10 +72,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
pw.println(prefix + " mConnectionReady=" + mConnectionReady);
}
- public void setCallback(Callback callback) {
- mCallback = callback;
- }
-
+ @Override
public void requestSelectRoute(String packageName, String routeId, int seq) {
if (mConnectionReady) {
mActiveConnection.requestSelectRoute(packageName, routeId, seq);
@@ -91,6 +80,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
}
+ @Override
public void unselectRoute(String packageName, String routeId) {
if (mConnectionReady) {
mActiveConnection.unselectRoute(packageName, routeId);
@@ -98,6 +88,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
}
+ @Override
public void sendControlRequest(MediaRoute2Info route, Intent request) {
if (mConnectionReady) {
mActiveConnection.sendControlRequest(route.getId(), request);
@@ -105,6 +96,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
}
+ @Override
public void requestSetVolume(MediaRoute2Info route, int volume) {
if (mConnectionReady) {
mActiveConnection.requestSetVolume(route.getId(), volume);
@@ -112,6 +104,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
}
+ @Override
public void requestUpdateVolume(MediaRoute2Info route, int delta) {
if (mConnectionReady) {
mActiveConnection.requestUpdateVolume(route.getId(), delta);
@@ -119,16 +112,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
}
- @NonNull
- public String getUniqueId() {
- return mUniqueId;
- }
-
- @Nullable
- public MediaRoute2ProviderInfo getProviderInfo() {
- return mProviderInfo;
- }
-
public boolean hasComponentName(String packageName, String className) {
return mComponentName.getPackageName().equals(packageName)
&& mComponentName.getClassName().equals(className);
@@ -270,20 +253,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
setAndNotifyProviderInfo(info);
}
- private void setAndNotifyProviderInfo(MediaRoute2ProviderInfo info) {
- //TODO: check if info is not updated
- if (info == null) {
- mProviderInfo = null;
- } else {
- mProviderInfo = new MediaRoute2ProviderInfo.Builder(info)
- .setUniqueId(mUniqueId)
- .build();
- }
- if (mCallback != null) {
- mCallback.onProviderStateChanged(MediaRoute2ProviderProxy.this);
- }
- }
-
private void disconnect() {
if (mActiveConnection != null) {
mConnectionReady = false;
@@ -298,10 +267,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
return "Service connection " + mComponentName.flattenToShortString();
}
- public interface Callback {
- void onProviderStateChanged(@NonNull MediaRoute2ProviderProxy provider);
- }
-
private final class Connection implements DeathRecipient {
private final IMediaRoute2Provider mProvider;
private final ProviderClient mClient;
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index adfb9cb0964e..7820cd705193 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -728,14 +728,15 @@ class MediaRouter2ServiceImpl {
static final class UserHandler extends Handler implements
MediaRoute2ProviderWatcher.Callback,
- MediaRoute2ProviderProxy.Callback {
+ MediaRoute2Provider.Callback {
private final WeakReference<MediaRouter2ServiceImpl> mServiceRef;
private final UserRecord mUserRecord;
private final MediaRoute2ProviderWatcher mWatcher;
//TODO: Make this thread-safe.
- private final ArrayList<MediaRoute2ProviderProxy> mMediaProviders =
+ private final SystemMediaRoute2Provider mSystemProvider;
+ private final ArrayList<MediaRoute2Provider> mMediaProviders =
new ArrayList<>();
private final List<MediaRoute2ProviderInfo> mProviderInfos = new ArrayList<>();
@@ -746,6 +747,8 @@ class MediaRouter2ServiceImpl {
super(Looper.getMainLooper(), null, true);
mServiceRef = new WeakReference<>(service);
mUserRecord = userRecord;
+ mSystemProvider = new SystemMediaRoute2Provider(service.mContext, this);
+ mMediaProviders.add(mSystemProvider);
mWatcher = new MediaRoute2ProviderWatcher(service.mContext, this,
this, mUserRecord.mUserId);
}
@@ -777,7 +780,7 @@ class MediaRouter2ServiceImpl {
}
@Override
- public void onProviderStateChanged(@NonNull MediaRoute2ProviderProxy provider) {
+ public void onProviderStateChanged(@NonNull MediaRoute2Provider provider) {
sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
}
@@ -790,7 +793,7 @@ class MediaRouter2ServiceImpl {
controlHints, seq));
}
- private void updateProvider(MediaRoute2ProviderProxy provider) {
+ private void updateProvider(MediaRoute2Provider provider) {
int providerIndex = getProviderInfoIndex(provider.getUniqueId());
MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo();
MediaRoute2ProviderInfo prevInfo =
@@ -954,7 +957,7 @@ class MediaRouter2ServiceImpl {
private void requestSelectRoute(String clientPackageName, MediaRoute2Info route, int seq) {
if (route != null) {
- MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
+ MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider == null) {
Slog.w(TAG, "Ignoring to select route of unknown provider " + route);
} else {
@@ -965,7 +968,7 @@ class MediaRouter2ServiceImpl {
private void unselectRoute(String clientPackageName, MediaRoute2Info route) {
if (route != null) {
- MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
+ MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider == null) {
Slog.w(TAG, "Ignoring to unselect route of unknown provider " + route);
} else {
@@ -975,21 +978,21 @@ class MediaRouter2ServiceImpl {
}
private void sendControlRequest(MediaRoute2Info route, Intent request) {
- final MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
+ final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
provider.sendControlRequest(route, request);
}
}
private void requestSetVolume(MediaRoute2Info route, int volume) {
- final MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
+ final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
provider.requestSetVolume(route, volume);
}
}
private void requestUpdateVolume(MediaRoute2Info route, int delta) {
- final MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
+ final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider != null) {
provider.requestUpdateVolume(route, delta);
}
@@ -1153,8 +1156,8 @@ class MediaRouter2ServiceImpl {
}
}
- private MediaRoute2ProviderProxy findProvider(String providerId) {
- for (MediaRoute2ProviderProxy provider : mMediaProviders) {
+ private MediaRoute2Provider findProvider(String providerId) {
+ for (MediaRoute2Provider provider : mMediaProviders) {
if (TextUtils.equals(provider.getUniqueId(), providerId)) {
return provider;
}
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
new file mode 100644
index 000000000000..13ded61f6fd7
--- /dev/null
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -0,0 +1,202 @@
+/*
+ * 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.server.media;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.AudioRoutesInfo;
+import android.media.IAudioRoutesObserver;
+import android.media.IAudioService;
+import android.media.MediaRoute2Info;
+import android.media.MediaRoute2ProviderInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.R;
+
+/**
+ * Provides routes for local playbacks such as phone speaker, wired headset, or Bluetooth speakers.
+ */
+class SystemMediaRoute2Provider extends MediaRoute2Provider {
+ private static final String TAG = "MR2SystemProvider";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE";
+ private static final String BLUETOOTH_ROUTE_ID = "BLUETOOTH_ROUTE";
+
+ // TODO: Move these to a proper place
+ public static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
+ public static final String CATEGORY_LIVE_VIDEO = "android.media.intent.category.LIVE_VIDEO";
+
+ private final AudioManager mAudioManager;
+ private final IAudioService mAudioService;
+ private final Handler mHandler;
+ private final Context mContext;
+
+ private static ComponentName sComponentName = new ComponentName(
+ SystemMediaRoute2Provider.class.getPackageName$(),
+ SystemMediaRoute2Provider.class.getName());
+
+ //TODO: Clean up these when audio manager support multiple bt devices
+ MediaRoute2Info mDefaultRoute;
+ MediaRoute2Info mBluetoothA2dpRoute;
+ final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo();
+
+ final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() {
+ @Override
+ public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
+ mHandler.post(new Runnable() {
+ @Override public void run() {
+ updateAudioRoutes(newRoutes);
+ }
+ });
+ }
+ };
+
+ SystemMediaRoute2Provider(Context context, Callback callback) {
+ super(sComponentName);
+ setCallback(callback);
+
+ mContext = context;
+ mHandler = new Handler(Looper.getMainLooper());
+
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mAudioService = IAudioService.Stub.asInterface(
+ ServiceManager.getService(Context.AUDIO_SERVICE));
+
+ initializeRoutes();
+ }
+
+ //TODO: implement method
+ @Override
+ public void requestSelectRoute(@NonNull String packageName, @NonNull String routeId, int seq) {
+ try {
+ mAudioService.setBluetoothA2dpOn(
+ !TextUtils.equals(routeId, mDefaultRoute.getId()));
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Error changing Bluetooth A2DP route");
+ }
+ }
+
+ //TODO: implement method
+ @Override
+ public void unselectRoute(@NonNull String packageName, @NonNull String routeId) {
+ // does nothing..?
+ }
+
+ //TODO: implement method
+ @Override
+ public void sendControlRequest(@NonNull MediaRoute2Info route, @NonNull Intent request) {
+ }
+
+ //TODO: implement method
+ @Override
+ public void requestSetVolume(MediaRoute2Info route, int volume) {
+ }
+
+ //TODO: implement method
+ @Override
+ public void requestUpdateVolume(MediaRoute2Info route, int delta) {
+ }
+
+ void initializeRoutes() {
+ //TODO: adds necessary info
+ mDefaultRoute = new MediaRoute2Info.Builder(
+ DEFAULT_ROUTE_ID,
+ mContext.getResources().getText(R.string.default_audio_route_name).toString())
+ .setVolumeHandling(mAudioManager.isVolumeFixed()
+ ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
+ : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
+ .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
+ .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
+ .addSupportedCategory(CATEGORY_LIVE_AUDIO)
+ .addSupportedCategory(CATEGORY_LIVE_VIDEO)
+ .build();
+
+ AudioRoutesInfo newAudioRoutes = null;
+ try {
+ newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver);
+ } catch (RemoteException e) {
+ }
+ if (newAudioRoutes != null) {
+ // This will select the active BT route if there is one and the current
+ // selected route is the default system route, or if there is no selected
+ // route yet.
+ updateAudioRoutes(newAudioRoutes);
+ }
+
+ publishRoutes();
+ }
+
+ void updateAudioRoutes(AudioRoutesInfo newRoutes) {
+ int name = R.string.default_audio_route_name;
+ mCurAudioRoutesInfo.mainType = newRoutes.mainType;
+ if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0
+ || (newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
+ name = com.android.internal.R.string.default_audio_route_name_headphones;
+ } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
+ name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
+ } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
+ name = com.android.internal.R.string.default_audio_route_name_hdmi;
+ } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) {
+ name = com.android.internal.R.string.default_audio_route_name_usb;
+ }
+
+ mDefaultRoute = new MediaRoute2Info.Builder(
+ DEFAULT_ROUTE_ID, mContext.getResources().getText(name).toString())
+ .setVolumeHandling(mAudioManager.isVolumeFixed()
+ ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
+ : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
+ .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
+ .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
+ .addSupportedCategory(CATEGORY_LIVE_AUDIO)
+ .addSupportedCategory(CATEGORY_LIVE_VIDEO)
+ .build();
+
+ if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
+ mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
+ if (mCurAudioRoutesInfo.bluetoothName != null) {
+ //TODO: mark as bluetooth once MediaRoute2Info has device type
+ mBluetoothA2dpRoute = new MediaRoute2Info.Builder(BLUETOOTH_ROUTE_ID,
+ mCurAudioRoutesInfo.bluetoothName.toString())
+ .setDescription(mContext.getResources().getText(
+ R.string.bluetooth_a2dp_audio_route_name).toString())
+ .addSupportedCategory(CATEGORY_LIVE_AUDIO)
+ .build();
+ } else if (mBluetoothA2dpRoute != null) {
+ mBluetoothA2dpRoute = null;
+ }
+ }
+
+ publishRoutes();
+ }
+ void publishRoutes() {
+ MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder()
+ .addRoute(mDefaultRoute);
+ if (mBluetoothA2dpRoute != null) {
+ builder.addRoute(mBluetoothA2dpRoute);
+ }
+ setAndNotifyProviderInfo(builder.build());
+ }
+}