blob: 72d296fc5f6b177b4e884d7a7d53976bfeb1c59f [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) {
Hyundo Moon369be952020-06-11 17:37:01 +0900570 Slog.w(TAG, "registerRouter2Locked: Same router already exists. packageName="
571 + packageName);
Hyundo Moone962ed42020-02-16 19:47:41 +0900572 return;
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900573 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900574
575 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900576 RouterRecord routerRecord = new RouterRecord(userRecord, router, uid, pid, packageName,
577 hasConfigureWifiDisplayPermission, hasModifyAudioRoutingPermission);
Hyundo Moone962ed42020-02-16 19:47:41 +0900578 try {
579 binder.linkToDeath(routerRecord, 0);
580 } catch (RemoteException ex) {
581 throw new RuntimeException("MediaRouter2 died prematurely.", ex);
582 }
583
584 userRecord.mRouterRecords.add(routerRecord);
585 mAllRouterRecords.put(binder, routerRecord);
586
587 userRecord.mHandler.sendMessage(
Hyundo Moonbc633272020-06-04 18:12:29 +0900588 obtainMessage(UserHandler::notifyRouterRegistered,
Hyundo Moonfa248a72020-05-12 20:05:27 +0900589 userRecord.mHandler, routerRecord));
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900590 }
591
Hyundo Moone962ed42020-02-16 19:47:41 +0900592 private void unregisterRouter2Locked(@NonNull IMediaRouter2 router, boolean died) {
Hyundo Moon56337492020-02-16 16:19:54 +0900593 RouterRecord routerRecord = mAllRouterRecords.remove(router.asBinder());
Hyundo Moone962ed42020-02-16 19:47:41 +0900594 if (routerRecord == null) {
595 Slog.w(TAG, "Ignoring unregistering unknown router2");
596 return;
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900597 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900598
599 UserRecord userRecord = routerRecord.mUserRecord;
600 userRecord.mRouterRecords.remove(routerRecord);
Hyundo Moonac9df102020-06-12 19:36:10 +0900601 routerRecord.mUserRecord.mHandler.sendMessage(
602 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
603 routerRecord.mUserRecord.mHandler,
604 routerRecord.mPackageName, /* preferredFeatures=*/ null));
Kyunglyul Hyunef7e88f2020-04-01 22:15:08 +0900605 userRecord.mHandler.sendMessage(
606 obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
607 userRecord.mHandler));
Hyundo Moone962ed42020-02-16 19:47:41 +0900608 routerRecord.dispose();
609 disposeUserIfNeededLocked(userRecord); // since router removed from user
Kyunglyul Hyundafac542019-04-29 18:07:21 +0900610 }
611
Hyundo Moone962ed42020-02-16 19:47:41 +0900612 private void setDiscoveryRequestWithRouter2Locked(@NonNull RouterRecord routerRecord,
613 @NonNull RouteDiscoveryPreference discoveryRequest) {
614 if (routerRecord.mDiscoveryPreference.equals(discoveryRequest)) {
615 return;
Kyunglyul Hyunc7847242019-12-30 17:46:04 +0900616 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900617 routerRecord.mDiscoveryPreference = discoveryRequest;
618 routerRecord.mUserRecord.mHandler.sendMessage(
619 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
Hyundo Moonac9df102020-06-12 19:36:10 +0900620 routerRecord.mUserRecord.mHandler,
621 routerRecord.mPackageName,
622 routerRecord.mDiscoveryPreference.getPreferredFeatures()));
Hyundo Moone962ed42020-02-16 19:47:41 +0900623 routerRecord.mUserRecord.mHandler.sendMessage(
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900624 obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
Hyundo Moone962ed42020-02-16 19:47:41 +0900625 routerRecord.mUserRecord.mHandler));
Hyundo Moon63a05402019-12-19 20:13:56 +0900626 }
627
Hyundo Moone962ed42020-02-16 19:47:41 +0900628 private void setRouteVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
629 @NonNull MediaRoute2Info route, int volume) {
Hyundo Moon56337492020-02-16 16:19:54 +0900630 final IBinder binder = router.asBinder();
631 RouterRecord routerRecord = mAllRouterRecords.get(binder);
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900632
Hyundo Moon56337492020-02-16 16:19:54 +0900633 if (routerRecord != null) {
634 routerRecord.mUserRecord.mHandler.sendMessage(
Hyundo Moone962ed42020-02-16 19:47:41 +0900635 obtainMessage(UserHandler::setRouteVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900636 routerRecord.mUserRecord.mHandler,
637 DUMMY_REQUEST_ID, route, volume));
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900638 }
639 }
640
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900641 private void requestCreateSessionWithRouter2Locked(int requestId, @NonNull IMediaRouter2 router,
642 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900643 final IBinder binder = router.asBinder();
644 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
645
646 if (routerRecord == null) {
647 return;
648 }
649
Hyundo Moonfa3d0ef2020-04-13 00:27:44 +0900650 if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
651 && !TextUtils.equals(route.getId(),
652 routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId())) {
653 Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
654 + route);
655 routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
656 routerRecord, requestId);
657 return;
658 }
659
Hyundo Moone962ed42020-02-16 19:47:41 +0900660 long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
661 routerRecord.mUserRecord.mHandler.sendMessage(
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900662 obtainMessage(UserHandler::requestCreateSessionWithRouter2OnHandler,
Hyundo Moone962ed42020-02-16 19:47:41 +0900663 routerRecord.mUserRecord.mHandler,
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900664 uniqueRequestId, routerRecord, route,
Hyundo Moon7c2059c2020-02-27 19:01:52 +0900665 sessionHints));
Hyundo Moone962ed42020-02-16 19:47:41 +0900666 }
667
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900668 private void notifySessionHintsForCreatingSessionLocked(long uniqueRequestId,
669 @NonNull IMediaRouter2 router,
670 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
671 final IBinder binder = router.asBinder();
672 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
673
674 if (routerRecord == null) {
Hyundo Moon369be952020-06-11 17:37:01 +0900675 Slog.w(TAG, "notifySessionHintsForCreatingSessionLocked: Ignoring unknown router.");
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900676 return;
677 }
678
679 routerRecord.mUserRecord.mHandler.sendMessage(
680 obtainMessage(UserHandler::requestCreateSessionWithManagerOnHandler,
681 routerRecord.mUserRecord.mHandler,
682 uniqueRequestId, routerRecord, route, sessionHints));
683 }
684
Hyundo Moone962ed42020-02-16 19:47:41 +0900685 private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
686 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
687 final IBinder binder = router.asBinder();
688 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
689
690 if (routerRecord == null) {
691 return;
692 }
693
694 routerRecord.mUserRecord.mHandler.sendMessage(
695 obtainMessage(UserHandler::selectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900696 routerRecord.mUserRecord.mHandler,
697 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900698 }
699
700 private void deselectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
701 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
702 final IBinder binder = router.asBinder();
703 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
704
705 if (routerRecord == null) {
706 return;
707 }
708
709 routerRecord.mUserRecord.mHandler.sendMessage(
710 obtainMessage(UserHandler::deselectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900711 routerRecord.mUserRecord.mHandler,
712 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900713 }
714
715 private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
716 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
717 final IBinder binder = router.asBinder();
718 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
719
720 if (routerRecord == null) {
721 return;
722 }
723
Sungsoo Limc27785a2020-03-27 16:57:47 +0900724 String defaultRouteId =
725 routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId();
726 if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission
727 && !TextUtils.equals(route.getId(), defaultRouteId)) {
728 routerRecord.mUserRecord.mHandler.sendMessage(
729 obtainMessage(UserHandler::notifySessionCreationFailedToRouter,
730 routerRecord.mUserRecord.mHandler,
731 routerRecord, toOriginalRequestId(DUMMY_REQUEST_ID)));
732 } else {
733 routerRecord.mUserRecord.mHandler.sendMessage(
734 obtainMessage(UserHandler::transferToRouteOnHandler,
735 routerRecord.mUserRecord.mHandler,
736 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
737 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900738 }
739
740 private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
741 @NonNull String uniqueSessionId, int volume) {
Hyundo Moon56337492020-02-16 16:19:54 +0900742 final IBinder binder = router.asBinder();
743 RouterRecord routerRecord = mAllRouterRecords.get(binder);
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900744
Hyundo Moone962ed42020-02-16 19:47:41 +0900745 if (routerRecord == null) {
746 return;
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900747 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900748
749 routerRecord.mUserRecord.mHandler.sendMessage(
750 obtainMessage(UserHandler::setSessionVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900751 routerRecord.mUserRecord.mHandler,
752 DUMMY_REQUEST_ID, uniqueSessionId, volume));
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900753 }
754
Hyundo Moone962ed42020-02-16 19:47:41 +0900755 private void releaseSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
756 @NonNull String uniqueSessionId) {
757 final IBinder binder = router.asBinder();
758 final RouterRecord routerRecord = mAllRouterRecords.get(binder);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900759
Hyundo Moone962ed42020-02-16 19:47:41 +0900760 if (routerRecord == null) {
761 return;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900762 }
Hyundo Moone962ed42020-02-16 19:47:41 +0900763
764 routerRecord.mUserRecord.mHandler.sendMessage(
765 obtainMessage(UserHandler::releaseSessionOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900766 routerRecord.mUserRecord.mHandler,
767 DUMMY_REQUEST_ID, routerRecord, uniqueSessionId));
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900768 }
769
Hyundo Moone962ed42020-02-16 19:47:41 +0900770 ////////////////////////////////////////////////////////////
771 //// ***Locked methods related to MediaRouter2Manager
772 //// - Should have @NonNull/@Nullable on all arguments
773 ////////////////////////////////////////////////////////////
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900774
Hyundo Moone962ed42020-02-16 19:47:41 +0900775 private List<RoutingSessionInfo> getActiveSessionsLocked(
776 @NonNull IMediaRouter2Manager manager) {
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900777 final IBinder binder = manager.asBinder();
778 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
779
780 if (managerRecord == null) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +0000781 Slog.w(TAG, "getActiveSessionLocked: Ignoring unknown manager");
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900782 return Collections.emptyList();
783 }
784
Hyundo Moonf829e6f2020-01-11 19:31:35 +0900785 List<RoutingSessionInfo> sessionInfos = new ArrayList<>();
Sungsoo Limddf140d2020-03-25 08:53:55 +0900786 for (MediaRoute2Provider provider : managerRecord.mUserRecord.mHandler.mRouteProviders) {
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900787 sessionInfos.addAll(provider.getSessionInfos());
788 }
789 return sessionInfos;
790 }
791
Hyundo Moone962ed42020-02-16 19:47:41 +0900792 private void registerManagerLocked(@NonNull IMediaRouter2Manager manager,
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900793 int uid, int pid, @NonNull String packageName, int userId) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900794 final IBinder binder = manager.asBinder();
795 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
796
797 if (managerRecord != null) {
Hyundo Moon369be952020-06-11 17:37:01 +0900798 Slog.w(TAG, "registerManagerLocked: Same manager already exists. packageName="
799 + packageName);
Hyundo Moone962ed42020-02-16 19:47:41 +0900800 return;
801 }
802
803 UserRecord userRecord = getOrCreateUserRecordLocked(userId);
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900804 managerRecord = new ManagerRecord(userRecord, manager, uid, pid, packageName);
Hyundo Moone962ed42020-02-16 19:47:41 +0900805 try {
806 binder.linkToDeath(managerRecord, 0);
807 } catch (RemoteException ex) {
808 throw new RuntimeException("Media router manager died prematurely.", ex);
809 }
810
811 userRecord.mManagerRecords.add(managerRecord);
812 mAllManagerRecords.put(binder, managerRecord);
813
814 userRecord.mHandler.sendMessage(obtainMessage(UserHandler::notifyRoutesToManager,
815 userRecord.mHandler, manager));
816
817 for (RouterRecord routerRecord : userRecord.mRouterRecords) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900818 // TODO: UserRecord <-> routerRecord, why do they reference each other?
819 // How about removing mUserRecord from routerRecord?
820 routerRecord.mUserRecord.mHandler.sendMessage(
Hyundo Moon38d06df2020-05-20 14:24:06 +0900821 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManager,
822 routerRecord.mUserRecord.mHandler, routerRecord, manager));
Hyundo Moone962ed42020-02-16 19:47:41 +0900823 }
824 }
825
826 private void unregisterManagerLocked(@NonNull IMediaRouter2Manager manager, boolean died) {
827 ManagerRecord managerRecord = mAllManagerRecords.remove(manager.asBinder());
828 if (managerRecord == null) {
829 return;
830 }
831 UserRecord userRecord = managerRecord.mUserRecord;
832 userRecord.mManagerRecords.remove(managerRecord);
833 managerRecord.dispose();
834 disposeUserIfNeededLocked(userRecord); // since manager removed from user
835 }
836
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900837 private void setRouteVolumeWithManagerLocked(int requestId,
838 @NonNull IMediaRouter2Manager manager,
839 @NonNull MediaRoute2Info route, int volume) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900840 final IBinder binder = manager.asBinder();
841 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
842
843 if (managerRecord == null) {
844 return;
845 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900846
847 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900848 managerRecord.mUserRecord.mHandler.sendMessage(
849 obtainMessage(UserHandler::setRouteVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900850 managerRecord.mUserRecord.mHandler,
851 uniqueRequestId, route, volume));
Hyundo Moone962ed42020-02-16 19:47:41 +0900852 }
853
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900854 private void requestCreateSessionWithManagerLocked(int requestId,
855 @NonNull IMediaRouter2Manager manager,
856 @NonNull String packageName, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900857 ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
Sungsoo Lim7065f1b2020-03-24 18:52:42 +0900858 if (managerRecord == null) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900859 return;
860 }
861
862 RouterRecord routerRecord = managerRecord.mUserRecord.findRouterRecordLocked(packageName);
863 if (routerRecord == null) {
Hyundo Moon369be952020-06-11 17:37:01 +0900864 Slog.w(TAG, "requestCreateSessionWithManagerLocked: Ignoring session creation for "
865 + "unknown router.");
Hyundo Moone962ed42020-02-16 19:47:41 +0900866 return;
867 }
868
869 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900870
871 // Before requesting to the provider, get session hints from the media router.
872 // As a return, media router will request to create a session.
Hyundo Moone962ed42020-02-16 19:47:41 +0900873 routerRecord.mUserRecord.mHandler.sendMessage(
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900874 obtainMessage(UserHandler::getSessionHintsForCreatingSessionOnHandler,
Hyundo Moone962ed42020-02-16 19:47:41 +0900875 routerRecord.mUserRecord.mHandler,
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +0900876 uniqueRequestId, routerRecord, managerRecord, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900877 }
878
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900879 private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
880 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900881 final IBinder binder = manager.asBinder();
882 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
883
884 if (managerRecord == null) {
885 return;
886 }
887
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +0900888 // Can be null if the session is system's or RCN.
Hyundo Moone962ed42020-02-16 19:47:41 +0900889 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
890 .findRouterforSessionLocked(uniqueSessionId);
891
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900892 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900893 managerRecord.mUserRecord.mHandler.sendMessage(
894 obtainMessage(UserHandler::selectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900895 managerRecord.mUserRecord.mHandler,
896 uniqueRequestId, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900897 }
898
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900899 private void deselectRouteWithManagerLocked(int requestId,
900 @NonNull IMediaRouter2Manager manager,
901 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900902 final IBinder binder = manager.asBinder();
903 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
904
905 if (managerRecord == null) {
906 return;
907 }
908
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +0900909 // Can be null if the session is system's or RCN.
Hyundo Moone962ed42020-02-16 19:47:41 +0900910 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
911 .findRouterforSessionLocked(uniqueSessionId);
912
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900913 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900914 managerRecord.mUserRecord.mHandler.sendMessage(
915 obtainMessage(UserHandler::deselectRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900916 managerRecord.mUserRecord.mHandler,
917 uniqueRequestId, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900918 }
919
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900920 private void transferToRouteWithManagerLocked(int requestId,
921 @NonNull IMediaRouter2Manager manager,
922 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900923 final IBinder binder = manager.asBinder();
924 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
925
926 if (managerRecord == null) {
927 return;
928 }
929
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +0900930 // Can be null if the session is system's or RCN.
Hyundo Moone962ed42020-02-16 19:47:41 +0900931 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
932 .findRouterforSessionLocked(uniqueSessionId);
933
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900934 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900935 managerRecord.mUserRecord.mHandler.sendMessage(
936 obtainMessage(UserHandler::transferToRouteOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900937 managerRecord.mUserRecord.mHandler,
938 uniqueRequestId, routerRecord, uniqueSessionId, route));
Hyundo Moone962ed42020-02-16 19:47:41 +0900939 }
940
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900941 private void setSessionVolumeWithManagerLocked(int requestId,
942 @NonNull IMediaRouter2Manager manager,
943 @NonNull String uniqueSessionId, int volume) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900944 final IBinder binder = manager.asBinder();
945 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
946
947 if (managerRecord == null) {
948 return;
949 }
950
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900951 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900952 managerRecord.mUserRecord.mHandler.sendMessage(
953 obtainMessage(UserHandler::setSessionVolumeOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900954 managerRecord.mUserRecord.mHandler,
955 uniqueRequestId, uniqueSessionId, volume));
Hyundo Moone962ed42020-02-16 19:47:41 +0900956 }
957
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900958 private void releaseSessionWithManagerLocked(int requestId,
959 @NonNull IMediaRouter2Manager manager,
960 @NonNull String uniqueSessionId) {
Hyundo Moone962ed42020-02-16 19:47:41 +0900961 final IBinder binder = manager.asBinder();
962 ManagerRecord managerRecord = mAllManagerRecords.get(binder);
963
964 if (managerRecord == null) {
965 return;
966 }
967
968 RouterRecord routerRecord = managerRecord.mUserRecord.mHandler
969 .findRouterforSessionLocked(uniqueSessionId);
970
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900971 long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
Hyundo Moone962ed42020-02-16 19:47:41 +0900972 managerRecord.mUserRecord.mHandler.sendMessage(
973 obtainMessage(UserHandler::releaseSessionOnHandler,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900974 managerRecord.mUserRecord.mHandler,
975 uniqueRequestId, routerRecord, uniqueSessionId));
Hyundo Moone962ed42020-02-16 19:47:41 +0900976 }
977
978 ////////////////////////////////////////////////////////////
979 //// ***Locked methods used by both router2 and manager
980 //// - Should have @NonNull/@Nullable on all arguments
981 ////////////////////////////////////////////////////////////
982
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900983 private UserRecord getOrCreateUserRecordLocked(int userId) {
984 UserRecord userRecord = mUserRecords.get(userId);
985 if (userRecord == null) {
986 userRecord = new UserRecord(userId);
987 mUserRecords.put(userId, userRecord);
Hyundo Moonaa803752020-06-17 23:02:49 +0900988 userRecord.init();
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900989 if (userId == mCurrentUserId) {
990 userRecord.mHandler.sendMessage(
991 obtainMessage(UserHandler::start, userRecord.mHandler));
992 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900993 }
Sungsoo Limdfafaf72020-01-07 13:04:05 +0900994 return userRecord;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900995 }
996
Hyundo Moone962ed42020-02-16 19:47:41 +0900997 private void disposeUserIfNeededLocked(@NonNull UserRecord userRecord) {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +0900998 // If there are no records left and the user is no longer current then go ahead
999 // and purge the user record and all of its associated state. If the user is current
1000 // then leave it alone since we might be connected to a route or want to query
1001 // the same route information again soon.
1002 if (userRecord.mUserId != mCurrentUserId
Hyundo Moon56337492020-02-16 16:19:54 +09001003 && userRecord.mRouterRecords.isEmpty()
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001004 && userRecord.mManagerRecords.isEmpty()) {
1005 if (DEBUG) {
1006 Slog.d(TAG, userRecord + ": Disposed");
1007 }
1008 mUserRecords.remove(userRecord.mUserId);
1009 // Note: User already stopped (by switchUser) so no need to send stop message here.
1010 }
1011 }
1012
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001013 static long toUniqueRequestId(int requesterId, int originalRequestId) {
1014 return ((long) requesterId << 32) | originalRequestId;
Kyunglyul Hyunc7847242019-12-30 17:46:04 +09001015 }
1016
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001017 static int toRequesterId(long uniqueRequestId) {
Kyunglyul Hyunc7847242019-12-30 17:46:04 +09001018 return (int) (uniqueRequestId >> 32);
1019 }
1020
Hyundo Moon56337492020-02-16 16:19:54 +09001021 static int toOriginalRequestId(long uniqueRequestId) {
Kyunglyul Hyunc7847242019-12-30 17:46:04 +09001022 return (int) uniqueRequestId;
1023 }
1024
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001025 final class UserRecord {
1026 public final int mUserId;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001027 //TODO: make records private for thread-safety
Hyundo Moon56337492020-02-16 16:19:54 +09001028 final ArrayList<RouterRecord> mRouterRecords = new ArrayList<>();
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001029 final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09001030 RouteDiscoveryPreference mCompositeDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001031 final UserHandler mHandler;
1032
1033 UserRecord(int userId) {
1034 mUserId = userId;
1035 mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
1036 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001037
Hyundo Moonaa803752020-06-17 23:02:49 +09001038 void init() {
1039 mHandler.init();
1040 }
1041
Hyundo Moon0f78fc62020-06-01 14:50:32 +09001042 // TODO: This assumes that only one router exists in a package.
1043 // Do this in Android S or later.
Hyundo Moon56337492020-02-16 16:19:54 +09001044 RouterRecord findRouterRecordLocked(String packageName) {
1045 for (RouterRecord routerRecord : mRouterRecords) {
1046 if (TextUtils.equals(routerRecord.mPackageName, packageName)) {
1047 return routerRecord;
Kyunglyul Hyuna0d47412019-07-01 11:14:24 +09001048 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001049 }
1050 return null;
1051 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001052 }
1053
Hyundo Moon56337492020-02-16 16:19:54 +09001054 final class RouterRecord implements IBinder.DeathRecipient {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001055 public final UserRecord mUserRecord;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001056 public final String mPackageName;
Hyundo Moon4140fee2019-11-08 14:47:50 +09001057 public final List<Integer> mSelectRouteSequenceNumbers;
Hyundo Moon56337492020-02-16 16:19:54 +09001058 public final IMediaRouter2 mRouter;
Kyunglyul Hyun86576712019-11-21 18:31:46 +09001059 public final int mUid;
1060 public final int mPid;
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001061 public final boolean mHasConfigureWifiDisplayPermission;
1062 public final boolean mHasModifyAudioRoutingPermission;
Hyundo Moon56337492020-02-16 16:19:54 +09001063 public final int mRouterId;
Kyunglyul Hyunf7d5e042019-11-11 13:56:28 +09001064
Kyunglyul Hyun616096e2020-01-09 16:15:03 +09001065 public RouteDiscoveryPreference mDiscoveryPreference;
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001066 public MediaRoute2Info mSelectedRoute;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001067
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001068 RouterRecord(UserRecord userRecord, IMediaRouter2 router, int uid, int pid,
1069 String packageName, boolean hasConfigureWifiDisplayPermission,
1070 boolean hasModifyAudioRoutingPermission) {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001071 mUserRecord = userRecord;
Kyunglyul Hyun2f43fd62019-09-16 18:47:52 +09001072 mPackageName = packageName;
Hyundo Moon4140fee2019-11-08 14:47:50 +09001073 mSelectRouteSequenceNumbers = new ArrayList<>();
Kyunglyul Hyun616096e2020-01-09 16:15:03 +09001074 mDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
Hyundo Moon56337492020-02-16 16:19:54 +09001075 mRouter = router;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001076 mUid = uid;
1077 mPid = pid;
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001078 mHasConfigureWifiDisplayPermission = hasConfigureWifiDisplayPermission;
1079 mHasModifyAudioRoutingPermission = hasModifyAudioRoutingPermission;
Hyundo Moon56337492020-02-16 16:19:54 +09001080 mRouterId = mNextRouterOrManagerId.getAndIncrement();
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001081 }
1082
1083 public void dispose() {
Hyundo Moon56337492020-02-16 16:19:54 +09001084 mRouter.asBinder().unlinkToDeath(this, 0);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001085 }
1086
1087 @Override
1088 public void binderDied() {
Hyundo Moon56337492020-02-16 16:19:54 +09001089 routerDied(this);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001090 }
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001091 }
1092
1093 final class ManagerRecord implements IBinder.DeathRecipient {
1094 public final UserRecord mUserRecord;
1095 public final IMediaRouter2Manager mManager;
1096 public final int mUid;
1097 public final int mPid;
1098 public final String mPackageName;
Hyundo Moon56337492020-02-16 16:19:54 +09001099 public final int mManagerId;
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001100
1101 ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager,
Sungsoo Lim7065f1b2020-03-24 18:52:42 +09001102 int uid, int pid, String packageName) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001103 mUserRecord = userRecord;
1104 mManager = manager;
1105 mUid = uid;
1106 mPid = pid;
1107 mPackageName = packageName;
Hyundo Moon56337492020-02-16 16:19:54 +09001108 mManagerId = mNextRouterOrManagerId.getAndIncrement();
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001109 }
1110
1111 public void dispose() {
1112 mManager.asBinder().unlinkToDeath(this, 0);
1113 }
1114
1115 @Override
1116 public void binderDied() {
1117 managerDied(this);
1118 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001119
1120 public void dump(PrintWriter pw, String prefix) {
1121 pw.println(prefix + this);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001122 }
1123
1124 @Override
1125 public String toString() {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001126 return "Manager " + mPackageName + " (pid " + mPid + ")";
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001127 }
1128 }
1129
1130 static final class UserHandler extends Handler implements
1131 MediaRoute2ProviderWatcher.Callback,
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001132 MediaRoute2Provider.Callback {
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001133
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001134 private final WeakReference<MediaRouter2ServiceImpl> mServiceRef;
1135 private final UserRecord mUserRecord;
1136 private final MediaRoute2ProviderWatcher mWatcher;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001137
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001138 private final SystemMediaRoute2Provider mSystemProvider;
Sungsoo Limddf140d2020-03-25 08:53:55 +09001139 private final ArrayList<MediaRoute2Provider> mRouteProviders =
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001140 new ArrayList<>();
Hyundo Moon63a05402019-12-19 20:13:56 +09001141
1142 private final List<MediaRoute2ProviderInfo> mLastProviderInfos = new ArrayList<>();
1143 private final CopyOnWriteArrayList<SessionCreationRequest> mSessionCreationRequests =
1144 new CopyOnWriteArrayList<>();
Hyundo Moon56337492020-02-16 16:19:54 +09001145 private final Map<String, RouterRecord> mSessionToRouterMap = new ArrayMap<>();
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001146
1147 private boolean mRunning;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001148
Hyundo Moonaa803752020-06-17 23:02:49 +09001149 // TODO: (In Android S+) Pull out SystemMediaRoute2Provider out of UserHandler.
Hyundo Moone962ed42020-02-16 19:47:41 +09001150 UserHandler(@NonNull MediaRouter2ServiceImpl service, @NonNull UserRecord userRecord) {
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +09001151 super(Looper.getMainLooper(), null, true);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001152 mServiceRef = new WeakReference<>(service);
1153 mUserRecord = userRecord;
Hyundo Moonaa803752020-06-17 23:02:49 +09001154 mSystemProvider = new SystemMediaRoute2Provider(service.mContext);
Sungsoo Limddf140d2020-03-25 08:53:55 +09001155 mRouteProviders.add(mSystemProvider);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001156 mWatcher = new MediaRoute2ProviderWatcher(service.mContext, this,
1157 this, mUserRecord.mUserId);
1158 }
1159
Hyundo Moonaa803752020-06-17 23:02:49 +09001160 void init() {
1161 mSystemProvider.setCallback(this);
1162 }
1163
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001164 private void start() {
1165 if (!mRunning) {
1166 mRunning = true;
1167 mWatcher.start();
1168 }
1169 }
1170
1171 private void stop() {
1172 if (mRunning) {
1173 mRunning = false;
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001174 mWatcher.stop(); // also stops all providers
1175 }
1176 }
1177
1178 @Override
Hyundo Moone962ed42020-02-16 19:47:41 +09001179 public void onAddProviderService(@NonNull MediaRoute2ProviderServiceProxy proxy) {
Hyundo Moon56337492020-02-16 16:19:54 +09001180 proxy.setCallback(this);
Sungsoo Limddf140d2020-03-25 08:53:55 +09001181 mRouteProviders.add(proxy);
Hyundo Moon56337492020-02-16 16:19:54 +09001182 proxy.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001183 }
1184
1185 @Override
Hyundo Moone962ed42020-02-16 19:47:41 +09001186 public void onRemoveProviderService(@NonNull MediaRoute2ProviderServiceProxy proxy) {
Sungsoo Limddf140d2020-03-25 08:53:55 +09001187 mRouteProviders.remove(proxy);
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001188 }
1189
1190 @Override
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +00001191 public void onProviderStateChanged(@NonNull MediaRoute2Provider provider) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001192 sendMessage(PooledLambda.obtainMessage(UserHandler::onProviderStateChangedOnHandler,
1193 this, provider));
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001194 }
1195
Kyunglyul Hyunf7d5e042019-11-11 13:56:28 +09001196 @Override
Hyundo Moon63a05402019-12-19 20:13:56 +09001197 public void onSessionCreated(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001198 long uniqueRequestId, @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001199 sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreatedOnHandler,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001200 this, provider, uniqueRequestId, sessionInfo));
Hyundo Moon63a05402019-12-19 20:13:56 +09001201 }
1202
Hyundo Moon6e30f1b2020-01-13 19:50:27 +09001203 @Override
1204 public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
Hyundo Moonf829e6f2020-01-11 19:31:35 +09001205 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001206 sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionInfoChangedOnHandler,
1207 this, provider, sessionInfo));
1208 }
1209
1210 @Override
Hyundo Moone962ed42020-02-16 19:47:41 +09001211 public void onSessionReleased(@NonNull MediaRoute2Provider provider,
1212 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001213 sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionReleasedOnHandler,
Hyundo Moon0a926572019-12-28 15:01:21 +09001214 this, provider, sessionInfo));
1215 }
1216
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001217 @Override
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001218 public void onRequestFailed(@NonNull MediaRoute2Provider provider, long uniqueRequestId,
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001219 int reason) {
1220 sendMessage(PooledLambda.obtainMessage(UserHandler::onRequestFailedOnHandler,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001221 this, provider, uniqueRequestId, reason));
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001222 }
1223
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001224 @Nullable
Hyundo Moone962ed42020-02-16 19:47:41 +09001225 public RouterRecord findRouterforSessionLocked(@NonNull String uniqueSessionId) {
1226 return mSessionToRouterMap.get(uniqueSessionId);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001227 }
1228
Hyundo Moone962ed42020-02-16 19:47:41 +09001229 private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
Sungsoo Limddf140d2020-03-25 08:53:55 +09001230 int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001231 MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001232 MediaRoute2ProviderInfo prevInfo =
Sungsoo Limddf140d2020-03-25 08:53:55 +09001233 (providerInfoIndex < 0) ? null : mLastProviderInfos.get(providerInfoIndex);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001234 if (Objects.equals(prevInfo, currentInfo)) return;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001235
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001236 List<MediaRoute2Info> addedRoutes = new ArrayList<>();
1237 List<MediaRoute2Info> removedRoutes = new ArrayList<>();
1238 List<MediaRoute2Info> changedRoutes = new ArrayList<>();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001239 if (prevInfo == null) {
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001240 mLastProviderInfos.add(currentInfo);
1241 addedRoutes.addAll(currentInfo.getRoutes());
1242 } else if (currentInfo == null) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001243 mLastProviderInfos.remove(prevInfo);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001244 removedRoutes.addAll(prevInfo.getRoutes());
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001245 } else {
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001246 mLastProviderInfos.set(providerInfoIndex, currentInfo);
1247 final Collection<MediaRoute2Info> prevRoutes = prevInfo.getRoutes();
1248 final Collection<MediaRoute2Info> currentRoutes = currentInfo.getRoutes();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001249
1250 for (MediaRoute2Info route : currentRoutes) {
1251 if (!route.isValid()) {
Hyundo Moon369be952020-06-11 17:37:01 +09001252 Slog.w(TAG, "onProviderStateChangedOnHandler: Ignoring invalid route : "
1253 + route);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001254 continue;
1255 }
Kyunglyul Hyun616096e2020-01-09 16:15:03 +09001256 MediaRoute2Info prevRoute = prevInfo.getRoute(route.getOriginalId());
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001257 if (prevRoute == null) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001258 addedRoutes.add(route);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001259 } else if (!Objects.equals(prevRoute, route)) {
1260 changedRoutes.add(route);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001261 }
1262 }
1263
1264 for (MediaRoute2Info prevRoute : prevInfo.getRoutes()) {
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001265 if (currentInfo.getRoute(prevRoute.getOriginalId()) == null) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001266 removedRoutes.add(prevRoute);
1267 }
1268 }
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001269 }
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001270
Sungsoo Limc27785a2020-03-27 16:57:47 +09001271 List<IMediaRouter2> routersWithModifyAudioRoutingPermission = getRouters(true);
1272 List<IMediaRouter2> routersWithoutModifyAudioRoutingPermission = getRouters(false);
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001273 List<IMediaRouter2Manager> managers = getManagers();
Sungsoo Limc27785a2020-03-27 16:57:47 +09001274 List<MediaRoute2Info> defaultRoute = new ArrayList<>();
1275 defaultRoute.add(mSystemProvider.getDefaultRoute());
1276
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001277 if (addedRoutes.size() > 0) {
Sungsoo Limc27785a2020-03-27 16:57:47 +09001278 notifyRoutesAddedToRouters(routersWithModifyAudioRoutingPermission, addedRoutes);
1279 if (!provider.mIsSystemRouteProvider) {
1280 notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission,
1281 addedRoutes);
1282 } else if (prevInfo == null) {
1283 notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission,
1284 defaultRoute);
1285 } // 'else' is handled as changed routes
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001286 notifyRoutesAddedToManagers(managers, addedRoutes);
1287 }
1288 if (removedRoutes.size() > 0) {
Sungsoo Limc27785a2020-03-27 16:57:47 +09001289 notifyRoutesRemovedToRouters(routersWithModifyAudioRoutingPermission,
1290 removedRoutes);
1291 if (!provider.mIsSystemRouteProvider) {
1292 notifyRoutesRemovedToRouters(routersWithoutModifyAudioRoutingPermission,
1293 removedRoutes);
1294 }
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001295 notifyRoutesRemovedToManagers(managers, removedRoutes);
1296 }
1297 if (changedRoutes.size() > 0) {
Sungsoo Limc27785a2020-03-27 16:57:47 +09001298 notifyRoutesChangedToRouters(routersWithModifyAudioRoutingPermission,
1299 changedRoutes);
1300 if (!provider.mIsSystemRouteProvider) {
1301 notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission,
1302 changedRoutes);
1303 } else if (prevInfo != null) {
1304 notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission,
1305 defaultRoute);
1306 } // 'else' is handled as added routes
Sungsoo Lim82268bd2020-04-02 16:00:22 +09001307 notifyRoutesChangedToManagers(managers, changedRoutes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001308 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001309 }
1310
Sungsoo Limddf140d2020-03-25 08:53:55 +09001311 private int getLastProviderInfoIndex(@NonNull String providerId) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001312 for (int i = 0; i < mLastProviderInfos.size(); i++) {
1313 MediaRoute2ProviderInfo providerInfo = mLastProviderInfos.get(i);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001314 if (TextUtils.equals(providerInfo.getUniqueId(), providerId)) {
1315 return i;
1316 }
1317 }
1318 return -1;
1319 }
1320
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001321 private void getSessionHintsForCreatingSessionOnHandler(long uniqueRequestId,
1322 @NonNull RouterRecord routerRecord, @NonNull ManagerRecord managerRecord,
1323 @NonNull MediaRoute2Info route) {
1324 SessionCreationRequest request =
1325 new SessionCreationRequest(routerRecord, uniqueRequestId, route, managerRecord);
1326 mSessionCreationRequests.add(request);
1327
1328 try {
1329 routerRecord.mRouter.getSessionHintsForCreatingSession(uniqueRequestId, route);
1330 } catch (RemoteException ex) {
Hyundo Moon369be952020-06-11 17:37:01 +09001331 Slog.w(TAG, "getSessionHintsForCreatingSessionOnHandler: "
1332 + "Failed to request. Router probably died.", ex);
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001333 mSessionCreationRequests.remove(request);
1334 notifyRequestFailedToManager(managerRecord.mManager,
1335 toOriginalRequestId(uniqueRequestId), REASON_UNKNOWN_ERROR);
1336 }
1337 }
1338
1339 private void requestCreateSessionWithRouter2OnHandler(long uniqueRequestId,
1340 @NonNull RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001341 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001342
1343 final MediaRoute2Provider provider = findProvider(route.getProviderId());
1344 if (provider == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001345 Slog.w(TAG, "requestCreateSessionWithRouter2OnHandler: Ignoring session "
1346 + "creation request since no provider found for given route=" + route);
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001347 notifySessionCreationFailedToRouter(routerRecord,
1348 toOriginalRequestId(uniqueRequestId));
Hyundo Moon63a05402019-12-19 20:13:56 +09001349 return;
1350 }
1351
Hyundo Moondc79a7a2020-01-16 15:18:33 +09001352 SessionCreationRequest request =
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001353 new SessionCreationRequest(routerRecord, uniqueRequestId, route, null);
Hyundo Moon63a05402019-12-19 20:13:56 +09001354 mSessionCreationRequests.add(request);
1355
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001356 provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001357 route.getOriginalId(), sessionHints);
Hyundo Moon63a05402019-12-19 20:13:56 +09001358 }
1359
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001360 private void requestCreateSessionWithManagerOnHandler(long uniqueRequestId,
1361 @NonNull RouterRecord routerRecord,
1362 @NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
1363 SessionCreationRequest matchingRequest = null;
1364 for (SessionCreationRequest request : mSessionCreationRequests) {
1365 if (request.mUniqueRequestId == uniqueRequestId) {
1366 matchingRequest = request;
1367 break;
1368 }
1369 }
1370 if (matchingRequest == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001371 Slog.w(TAG, "requestCreateSessionWithManagerOnHandler: "
1372 + "Ignoring an unknown session creation request.");
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001373 return;
1374 }
1375
1376 if (!TextUtils.equals(matchingRequest.mRoute.getId(), route.getId())) {
Hyundo Moon369be952020-06-11 17:37:01 +09001377 Slog.w(TAG, "requestCreateSessionWithManagerOnHandler: "
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001378 + "The given route is different from the requested route.");
1379 return;
1380 }
1381
1382 final MediaRoute2Provider provider = findProvider(route.getProviderId());
1383 if (provider == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001384 Slog.w(TAG, "requestCreateSessionWithManagerOnHandler: Ignoring session "
1385 + "creation request since no provider found for given route=" + route);
Kyunglyul Hyunf0eb51b2020-04-14 19:56:16 +09001386 mSessionCreationRequests.remove(matchingRequest);
1387 notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
1388 toOriginalRequestId(uniqueRequestId), REASON_ROUTE_NOT_AVAILABLE);
1389 return;
1390 }
1391
1392 provider.requestCreateSession(uniqueRequestId, routerRecord.mPackageName,
1393 route.getOriginalId(), sessionHints);
1394 }
1395
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001396 // routerRecord can be null if the session is system's or RCN.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001397 private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001398 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +09001399 if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
Hyundo Moon0a926572019-12-28 15:01:21 +09001400 "selecting")) {
1401 return;
1402 }
1403
1404 final String providerId = route.getProviderId();
1405 final MediaRoute2Provider provider = findProvider(providerId);
Hyundo Moon0a926572019-12-28 15:01:21 +09001406 if (provider == null) {
1407 return;
1408 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001409 provider.selectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
1410 route.getOriginalId());
Hyundo Moon0a926572019-12-28 15:01:21 +09001411 }
1412
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001413 // routerRecord can be null if the session is system's or RCN.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001414 private void deselectRouteOnHandler(long uniqueRequestId,
1415 @Nullable RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001416 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +09001417 if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
Hyundo Moon0a926572019-12-28 15:01:21 +09001418 "deselecting")) {
1419 return;
1420 }
1421
1422 final String providerId = route.getProviderId();
1423 final MediaRoute2Provider provider = findProvider(providerId);
Hyundo Moon0a926572019-12-28 15:01:21 +09001424 if (provider == null) {
1425 return;
1426 }
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001427
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001428 provider.deselectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001429 route.getOriginalId());
Hyundo Moon0a926572019-12-28 15:01:21 +09001430 }
1431
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001432 // routerRecord can be null if the session is system's or RCN.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001433 private void transferToRouteOnHandler(long uniqueRequestId,
1434 @Nullable RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001435 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
Hyundo Moon56337492020-02-16 16:19:54 +09001436 if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
Hyundo Moon0a926572019-12-28 15:01:21 +09001437 "transferring to")) {
1438 return;
1439 }
1440
1441 final String providerId = route.getProviderId();
1442 final MediaRoute2Provider provider = findProvider(providerId);
Hyundo Moon0a926572019-12-28 15:01:21 +09001443 if (provider == null) {
1444 return;
1445 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001446 provider.transferToRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001447 route.getOriginalId());
Hyundo Moon0a926572019-12-28 15:01:21 +09001448 }
1449
Kyunglyul Hyuna69280b2020-04-03 15:15:09 +09001450 // routerRecord is null if and only if the session is created without the request, which
1451 // includes the system's session and RCN cases.
Hyundo Moon56337492020-02-16 16:19:54 +09001452 private boolean checkArgumentsForSessionControl(@Nullable RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001453 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route,
1454 @NonNull String description) {
Hyundo Moon0a926572019-12-28 15:01:21 +09001455 final String providerId = route.getProviderId();
1456 final MediaRoute2Provider provider = findProvider(providerId);
1457 if (provider == null) {
1458 Slog.w(TAG, "Ignoring " + description + " route since no provider found for "
1459 + "given route=" + route);
1460 return false;
1461 }
1462
Hyundo Moon56337492020-02-16 16:19:54 +09001463 // Bypass checking router if it's the system session (routerRecord should be null)
Kyunglyul Hyun581fc982020-01-21 16:30:28 +09001464 if (TextUtils.equals(getProviderId(uniqueSessionId), mSystemProvider.getUniqueId())) {
1465 return true;
1466 }
1467
Hyundo Moon56337492020-02-16 16:19:54 +09001468 RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId);
1469 if (matchingRecord != routerRecord) {
1470 Slog.w(TAG, "Ignoring " + description + " route from non-matching router. "
1471 + "packageName=" + routerRecord.mPackageName + " route=" + route);
Hyundo Moon0a926572019-12-28 15:01:21 +09001472 return false;
1473 }
1474
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001475 final String sessionId = getOriginalId(uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001476 if (sessionId == null) {
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001477 Slog.w(TAG, "Failed to get original session id from unique session id. "
Hyundo Moonca9db782020-01-01 18:31:15 +09001478 + "uniqueSessionId=" + uniqueSessionId);
Hyundo Moon0a926572019-12-28 15:01:21 +09001479 return false;
1480 }
1481
1482 return true;
1483 }
1484
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001485 private void setRouteVolumeOnHandler(long uniqueRequestId, @NonNull MediaRoute2Info route,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001486 int volume) {
1487 final MediaRoute2Provider provider = findProvider(route.getProviderId());
1488 if (provider == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001489 Slog.w(TAG, "setRouteVolumeOnHandler: Couldn't find provider for route=" + route);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001490 return;
1491 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001492 provider.setRouteVolume(uniqueRequestId, route.getOriginalId(), volume);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001493 }
1494
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001495 private void setSessionVolumeOnHandler(long uniqueRequestId,
1496 @NonNull String uniqueSessionId, int volume) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001497 final MediaRoute2Provider provider = findProvider(getProviderId(uniqueSessionId));
1498 if (provider == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001499 Slog.w(TAG, "setSessionVolumeOnHandler: Couldn't find provider for session id="
1500 + uniqueSessionId);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001501 return;
1502 }
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001503 provider.setSessionVolume(uniqueRequestId, getOriginalId(uniqueSessionId), volume);
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001504 }
1505
1506 private void releaseSessionOnHandler(long uniqueRequestId,
Hyundo Moon1f066682020-04-13 04:04:15 +09001507 @Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId) {
Hyundo Moon56337492020-02-16 16:19:54 +09001508 final RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId);
1509 if (matchingRecord != routerRecord) {
Hyundo Moon1f066682020-04-13 04:04:15 +09001510 Slog.w(TAG, "Ignoring releasing session from non-matching router. packageName="
1511 + (routerRecord == null ? null : routerRecord.mPackageName)
Hyundo Moonca9db782020-01-01 18:31:15 +09001512 + " uniqueSessionId=" + uniqueSessionId);
1513 return;
1514 }
1515
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001516 final String providerId = getProviderId(uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001517 if (providerId == null) {
1518 Slog.w(TAG, "Ignoring releasing session with invalid unique session ID. "
1519 + "uniqueSessionId=" + uniqueSessionId);
1520 return;
1521 }
1522
Hyundo Moonb26c4b22020-01-08 19:44:43 +09001523 final String sessionId = getOriginalId(uniqueSessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001524 if (sessionId == null) {
1525 Slog.w(TAG, "Ignoring releasing session with invalid unique session ID. "
1526 + "uniqueSessionId=" + uniqueSessionId + " providerId=" + providerId);
1527 return;
1528 }
1529
1530 final MediaRoute2Provider provider = findProvider(providerId);
1531 if (provider == null) {
1532 Slog.w(TAG, "Ignoring releasing session since no provider found for given "
1533 + "providerId=" + providerId);
1534 return;
1535 }
1536
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001537 provider.releaseSession(uniqueRequestId, sessionId);
Hyundo Moonca9db782020-01-01 18:31:15 +09001538 }
1539
1540 private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001541 long uniqueRequestId, @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001542 notifySessionCreatedToManagers(getManagers(),
1543 toOriginalRequestId(uniqueRequestId), sessionInfo);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001544
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001545 if (uniqueRequestId == REQUEST_ID_NONE) {
Hyundo Moon6e30f1b2020-01-13 19:50:27 +09001546 // The session is created without any matching request.
Hyundo Moon6e30f1b2020-01-13 19:50:27 +09001547 return;
1548 }
1549
Hyundo Moon63a05402019-12-19 20:13:56 +09001550 SessionCreationRequest matchingRequest = null;
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +09001551
Hyundo Moon63a05402019-12-19 20:13:56 +09001552 for (SessionCreationRequest request : mSessionCreationRequests) {
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001553 if (request.mUniqueRequestId == uniqueRequestId
Hyundo Moon63a05402019-12-19 20:13:56 +09001554 && TextUtils.equals(
1555 request.mRoute.getProviderId(), provider.getUniqueId())) {
1556 matchingRequest = request;
1557 break;
1558 }
1559 }
1560
1561 if (matchingRequest == null) {
1562 Slog.w(TAG, "Ignoring session creation result for unknown request. "
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001563 + "uniqueRequestId=" + uniqueRequestId + ", sessionInfo=" + sessionInfo);
Hyundo Moon63a05402019-12-19 20:13:56 +09001564 return;
1565 }
1566
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +09001567 mSessionCreationRequests.remove(matchingRequest);
1568
Hyundo Moon63a05402019-12-19 20:13:56 +09001569 if (sessionInfo == null) {
1570 // Failed
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 String originalRouteId = matchingRequest.mRoute.getId();
Hyundo Moon56337492020-02-16 16:19:54 +09001577 RouterRecord routerRecord = matchingRequest.mRouterRecord;
Hyundo Moon0a926572019-12-28 15:01:21 +09001578
Hyundo Moondc79a7a2020-01-16 15:18:33 +09001579 if (!sessionInfo.getSelectedRoutes().contains(originalRouteId)) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001580 Slog.w(TAG, "Created session doesn't match the original request."
1581 + " originalRouteId=" + originalRouteId
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001582 + ", uniqueRequestId=" + uniqueRequestId + ", sessionInfo=" + sessionInfo);
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001583 notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001584 toOriginalRequestId(uniqueRequestId));
Hyundo Moon63a05402019-12-19 20:13:56 +09001585 return;
1586 }
1587
1588 // Succeeded
Kyunglyul Hyun22d4e052020-04-21 10:10:48 +09001589 if (sessionInfo.isSystemSession()
1590 && !matchingRequest.mRouterRecord.mHasModifyAudioRoutingPermission) {
1591 notifySessionCreatedToRouter(matchingRequest.mRouterRecord,
1592 toOriginalRequestId(uniqueRequestId),
1593 mSystemProvider.getDefaultSessionInfo());
1594 } else {
1595 notifySessionCreatedToRouter(matchingRequest.mRouterRecord,
1596 toOriginalRequestId(uniqueRequestId), sessionInfo);
1597 }
Hyundo Moon56337492020-02-16 16:19:54 +09001598 mSessionToRouterMap.put(sessionInfo.getId(), routerRecord);
Hyundo Moon63a05402019-12-19 20:13:56 +09001599 }
1600
Hyundo Moonca9db782020-01-01 18:31:15 +09001601 private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
Hyundo Moonf829e6f2020-01-11 19:31:35 +09001602 @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001603 List<IMediaRouter2Manager> managers = getManagers();
Kyunglyul Hyunfe7b5b12020-06-04 20:17:59 +09001604 notifySessionUpdatedToManagers(managers, sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001605
Hyundo Moon56337492020-02-16 16:19:54 +09001606 // For system provider, notify all routers.
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001607 if (provider == mSystemProvider) {
1608 MediaRouter2ServiceImpl service = mServiceRef.get();
1609 if (service == null) {
1610 return;
1611 }
Sungsoo Limc27785a2020-03-27 16:57:47 +09001612 notifySessionInfoChangedToRouters(getRouters(true), sessionInfo);
1613 notifySessionInfoChangedToRouters(getRouters(false),
1614 mSystemProvider.getDefaultSessionInfo());
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001615 return;
1616 }
1617
Hyundo Moon56337492020-02-16 16:19:54 +09001618 RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
1619 if (routerRecord == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001620 Slog.w(TAG, "onSessionInfoChangedOnHandler: No matching router found for session="
1621 + sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001622 return;
1623 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001624 notifySessionInfoChangedToRouter(routerRecord, sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001625 }
1626
Hyundo Moonca9db782020-01-01 18:31:15 +09001627 private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
Hyundo Moonf829e6f2020-01-11 19:31:35 +09001628 @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001629 List<IMediaRouter2Manager> managers = getManagers();
Kyunglyul Hyunfe7b5b12020-06-04 20:17:59 +09001630 notifySessionReleasedToManagers(managers, sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001631
Hyundo Moon56337492020-02-16 16:19:54 +09001632 RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
1633 if (routerRecord == null) {
Hyundo Moon369be952020-06-11 17:37:01 +09001634 Slog.w(TAG, "onSessionReleasedOnHandler: No matching router found for session="
1635 + sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001636 return;
1637 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001638 notifySessionReleasedToRouter(routerRecord, sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001639 }
1640
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001641 private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001642 long uniqueRequestId, int reason) {
1643 if (handleSessionCreationRequestFailed(provider, uniqueRequestId, reason)) {
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001644 return;
1645 }
1646
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001647 final int requesterId = toRequesterId(uniqueRequestId);
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001648 for (ManagerRecord manager : getManagerRecords()) {
1649 if (manager.mManagerId == requesterId) {
1650 notifyRequestFailedToManager(
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001651 manager.mManager, toOriginalRequestId(uniqueRequestId), reason);
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001652 return;
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001653 }
1654 }
1655
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001656 // Currently, only the manager can get notified of failures.
1657 // TODO: Notify router too when the related callback is introduced.
1658 }
1659
Hyundo Moon0f78fc62020-06-01 14:50:32 +09001660 // TODO(b/157873556): Find a way to prevent providers from notifying error on random reqID.
1661 // Possible solutions can be:
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001662 // 1) Record the other type of requests too (not only session creation request)
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001663 // 2) Throw exception on providers when they try to notify error on
1664 // random uniqueRequestId.
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001665 private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001666 long uniqueRequestId, int reason) {
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001667 // Check whether the failure is about creating a session
1668 SessionCreationRequest matchingRequest = null;
1669 for (SessionCreationRequest request : mSessionCreationRequests) {
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001670 if (request.mUniqueRequestId == uniqueRequestId && TextUtils.equals(
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001671 request.mRoute.getProviderId(), provider.getUniqueId())) {
1672 matchingRequest = request;
1673 break;
1674 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001675 }
1676
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001677 if (matchingRequest == null) {
1678 // The failure is not about creating a session.
1679 return false;
1680 }
1681
1682 mSessionCreationRequests.remove(matchingRequest);
1683
1684 // Notify the requester about the failure.
1685 // The call should be made by either MediaRouter2 or MediaRouter2Manager.
1686 if (matchingRequest.mRequestedManagerRecord == null) {
1687 notifySessionCreationFailedToRouter(
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001688 matchingRequest.mRouterRecord, toOriginalRequestId(uniqueRequestId));
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001689 } else {
1690 notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09001691 toOriginalRequestId(uniqueRequestId), reason);
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001692 }
1693 return true;
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001694 }
1695
1696 private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001697 int requestId, @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001698 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001699 routerRecord.mRouter.notifySessionCreated(requestId, sessionInfo);
Hyundo Moon63a05402019-12-19 20:13:56 +09001700 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001701 Slog.w(TAG, "Failed to notify router of the session creation."
1702 + " Router probably died.", ex);
Hyundo Moon63a05402019-12-19 20:13:56 +09001703 }
1704 }
1705
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001706 private void notifySessionCreationFailedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001707 int requestId) {
Hyundo Moon63a05402019-12-19 20:13:56 +09001708 try {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001709 routerRecord.mRouter.notifySessionCreated(requestId,
1710 /* sessionInfo= */ null);
Hyundo Moon63a05402019-12-19 20:13:56 +09001711 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001712 Slog.w(TAG, "Failed to notify router of the session creation failure."
1713 + " Router probably died.", ex);
Hyundo Moon63a05402019-12-19 20:13:56 +09001714 }
1715 }
1716
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001717 private void notifySessionInfoChangedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001718 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon0a926572019-12-28 15:01:21 +09001719 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001720 routerRecord.mRouter.notifySessionInfoChanged(sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +09001721 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001722 Slog.w(TAG, "Failed to notify router of the session info change."
1723 + " Router probably died.", ex);
Hyundo Moon0a926572019-12-28 15:01:21 +09001724 }
1725 }
1726
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001727 private void notifySessionReleasedToRouter(@NonNull RouterRecord routerRecord,
Hyundo Moone962ed42020-02-16 19:47:41 +09001728 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moonca9db782020-01-01 18:31:15 +09001729 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001730 routerRecord.mRouter.notifySessionReleased(sessionInfo);
Hyundo Moonca9db782020-01-01 18:31:15 +09001731 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001732 Slog.w(TAG, "Failed to notify router of the session release."
1733 + " Router probably died.", ex);
Hyundo Moonca9db782020-01-01 18:31:15 +09001734 }
1735 }
1736
Sungsoo Limc27785a2020-03-27 16:57:47 +09001737 private List<IMediaRouter2> getAllRouters() {
Hyundo Moon56337492020-02-16 16:19:54 +09001738 final List<IMediaRouter2> routers = new ArrayList<>();
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001739 MediaRouter2ServiceImpl service = mServiceRef.get();
1740 if (service == null) {
Hyundo Moon56337492020-02-16 16:19:54 +09001741 return routers;
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001742 }
1743 synchronized (service.mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +09001744 for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
1745 routers.add(routerRecord.mRouter);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001746 }
1747 }
Hyundo Moon56337492020-02-16 16:19:54 +09001748 return routers;
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001749 }
1750
Sungsoo Limc27785a2020-03-27 16:57:47 +09001751 private List<IMediaRouter2> getRouters(boolean hasModifyAudioRoutingPermission) {
1752 final List<IMediaRouter2> routers = new ArrayList<>();
1753 MediaRouter2ServiceImpl service = mServiceRef.get();
1754 if (service == null) {
1755 return routers;
1756 }
1757 synchronized (service.mLock) {
1758 for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
1759 if (hasModifyAudioRoutingPermission
1760 == routerRecord.mHasModifyAudioRoutingPermission) {
1761 routers.add(routerRecord.mRouter);
1762 }
1763 }
1764 }
1765 return routers;
1766 }
1767
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001768 private List<IMediaRouter2Manager> getManagers() {
1769 final List<IMediaRouter2Manager> managers = new ArrayList<>();
1770 MediaRouter2ServiceImpl service = mServiceRef.get();
1771 if (service == null) {
1772 return managers;
1773 }
1774 synchronized (service.mLock) {
1775 for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
1776 managers.add(managerRecord.mManager);
1777 }
1778 }
1779 return managers;
1780 }
1781
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001782 private List<ManagerRecord> getManagerRecords() {
1783 MediaRouter2ServiceImpl service = mServiceRef.get();
1784 if (service == null) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09001785 return Collections.emptyList();
Hyundo Moon7c2059c2020-02-27 19:01:52 +09001786 }
1787 synchronized (service.mLock) {
1788 return new ArrayList<>(mUserRecord.mManagerRecords);
1789 }
1790 }
1791
Hyundo Moonbc633272020-06-04 18:12:29 +09001792 private void notifyRouterRegistered(@NonNull RouterRecord routerRecord) {
1793 List<MediaRoute2Info> currentRoutes = new ArrayList<>();
Hyundo Moonfa248a72020-05-12 20:05:27 +09001794
1795 MediaRoute2ProviderInfo systemProviderInfo = null;
Hyundo Moon63a05402019-12-19 20:13:56 +09001796 for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
Hyundo Moonfa248a72020-05-12 20:05:27 +09001797 // TODO: Create MediaRoute2ProviderInfo#isSystemProvider()
1798 if (TextUtils.equals(providerInfo.getUniqueId(), mSystemProvider.getUniqueId())) {
1799 // Adding routes from system provider will be handled below, so skip it here.
1800 systemProviderInfo = providerInfo;
1801 continue;
1802 }
Hyundo Moonbc633272020-06-04 18:12:29 +09001803 currentRoutes.addAll(providerInfo.getRoutes());
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001804 }
Hyundo Moonfa248a72020-05-12 20:05:27 +09001805
Hyundo Moonbc633272020-06-04 18:12:29 +09001806 RoutingSessionInfo currentSystemSessionInfo;
Hyundo Moonfa248a72020-05-12 20:05:27 +09001807 if (routerRecord.mHasModifyAudioRoutingPermission) {
1808 if (systemProviderInfo != null) {
Hyundo Moonbc633272020-06-04 18:12:29 +09001809 currentRoutes.addAll(systemProviderInfo.getRoutes());
Hyundo Moonfa248a72020-05-12 20:05:27 +09001810 } else {
1811 // This shouldn't happen.
Hyundo Moon369be952020-06-11 17:37:01 +09001812 Slog.wtf(TAG, "System route provider not found.");
Hyundo Moonfa248a72020-05-12 20:05:27 +09001813 }
Hyundo Moonbc633272020-06-04 18:12:29 +09001814 currentSystemSessionInfo = mSystemProvider.getSessionInfos().get(0);
Hyundo Moonfa248a72020-05-12 20:05:27 +09001815 } else {
Hyundo Moonbc633272020-06-04 18:12:29 +09001816 currentRoutes.add(mSystemProvider.getDefaultRoute());
1817 currentSystemSessionInfo = mSystemProvider.getDefaultSessionInfo();
Hyundo Moonfa248a72020-05-12 20:05:27 +09001818 }
1819
Hyundo Moonbc633272020-06-04 18:12:29 +09001820 if (currentRoutes.size() == 0) {
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001821 return;
1822 }
Hyundo Moonbc633272020-06-04 18:12:29 +09001823
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001824 try {
Hyundo Moonbc633272020-06-04 18:12:29 +09001825 routerRecord.mRouter.notifyRouterRegistered(
1826 currentRoutes, currentSystemSessionInfo);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001827 } catch (RemoteException ex) {
Hyundo Moonbc633272020-06-04 18:12:29 +09001828 Slog.w(TAG, "Failed to notify router registered. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001829 }
1830 }
1831
Hyundo Moone962ed42020-02-16 19:47:41 +09001832 private void notifyRoutesAddedToRouters(@NonNull List<IMediaRouter2> routers,
1833 @NonNull List<MediaRoute2Info> routes) {
Hyundo Moon56337492020-02-16 16:19:54 +09001834 for (IMediaRouter2 router : routers) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001835 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001836 router.notifyRoutesAdded(routes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001837 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001838 Slog.w(TAG, "Failed to notify routes added. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001839 }
1840 }
1841 }
1842
Hyundo Moone962ed42020-02-16 19:47:41 +09001843 private void notifyRoutesRemovedToRouters(@NonNull List<IMediaRouter2> routers,
1844 @NonNull List<MediaRoute2Info> routes) {
Hyundo Moon56337492020-02-16 16:19:54 +09001845 for (IMediaRouter2 router : routers) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001846 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001847 router.notifyRoutesRemoved(routes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001848 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001849 Slog.w(TAG, "Failed to notify routes removed. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001850 }
1851 }
1852 }
1853
Hyundo Moone962ed42020-02-16 19:47:41 +09001854 private void notifyRoutesChangedToRouters(@NonNull List<IMediaRouter2> routers,
1855 @NonNull List<MediaRoute2Info> routes) {
Hyundo Moon56337492020-02-16 16:19:54 +09001856 for (IMediaRouter2 router : routers) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001857 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001858 router.notifyRoutesChanged(routes);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001859 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001860 Slog.w(TAG, "Failed to notify routes changed. Router probably died.", ex);
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09001861 }
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001862 }
1863 }
1864
Hyundo Moone962ed42020-02-16 19:47:41 +09001865 private void notifySessionInfoChangedToRouters(@NonNull List<IMediaRouter2> routers,
1866 @NonNull RoutingSessionInfo sessionInfo) {
Hyundo Moon56337492020-02-16 16:19:54 +09001867 for (IMediaRouter2 router : routers) {
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001868 try {
Hyundo Moon56337492020-02-16 16:19:54 +09001869 router.notifySessionInfoChanged(sessionInfo);
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001870 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001871 Slog.w(TAG, "Failed to notify session info changed. Router probably died.", ex);
Hyundo Moon67c41fd2020-01-17 14:22:42 +09001872 }
1873 }
1874 }
1875
Hyundo Moone962ed42020-02-16 19:47:41 +09001876 private void notifyRoutesToManager(@NonNull IMediaRouter2Manager manager) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001877 List<MediaRoute2Info> routes = new ArrayList<>();
Hyundo Moon63a05402019-12-19 20:13:56 +09001878 for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001879 routes.addAll(providerInfo.getRoutes());
1880 }
1881 if (routes.size() == 0) {
1882 return;
1883 }
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001884 try {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001885 manager.notifyRoutesAdded(routes);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +09001886 } catch (RemoteException ex) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001887 Slog.w(TAG, "Failed to notify all routes. Manager probably died.", ex);
1888 }
1889 }
1890
Hyundo Moone962ed42020-02-16 19:47:41 +09001891 private void notifyRoutesAddedToManagers(@NonNull List<IMediaRouter2Manager> managers,
1892 @NonNull List<MediaRoute2Info> routes) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001893 for (IMediaRouter2Manager manager : managers) {
1894 try {
1895 manager.notifyRoutesAdded(routes);
1896 } catch (RemoteException ex) {
1897 Slog.w(TAG, "Failed to notify routes added. Manager probably died.", ex);
1898 }
1899 }
1900 }
1901
Hyundo Moone962ed42020-02-16 19:47:41 +09001902 private void notifyRoutesRemovedToManagers(@NonNull List<IMediaRouter2Manager> managers,
1903 @NonNull List<MediaRoute2Info> routes) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001904 for (IMediaRouter2Manager manager : managers) {
1905 try {
1906 manager.notifyRoutesRemoved(routes);
1907 } catch (RemoteException ex) {
1908 Slog.w(TAG, "Failed to notify routes removed. Manager probably died.", ex);
1909 }
1910 }
1911 }
1912
Hyundo Moone962ed42020-02-16 19:47:41 +09001913 private void notifyRoutesChangedToManagers(@NonNull List<IMediaRouter2Manager> managers,
1914 @NonNull List<MediaRoute2Info> routes) {
Kyunglyul Hyun4ed68752019-11-04 16:05:34 +09001915 for (IMediaRouter2Manager manager : managers) {
1916 try {
1917 manager.notifyRoutesChanged(routes);
1918 } catch (RemoteException ex) {
1919 Slog.w(TAG, "Failed to notify routes changed. Manager probably died.", ex);
1920 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001921 }
1922 }
1923
Hyundo Moone962ed42020-02-16 19:47:41 +09001924 private void notifySessionCreatedToManagers(@NonNull List<IMediaRouter2Manager> managers,
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001925 int requestId, @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001926 for (IMediaRouter2Manager manager : managers) {
1927 try {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001928 manager.notifySessionCreated(requestId, sessionInfo);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001929 } catch (RemoteException ex) {
1930 Slog.w(TAG, "notifySessionCreatedToManagers: "
1931 + "failed to notify. Manager probably died.", ex);
1932 }
1933 }
1934 }
1935
Kyunglyul Hyunfe7b5b12020-06-04 20:17:59 +09001936 private void notifySessionUpdatedToManagers(
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001937 @NonNull List<IMediaRouter2Manager> managers,
1938 @NonNull RoutingSessionInfo sessionInfo) {
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001939 for (IMediaRouter2Manager manager : managers) {
1940 try {
Kyunglyul Hyunf064dcae2020-03-06 22:59:14 +09001941 manager.notifySessionUpdated(sessionInfo);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001942 } catch (RemoteException ex) {
Kyunglyul Hyunfe7b5b12020-06-04 20:17:59 +09001943 Slog.w(TAG, "notifySessionUpdatedToManagers: "
1944 + "Failed to notify. Manager probably died.", ex);
1945 }
1946 }
1947 }
1948
1949 private void notifySessionReleasedToManagers(
1950 @NonNull List<IMediaRouter2Manager> managers,
1951 @NonNull RoutingSessionInfo sessionInfo) {
1952 for (IMediaRouter2Manager manager : managers) {
1953 try {
1954 manager.notifySessionReleased(sessionInfo);
1955 } catch (RemoteException ex) {
1956 Slog.w(TAG, "notifySessionReleasedToManagers: "
1957 + "Failed to notify. Manager probably died.", ex);
Kyunglyul Hyunc6583832020-01-17 11:11:46 +00001958 }
1959 }
1960 }
1961
Hyundo Moon38d06df2020-05-20 14:24:06 +09001962 private void notifyPreferredFeaturesChangedToManager(@NonNull RouterRecord routerRecord,
1963 @NonNull IMediaRouter2Manager manager) {
1964 try {
1965 manager.notifyPreferredFeaturesChanged(routerRecord.mPackageName,
1966 routerRecord.mDiscoveryPreference.getPreferredFeatures());
1967 } catch (RemoteException ex) {
1968 Slog.w(TAG, "Failed to notify preferred features changed."
1969 + " Manager probably died.", ex);
1970 }
1971 }
1972
Hyundo Moonac9df102020-06-12 19:36:10 +09001973 private void notifyPreferredFeaturesChangedToManagers(@NonNull String routerPackageName,
1974 @Nullable List<String> preferredFeatures) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001975 MediaRouter2ServiceImpl service = mServiceRef.get();
1976 if (service == null) {
1977 return;
1978 }
1979 List<IMediaRouter2Manager> managers = new ArrayList<>();
1980 synchronized (service.mLock) {
Hyundo Moon7d3ab332019-10-16 11:09:56 +09001981 for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
1982 managers.add(managerRecord.mManager);
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001983 }
1984 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001985 for (IMediaRouter2Manager manager : managers) {
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001986 try {
Hyundo Moonac9df102020-06-12 19:36:10 +09001987 manager.notifyPreferredFeaturesChanged(routerPackageName, preferredFeatures);
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001988 } catch (RemoteException ex) {
Hyundo Moon56337492020-02-16 16:19:54 +09001989 Slog.w(TAG, "Failed to notify preferred features changed."
1990 + " Manager probably died.", ex);
Kyunglyul Hyundafac542019-04-29 18:07:21 +09001991 }
1992 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09001993 }
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09001994
Hyundo Moon0fa60e82020-02-14 11:44:45 +09001995 private void notifyRequestFailedToManager(@NonNull IMediaRouter2Manager manager,
1996 int requestId, int reason) {
1997 try {
1998 manager.notifyRequestFailed(requestId, reason);
1999 } catch (RemoteException ex) {
2000 Slog.w(TAG, "Failed to notify manager of the request failure."
2001 + " Manager probably died.", ex);
2002 }
2003 }
2004
2005 private void updateDiscoveryPreferenceOnHandler() {
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09002006 MediaRouter2ServiceImpl service = mServiceRef.get();
2007 if (service == null) {
2008 return;
2009 }
2010 List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>();
2011 synchronized (service.mLock) {
Hyundo Moon56337492020-02-16 16:19:54 +09002012 for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
2013 discoveryPreferences.add(routerRecord.mDiscoveryPreference);
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09002014 }
2015 mUserRecord.mCompositeDiscoveryPreference =
2016 new RouteDiscoveryPreference.Builder(discoveryPreferences)
2017 .build();
2018 }
Sungsoo Limddf140d2020-03-25 08:53:55 +09002019 for (MediaRoute2Provider provider : mRouteProviders) {
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +09002020 provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
2021 }
2022 }
2023
Hyundo Moone962ed42020-02-16 19:47:41 +09002024 private MediaRoute2Provider findProvider(@Nullable String providerId) {
Sungsoo Limddf140d2020-03-25 08:53:55 +09002025 for (MediaRoute2Provider provider : mRouteProviders) {
Kyunglyul Hyun7af73012019-10-11 20:01:30 +09002026 if (TextUtils.equals(provider.getUniqueId(), providerId)) {
Kyunglyul Hyun13bc1052019-05-31 17:00:36 +09002027 return provider;
2028 }
2029 }
2030 return null;
2031 }
Hyundo Moon63a05402019-12-19 20:13:56 +09002032
2033 final class SessionCreationRequest {
Hyundo Moon56337492020-02-16 16:19:54 +09002034 public final RouterRecord mRouterRecord;
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09002035 public final long mUniqueRequestId;
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09002036 public final MediaRoute2Info mRoute;
2037 public final ManagerRecord mRequestedManagerRecord;
Hyundo Moon63a05402019-12-19 20:13:56 +09002038
Hyundo Moon7c2059c2020-02-27 19:01:52 +09002039 // requestedManagerRecord is not null only when the request is made by manager.
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09002040 SessionCreationRequest(@NonNull RouterRecord routerRecord, long uniqueRequestId,
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09002041 @NonNull MediaRoute2Info route,
2042 @Nullable ManagerRecord requestedManagerRecord) {
Hyundo Moon56337492020-02-16 16:19:54 +09002043 mRouterRecord = routerRecord;
Kyunglyul Hyun3b27d9d2020-03-31 19:56:10 +09002044 mUniqueRequestId = uniqueRequestId;
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +09002045 mRoute = route;
2046 mRequestedManagerRecord = requestedManagerRecord;
Hyundo Moon63a05402019-12-19 20:13:56 +09002047 }
2048 }
Kyunglyul Hyun5aa60822019-04-18 16:57:53 +09002049 }
2050}