blob: 2c089ca8300ea298209405c277d99e098c82a76c [file] [log] [blame]
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001/*
2 * Copyright 2019 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
17package com.android.server.media;
18
Hyundo Moon42bef142020-01-14 14:16:30 +090019import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
20import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO;
Kyunglyul Hyunc0363502020-06-19 13:33:16 +090021import static android.media.MediaRoute2Info.FEATURE_LOCAL_PLAYBACK;
Kyunglyul Hyun8828c892020-02-17 20:49:58 +090022import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
Kyunglyul Hyun1080caf2020-04-20 13:48:15 +090023import static android.media.MediaRoute2Info.TYPE_DOCK;
24import static android.media.MediaRoute2Info.TYPE_HDMI;
25import static android.media.MediaRoute2Info.TYPE_USB_DEVICE;
26import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
27import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
Hyundo Moon42bef142020-01-14 14:16:30 +090028
Hyundo Moon717ef722020-02-06 18:44:13 +090029import android.content.BroadcastReceiver;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000030import android.content.ComponentName;
31import android.content.Context;
32import android.content.Intent;
Hyundo Moon717ef722020-02-06 18:44:13 +090033import android.content.IntentFilter;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000034import android.media.AudioManager;
35import android.media.AudioRoutesInfo;
36import android.media.IAudioRoutesObserver;
37import android.media.IAudioService;
38import android.media.MediaRoute2Info;
39import android.media.MediaRoute2ProviderInfo;
Kyunglyul Hyun22d4e052020-04-21 10:10:48 +090040import android.media.MediaRoute2ProviderService;
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +090041import android.media.RouteDiscoveryPreference;
Hyundo Moon67c41fd2020-01-17 14:22:42 +090042import android.media.RoutingSessionInfo;
Hyundo Moon84e027d2020-01-16 17:39:05 +090043import android.os.Bundle;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000044import android.os.Handler;
45import android.os.Looper;
46import android.os.RemoteException;
47import android.os.ServiceManager;
Hyundo Moon67c41fd2020-01-17 14:22:42 +090048import android.text.TextUtils;
Kyunglyul Hyuna4648372020-06-15 16:52:14 +090049import android.util.Log;
Kyunglyul Hyun5ff55ec2020-05-18 16:37:43 +090050import android.util.Slog;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000051
52import com.android.internal.R;
Kyunglyul Hyun22d4e052020-04-21 10:10:48 +090053import com.android.internal.annotations.GuardedBy;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000054
Hyundo Moon67c41fd2020-01-17 14:22:42 +090055import java.util.Objects;
Kyunglyul Hyunefe43742019-12-31 18:32:28 +090056
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000057/**
58 * Provides routes for local playbacks such as phone speaker, wired headset, or Bluetooth speakers.
59 */
Sungsoo Limea1eaf72020-02-12 11:00:06 +090060// TODO: check thread safety. We may need to use lock to protect variables.
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000061class SystemMediaRoute2Provider extends MediaRoute2Provider {
62 private static final String TAG = "MR2SystemProvider";
Kyunglyul Hyuna4648372020-06-15 16:52:14 +090063 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000064
Hyundo Moon5736a612019-11-19 15:08:32 +090065 static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE";
Sungsoo Limddf140d2020-03-25 08:53:55 +090066 static final String DEVICE_ROUTE_ID = "DEVICE_ROUTE";
Hyundo Moon67c41fd2020-01-17 14:22:42 +090067 static final String SYSTEM_SESSION_ID = "SYSTEM_SESSION";
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000068
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000069 private final AudioManager mAudioManager;
70 private final IAudioService mAudioService;
71 private final Handler mHandler;
72 private final Context mContext;
Sungsoo Limbb3ee6e2019-12-23 17:47:24 +090073 private final BluetoothRouteProvider mBtRouteProvider;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000074
75 private static ComponentName sComponentName = new ComponentName(
Kyunglyul Hyund9bb4d72020-02-18 15:05:26 +090076 SystemMediaRoute2Provider.class.getPackage().getName(),
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000077 SystemMediaRoute2Provider.class.getName());
78
Kyunglyul Hyun5161b372020-02-05 18:45:35 +090079 private String mSelectedRouteId;
Sungsoo Limddf140d2020-03-25 08:53:55 +090080 // For apps without MODIFYING_AUDIO_ROUTING permission.
81 // This should be the currently selected route.
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000082 MediaRoute2Info mDefaultRoute;
Sungsoo Limddf140d2020-03-25 08:53:55 +090083 MediaRoute2Info mDeviceRoute;
Sungsoo Limc27785a2020-03-27 16:57:47 +090084 RoutingSessionInfo mDefaultSessionInfo;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000085 final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo();
Kyunglyul Hyunf8f170c2020-05-13 21:31:26 +090086 int mDeviceVolume;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000087
Kyunglyul Hyun22d4e052020-04-21 10:10:48 +090088 private final Object mRequestLock = new Object();
89 @GuardedBy("mRequestLock")
90 private volatile SessionCreationRequest mPendingSessionCreationRequest;
91
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000092 final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() {
93 @Override
94 public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
Sungsoo Limea1eaf72020-02-12 11:00:06 +090095 mHandler.post(() -> {
Sungsoo Limddf140d2020-03-25 08:53:55 +090096 updateDeviceRoute(newRoutes);
Sungsoo Limea1eaf72020-02-12 11:00:06 +090097 notifyProviderState();
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000098 });
99 }
100 };
101
Hyundo Moonaa803752020-06-17 23:02:49 +0900102 SystemMediaRoute2Provider(Context context) {
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000103 super(sComponentName);
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000104
Kyunglyul Hyun96d36ce2020-01-29 19:59:33 +0900105 mIsSystemRouteProvider = true;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000106 mContext = context;
107 mHandler = new Handler(Looper.getMainLooper());
108
109 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
110 mAudioService = IAudioService.Stub.asInterface(
111 ServiceManager.getService(Context.AUDIO_SERVICE));
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900112 AudioRoutesInfo newAudioRoutes = null;
113 try {
114 newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver);
115 } catch (RemoteException e) {
116 }
Sungsoo Limddf140d2020-03-25 08:53:55 +0900117 updateDeviceRoute(newAudioRoutes);
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000118
Roman Kiryanovfe87df92020-03-27 17:40:27 -0700119 // .getInstance returns null if there is no bt adapter available
Sungsoo Limbb3ee6e2019-12-23 17:47:24 +0900120 mBtRouteProvider = BluetoothRouteProvider.getInstance(context, (routes) -> {
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900121 publishProviderState();
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900122
123 boolean sessionInfoChanged;
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900124 sessionInfoChanged = updateSessionInfosIfNeeded();
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900125 if (sessionInfoChanged) {
126 notifySessionInfoUpdated();
127 }
Sungsoo Limbb3ee6e2019-12-23 17:47:24 +0900128 });
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900129 updateSessionInfosIfNeeded();
Sungsoo Limc27785a2020-03-27 16:57:47 +0900130
Kyunglyul Hyunf8f170c2020-05-13 21:31:26 +0900131 IntentFilter intentFilter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
132 intentFilter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
133 mContext.registerReceiver(new AudioManagerBroadcastReceiver(), intentFilter);
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900134
Roman Kiryanovfe87df92020-03-27 17:40:27 -0700135 if (mBtRouteProvider != null) {
136 mHandler.post(() -> {
137 mBtRouteProvider.start();
138 notifyProviderState();
139 });
140 }
Kyunglyul Hyunf8f170c2020-05-13 21:31:26 +0900141 updateVolume();
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000142 }
143
Hyundo Moon63a05402019-12-19 20:13:56 +0900144 @Override
Hyundo Moonaa803752020-06-17 23:02:49 +0900145 public void setCallback(Callback callback) {
146 super.setCallback(callback);
147 notifyProviderState();
148 notifySessionInfoUpdated();
149 }
150
151 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900152 public void requestCreateSession(long requestId, String packageName, String routeId,
Hyundo Moon84e027d2020-01-16 17:39:05 +0900153 Bundle sessionHints) {
Kyunglyul Hyun22d4e052020-04-21 10:10:48 +0900154 // Assume a router without MODIFY_AUDIO_ROUTING permission can't request with
155 // a route ID different from the default route ID. The service should've filtered.
156 if (TextUtils.equals(routeId, DEFAULT_ROUTE_ID)) {
157 mCallback.onSessionCreated(this, requestId, mDefaultSessionInfo);
158 return;
159 }
160 if (TextUtils.equals(routeId, mSelectedRouteId)) {
161 mCallback.onSessionCreated(this, requestId, mSessionInfos.get(0));
162 return;
163 }
164
165 synchronized (mRequestLock) {
166 // Handle the previous request as a failure if exists.
167 if (mPendingSessionCreationRequest != null) {
168 mCallback.onRequestFailed(this, mPendingSessionCreationRequest.mRequestId,
169 MediaRoute2ProviderService.REASON_UNKNOWN_ERROR);
170 }
171 mPendingSessionCreationRequest = new SessionCreationRequest(requestId, routeId);
172 }
Kyunglyul Hyun923ef0d2020-03-13 20:55:11 +0900173
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900174 transferToRoute(requestId, SYSTEM_SESSION_ID, routeId);
Hyundo Moon63a05402019-12-19 20:13:56 +0900175 }
176
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000177 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900178 public void releaseSession(long requestId, String sessionId) {
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900179 // Do nothing
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000180 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900181
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +0900182 @Override
183 public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
184 // Do nothing
185 }
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000186
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000187 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900188 public void selectRoute(long requestId, String sessionId, String routeId) {
Kyunglyul Hyun581fc982020-01-21 16:30:28 +0900189 // Do nothing since we don't support multiple BT yet.
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900190 }
191
192 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900193 public void deselectRoute(long requestId, String sessionId, String routeId) {
Kyunglyul Hyun581fc982020-01-21 16:30:28 +0900194 // Do nothing since we don't support multiple BT yet.
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900195 }
196
197 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900198 public void transferToRoute(long requestId, String sessionId, String routeId) {
Sungsoo Limc27785a2020-03-27 16:57:47 +0900199 if (TextUtils.equals(routeId, DEFAULT_ROUTE_ID)) {
200 // The currently selected route is the default route.
201 return;
202 }
Roman Kiryanovfe87df92020-03-27 17:40:27 -0700203 if (mBtRouteProvider != null) {
204 if (TextUtils.equals(routeId, mDeviceRoute.getId())) {
205 mBtRouteProvider.transferTo(null);
206 } else {
207 mBtRouteProvider.transferTo(routeId);
208 }
Kyunglyul Hyun581fc982020-01-21 16:30:28 +0900209 }
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000210 }
211
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000212 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900213 public void setRouteVolume(long requestId, String routeId, int volume) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900214 if (!TextUtils.equals(routeId, mSelectedRouteId)) {
215 return;
216 }
217 mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
218 }
219
220 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900221 public void setSessionVolume(long requestId, String sessionId, int volume) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900222 // Do nothing since we don't support grouping volume yet.
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000223 }
224
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900225 @Override
226 public void prepareReleaseSession(String sessionId) {
227 // Do nothing since the system session persists.
228 }
229
Sungsoo Limddf140d2020-03-25 08:53:55 +0900230 public MediaRoute2Info getDefaultRoute() {
231 return mDefaultRoute;
232 }
233
Sungsoo Limc27785a2020-03-27 16:57:47 +0900234 public RoutingSessionInfo getDefaultSessionInfo() {
235 return mDefaultSessionInfo;
236 }
237
Sungsoo Limddf140d2020-03-25 08:53:55 +0900238 private void updateDeviceRoute(AudioRoutesInfo newRoutes) {
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000239 int name = R.string.default_audio_route_name;
Kyunglyul Hyun1080caf2020-04-20 13:48:15 +0900240 int type = TYPE_BUILTIN_SPEAKER;
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900241 if (newRoutes != null) {
242 mCurAudioRoutesInfo.mainType = newRoutes.mainType;
Kyunglyul Hyun1080caf2020-04-20 13:48:15 +0900243 if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0) {
244 type = TYPE_WIRED_HEADPHONES;
245 name = com.android.internal.R.string.default_audio_route_name_headphones;
246 } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
247 type = TYPE_WIRED_HEADSET;
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900248 name = com.android.internal.R.string.default_audio_route_name_headphones;
249 } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
Kyunglyul Hyun1080caf2020-04-20 13:48:15 +0900250 type = TYPE_DOCK;
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900251 name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
252 } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
Kyunglyul Hyun1080caf2020-04-20 13:48:15 +0900253 type = TYPE_HDMI;
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900254 name = com.android.internal.R.string.default_audio_route_name_hdmi;
255 } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) {
Kyunglyul Hyun1080caf2020-04-20 13:48:15 +0900256 type = TYPE_USB_DEVICE;
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900257 name = com.android.internal.R.string.default_audio_route_name_usb;
258 }
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000259 }
Kyunglyul Hyun1080caf2020-04-20 13:48:15 +0900260
Sungsoo Limddf140d2020-03-25 08:53:55 +0900261 mDeviceRoute = new MediaRoute2Info.Builder(
262 DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString())
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000263 .setVolumeHandling(mAudioManager.isVolumeFixed()
264 ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
265 : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
Kyunglyul Hyunf8f170c2020-05-13 21:31:26 +0900266 .setVolume(mDeviceVolume)
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000267 .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
Kyunglyul Hyun1080caf2020-04-20 13:48:15 +0900268 .setType(type)
Hyundo Moon42bef142020-01-14 14:16:30 +0900269 .addFeature(FEATURE_LIVE_AUDIO)
270 .addFeature(FEATURE_LIVE_VIDEO)
Kyunglyul Hyunc0363502020-06-19 13:33:16 +0900271 .addFeature(FEATURE_LOCAL_PLAYBACK)
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900272 .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED)
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000273 .build();
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900274 updateProviderState();
275 }
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000276
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900277 private void updateProviderState() {
278 MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder();
Sungsoo Limddf140d2020-03-25 08:53:55 +0900279 builder.addRoute(mDeviceRoute);
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900280 if (mBtRouteProvider != null) {
281 for (MediaRoute2Info route : mBtRouteProvider.getAllBluetoothRoutes()) {
282 builder.addRoute(route);
283 }
284 }
Kyunglyul Hyun5ff55ec2020-05-18 16:37:43 +0900285 MediaRoute2ProviderInfo providerInfo = builder.build();
286 setProviderState(providerInfo);
287 if (DEBUG) {
288 Slog.d(TAG, "Updating system provider info : " + providerInfo);
289 }
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000290 }
Hyundo Moon5736a612019-11-19 15:08:32 +0900291
292 /**
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900293 * Updates the mSessionInfo. Returns true if the session info is changed.
294 */
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900295 boolean updateSessionInfosIfNeeded() {
296 synchronized (mLock) {
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900297 RoutingSessionInfo oldSessionInfo = mSessionInfos.isEmpty() ? null : mSessionInfos.get(
298 0);
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900299
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900300 RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
301 SYSTEM_SESSION_ID, "" /* clientPackageName */)
302 .setSystemSession(true);
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900303
Sungsoo Limc27785a2020-03-27 16:57:47 +0900304 MediaRoute2Info selectedRoute = mDeviceRoute;
305 if (mBtRouteProvider != null) {
306 MediaRoute2Info selectedBtRoute = mBtRouteProvider.getSelectedRoute();
307 if (selectedBtRoute != null) {
308 selectedRoute = selectedBtRoute;
309 builder.addTransferableRoute(mDeviceRoute.getId());
310 }
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900311 }
312 mSelectedRouteId = selectedRoute.getId();
Sungsoo Limc27785a2020-03-27 16:57:47 +0900313 mDefaultRoute = new MediaRoute2Info.Builder(DEFAULT_ROUTE_ID, selectedRoute)
314 .setSystemRoute(true)
315 .setProviderId(mUniqueId)
316 .build();
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900317 builder.addSelectedRoute(mSelectedRouteId);
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900318
Roman Kiryanov39961302020-04-15 11:49:19 -0700319 if (mBtRouteProvider != null) {
320 for (MediaRoute2Info route : mBtRouteProvider.getTransferableRoutes()) {
321 builder.addTransferableRoute(route.getId());
322 }
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900323 }
Kyunglyul Hyun581fc982020-01-21 16:30:28 +0900324
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900325 RoutingSessionInfo newSessionInfo = builder.setProviderId(mUniqueId).build();
Kyunglyul Hyun22d4e052020-04-21 10:10:48 +0900326
327 if (mPendingSessionCreationRequest != null) {
328 SessionCreationRequest sessionCreationRequest;
329 synchronized (mRequestLock) {
330 sessionCreationRequest = mPendingSessionCreationRequest;
331 mPendingSessionCreationRequest = null;
332 }
333 if (sessionCreationRequest != null) {
334 if (TextUtils.equals(mSelectedRouteId, sessionCreationRequest.mRouteId)) {
335 mCallback.onSessionCreated(this,
336 sessionCreationRequest.mRequestId, newSessionInfo);
337 } else {
338 mCallback.onRequestFailed(this, sessionCreationRequest.mRequestId,
339 MediaRoute2ProviderService.REASON_UNKNOWN_ERROR);
340 }
341 }
342 }
343
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900344 if (Objects.equals(oldSessionInfo, newSessionInfo)) {
345 return false;
346 } else {
Kyunglyul Hyun5ff55ec2020-05-18 16:37:43 +0900347 if (DEBUG) {
348 Slog.d(TAG, "Updating system routing session info : " + newSessionInfo);
349 }
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900350 mSessionInfos.clear();
351 mSessionInfos.add(newSessionInfo);
Sungsoo Limc27785a2020-03-27 16:57:47 +0900352 mDefaultSessionInfo = new RoutingSessionInfo.Builder(
353 SYSTEM_SESSION_ID, "" /* clientPackageName */)
354 .setProviderId(mUniqueId)
355 .setSystemSession(true)
356 .addSelectedRoute(DEFAULT_ROUTE_ID)
357 .build();
Sungsoo Lim613a77a2020-03-16 15:44:51 +0900358 return true;
359 }
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900360 }
361 }
362
Sungsoo Limea1eaf72020-02-12 11:00:06 +0900363 void publishProviderState() {
364 updateProviderState();
365 notifyProviderState();
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000366 }
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900367
368 void notifySessionInfoUpdated() {
Hyundo Moonaa803752020-06-17 23:02:49 +0900369 if (mCallback == null) {
370 return;
371 }
372
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900373 RoutingSessionInfo sessionInfo;
374 synchronized (mLock) {
375 sessionInfo = mSessionInfos.get(0);
376 }
Kyunglyul Hyun923ef0d2020-03-13 20:55:11 +0900377
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900378 mCallback.onSessionUpdated(this, sessionInfo);
379 }
Hyundo Moon717ef722020-02-06 18:44:13 +0900380
Kyunglyul Hyun22d4e052020-04-21 10:10:48 +0900381 private static class SessionCreationRequest {
382 final long mRequestId;
383 final String mRouteId;
384
385 SessionCreationRequest(long requestId, String routeId) {
386 this.mRequestId = requestId;
387 this.mRouteId = routeId;
388 }
389 }
390
Kyunglyul Hyunf8f170c2020-05-13 21:31:26 +0900391 void updateVolume() {
392 int devices = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
393 int volume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
394
395 if (mDefaultRoute.getVolume() != volume) {
396 mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute)
397 .setVolume(volume)
398 .build();
399 }
400
401 if (mBtRouteProvider != null && mBtRouteProvider.updateVolumeForDevices(devices, volume)) {
402 return;
403 }
404 if (mDeviceVolume != volume) {
405 mDeviceVolume = volume;
406 mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute)
407 .setVolume(volume)
408 .build();
409 }
410 publishProviderState();
411 }
412
413 private class AudioManagerBroadcastReceiver extends BroadcastReceiver {
Hyundo Moon717ef722020-02-06 18:44:13 +0900414 // This will be called in the main thread.
415 @Override
416 public void onReceive(Context context, Intent intent) {
Kyunglyul Hyunf8f170c2020-05-13 21:31:26 +0900417 if (!intent.getAction().equals(AudioManager.VOLUME_CHANGED_ACTION)
418 && !intent.getAction().equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) {
Hyundo Moon717ef722020-02-06 18:44:13 +0900419 return;
420 }
421
Kyunglyul Hyunf8f170c2020-05-13 21:31:26 +0900422 int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
Hyundo Moon717ef722020-02-06 18:44:13 +0900423 if (streamType != AudioManager.STREAM_MUSIC) {
424 return;
425 }
426
Kyunglyul Hyunf8f170c2020-05-13 21:31:26 +0900427 updateVolume();
Hyundo Moon717ef722020-02-06 18:44:13 +0900428 }
429 }
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000430}