blob: 5e865e7cb71532be6e875fcaa7635b68955aba0a [file] [log] [blame]
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001/*
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
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +090019import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE;
20import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
Hyundo Moon0fa60e82020-02-14 11:44:45 +090021import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
Hyundo Moonb26c4b22020-01-08 19:44:43 +090022import static android.media.MediaRouter2Utils.getOriginalId;
23import static android.media.MediaRouter2Utils.getProviderId;
24
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +090025import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
26
Kyunglyul Hyundafac542019-04-29 18:07:21 +090027import android.annotation.NonNull;
Kyunglyul Hyunc6583832020-01-17 11:11:46 +000028import android.annotation.Nullable;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090029import android.app.ActivityManager;
30import android.content.Context;
Kyunglyul Hyundafac542019-04-29 18:07:21 +090031import android.content.pm.PackageManager;
Hyundo Moon56337492020-02-16 16:19:54 +090032import android.media.IMediaRouter2;
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +090033import android.media.IMediaRouter2Manager;
Kyunglyul Hyuncaae8dc2019-04-29 15:45:23 +090034import android.media.MediaRoute2Info;
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +090035import android.media.MediaRoute2ProviderInfo;
Kyunglyul Hyun616096e2020-01-09 16:15:03 +090036import android.media.RouteDiscoveryPreference;
Hyundo Moonf829e6f2020-01-11 19:31:35 +090037import android.media.RoutingSessionInfo;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090038import android.os.Binder;
Kyunglyul Hyun7d720f72020-01-17 11:03:28 +000039import android.os.Bundle;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090040import android.os.Handler;
41import android.os.IBinder;
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +090042import android.os.Looper;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090043import android.os.RemoteException;
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +090044import android.os.UserHandle;
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +090045import android.text.TextUtils;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090046import android.util.ArrayMap;
47import android.util.Log;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090048import android.util.Slog;
49import android.util.SparseArray;
50
Kyunglyul Hyundafac542019-04-29 18:07:21 +090051import com.android.internal.annotations.GuardedBy;
Kyunglyul Hyun30e2c652019-07-11 16:25:31 +090052import com.android.internal.util.function.pooled.PooledLambda;
Kyunglyul Hyundafac542019-04-29 18:07:21 +090053
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090054import java.io.PrintWriter;
55import java.lang.ref.WeakReference;
56import java.util.ArrayList;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +090057import java.util.Collection;
Kyunglyul Hyundafac542019-04-29 18:07:21 +090058import java.util.Collections;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090059import java.util.List;
Hyundo Moon0a926572019-12-28 15:01:21 +090060import java.util.Map;
Kyunglyul Hyundafac542019-04-29 18:07:21 +090061import java.util.Objects;
Hyundo Moon63a05402019-12-19 20:13:56 +090062import java.util.concurrent.CopyOnWriteArrayList;
Kyunglyul Hyunc7847242019-12-30 17:46:04 +090063import java.util.concurrent.atomic.AtomicInteger;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090064
65/**
Kyunglyul Hyunc6583832020-01-17 11:11:46 +000066 * Implements features related to {@link android.media.MediaRouter2} and
67 * {@link android.media.MediaRouter2Manager}.
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090068 */
69class MediaRouter2ServiceImpl {
Hyundo Moon7d3ab332019-10-16 11:09:56 +090070 private static final String TAG = "MR2ServiceImpl";
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090071 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
72
Hyundo Moon8ca032d2020-03-31 15:45:45 +090073 // TODO: (In Android S or later) if we add callback methods for generic failures
74 // in MediaRouter2, remove this constant and replace the usages with the real request IDs.
Hyundo Moon0fa60e82020-02-14 11:44:45 +090075 private static final long DUMMY_REQUEST_ID = -1;
76
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090077 private final Context mContext;
78 private final Object mLock = new Object();
Hyundo Moon56337492020-02-16 16:19:54 +090079 final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090080
Kyunglyul Hyundafac542019-04-29 18:07:21 +090081 @GuardedBy("mLock")
82 private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
83 @GuardedBy("mLock")
Hyundo Moon56337492020-02-16 16:19:54 +090084 private final ArrayMap<IBinder, RouterRecord> mAllRouterRecords = new ArrayMap<>();
Kyunglyul Hyundafac542019-04-29 18:07:21 +090085 @GuardedBy("mLock")
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090086 private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
Kyunglyul Hyundafac542019-04-29 18:07:21 +090087 @GuardedBy("mLock")
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +090088 private int mCurrentUserId = -1;
89
90 MediaRouter2ServiceImpl(Context context) {
91 mContext = context;
92 }
93
Hyundo Moone962ed42020-02-16 19:47:41 +090094 ////////////////////////////////////////////////////////////////
95 //// Calls from MediaRouter2
96 //// - Should not have @NonNull/@Nullable on any arguments
97 ////////////////////////////////////////////////////////////////
98
Hyundo Moon5736a612019-11-19 15:08:32 +090099 @NonNull
100 public List<MediaRoute2Info> getSystemRoutes() {
101 final int uid = Binder.getCallingUid();
Sungsoo Lim277ea282020-01-14 16:35:05 +0900102 final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
Sungsoo Limc27785a2020-03-27 16:57:47 +0900103 final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission(
104 android.Manifest.permission.MODIFY_AUDIO_ROUTING)
105 == PackageManager.PERMISSION_GRANTED;
Hyundo Moon5736a612019-11-19 15:08:32 +0900106
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900107 final long token = Binder.clearCallingIdentity();
108 try {
109 Collection<MediaRoute2Info> systemRoutes;
110 synchronized (mLock) {
111 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Limc27785a2020-03-27 16:57:47 +0900112 if (hasModifyAudioRoutingPermission) {
113 MediaRoute2ProviderInfo providerInfo =
114 userRecord.mHandler.mSystemProvider.getProviderInfo();
115 if (providerInfo != null) {
116 systemRoutes = providerInfo.getRoutes();
117 } else {
118 systemRoutes = Collections.emptyList();
119 }
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900120 } else {
Sungsoo Limc27785a2020-03-27 16:57:47 +0900121 systemRoutes = new ArrayList<>();
122 systemRoutes.add(userRecord.mHandler.mSystemProvider.getDefaultRoute());
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900123 }
Hyundo Moon5736a612019-11-19 15:08:32 +0900124 }
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900125 return new ArrayList<>(systemRoutes);
126 } finally {
127 Binder.restoreCallingIdentity(token);
Hyundo Moon5736a612019-11-19 15:08:32 +0900128 }
Hyundo Moon5736a612019-11-19 15:08:32 +0900129 }
130
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900131 @NonNull
132 public RoutingSessionInfo getSystemSessionInfo() {
133 final int uid = Binder.getCallingUid();
134 final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
Sungsoo Limc27785a2020-03-27 16:57:47 +0900135 final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission(
136 android.Manifest.permission.MODIFY_AUDIO_ROUTING)
137 == PackageManager.PERMISSION_GRANTED;
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900138
139 final long token = Binder.clearCallingIdentity();
140 try {
141 RoutingSessionInfo systemSessionInfo = null;
142 synchronized (mLock) {
143 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Limc27785a2020-03-27 16:57:47 +0900144 List<RoutingSessionInfo> sessionInfos;
145 if (hasModifyAudioRoutingPermission) {
146 sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos();
147 if (sessionInfos != null && !sessionInfos.isEmpty()) {
148 systemSessionInfo = sessionInfos.get(0);
149 } else {
150 Slog.w(TAG, "System provider does not have any session info.");
151 }
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900152 } else {
Sungsoo Limc27785a2020-03-27 16:57:47 +0900153 systemSessionInfo = userRecord.mHandler.mSystemProvider.getDefaultSessionInfo();
Hyundo Moon67c41fd2020-01-17 14:22:42 +0900154 }
155 }
156 return systemSessionInfo;
157 } finally {
158 Binder.restoreCallingIdentity(token);
159 }
160 }
161
Hyundo Moone962ed42020-02-16 19:47:41 +0900162 public void registerRouter2(IMediaRouter2 router, String packageName) {
Hyundo Moon56337492020-02-16 16:19:54 +0900163 Objects.requireNonNull(router, "router must not be null");
Hyundo Moone962ed42020-02-16 19:47:41 +0900164 if (TextUtils.isEmpty(packageName)) {
165 throw new IllegalArgumentException("packageName must not be empty");
166 }
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900167
168 final int uid = Binder.getCallingUid();
169 final int pid = Binder.getCallingPid();
Sungsoo Lim277ea282020-01-14 16:35:05 +0900170 final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900171 final boolean hasConfigureWifiDisplayPermission = mContext.checkCallingOrSelfPermission(
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900172 android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
173 == PackageManager.PERMISSION_GRANTED;
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900174 final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission(
175 android.Manifest.permission.MODIFY_AUDIO_ROUTING)
176 == PackageManager.PERMISSION_GRANTED;
177
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900178 final long token = Binder.clearCallingIdentity();
179 try {
180 synchronized (mLock) {
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900181 registerRouter2Locked(router, uid, pid, packageName, userId,
182 hasConfigureWifiDisplayPermission, hasModifyAudioRoutingPermission);
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900183 }
184 } finally {
185 Binder.restoreCallingIdentity(token);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900186 }
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900187 }
188
Hyundo Moone962ed42020-02-16 19:47:41 +0900189 public void unregisterRouter2(IMediaRouter2 router) {
Hyundo Moon56337492020-02-16 16:19:54 +0900190 Objects.requireNonNull(router, "router must not be null");
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900191
192 final long token = Binder.clearCallingIdentity();
193 try {
194 synchronized (mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +0900195 unregisterRouter2Locked(router, false);
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900196 }
197 } finally {
198 Binder.restoreCallingIdentity(token);
199 }
200 }
201
Hyundo Moone962ed42020-02-16 19:47:41 +0900202 public void setDiscoveryRequestWithRouter2(IMediaRouter2 router,
203 RouteDiscoveryPreference preference) {
204 Objects.requireNonNull(router, "router must not be null");
205 Objects.requireNonNull(preference, "preference must not be null");
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +0900206
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900207 final long token = Binder.clearCallingIdentity();
208 try {
209 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900210 RouterRecord routerRecord = mAllRouterRecords.get(router.asBinder());
211 if (routerRecord == null) {
212 Slog.w(TAG, "Ignoring updating discoveryRequest of null routerRecord.");
213 return;
214 }
215 setDiscoveryRequestWithRouter2Locked(routerRecord, preference);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900216 }
217 } finally {
218 Binder.restoreCallingIdentity(token);
219 }
220 }
221
Hyundo Moone962ed42020-02-16 19:47:41 +0900222 public void setRouteVolumeWithRouter2(IMediaRouter2 router,
223 MediaRoute2Info route, int volume) {
224 Objects.requireNonNull(router, "router must not be null");
225 Objects.requireNonNull(route, "route must not be null");
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900226
227 final long token = Binder.clearCallingIdentity();
228 try {
229 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900230 setRouteVolumeWithRouter2Locked(router, route, volume);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900231 }
232 } finally {
233 Binder.restoreCallingIdentity(token);
234 }
235 }
236
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900237 public void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId,
238 MediaRoute2Info route, Bundle sessionHints) {
Hyundo Moon56337492020-02-16 16:19:54 +0900239 Objects.requireNonNull(router, "router must not be null");
Hyundo Moon63a05402019-12-19 20:13:56 +0900240 Objects.requireNonNull(route, "route must not be null");
Hyundo Moon63a05402019-12-19 20:13:56 +0900241
242 final long token = Binder.clearCallingIdentity();
243 try {
244 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900245 requestCreateSessionWithRouter2Locked(requestId, router, route, sessionHints);
Hyundo Moon63a05402019-12-19 20:13:56 +0900246 }
247 } finally {
248 Binder.restoreCallingIdentity(token);
249 }
250 }
251
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900252 public void notifySessionHintsForCreatingSession(IMediaRouter2 router,
253 long uniqueRequestId, MediaRoute2Info route, Bundle sessionHints) {
254 Objects.requireNonNull(router, "router must not be null");
255 Objects.requireNonNull(route, "route must not be null");
256
257 final long token = Binder.clearCallingIdentity();
258 try {
259 synchronized (mLock) {
260 notifySessionHintsForCreatingSessionLocked(uniqueRequestId,
261 router, route, sessionHints);
262 }
263 } finally {
264 Binder.restoreCallingIdentity(token);
265 }
266 }
267
Hyundo Moon56337492020-02-16 16:19:54 +0900268 public void selectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
Hyundo Moon0a926572019-12-28 15:01:21 +0900269 MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +0900270 Objects.requireNonNull(router, "router must not be null");
Hyundo Moon0a926572019-12-28 15:01:21 +0900271 Objects.requireNonNull(route, "route must not be null");
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900272 if (TextUtils.isEmpty(uniqueSessionId)) {
273 throw new IllegalArgumentException("uniqueSessionId must not be empty");
274 }
Hyundo Moon0a926572019-12-28 15:01:21 +0900275
276 final long token = Binder.clearCallingIdentity();
277 try {
278 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900279 selectRouteWithRouter2Locked(router, uniqueSessionId, route);
Hyundo Moon0a926572019-12-28 15:01:21 +0900280 }
281 } finally {
282 Binder.restoreCallingIdentity(token);
283 }
284 }
285
Hyundo Moon56337492020-02-16 16:19:54 +0900286 public void deselectRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
Hyundo Moon0a926572019-12-28 15:01:21 +0900287 MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +0900288 Objects.requireNonNull(router, "router must not be null");
Hyundo Moon0a926572019-12-28 15:01:21 +0900289 Objects.requireNonNull(route, "route must not be null");
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900290 if (TextUtils.isEmpty(uniqueSessionId)) {
291 throw new IllegalArgumentException("uniqueSessionId must not be empty");
292 }
Hyundo Moon0a926572019-12-28 15:01:21 +0900293
294 final long token = Binder.clearCallingIdentity();
295 try {
296 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900297 deselectRouteWithRouter2Locked(router, uniqueSessionId, route);
Hyundo Moon0a926572019-12-28 15:01:21 +0900298 }
299 } finally {
300 Binder.restoreCallingIdentity(token);
301 }
302 }
303
Hyundo Moon56337492020-02-16 16:19:54 +0900304 public void transferToRouteWithRouter2(IMediaRouter2 router, String uniqueSessionId,
Hyundo Moon0a926572019-12-28 15:01:21 +0900305 MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +0900306 Objects.requireNonNull(router, "router must not be null");
Hyundo Moon0a926572019-12-28 15:01:21 +0900307 Objects.requireNonNull(route, "route must not be null");
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900308 if (TextUtils.isEmpty(uniqueSessionId)) {
309 throw new IllegalArgumentException("uniqueSessionId must not be empty");
310 }
Hyundo Moon0a926572019-12-28 15:01:21 +0900311
312 final long token = Binder.clearCallingIdentity();
313 try {
314 synchronized (mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +0900315 transferToRouteWithRouter2Locked(router, uniqueSessionId, route);
Hyundo Moon0a926572019-12-28 15:01:21 +0900316 }
317 } finally {
318 Binder.restoreCallingIdentity(token);
319 }
320 }
321
Hyundo Moone962ed42020-02-16 19:47:41 +0900322 public void setSessionVolumeWithRouter2(IMediaRouter2 router, String uniqueSessionId,
323 int volume) {
324 Objects.requireNonNull(router, "router must not be null");
325 Objects.requireNonNull(uniqueSessionId, "uniqueSessionId must not be null");
326
327 final long token = Binder.clearCallingIdentity();
328 try {
329 synchronized (mLock) {
330 setSessionVolumeWithRouter2Locked(router, uniqueSessionId, volume);
331 }
332 } finally {
333 Binder.restoreCallingIdentity(token);
334 }
335 }
336
Hyundo Moon56337492020-02-16 16:19:54 +0900337 public void releaseSessionWithRouter2(IMediaRouter2 router, String uniqueSessionId) {
338 Objects.requireNonNull(router, "router must not be null");
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900339 if (TextUtils.isEmpty(uniqueSessionId)) {
340 throw new IllegalArgumentException("uniqueSessionId must not be empty");
341 }
Hyundo Moonca9db782020-01-01 18:31:15 +0900342
343 final long token = Binder.clearCallingIdentity();
344 try {
345 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900346 releaseSessionWithRouter2Locked(router, uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +0900347 }
348 } finally {
349 Binder.restoreCallingIdentity(token);
350 }
351 }
352
Hyundo Moone962ed42020-02-16 19:47:41 +0900353 ////////////////////////////////////////////////////////////////
354 //// Calls from MediaRouter2Manager
355 //// - Should not have @NonNull/@Nullable on any arguments
356 ////////////////////////////////////////////////////////////////
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900357
Hyundo Moone962ed42020-02-16 19:47:41 +0900358 @NonNull
359 public List<RoutingSessionInfo> getActiveSessions(IMediaRouter2Manager manager) {
360 Objects.requireNonNull(manager, "manager must not be null");
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900361 final long token = Binder.clearCallingIdentity();
362 try {
363 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900364 return getActiveSessionsLocked(manager);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900365 }
366 } finally {
367 Binder.restoreCallingIdentity(token);
368 }
369 }
370
Hyundo Moone962ed42020-02-16 19:47:41 +0900371 public void registerManager(IMediaRouter2Manager manager, String packageName) {
372 Objects.requireNonNull(manager, "manager must not be null");
373 if (TextUtils.isEmpty(packageName)) {
374 throw new IllegalArgumentException("packageName must not be empty");
375 }
376
Hyundo Moone962ed42020-02-16 19:47:41 +0900377 final int uid = Binder.getCallingUid();
378 final int pid = Binder.getCallingPid();
379 final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900380
381 final long token = Binder.clearCallingIdentity();
382 try {
383 synchronized (mLock) {
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900384 registerManagerLocked(manager, uid, pid, packageName, userId);
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900385 }
386 } finally {
387 Binder.restoreCallingIdentity(token);
388 }
389 }
390
Hyundo Moone962ed42020-02-16 19:47:41 +0900391 public void unregisterManager(IMediaRouter2Manager manager) {
392 Objects.requireNonNull(manager, "manager must not be null");
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900393
394 final long token = Binder.clearCallingIdentity();
395 try {
396 synchronized (mLock) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900397 unregisterManagerLocked(manager, false);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900398 }
399 } finally {
400 Binder.restoreCallingIdentity(token);
401 }
402 }
403
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900404 public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
405 MediaRoute2Info route, int volume) {
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900406 Objects.requireNonNull(manager, "manager must not be null");
407 Objects.requireNonNull(route, "route must not be null");
408
409 final long token = Binder.clearCallingIdentity();
410 try {
411 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900412 setRouteVolumeWithManagerLocked(requestId, manager, route, volume);
Hyundo Moone962ed42020-02-16 19:47:41 +0900413 }
414 } finally {
415 Binder.restoreCallingIdentity(token);
416 }
417 }
418
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900419 public void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
420 String packageName, MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900421 Objects.requireNonNull(manager, "manager must not be null");
422 if (TextUtils.isEmpty(packageName)) {
423 throw new IllegalArgumentException("packageName must not be empty");
424 }
425
426 final long token = Binder.clearCallingIdentity();
427 try {
428 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900429 requestCreateSessionWithManagerLocked(requestId, manager, packageName, route);
Hyundo Moone962ed42020-02-16 19:47:41 +0900430 }
431 } finally {
432 Binder.restoreCallingIdentity(token);
433 }
434 }
435
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900436 public void selectRouteWithManager(IMediaRouter2Manager manager, int requestId,
437 String uniqueSessionId, MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900438 Objects.requireNonNull(manager, "manager must not be null");
439 if (TextUtils.isEmpty(uniqueSessionId)) {
440 throw new IllegalArgumentException("uniqueSessionId must not be empty");
441 }
442 Objects.requireNonNull(route, "route must not be null");
443
444 final long token = Binder.clearCallingIdentity();
445 try {
446 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900447 selectRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
Hyundo Moone962ed42020-02-16 19:47:41 +0900448 }
449 } finally {
450 Binder.restoreCallingIdentity(token);
451 }
452 }
453
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900454 public void deselectRouteWithManager(IMediaRouter2Manager manager, int requestId,
455 String uniqueSessionId, MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900456 Objects.requireNonNull(manager, "manager must not be null");
457 if (TextUtils.isEmpty(uniqueSessionId)) {
458 throw new IllegalArgumentException("uniqueSessionId must not be empty");
459 }
460 Objects.requireNonNull(route, "route must not be null");
461
462 final long token = Binder.clearCallingIdentity();
463 try {
464 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900465 deselectRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
Hyundo Moone962ed42020-02-16 19:47:41 +0900466 }
467 } finally {
468 Binder.restoreCallingIdentity(token);
469 }
470 }
471
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900472 public void transferToRouteWithManager(IMediaRouter2Manager manager, int requestId,
473 String uniqueSessionId, MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900474 Objects.requireNonNull(manager, "manager must not be null");
475 if (TextUtils.isEmpty(uniqueSessionId)) {
476 throw new IllegalArgumentException("uniqueSessionId must not be empty");
477 }
478 Objects.requireNonNull(route, "route must not be null");
479
480 final long token = Binder.clearCallingIdentity();
481 try {
482 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900483 transferToRouteWithManagerLocked(requestId, manager, uniqueSessionId, route);
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900484 }
485 } finally {
486 Binder.restoreCallingIdentity(token);
487 }
488 }
489
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900490 public void setSessionVolumeWithManager(IMediaRouter2Manager manager, int requestId,
491 String uniqueSessionId, int volume) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900492 Objects.requireNonNull(manager, "manager must not be null");
Hyundo Moone962ed42020-02-16 19:47:41 +0900493 if (TextUtils.isEmpty(uniqueSessionId)) {
494 throw new IllegalArgumentException("uniqueSessionId must not be empty");
495 }
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900496
497 final long token = Binder.clearCallingIdentity();
498 try {
499 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900500 setSessionVolumeWithManagerLocked(requestId, manager, uniqueSessionId, volume);
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900501 }
502 } finally {
503 Binder.restoreCallingIdentity(token);
504 }
505 }
506
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900507 public void releaseSessionWithManager(IMediaRouter2Manager manager, int requestId,
508 String uniqueSessionId) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900509 Objects.requireNonNull(manager, "manager must not be null");
510 if (TextUtils.isEmpty(uniqueSessionId)) {
511 throw new IllegalArgumentException("uniqueSessionId must not be empty");
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900512 }
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900513
Kyunglyul Hyunc6583832020-01-17 11:11:46 +0000514 final long token = Binder.clearCallingIdentity();
515 try {
516 synchronized (mLock) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900517 releaseSessionWithManagerLocked(requestId, manager, uniqueSessionId);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +0000518 }
519 } finally {
520 Binder.restoreCallingIdentity(token);
521 }
522 }
523
Kyunglyul Hyunef7e88f2020-04-01 22:15:08 +0900524 //TODO(b/136703681): Review this is handling multi-user properly.
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +0900525 void switchUser() {
526 synchronized (mLock) {
527 int userId = ActivityManager.getCurrentUser();
528 if (mCurrentUserId != userId) {
529 final int oldUserId = mCurrentUserId;
530 mCurrentUserId = userId; // do this first
531
532 UserRecord oldUser = mUserRecords.get(oldUserId);
533 if (oldUser != null) {
Kyunglyul Hyun30e2c652019-07-11 16:25:31 +0900534 oldUser.mHandler.sendMessage(
535 obtainMessage(UserHandler::stop, oldUser.mHandler));
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +0900536 disposeUserIfNeededLocked(oldUser); // since no longer current user
537 }
538
539 UserRecord newUser = mUserRecords.get(userId);
540 if (newUser != null) {
Kyunglyul Hyun30e2c652019-07-11 16:25:31 +0900541 newUser.mHandler.sendMessage(
542 obtainMessage(UserHandler::start, newUser.mHandler));
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +0900543 }
544 }
545 }
546 }
547
Hyundo Moone962ed42020-02-16 19:47:41 +0900548 void routerDied(@NonNull RouterRecord routerRecord) {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900549 synchronized (mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +0900550 unregisterRouter2Locked(routerRecord.mRouter, true);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900551 }
552 }
553
Hyundo Moone962ed42020-02-16 19:47:41 +0900554 void managerDied(@NonNull ManagerRecord managerRecord) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900555 synchronized (mLock) {
556 unregisterManagerLocked(managerRecord.mManager, true);
557 }
558 }
559
Hyundo Moone962ed42020-02-16 19:47:41 +0900560 ////////////////////////////////////////////////////////////////
561 //// ***Locked methods related to MediaRouter2
562 //// - Should have @NonNull/@Nullable on all arguments
563 ////////////////////////////////////////////////////////////////
564
565 private void registerRouter2Locked(@NonNull IMediaRouter2 router, int uid, int pid,
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900566 @NonNull String packageName, int userId, boolean hasConfigureWifiDisplayPermission,
567 boolean hasModifyAudioRoutingPermission) {
Hyundo Moon56337492020-02-16 16:19:54 +0900568 final IBinder binder = router.asBinder();
Hyundo Moone962ed42020-02-16 19:47:41 +0900569 if (mAllRouterRecords.get(binder) != null) {
570 Slog.w(TAG, "Same router already exists. packageName=" + packageName);
571 return;
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900572 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900573
574 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900575 RouterRecord routerRecord = new RouterRecord(userRecord, router, uid, pid, packageName,
576 hasConfigureWifiDisplayPermission, hasModifyAudioRoutingPermission);
Hyundo Moone962ed42020-02-16 19:47:41 +0900577 try {
578 binder.linkToDeath(routerRecord, 0);
579 } catch (RemoteException ex) {
580 throw new RuntimeException("MediaRouter2 died prematurely.", ex);
581 }
582
583 userRecord.mRouterRecords.add(routerRecord);
584 mAllRouterRecords.put(binder, routerRecord);
585
586 userRecord.mHandler.sendMessage(
587 obtainMessage(UserHandler::notifyRoutesToRouter, userRecord.mHandler, router));
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900588 }
589
Hyundo Moone962ed42020-02-16 19:47:41 +0900590 private void unregisterRouter2Locked(@NonNull IMediaRouter2 router, boolean died) {
Hyundo Moon56337492020-02-16 16:19:54 +0900591 RouterRecord routerRecord = mAllRouterRecords.remove(router.asBinder());
Hyundo Moone962ed42020-02-16 19:47:41 +0900592 if (routerRecord == null) {
593 Slog.w(TAG, "Ignoring unregistering unknown router2");
594 return;
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900595 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900596
597 UserRecord userRecord = routerRecord.mUserRecord;
598 userRecord.mRouterRecords.remove(routerRecord);
Kyunglyul Hyunef7e88f2020-04-01 22:15:08 +0900599 userRecord.mHandler.sendMessage(
600 obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
601 userRecord.mHandler));
Hyundo Moone962ed42020-02-16 19:47:41 +0900602 routerRecord.dispose();
603 disposeUserIfNeededLocked(userRecord); // since router removed from user
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900604 }
605
Hyundo Moone962ed42020-02-16 19:47:41 +0900606 private void setDiscoveryRequestWithRouter2Locked(@NonNull RouterRecord routerRecord,
607 @NonNull RouteDiscoveryPreference discoveryRequest) {
608 if (routerRecord.mDiscoveryPreference.equals(discoveryRequest)) {
609 return;
Kyunglyul Hyunc7847242019-12-30 17:46:04 +0900610 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900611 routerRecord.mDiscoveryPreference = discoveryRequest;
612 routerRecord.mUserRecord.mHandler.sendMessage(
613 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
614 routerRecord.mUserRecord.mHandler, routerRecord));
615 routerRecord.mUserRecord.mHandler.sendMessage(
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900616 obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
Hyundo Moone962ed42020-02-16 19:47:41 +0900617 routerRecord.mUserRecord.mHandler));
Hyundo Moon63a05402019-12-19 20:13:56 +0900618 }
619
Hyundo Moone962ed42020-02-16 19:47:41 +0900620 private void setRouteVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
621 @NonNull MediaRoute2Info route, int volume) {
Hyundo Moon56337492020-02-16 16:19:54 +0900622 final IBinder binder = router.asBinder();
623 RouterRecord routerRecord = mAllRouterRecords.get(binder);
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900624
Hyundo Moon56337492020-02-16 16:19:54 +0900625 if (routerRecord != null) {
626 routerRecord.mUserRecord.mHandler.sendMessage(
Hyundo Moone962ed42020-02-16 19:47:41 +0900627 obtainMessage(UserHandler::setRouteVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900628 routerRecord.mUserRecord.mHandler,
629 DUMMY_REQUEST_ID, route, volume));
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900630 }
631 }
632
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900633 private void requestCreateSessionWithRouter2Locked(int requestId, @NonNull IMediaRouter2 router,
634 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900635 final IBinder binder = router.asBinder();
636 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
637
638 if (routerRecord == null) {
639 return;
640 }
641
Hyundo Moonfa3d0ef2020-04-13 00:27:44 +0900642 if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
643 && !TextUtils.equals(route.getId(),
644 routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId())) {
645 Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
646 + route);
647 routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
648 routerRecord, requestId);
649 return;
650 }
651
Hyundo Moone962ed42020-02-16 19:47:41 +0900652 long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
653 routerRecord.mUserRecord.mHandler.sendMessage(
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900654 obtainMessage(UserHandler::requestCreateSessionWithRouter2OnHandler,
Hyundo Moone962ed42020-02-16 19:47:41 +0900655 routerRecord.mUserRecord.mHandler,
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900656 uniqueRequestId, routerRecord, route,
Hyundo Moon7c2059c2020-02-27 19:01:52 +0900657 sessionHints));
Hyundo Moone962ed42020-02-16 19:47:41 +0900658 }
659
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900660 private void notifySessionHintsForCreatingSessionLocked(long uniqueRequestId,
661 @NonNull IMediaRouter2 router,
662 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
663 final IBinder binder = router.asBinder();
664 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
665
666 if (routerRecord == null) {
667 Slog.w(TAG, "requestCreateSessionWithRouter2ByManagerRequestLocked: "
668 + "Ignoring unknown router.");
669 return;
670 }
671
672 routerRecord.mUserRecord.mHandler.sendMessage(
673 obtainMessage(UserHandler::requestCreateSessionWithManagerOnHandler,
674 routerRecord.mUserRecord.mHandler,
675 uniqueRequestId, routerRecord, route, sessionHints));
676 }
677
Hyundo Moone962ed42020-02-16 19:47:41 +0900678 private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
679 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
680 final IBinder binder = router.asBinder();
681 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
682
683 if (routerRecord == null) {
684 return;
685 }
686
687 routerRecord.mUserRecord.mHandler.sendMessage(
688 obtainMessage(UserHandler::selectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900689 routerRecord.mUserRecord.mHandler,
690 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900691 }
692
693 private void deselectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
694 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
695 final IBinder binder = router.asBinder();
696 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
697
698 if (routerRecord == null) {
699 return;
700 }
701
702 routerRecord.mUserRecord.mHandler.sendMessage(
703 obtainMessage(UserHandler::deselectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900704 routerRecord.mUserRecord.mHandler,
705 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900706 }
707
708 private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
709 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
710 final IBinder binder = router.asBinder();
711 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
712
713 if (routerRecord == null) {
714 return;
715 }
716
Sungsoo Limc27785a2020-03-27 16:57:47 +0900717 String defaultRouteId =
718 routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId();
719 if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
720 && !TextUtils.equals(route.getId(), defaultRouteId)) {
721 routerRecord.mUserRecord.mHandler.sendMessage(
722 obtainMessage(UserHandler::notifySessionCreationFailedToRouter,
723 routerRecord.mUserRecord.mHandler,
724 routerRecord, toOriginalRequestId(DUMMY_REQUEST_ID)));
725 } else {
726 routerRecord.mUserRecord.mHandler.sendMessage(
727 obtainMessage(UserHandler::transferToRouteOnHandler,
728 routerRecord.mUserRecord.mHandler,
729 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
730 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900731 }
732
733 private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
734 @NonNull String uniqueSessionId, int volume) {
Hyundo Moon56337492020-02-16 16:19:54 +0900735 final IBinder binder = router.asBinder();
736 RouterRecord routerRecord = mAllRouterRecords.get(binder);
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900737
Hyundo Moone962ed42020-02-16 19:47:41 +0900738 if (routerRecord == null) {
739 return;
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900740 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900741
742 routerRecord.mUserRecord.mHandler.sendMessage(
743 obtainMessage(UserHandler::setSessionVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900744 routerRecord.mUserRecord.mHandler,
745 DUMMY_REQUEST_ID, uniqueSessionId, volume));
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900746 }
747
Hyundo Moone962ed42020-02-16 19:47:41 +0900748 private void releaseSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
749 @NonNull String uniqueSessionId) {
750 final IBinder binder = router.asBinder();
751 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900752
Hyundo Moone962ed42020-02-16 19:47:41 +0900753 if (routerRecord == null) {
754 return;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900755 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900756
757 routerRecord.mUserRecord.mHandler.sendMessage(
758 obtainMessage(UserHandler::releaseSessionOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900759 routerRecord.mUserRecord.mHandler,
760 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId));
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900761 }
762
Hyundo Moone962ed42020-02-16 19:47:41 +0900763 ////////////////////////////////////////////////////////////
764 //// ***Locked methods related to MediaRouter2Manager
765 //// - Should have @NonNull/@Nullable on all arguments
766 ////////////////////////////////////////////////////////////
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900767
Hyundo Moone962ed42020-02-16 19:47:41 +0900768 private List<RoutingSessionInfo> getActiveSessionsLocked(
769 @NonNull IMediaRouter2Manager manager) {
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900770 final IBinder binder = manager.asBinder();
771 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
772
773 if (managerRecord == null) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +0000774 Slog.w(TAG, "getActiveSessionLocked: Ignoring unknown manager");
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900775 return Collections.emptyList();
776 }
777
Hyundo Moonf829e6f2020-01-11 19:31:35 +0900778 List<RoutingSessionInfo> sessionInfos = new ArrayList<>();
Sungsoo Limddf140d2020-03-25 08:53:55 +0900779 for (MediaRoute2Provider provider : managerRecord.mUserRecord.mHandler.mRouteProviders) {
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900780 sessionInfos.addAll(provider.getSessionInfos());
781 }
782 return sessionInfos;
783 }
784
Hyundo Moone962ed42020-02-16 19:47:41 +0900785 private void registerManagerLocked(@NonNull IMediaRouter2Manager manager,
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900786 int uid, int pid, @NonNull String packageName, int userId) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900787 final IBinder binder = manager.asBinder();
788 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
789
790 if (managerRecord != null) {
791 Slog.w(TAG, "Same manager already exists. packageName=" + packageName);
792 return;
793 }
794
795 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900796 managerRecord = new ManagerRecord(userRecord, manager, uid, pid, packageName);
Hyundo Moone962ed42020-02-16 19:47:41 +0900797 try {
798 binder.linkToDeath(managerRecord, 0);
799 } catch (RemoteException ex) {
800 throw new RuntimeException("Media router manager died prematurely.", ex);
801 }
802
803 userRecord.mManagerRecords.add(managerRecord);
804 mAllManagerRecords.put(binder, managerRecord);
805
806 userRecord.mHandler.sendMessage(obtainMessage(UserHandler::notifyRoutesToManager,
807 userRecord.mHandler, manager));
808
809 for (RouterRecord routerRecord : userRecord.mRouterRecords) {
810 // TODO: Do not use notifyPreferredFeaturesChangedToManagers since it updates all
811 // managers. Instead, Notify only to the manager that is currently being registered.
812
813 // TODO: UserRecord <-> routerRecord, why do they reference each other?
814 // How about removing mUserRecord from routerRecord?
815 routerRecord.mUserRecord.mHandler.sendMessage(
816 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
817 routerRecord.mUserRecord.mHandler, routerRecord));
818 }
819 }
820
821 private void unregisterManagerLocked(@NonNull IMediaRouter2Manager manager, boolean died) {
822 ManagerRecord managerRecord = mAllManagerRecords.remove(manager.asBinder());
823 if (managerRecord == null) {
824 return;
825 }
826 UserRecord userRecord = managerRecord.mUserRecord;
827 userRecord.mManagerRecords.remove(managerRecord);
828 managerRecord.dispose();
829 disposeUserIfNeededLocked(userRecord); // since manager removed from user
830 }
831
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900832 private void setRouteVolumeWithManagerLocked(int requestId,
833 @NonNull IMediaRouter2Manager manager,
834 @NonNull MediaRoute2Info route, int volume) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900835 final IBinder binder = manager.asBinder();
836 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
837
838 if (managerRecord == null) {
839 return;
840 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900841
842 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900843 managerRecord.mUserRecord.mHandler.sendMessage(
844 obtainMessage(UserHandler::setRouteVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900845 managerRecord.mUserRecord.mHandler,
846 uniqueRequestId, route, volume));
Hyundo Moone962ed42020-02-16 19:47:41 +0900847 }
848
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900849 private void requestCreateSessionWithManagerLocked(int requestId,
850 @NonNull IMediaRouter2Manager manager,
851 @NonNull String packageName, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900852 ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900853 if (managerRecord == null) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900854 return;
855 }
856
857 RouterRecord routerRecord = managerRecord.mUserRecord.findRouterRecordLocked(packageName);
858 if (routerRecord == null) {
859 Slog.w(TAG, "Ignoring session creation for unknown router.");
860 return;
861 }
862
863 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900864
865 // Before requesting to the provider, get session hints from the media router.
866 // As a return, media router will request to create a session.
Hyundo Moone962ed42020-02-16 19:47:41 +0900867 routerRecord.mUserRecord.mHandler.sendMessage(
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900868 obtainMessage(UserHandler::getSessionHintsForCreatingSessionOnHandler,
Hyundo Moone962ed42020-02-16 19:47:41 +0900869 routerRecord.mUserRecord.mHandler,
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900870 uniqueRequestId, routerRecord, managerRecord, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900871 }
872
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900873 private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
874 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900875 final IBinder binder = manager.asBinder();
876 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
877
878 if (managerRecord == null) {
879 return;
880 }
881
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +0900882 // Can be null if the session is system's or RCN.
Hyundo Moone962ed42020-02-16 19:47:41 +0900883 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
884 .findRouterforSessionLocked(uniqueSessionId);
885
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900886 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900887 managerRecord.mUserRecord.mHandler.sendMessage(
888 obtainMessage(UserHandler::selectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900889 managerRecord.mUserRecord.mHandler,
890 uniqueRequestId, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900891 }
892
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900893 private void deselectRouteWithManagerLocked(int requestId,
894 @NonNull IMediaRouter2Manager manager,
895 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900896 final IBinder binder = manager.asBinder();
897 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
898
899 if (managerRecord == null) {
900 return;
901 }
902
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +0900903 // Can be null if the session is system's or RCN.
Hyundo Moone962ed42020-02-16 19:47:41 +0900904 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
905 .findRouterforSessionLocked(uniqueSessionId);
906
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900907 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900908 managerRecord.mUserRecord.mHandler.sendMessage(
909 obtainMessage(UserHandler::deselectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900910 managerRecord.mUserRecord.mHandler,
911 uniqueRequestId, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900912 }
913
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900914 private void transferToRouteWithManagerLocked(int requestId,
915 @NonNull IMediaRouter2Manager manager,
916 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900917 final IBinder binder = manager.asBinder();
918 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
919
920 if (managerRecord == null) {
921 return;
922 }
923
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +0900924 // Can be null if the session is system's or RCN.
Hyundo Moone962ed42020-02-16 19:47:41 +0900925 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
926 .findRouterforSessionLocked(uniqueSessionId);
927
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900928 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900929 managerRecord.mUserRecord.mHandler.sendMessage(
930 obtainMessage(UserHandler::transferToRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900931 managerRecord.mUserRecord.mHandler,
932 uniqueRequestId, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900933 }
934
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900935 private void setSessionVolumeWithManagerLocked(int requestId,
936 @NonNull IMediaRouter2Manager manager,
937 @NonNull String uniqueSessionId, int volume) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900938 final IBinder binder = manager.asBinder();
939 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
940
941 if (managerRecord == null) {
942 return;
943 }
944
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900945 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900946 managerRecord.mUserRecord.mHandler.sendMessage(
947 obtainMessage(UserHandler::setSessionVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900948 managerRecord.mUserRecord.mHandler,
949 uniqueRequestId, uniqueSessionId, volume));
Hyundo Moone962ed42020-02-16 19:47:41 +0900950 }
951
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900952 private void releaseSessionWithManagerLocked(int requestId,
953 @NonNull IMediaRouter2Manager manager,
954 @NonNull String uniqueSessionId) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900955 final IBinder binder = manager.asBinder();
956 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
957
958 if (managerRecord == null) {
959 return;
960 }
961
962 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
963 .findRouterforSessionLocked(uniqueSessionId);
964
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900965 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900966 managerRecord.mUserRecord.mHandler.sendMessage(
967 obtainMessage(UserHandler::releaseSessionOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900968 managerRecord.mUserRecord.mHandler,
969 uniqueRequestId, routerRecord, uniqueSessionId));
Hyundo Moone962ed42020-02-16 19:47:41 +0900970 }
971
972 ////////////////////////////////////////////////////////////
973 //// ***Locked methods used by both router2 and manager
974 //// - Should have @NonNull/@Nullable on all arguments
975 ////////////////////////////////////////////////////////////
976
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900977 private UserRecord getOrCreateUserRecordLocked(int userId) {
978 UserRecord userRecord = mUserRecords.get(userId);
979 if (userRecord == null) {
980 userRecord = new UserRecord(userId);
981 mUserRecords.put(userId, userRecord);
982 if (userId == mCurrentUserId) {
983 userRecord.mHandler.sendMessage(
984 obtainMessage(UserHandler::start, userRecord.mHandler));
985 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900986 }
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900987 return userRecord;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900988 }
989
Hyundo Moone962ed42020-02-16 19:47:41 +0900990 private void disposeUserIfNeededLocked(@NonNull UserRecord userRecord) {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900991 // If there are no records left and the user is no longer current then go ahead
992 // and purge the user record and all of its associated state. If the user is current
993 // then leave it alone since we might be connected to a route or want to query
994 // the same route information again soon.
995 if (userRecord.mUserId != mCurrentUserId
Hyundo Moon56337492020-02-16 16:19:54 +0900996 && userRecord.mRouterRecords.isEmpty()
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900997 && userRecord.mManagerRecords.isEmpty()) {
998 if (DEBUG) {
999 Slog.d(TAG, userRecord + ": Disposed");
1000 }
1001 mUserRecords.remove(userRecord.mUserId);
1002 // Note: User already stopped (by switchUser) so no need to send stop message here.
1003 }
1004 }
1005
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001006 static long toUniqueRequestId(int requesterId, int originalRequestId) {
1007 return ((long) requesterId << 32) | originalRequestId;
Kyunglyul Hyunc7847242019-12-30 17:46:04 +09001008 }
1009
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001010 static int toRequesterId(long uniqueRequestId) {
Kyunglyul Hyunc7847242019-12-30 17:46:04 +09001011 return (int) (uniqueRequestId >> 32);
1012 }
1013
Hyundo Moon56337492020-02-16 16:19:54 +09001014 static int toOriginalRequestId(long uniqueRequestId) {
Kyunglyul Hyunc7847242019-12-30 17:46:04 +09001015 return (int) uniqueRequestId;
1016 }
1017
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001018 final class UserRecord {
1019 public final int mUserId;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001020 //TODO: make records private for thread-safety
Hyundo Moon56337492020-02-16 16:19:54 +09001021 final ArrayList<RouterRecord> mRouterRecords = new ArrayList<>();
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001022 final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09001023 RouteDiscoveryPreference mCompositeDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001024 final UserHandler mHandler;
1025
1026 UserRecord(int userId) {
1027 mUserId = userId;
1028 mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
1029 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001030
Hyundo Moon56337492020-02-16 16:19:54 +09001031 // TODO: This assumes that only one router exists in a package. Is it true?
1032 RouterRecord findRouterRecordLocked(String packageName) {
1033 for (RouterRecord routerRecord : mRouterRecords) {
1034 if (TextUtils.equals(routerRecord.mPackageName, packageName)) {
1035 return routerRecord;
Kyunglyul Hyuna0d47412019-07-01 11:14:24 +09001036 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001037 }
1038 return null;
1039 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001040 }
1041
Hyundo Moon56337492020-02-16 16:19:54 +09001042 final class RouterRecord implements IBinder.DeathRecipient {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001043 public final UserRecord mUserRecord;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001044 public final String mPackageName;
Hyundo Moon4140fee2019-11-08 14:47:50 +09001045 public final List<Integer> mSelectRouteSequenceNumbers;
Hyundo Moon56337492020-02-16 16:19:54 +09001046 public final IMediaRouter2 mRouter;
Kyunglyul Hyun86576712019-11-21 18:31:46 +09001047 public final int mUid;
1048 public final int mPid;
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001049 public final boolean mHasConfigureWifiDisplayPermission;
1050 public final boolean mHasModifyAudioRoutingPermission;
Hyundo Moon56337492020-02-16 16:19:54 +09001051 public final int mRouterId;
Kyunglyul Hyunf7d5e042019-11-11 13:56:28 +09001052
Kyunglyul Hyun616096e2020-01-09 16:15:03 +09001053 public RouteDiscoveryPreference mDiscoveryPreference;
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001054 public MediaRoute2Info mSelectedRoute;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001055
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001056 RouterRecord(UserRecord userRecord, IMediaRouter2 router, int uid, int pid,
1057 String packageName, boolean hasConfigureWifiDisplayPermission,
1058 boolean hasModifyAudioRoutingPermission) {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001059 mUserRecord = userRecord;
Kyunglyul Hyun2f43fd62019-09-16 18:47:52 +09001060 mPackageName = packageName;
Hyundo Moon4140fee2019-11-08 14:47:50 +09001061 mSelectRouteSequenceNumbers = new ArrayList<>();
Kyunglyul Hyun616096e2020-01-09 16:15:03 +09001062 mDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
Hyundo Moon56337492020-02-16 16:19:54 +09001063 mRouter = router;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001064 mUid = uid;
1065 mPid = pid;
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001066 mHasConfigureWifiDisplayPermission = hasConfigureWifiDisplayPermission;
1067 mHasModifyAudioRoutingPermission = hasModifyAudioRoutingPermission;
Hyundo Moon56337492020-02-16 16:19:54 +09001068 mRouterId = mNextRouterOrManagerId.getAndIncrement();
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001069 }
1070
1071 public void dispose() {
Hyundo Moon56337492020-02-16 16:19:54 +09001072 mRouter.asBinder().unlinkToDeath(this, 0);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001073 }
1074
1075 @Override
1076 public void binderDied() {
Hyundo Moon56337492020-02-16 16:19:54 +09001077 routerDied(this);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001078 }
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001079 }
1080
1081 final class ManagerRecord implements IBinder.DeathRecipient {
1082 public final UserRecord mUserRecord;
1083 public final IMediaRouter2Manager mManager;
1084 public final int mUid;
1085 public final int mPid;
1086 public final String mPackageName;
Hyundo Moon56337492020-02-16 16:19:54 +09001087 public final int mManagerId;
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001088
1089 ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager,
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001090 int uid, int pid, String packageName) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001091 mUserRecord = userRecord;
1092 mManager = manager;
1093 mUid = uid;
1094 mPid = pid;
1095 mPackageName = packageName;
Hyundo Moon56337492020-02-16 16:19:54 +09001096 mManagerId = mNextRouterOrManagerId.getAndIncrement();
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001097 }
1098
1099 public void dispose() {
1100 mManager.asBinder().unlinkToDeath(this, 0);
1101 }
1102
1103 @Override
1104 public void binderDied() {
1105 managerDied(this);
1106 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001107
1108 public void dump(PrintWriter pw, String prefix) {
1109 pw.println(prefix + this);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001110 }
1111
1112 @Override
1113 public String toString() {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001114 return "Manager " + mPackageName + " (pid " + mPid + ")";
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001115 }
1116 }
1117
1118 static final class UserHandler extends Handler implements
1119 MediaRoute2ProviderWatcher.Callback,
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001120 MediaRoute2Provider.Callback {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001121
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001122 private final WeakReference<MediaRouter2ServiceImpl> mServiceRef;
1123 private final UserRecord mUserRecord;
1124 private final MediaRoute2ProviderWatcher mWatcher;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001125
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001126 //TODO: Make this thread-safe.
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001127 private final SystemMediaRoute2Provider mSystemProvider;
Sungsoo Limddf140d2020-03-25 08:53:55 +09001128 private final ArrayList<MediaRoute2Provider> mRouteProviders =
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001129 new ArrayList<>();
Hyundo Moon63a05402019-12-19 20:13:56 +09001130
1131 private final List<MediaRoute2ProviderInfo> mLastProviderInfos = new ArrayList<>();
1132 private final CopyOnWriteArrayList<SessionCreationRequest> mSessionCreationRequests =
1133 new CopyOnWriteArrayList<>();
Hyundo Moon56337492020-02-16 16:19:54 +09001134 private final Map<String, RouterRecord> mSessionToRouterMap = new ArrayMap<>();
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001135
1136 private boolean mRunning;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001137
Hyundo Moone962ed42020-02-16 19:47:41 +09001138 UserHandler(@NonNull MediaRouter2ServiceImpl service, @NonNull UserRecord userRecord) {
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +09001139 super(Looper.getMainLooper(), null, true);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001140 mServiceRef = new WeakReference<>(service);
1141 mUserRecord = userRecord;
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001142 mSystemProvider = new SystemMediaRoute2Provider(service.mContext, this);
Sungsoo Limddf140d2020-03-25 08:53:55 +09001143 mRouteProviders.add(mSystemProvider);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001144 mWatcher = new MediaRoute2ProviderWatcher(service.mContext, this,
1145 this, mUserRecord.mUserId);
1146 }
1147
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001148 private void start() {
1149 if (!mRunning) {
1150 mRunning = true;
1151 mWatcher.start();
1152 }
1153 }
1154
1155 private void stop() {
1156 if (mRunning) {
1157 mRunning = false;
1158 //TODO: may unselect routes
1159 mWatcher.stop(); // also stops all providers
1160 }
1161 }
1162
1163 @Override
Hyundo Moone962ed42020-02-16 19:47:41 +09001164 public void onAddProviderService(@NonNull MediaRoute2ProviderServiceProxy proxy) {
Hyundo Moon56337492020-02-16 16:19:54 +09001165 proxy.setCallback(this);
Sungsoo Limddf140d2020-03-25 08:53:55 +09001166 mRouteProviders.add(proxy);
Hyundo Moon56337492020-02-16 16:19:54 +09001167 proxy.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001168 }
1169
1170 @Override
Hyundo Moone962ed42020-02-16 19:47:41 +09001171 public void onRemoveProviderService(@NonNull MediaRoute2ProviderServiceProxy proxy) {
Sungsoo Limddf140d2020-03-25 08:53:55 +09001172 mRouteProviders.remove(proxy);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001173 }
1174
1175 @Override
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001176 public void onProviderStateChanged(@NonNull MediaRoute2Provider provider) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001177 sendMessage(PooledLambda.obtainMessage(UserHandler::onProviderStateChangedOnHandler,
1178 this, provider));
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001179 }
1180
Kyunglyul Hyunf7d5e042019-11-11 13:56:28 +09001181 @Override
Hyundo Moon63a05402019-12-19 20:13:56 +09001182 public void onSessionCreated(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001183 long uniqueRequestId, @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001184 sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreatedOnHandler,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001185 this, provider, uniqueRequestId, sessionInfo));
Hyundo Moon63a05402019-12-19 20:13:56 +09001186 }
1187
Hyundo Moon6e30f1b2020-01-13 19:50:27 +09001188 @Override
1189 public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
Hyundo Moonf829e6f2020-01-11 19:31:35 +09001190 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001191 sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionInfoChangedOnHandler,
1192 this, provider, sessionInfo));
1193 }
1194
1195 @Override
Hyundo Moone962ed42020-02-16 19:47:41 +09001196 public void onSessionReleased(@NonNull MediaRoute2Provider provider,
1197 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001198 sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionReleasedOnHandler,
Hyundo Moon0a926572019-12-28 15:01:21 +09001199 this, provider, sessionInfo));
1200 }
1201
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001202 @Override
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001203 public void onRequestFailed(@NonNull MediaRoute2Provider provider, long uniqueRequestId,
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001204 int reason) {
1205 sendMessage(PooledLambda.obtainMessage(UserHandler::onRequestFailedOnHandler,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001206 this, provider, uniqueRequestId, reason));
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001207 }
1208
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001209 @Nullable
Hyundo Moone962ed42020-02-16 19:47:41 +09001210 public RouterRecord findRouterforSessionLocked(@NonNull String uniqueSessionId) {
1211 return mSessionToRouterMap.get(uniqueSessionId);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001212 }
1213
Hyundo Moone962ed42020-02-16 19:47:41 +09001214 private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
Sungsoo Limddf140d2020-03-25 08:53:55 +09001215 int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001216 MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001217 MediaRoute2ProviderInfo prevInfo =
Sungsoo Limddf140d2020-03-25 08:53:55 +09001218 (providerInfoIndex < 0) ? null : mLastProviderInfos.get(providerInfoIndex);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001219 if (Objects.equals(prevInfo, currentInfo)) return;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001220
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001221 List<MediaRoute2Info> addedRoutes = new ArrayList<>();
1222 List<MediaRoute2Info> removedRoutes = new ArrayList<>();
1223 List<MediaRoute2Info> changedRoutes = new ArrayList<>();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001224 if (prevInfo == null) {
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001225 mLastProviderInfos.add(currentInfo);
1226 addedRoutes.addAll(currentInfo.getRoutes());
1227 } else if (currentInfo == null) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001228 mLastProviderInfos.remove(prevInfo);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001229 removedRoutes.addAll(prevInfo.getRoutes());
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001230 } else {
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001231 mLastProviderInfos.set(providerInfoIndex, currentInfo);
1232 final Collection<MediaRoute2Info> prevRoutes = prevInfo.getRoutes();
1233 final Collection<MediaRoute2Info> currentRoutes = currentInfo.getRoutes();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001234
1235 for (MediaRoute2Info route : currentRoutes) {
1236 if (!route.isValid()) {
1237 Slog.w(TAG, "Ignoring invalid route : " + route);
1238 continue;
1239 }
Kyunglyul Hyun616096e2020-01-09 16:15:03 +09001240 MediaRoute2Info prevRoute = prevInfo.getRoute(route.getOriginalId());
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001241 if (prevRoute == null) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001242 addedRoutes.add(route);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001243 } else if (!Objects.equals(prevRoute, route)) {
1244 changedRoutes.add(route);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001245 }
1246 }
1247
1248 for (MediaRoute2Info prevRoute : prevInfo.getRoutes()) {
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001249 if (currentInfo.getRoute(prevRoute.getOriginalId()) == null) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001250 removedRoutes.add(prevRoute);
1251 }
1252 }
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001253 }
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001254
Sungsoo Limc27785a2020-03-27 16:57:47 +09001255 List<IMediaRouter2> routersWithModifyAudioRoutingPermission = getRouters(true);
1256 List<IMediaRouter2> routersWithoutModifyAudioRoutingPermission = getRouters(false);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001257 List<IMediaRouter2Manager> managers = getManagers();
Sungsoo Limc27785a2020-03-27 16:57:47 +09001258 List<MediaRoute2Info> defaultRoute = new ArrayList<>();
1259 defaultRoute.add(mSystemProvider.getDefaultRoute());
1260
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001261 if (addedRoutes.size() > 0) {
Sungsoo Limc27785a2020-03-27 16:57:47 +09001262 notifyRoutesAddedToRouters(routersWithModifyAudioRoutingPermission, addedRoutes);
1263 if (!provider.mIsSystemRouteProvider) {
1264 notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission,
1265 addedRoutes);
1266 } else if (prevInfo == null) {
1267 notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission,
1268 defaultRoute);
1269 } // 'else' is handled as changed routes
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001270 notifyRoutesAddedToManagers(managers, addedRoutes);
1271 }
1272 if (removedRoutes.size() > 0) {
Sungsoo Limc27785a2020-03-27 16:57:47 +09001273 notifyRoutesRemovedToRouters(routersWithModifyAudioRoutingPermission,
1274 removedRoutes);
1275 if (!provider.mIsSystemRouteProvider) {
1276 notifyRoutesRemovedToRouters(routersWithoutModifyAudioRoutingPermission,
1277 removedRoutes);
1278 }
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001279 notifyRoutesRemovedToManagers(managers, removedRoutes);
1280 }
1281 if (changedRoutes.size() > 0) {
Sungsoo Limc27785a2020-03-27 16:57:47 +09001282 notifyRoutesChangedToRouters(routersWithModifyAudioRoutingPermission,
1283 changedRoutes);
1284 if (!provider.mIsSystemRouteProvider) {
1285 notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission,
1286 changedRoutes);
1287 } else if (prevInfo != null) {
1288 notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission,
1289 defaultRoute);
1290 } // 'else' is handled as added routes
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001291 notifyRoutesChangedToManagers(managers, changedRoutes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001292 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001293 }
1294
Sungsoo Limddf140d2020-03-25 08:53:55 +09001295 private int getLastProviderInfoIndex(@NonNull String providerId) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001296 for (int i = 0; i < mLastProviderInfos.size(); i++) {
1297 MediaRoute2ProviderInfo providerInfo = mLastProviderInfos.get(i);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001298 if (TextUtils.equals(providerInfo.getUniqueId(), providerId)) {
1299 return i;
1300 }
1301 }
1302 return -1;
1303 }
1304
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001305 private void getSessionHintsForCreatingSessionOnHandler(long uniqueRequestId,
1306 @NonNull RouterRecord routerRecord, @NonNull ManagerRecord managerRecord,
1307 @NonNull MediaRoute2Info route) {
1308 SessionCreationRequest request =
1309 new SessionCreationRequest(routerRecord, uniqueRequestId, route, managerRecord);
1310 mSessionCreationRequests.add(request);
1311
1312 try {
1313 routerRecord.mRouter.getSessionHintsForCreatingSession(uniqueRequestId, route);
1314 } catch (RemoteException ex) {
1315 Slog.w(TAG, "requestGetSessionHintsOnHandler: "
1316 + "Failed to request. Router probably died.");
1317 mSessionCreationRequests.remove(request);
1318 notifyRequestFailedToManager(managerRecord.mManager,
1319 toOriginalRequestId(uniqueRequestId), REASON_UNKNOWN_ERROR);
1320 }
1321 }
1322
1323 private void requestCreateSessionWithRouter2OnHandler(long uniqueRequestId,
1324 @NonNull RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001325 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001326
1327 final MediaRoute2Provider provider = findProvider(route.getProviderId());
1328 if (provider == null) {
1329 Slog.w(TAG, "Ignoring session creation request since no provider found for"
1330 + " given route=" + route);
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001331 notifySessionCreationFailedToRouter(routerRecord,
1332 toOriginalRequestId(uniqueRequestId));
Hyundo Moon63a05402019-12-19 20:13:56 +09001333 return;
1334 }
1335
Hyundo Moondc79a7a2020-01-16 15:18:33 +09001336 SessionCreationRequest request =
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001337 new SessionCreationRequest(routerRecord, uniqueRequestId, route, null);
Hyundo Moon63a05402019-12-19 20:13:56 +09001338 mSessionCreationRequests.add(request);
1339
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001340 provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001341 route.getOriginalId(), sessionHints);
Hyundo Moon63a05402019-12-19 20:13:56 +09001342 }
1343
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001344 private void requestCreateSessionWithManagerOnHandler(long uniqueRequestId,
1345 @NonNull RouterRecord routerRecord,
1346 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
1347 SessionCreationRequest matchingRequest = null;
1348 for (SessionCreationRequest request : mSessionCreationRequests) {
1349 if (request.mUniqueRequestId == uniqueRequestId) {
1350 matchingRequest = request;
1351 break;
1352 }
1353 }
1354 if (matchingRequest == null) {
1355 Slog.w(TAG, "requestCreateSessionWithKnownRequestOnHandler: "
1356 + "Ignoring an unknown request.");
1357 return;
1358 }
1359
1360 if (!TextUtils.equals(matchingRequest.mRoute.getId(), route.getId())) {
1361 Slog.w(TAG, "requestCreateSessionWithKnownRequestOnHandler: "
1362 + "The given route is different from the requested route.");
1363 return;
1364 }
1365
1366 final MediaRoute2Provider provider = findProvider(route.getProviderId());
1367 if (provider == null) {
1368 Slog.w(TAG, "Ignoring session creation request since no provider found for"
1369 + " given route=" + route);
1370
1371 mSessionCreationRequests.remove(matchingRequest);
1372 notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
1373 toOriginalRequestId(uniqueRequestId), REASON_ROUTE_NOT_AVAILABLE);
1374 return;
1375 }
1376
1377 provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
1378 route.getOriginalId(), sessionHints);
1379 }
1380
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001381 // routerRecord can be null if the session is system's or RCN.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001382 private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001383 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +09001384 if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
Hyundo Moon0a926572019-12-28 15:01:21 +09001385 "selecting")) {
1386 return;
1387 }
1388
1389 final String providerId = route.getProviderId();
1390 final MediaRoute2Provider provider = findProvider(providerId);
1391 // TODO: Remove this null check when the mMediaProviders are referenced only in handler.
1392 if (provider == null) {
1393 return;
1394 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001395 provider.selectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
1396 route.getOriginalId());
Hyundo Moon0a926572019-12-28 15:01:21 +09001397 }
1398
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001399 // routerRecord can be null if the session is system's or RCN.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001400 private void deselectRouteOnHandler(long uniqueRequestId,
1401 @Nullable RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001402 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +09001403 if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
Hyundo Moon0a926572019-12-28 15:01:21 +09001404 "deselecting")) {
1405 return;
1406 }
1407
1408 final String providerId = route.getProviderId();
1409 final MediaRoute2Provider provider = findProvider(providerId);
1410 // TODO: Remove this null check when the mMediaProviders are referenced only in handler.
1411 if (provider == null) {
1412 return;
1413 }
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001414
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001415 provider.deselectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001416 route.getOriginalId());
Hyundo Moon0a926572019-12-28 15:01:21 +09001417 }
1418
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001419 // routerRecord can be null if the session is system's or RCN.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001420 private void transferToRouteOnHandler(long uniqueRequestId,
1421 @Nullable RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001422 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +09001423 if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
Hyundo Moon0a926572019-12-28 15:01:21 +09001424 "transferring to")) {
1425 return;
1426 }
1427
1428 final String providerId = route.getProviderId();
1429 final MediaRoute2Provider provider = findProvider(providerId);
1430 // TODO: Remove this null check when the mMediaProviders are referenced only in handler.
1431 if (provider == null) {
1432 return;
1433 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001434 provider.transferToRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001435 route.getOriginalId());
Hyundo Moon0a926572019-12-28 15:01:21 +09001436 }
1437
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001438 // routerRecord is null if and only if the session is created without the request, which
1439 // includes the system's session and RCN cases.
Hyundo Moon56337492020-02-16 16:19:54 +09001440 private boolean checkArgumentsForSessionControl(@Nullable RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001441 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route,
1442 @NonNull String description) {
Hyundo Moon0a926572019-12-28 15:01:21 +09001443 final String providerId = route.getProviderId();
1444 final MediaRoute2Provider provider = findProvider(providerId);
1445 if (provider == null) {
1446 Slog.w(TAG, "Ignoring " + description + " route since no provider found for "
1447 + "given route=" + route);
1448 return false;
1449 }
1450
Hyundo Moon56337492020-02-16 16:19:54 +09001451 // Bypass checking router if it's the system session (routerRecord should be null)
Kyunglyul Hyun581fc982020-01-21 16:30:28 +09001452 if (TextUtils.equals(getProviderId(uniqueSessionId), mSystemProvider.getUniqueId())) {
1453 return true;
1454 }
1455
Hyundo Moon56337492020-02-16 16:19:54 +09001456 RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId);
1457 if (matchingRecord != routerRecord) {
1458 Slog.w(TAG, "Ignoring " + description + " route from non-matching router. "
1459 + "packageName=" + routerRecord.mPackageName + " route=" + route);
Hyundo Moon0a926572019-12-28 15:01:21 +09001460 return false;
1461 }
1462
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001463 final String sessionId = getOriginalId(uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001464 if (sessionId == null) {
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001465 Slog.w(TAG, "Failed to get original session id from unique session id. "
Hyundo Moonca9db782020-01-01 18:31:15 +09001466 + "uniqueSessionId=" + uniqueSessionId);
Hyundo Moon0a926572019-12-28 15:01:21 +09001467 return false;
1468 }
1469
1470 return true;
1471 }
1472
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001473 private void setRouteVolumeOnHandler(long uniqueRequestId, @NonNull MediaRoute2Info route,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001474 int volume) {
1475 final MediaRoute2Provider provider = findProvider(route.getProviderId());
1476 if (provider == null) {
1477 Slog.w(TAG, "setRouteVolume: couldn't find provider for route=" + route);
1478 return;
1479 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001480 provider.setRouteVolume(uniqueRequestId, route.getOriginalId(), volume);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001481 }
1482
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001483 private void setSessionVolumeOnHandler(long uniqueRequestId,
1484 @NonNull String uniqueSessionId, int volume) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001485 final MediaRoute2Provider provider = findProvider(getProviderId(uniqueSessionId));
1486 if (provider == null) {
1487 Slog.w(TAG, "setSessionVolume: couldn't find provider for session "
1488 + "id=" + uniqueSessionId);
1489 return;
1490 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001491 provider.setSessionVolume(uniqueRequestId, getOriginalId(uniqueSessionId), volume);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001492 }
1493
1494 private void releaseSessionOnHandler(long uniqueRequestId,
Hyundo Moon1f066682020-04-13 04:04:15 +09001495 @Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId) {
Hyundo Moon56337492020-02-16 16:19:54 +09001496 final RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId);
1497 if (matchingRecord != routerRecord) {
Hyundo Moon1f066682020-04-13 04:04:15 +09001498 Slog.w(TAG, "Ignoring releasing session from non-matching router. packageName="
1499 + (routerRecord == null ? null : routerRecord.mPackageName)
Hyundo Moonca9db782020-01-01 18:31:15 +09001500 + " uniqueSessionId=" + uniqueSessionId);
1501 return;
1502 }
1503
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001504 final String providerId = getProviderId(uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001505 if (providerId == null) {
1506 Slog.w(TAG, "Ignoring releasing session with invalid unique session ID. "
1507 + "uniqueSessionId=" + uniqueSessionId);
1508 return;
1509 }
1510
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001511 final String sessionId = getOriginalId(uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001512 if (sessionId == null) {
1513 Slog.w(TAG, "Ignoring releasing session with invalid unique session ID. "
1514 + "uniqueSessionId=" + uniqueSessionId + " providerId=" + providerId);
1515 return;
1516 }
1517
1518 final MediaRoute2Provider provider = findProvider(providerId);
1519 if (provider == null) {
1520 Slog.w(TAG, "Ignoring releasing session since no provider found for given "
1521 + "providerId=" + providerId);
1522 return;
1523 }
1524
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001525 provider.releaseSession(uniqueRequestId, sessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001526 }
1527
1528 private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001529 long uniqueRequestId, @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001530 notifySessionCreatedToManagers(getManagers(),
1531 toOriginalRequestId(uniqueRequestId), sessionInfo);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001532
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001533 if (uniqueRequestId == REQUEST_ID_NONE) {
Hyundo Moon6e30f1b2020-01-13 19:50:27 +09001534 // The session is created without any matching request.
Hyundo Moon6e30f1b2020-01-13 19:50:27 +09001535 return;
1536 }
1537
Hyundo Moon63a05402019-12-19 20:13:56 +09001538 SessionCreationRequest matchingRequest = null;
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +09001539
Hyundo Moon63a05402019-12-19 20:13:56 +09001540 for (SessionCreationRequest request : mSessionCreationRequests) {
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001541 if (request.mUniqueRequestId == uniqueRequestId
Hyundo Moon63a05402019-12-19 20:13:56 +09001542 && TextUtils.equals(
1543 request.mRoute.getProviderId(), provider.getUniqueId())) {
1544 matchingRequest = request;
1545 break;
1546 }
1547 }
1548
1549 if (matchingRequest == null) {
1550 Slog.w(TAG, "Ignoring session creation result for unknown request. "
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001551 + "uniqueRequestId=" + uniqueRequestId + ", sessionInfo=" + sessionInfo);
Hyundo Moon63a05402019-12-19 20:13:56 +09001552 return;
1553 }
1554
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +09001555 mSessionCreationRequests.remove(matchingRequest);
1556
Hyundo Moon63a05402019-12-19 20:13:56 +09001557 if (sessionInfo == null) {
1558 // Failed
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001559 notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001560 toOriginalRequestId(uniqueRequestId));
Hyundo Moon63a05402019-12-19 20:13:56 +09001561 return;
1562 }
1563
1564 String originalRouteId = matchingRequest.mRoute.getId();
Hyundo Moon56337492020-02-16 16:19:54 +09001565 RouterRecord routerRecord = matchingRequest.mRouterRecord;
Hyundo Moon0a926572019-12-28 15:01:21 +09001566
Hyundo Moondc79a7a2020-01-16 15:18:33 +09001567 if (!sessionInfo.getSelectedRoutes().contains(originalRouteId)) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001568 Slog.w(TAG, "Created session doesn't match the original request."
1569 + " originalRouteId=" + originalRouteId
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001570 + ", uniqueRequestId=" + uniqueRequestId + ", sessionInfo=" + sessionInfo);
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001571 notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001572 toOriginalRequestId(uniqueRequestId));
Hyundo Moon63a05402019-12-19 20:13:56 +09001573 return;
1574 }
1575
1576 // Succeeded
Kyunglyul Hyun22d4e052020-04-21 10:10:48 +09001577 if (sessionInfo.isSystemSession()
1578 && !matchingRequest.mRouterRecord.mHasModifyAudioRoutingPermission) {
1579 notifySessionCreatedToRouter(matchingRequest.mRouterRecord,
1580 toOriginalRequestId(uniqueRequestId),
1581 mSystemProvider.getDefaultSessionInfo());
1582 } else {
1583 notifySessionCreatedToRouter(matchingRequest.mRouterRecord,
1584 toOriginalRequestId(uniqueRequestId), sessionInfo);
1585 }
Hyundo Moon56337492020-02-16 16:19:54 +09001586 mSessionToRouterMap.put(sessionInfo.getId(), routerRecord);
Hyundo Moon63a05402019-12-19 20:13:56 +09001587 }
1588
Hyundo Moonca9db782020-01-01 18:31:15 +09001589 private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
Hyundo Moonf829e6f2020-01-11 19:31:35 +09001590 @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001591 List<IMediaRouter2Manager> managers = getManagers();
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001592 notifySessionInfoChangedToManagers(managers, sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001593
Hyundo Moon56337492020-02-16 16:19:54 +09001594 // For system provider, notify all routers.
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001595 if (provider == mSystemProvider) {
1596 MediaRouter2ServiceImpl service = mServiceRef.get();
1597 if (service == null) {
1598 return;
1599 }
Sungsoo Limc27785a2020-03-27 16:57:47 +09001600 notifySessionInfoChangedToRouters(getRouters(true), sessionInfo);
1601 notifySessionInfoChangedToRouters(getRouters(false),
1602 mSystemProvider.getDefaultSessionInfo());
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001603 return;
1604 }
1605
Hyundo Moon56337492020-02-16 16:19:54 +09001606 RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
1607 if (routerRecord == null) {
1608 Slog.w(TAG, "No matching router found for session=" + sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001609 return;
1610 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001611 notifySessionInfoChangedToRouter(routerRecord, sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001612 }
1613
Hyundo Moonca9db782020-01-01 18:31:15 +09001614 private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
Hyundo Moonf829e6f2020-01-11 19:31:35 +09001615 @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001616 List<IMediaRouter2Manager> managers = getManagers();
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001617 notifySessionInfoChangedToManagers(managers, sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001618
Hyundo Moon56337492020-02-16 16:19:54 +09001619 RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
1620 if (routerRecord == null) {
1621 Slog.w(TAG, "No matching router found for session=" + sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001622 return;
1623 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001624 notifySessionReleasedToRouter(routerRecord, sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001625 }
1626
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001627 private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001628 long uniqueRequestId, int reason) {
1629 if (handleSessionCreationRequestFailed(provider, uniqueRequestId, reason)) {
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001630 return;
1631 }
1632
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001633 final int requesterId = toRequesterId(uniqueRequestId);
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001634 for (ManagerRecord manager : getManagerRecords()) {
1635 if (manager.mManagerId == requesterId) {
1636 notifyRequestFailedToManager(
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001637 manager.mManager, toOriginalRequestId(uniqueRequestId), reason);
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001638 return;
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001639 }
1640 }
1641
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001642 // Currently, only the manager can get notified of failures.
1643 // TODO: Notify router too when the related callback is introduced.
1644 }
1645
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001646 // TODO: Find a way to prevent providers from notifying error on random uniqueRequestId.
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001647 // Solutions can be:
1648 // 1) Record the other type of requests too (not only session creation request)
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001649 // 2) Throw exception on providers when they try to notify error on
1650 // random uniqueRequestId.
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001651 private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001652 long uniqueRequestId, int reason) {
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001653 // Check whether the failure is about creating a session
1654 SessionCreationRequest matchingRequest = null;
1655 for (SessionCreationRequest request : mSessionCreationRequests) {
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001656 if (request.mUniqueRequestId == uniqueRequestId && TextUtils.equals(
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001657 request.mRoute.getProviderId(), provider.getUniqueId())) {
1658 matchingRequest = request;
1659 break;
1660 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001661 }
1662
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001663 if (matchingRequest == null) {
1664 // The failure is not about creating a session.
1665 return false;
1666 }
1667
1668 mSessionCreationRequests.remove(matchingRequest);
1669
1670 // Notify the requester about the failure.
1671 // The call should be made by either MediaRouter2 or MediaRouter2Manager.
1672 if (matchingRequest.mRequestedManagerRecord == null) {
1673 notifySessionCreationFailedToRouter(
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001674 matchingRequest.mRouterRecord, toOriginalRequestId(uniqueRequestId));
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001675 } else {
1676 notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001677 toOriginalRequestId(uniqueRequestId), reason);
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001678 }
1679 return true;
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001680 }
1681
1682 private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001683 int requestId, @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001684 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001685 routerRecord.mRouter.notifySessionCreated(requestId, sessionInfo);
Hyundo Moon63a05402019-12-19 20:13:56 +09001686 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001687 Slog.w(TAG, "Failed to notify router of the session creation."
1688 + " Router probably died.", ex);
Hyundo Moon63a05402019-12-19 20:13:56 +09001689 }
1690 }
1691
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001692 private void notifySessionCreationFailedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001693 int requestId) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001694 try {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001695 routerRecord.mRouter.notifySessionCreated(requestId,
1696 /* sessionInfo= */ null);
Hyundo Moon63a05402019-12-19 20:13:56 +09001697 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001698 Slog.w(TAG, "Failed to notify router of the session creation failure."
1699 + " Router probably died.", ex);
Hyundo Moon63a05402019-12-19 20:13:56 +09001700 }
1701 }
1702
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001703 private void notifySessionInfoChangedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001704 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon0a926572019-12-28 15:01:21 +09001705 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001706 routerRecord.mRouter.notifySessionInfoChanged(sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001707 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001708 Slog.w(TAG, "Failed to notify router of the session info change."
1709 + " Router probably died.", ex);
Hyundo Moon0a926572019-12-28 15:01:21 +09001710 }
1711 }
1712
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001713 private void notifySessionReleasedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001714 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001715 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001716 routerRecord.mRouter.notifySessionReleased(sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001717 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001718 Slog.w(TAG, "Failed to notify router of the session release."
1719 + " Router probably died.", ex);
Hyundo Moonca9db782020-01-01 18:31:15 +09001720 }
1721 }
1722
Sungsoo Limc27785a2020-03-27 16:57:47 +09001723 private List<IMediaRouter2> getAllRouters() {
Hyundo Moon56337492020-02-16 16:19:54 +09001724 final List<IMediaRouter2> routers = new ArrayList<>();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001725 MediaRouter2ServiceImpl service = mServiceRef.get();
1726 if (service == null) {
Hyundo Moon56337492020-02-16 16:19:54 +09001727 return routers;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001728 }
1729 synchronized (service.mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +09001730 for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
1731 routers.add(routerRecord.mRouter);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001732 }
1733 }
Hyundo Moon56337492020-02-16 16:19:54 +09001734 return routers;
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001735 }
1736
Sungsoo Limc27785a2020-03-27 16:57:47 +09001737 private List<IMediaRouter2> getRouters(boolean hasModifyAudioRoutingPermission) {
1738 final List<IMediaRouter2> routers = new ArrayList<>();
1739 MediaRouter2ServiceImpl service = mServiceRef.get();
1740 if (service == null) {
1741 return routers;
1742 }
1743 synchronized (service.mLock) {
1744 for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
1745 if (hasModifyAudioRoutingPermission
1746 == routerRecord.mHasModifyAudioRoutingPermission) {
1747 routers.add(routerRecord.mRouter);
1748 }
1749 }
1750 }
1751 return routers;
1752 }
1753
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001754 private List<IMediaRouter2Manager> getManagers() {
1755 final List<IMediaRouter2Manager> managers = new ArrayList<>();
1756 MediaRouter2ServiceImpl service = mServiceRef.get();
1757 if (service == null) {
1758 return managers;
1759 }
1760 synchronized (service.mLock) {
1761 for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
1762 managers.add(managerRecord.mManager);
1763 }
1764 }
1765 return managers;
1766 }
1767
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001768 private List<ManagerRecord> getManagerRecords() {
1769 MediaRouter2ServiceImpl service = mServiceRef.get();
1770 if (service == null) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001771 return Collections.emptyList();
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001772 }
1773 synchronized (service.mLock) {
1774 return new ArrayList<>(mUserRecord.mManagerRecords);
1775 }
1776 }
1777
Hyundo Moone962ed42020-02-16 19:47:41 +09001778 private void notifyRoutesToRouter(@NonNull IMediaRouter2 router) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001779 List<MediaRoute2Info> routes = new ArrayList<>();
Hyundo Moon63a05402019-12-19 20:13:56 +09001780 for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001781 routes.addAll(providerInfo.getRoutes());
1782 }
1783 if (routes.size() == 0) {
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001784 return;
1785 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001786 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001787 router.notifyRoutesAdded(routes);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001788 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001789 Slog.w(TAG, "Failed to notify all routes. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001790 }
1791 }
1792
Hyundo Moone962ed42020-02-16 19:47:41 +09001793 private void notifyRoutesAddedToRouters(@NonNull List<IMediaRouter2> routers,
1794 @NonNull List<MediaRoute2Info> routes) {
Hyundo Moon56337492020-02-16 16:19:54 +09001795 for (IMediaRouter2 router : routers) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001796 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001797 router.notifyRoutesAdded(routes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001798 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001799 Slog.w(TAG, "Failed to notify routes added. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001800 }
1801 }
1802 }
1803
Hyundo Moone962ed42020-02-16 19:47:41 +09001804 private void notifyRoutesRemovedToRouters(@NonNull List<IMediaRouter2> routers,
1805 @NonNull List<MediaRoute2Info> routes) {
Hyundo Moon56337492020-02-16 16:19:54 +09001806 for (IMediaRouter2 router : routers) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001807 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001808 router.notifyRoutesRemoved(routes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001809 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001810 Slog.w(TAG, "Failed to notify routes removed. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001811 }
1812 }
1813 }
1814
Hyundo Moone962ed42020-02-16 19:47:41 +09001815 private void notifyRoutesChangedToRouters(@NonNull List<IMediaRouter2> routers,
1816 @NonNull List<MediaRoute2Info> routes) {
Hyundo Moon56337492020-02-16 16:19:54 +09001817 for (IMediaRouter2 router : routers) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001818 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001819 router.notifyRoutesChanged(routes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001820 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001821 Slog.w(TAG, "Failed to notify routes changed. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001822 }
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001823 }
1824 }
1825
Hyundo Moone962ed42020-02-16 19:47:41 +09001826 private void notifySessionInfoChangedToRouters(@NonNull List<IMediaRouter2> routers,
1827 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon56337492020-02-16 16:19:54 +09001828 for (IMediaRouter2 router : routers) {
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001829 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001830 router.notifySessionInfoChanged(sessionInfo);
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001831 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001832 Slog.w(TAG, "Failed to notify session info changed. Router probably died.", ex);
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001833 }
1834 }
1835 }
1836
Hyundo Moone962ed42020-02-16 19:47:41 +09001837 private void notifyRoutesToManager(@NonNull IMediaRouter2Manager manager) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001838 List<MediaRoute2Info> routes = new ArrayList<>();
Hyundo Moon63a05402019-12-19 20:13:56 +09001839 for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001840 routes.addAll(providerInfo.getRoutes());
1841 }
1842 if (routes.size() == 0) {
1843 return;
1844 }
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001845 try {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001846 manager.notifyRoutesAdded(routes);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001847 } catch (RemoteException ex) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001848 Slog.w(TAG, "Failed to notify all routes. Manager probably died.", ex);
1849 }
1850 }
1851
Hyundo Moone962ed42020-02-16 19:47:41 +09001852 private void notifyRoutesAddedToManagers(@NonNull List<IMediaRouter2Manager> managers,
1853 @NonNull List<MediaRoute2Info> routes) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001854 for (IMediaRouter2Manager manager : managers) {
1855 try {
1856 manager.notifyRoutesAdded(routes);
1857 } catch (RemoteException ex) {
1858 Slog.w(TAG, "Failed to notify routes added. Manager probably died.", ex);
1859 }
1860 }
1861 }
1862
Hyundo Moone962ed42020-02-16 19:47:41 +09001863 private void notifyRoutesRemovedToManagers(@NonNull List<IMediaRouter2Manager> managers,
1864 @NonNull List<MediaRoute2Info> routes) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001865 for (IMediaRouter2Manager manager : managers) {
1866 try {
1867 manager.notifyRoutesRemoved(routes);
1868 } catch (RemoteException ex) {
1869 Slog.w(TAG, "Failed to notify routes removed. Manager probably died.", ex);
1870 }
1871 }
1872 }
1873
Hyundo Moone962ed42020-02-16 19:47:41 +09001874 private void notifyRoutesChangedToManagers(@NonNull List<IMediaRouter2Manager> managers,
1875 @NonNull List<MediaRoute2Info> routes) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001876 for (IMediaRouter2Manager manager : managers) {
1877 try {
1878 manager.notifyRoutesChanged(routes);
1879 } catch (RemoteException ex) {
1880 Slog.w(TAG, "Failed to notify routes changed. Manager probably died.", ex);
1881 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001882 }
1883 }
1884
Hyundo Moone962ed42020-02-16 19:47:41 +09001885 private void notifySessionCreatedToManagers(@NonNull List<IMediaRouter2Manager> managers,
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001886 int requestId, @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001887 for (IMediaRouter2Manager manager : managers) {
1888 try {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001889 manager.notifySessionCreated(requestId, sessionInfo);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001890 } catch (RemoteException ex) {
1891 Slog.w(TAG, "notifySessionCreatedToManagers: "
1892 + "failed to notify. Manager probably died.", ex);
1893 }
1894 }
1895 }
1896
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001897 private void notifySessionInfoChangedToManagers(
1898 @NonNull List<IMediaRouter2Manager> managers,
1899 @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001900 for (IMediaRouter2Manager manager : managers) {
1901 try {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001902 manager.notifySessionUpdated(sessionInfo);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001903 } catch (RemoteException ex) {
1904 Slog.w(TAG, "notifySessionInfosChangedToManagers: "
1905 + "failed to notify. Manager probably died.", ex);
1906 }
1907 }
1908 }
1909
Hyundo Moone962ed42020-02-16 19:47:41 +09001910 private void notifyPreferredFeaturesChangedToManagers(@NonNull RouterRecord routerRecord) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001911 MediaRouter2ServiceImpl service = mServiceRef.get();
1912 if (service == null) {
1913 return;
1914 }
1915 List<IMediaRouter2Manager> managers = new ArrayList<>();
1916 synchronized (service.mLock) {
Hyundo Moon7d3ab332019-10-16 11:09:56 +09001917 for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
1918 managers.add(managerRecord.mManager);
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001919 }
1920 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001921 for (IMediaRouter2Manager manager : managers) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001922 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001923 manager.notifyPreferredFeaturesChanged(routerRecord.mPackageName,
1924 routerRecord.mDiscoveryPreference.getPreferredFeatures());
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001925 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001926 Slog.w(TAG, "Failed to notify preferred features changed."
1927 + " Manager probably died.", ex);
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001928 }
1929 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001930 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001931
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001932 private void notifyRequestFailedToManager(@NonNull IMediaRouter2Manager manager,
1933 int requestId, int reason) {
1934 try {
1935 manager.notifyRequestFailed(requestId, reason);
1936 } catch (RemoteException ex) {
1937 Slog.w(TAG, "Failed to notify manager of the request failure."
1938 + " Manager probably died.", ex);
1939 }
1940 }
1941
1942 private void updateDiscoveryPreferenceOnHandler() {
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09001943 MediaRouter2ServiceImpl service = mServiceRef.get();
1944 if (service == null) {
1945 return;
1946 }
1947 List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>();
1948 synchronized (service.mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +09001949 for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
1950 discoveryPreferences.add(routerRecord.mDiscoveryPreference);
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09001951 }
1952 mUserRecord.mCompositeDiscoveryPreference =
1953 new RouteDiscoveryPreference.Builder(discoveryPreferences)
1954 .build();
1955 }
Sungsoo Limddf140d2020-03-25 08:53:55 +09001956 for (MediaRoute2Provider provider : mRouteProviders) {
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09001957 provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
1958 }
1959 }
1960
Hyundo Moone962ed42020-02-16 19:47:41 +09001961 private MediaRoute2Provider findProvider(@Nullable String providerId) {
Sungsoo Limddf140d2020-03-25 08:53:55 +09001962 for (MediaRoute2Provider provider : mRouteProviders) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001963 if (TextUtils.equals(provider.getUniqueId(), providerId)) {
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001964 return provider;
1965 }
1966 }
1967 return null;
1968 }
Hyundo Moon63a05402019-12-19 20:13:56 +09001969
1970 final class SessionCreationRequest {
Hyundo Moon56337492020-02-16 16:19:54 +09001971 public final RouterRecord mRouterRecord;
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001972 public final long mUniqueRequestId;
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001973 public final MediaRoute2Info mRoute;
1974 public final ManagerRecord mRequestedManagerRecord;
Hyundo Moon63a05402019-12-19 20:13:56 +09001975
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001976 // requestedManagerRecord is not null only when the request is made by manager.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001977 SessionCreationRequest(@NonNull RouterRecord routerRecord, long uniqueRequestId,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001978 @NonNull MediaRoute2Info route,
1979 @Nullable ManagerRecord requestedManagerRecord) {
Hyundo Moon56337492020-02-16 16:19:54 +09001980 mRouterRecord = routerRecord;
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001981 mUniqueRequestId = uniqueRequestId;
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001982 mRoute = route;
1983 mRequestedManagerRecord = requestedManagerRecord;
Hyundo Moon63a05402019-12-19 20:13:56 +09001984 }
1985 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001986 }
1987}