169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown/* 269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Copyright (C) 2013 The Android Open Source Project 369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * you may not use this file except in compliance with the License. 669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * You may obtain a copy of the License at 769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * 1069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Unless required by applicable law or agreed to in writing, software 1169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 1269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * See the License for the specific language governing permissions and 1469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * limitations under the License. 1569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 1669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 1769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownpackage com.android.server.media; 1869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 19fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkeyimport com.android.internal.util.DumpUtils; 2069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport com.android.server.Watchdog; 2169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 2269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.Manifest; 2369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.app.ActivityManager; 2469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.BroadcastReceiver; 2569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.Context; 2669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.Intent; 2769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.IntentFilter; 2869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.pm.PackageManager; 2969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.AudioSystem; 3069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.IMediaRouterClient; 3169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.IMediaRouterService; 3269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.MediaRouter; 3369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.MediaRouterClientState; 3469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.RemoteDisplayState; 3569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.RemoteDisplayState.RemoteDisplayInfo; 3669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Binder; 3769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Handler; 3869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.IBinder; 3969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Looper; 4069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Message; 4169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.RemoteException; 4269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.SystemClock; 4369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.text.TextUtils; 4469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.ArrayMap; 4569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.Log; 4669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.Slog; 4769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.SparseArray; 4869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.TimeUtils; 4969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 5069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.io.FileDescriptor; 5169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.io.PrintWriter; 5269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.util.ArrayList; 5369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.util.Collections; 5469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.util.List; 55e6585b32ea586743258a5457e2184ffc087f2d2fKenny Rootimport java.util.Objects; 5669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 5769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown/** 5869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Provides a mechanism for discovering media routes and manages media playback 5969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * behalf of applications. 6069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * <p> 6169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Currently supports discovering remote displays via remote display provider 6269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * services that have been registered by applications. 6369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p> 6469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 6569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownpublic final class MediaRouterService extends IMediaRouterService.Stub 6669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown implements Watchdog.Monitor { 6769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final String TAG = "MediaRouterService"; 6869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 6969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 7069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 7169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Timeout in milliseconds for a selected route to transition from a 7269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * disconnected state to a connecting state. If we don't observe any 7369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * progress within this interval, then we will give up and unselect the route. 7469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 7569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final long CONNECTING_TIMEOUT = 5000; 7669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 7769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 7869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Timeout in milliseconds for a selected route to transition from a 7969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * connecting state to a connected state. If we don't observe any 8069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * progress within this interval, then we will give up and unselect the route. 8169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 8269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final long CONNECTED_TIMEOUT = 60000; 8369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 8469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final Context mContext; 8569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 8669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // State guarded by mLock. 8769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final Object mLock = new Object(); 8869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>(); 8969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = 9069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new ArrayMap<IBinder, ClientRecord>(); 9169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int mCurrentUserId = -1; 9269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public MediaRouterService(Context context) { 9469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mContext = context; 9569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Watchdog.getInstance().addMonitor(this); 9669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 9769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 9869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void systemRunning() { 9969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); 10069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mContext.registerReceiver(new BroadcastReceiver() { 10169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 10269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onReceive(Context context, Intent intent) { 10369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) { 10469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switchUser(); 10569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 10669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 10769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }, filter); 10869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 10969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switchUser(); 11069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 11169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 11269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 11369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void monitor() { 11469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { /* check for deadlock */ } 11569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 11669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 11769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 11869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 11969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void registerClientAsUser(IMediaRouterClient client, String packageName, int userId) { 12069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 12169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 12269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 12369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 12469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int uid = Binder.getCallingUid(); 12569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!validatePackageName(uid, packageName)) { 12669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new SecurityException("packageName must match the calling uid"); 12769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 12869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 12969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int pid = Binder.getCallingPid(); 13069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, 13169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown false /*allowAll*/, true /*requireFull*/, "registerClientAsUser", packageName); 132af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final boolean trusted = mContext.checkCallingOrSelfPermission( 133af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) == 134af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown PackageManager.PERMISSION_GRANTED; 13569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 13669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 13769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 138af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown registerClientLocked(client, pid, packageName, resolvedUserId, trusted); 13969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 14069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 14169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 14269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 14369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 14469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 14569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 14669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 14769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void unregisterClient(IMediaRouterClient client) { 14869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 14969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 15069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 15169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 15269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 15369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 15469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 15569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unregisterClientLocked(client, false); 15669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 15769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 15869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 15969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 16069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 16169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 16269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 16369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 16469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public MediaRouterClientState getState(IMediaRouterClient client) { 16569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 16669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 16769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 16869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 16969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 17069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 17169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 17269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return getStateLocked(client); 17369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 17469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 17569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 17669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 17769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 17869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 17969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 18069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 18169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void setDiscoveryRequest(IMediaRouterClient client, 18269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes, boolean activeScan) { 18369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 18469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 18569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 18669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 18769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 18869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 18969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 19069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown setDiscoveryRequestLocked(client, routeTypes, activeScan); 19169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 19269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 19369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 19469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 19569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 19669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 19769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 19869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // A null routeId means that the client wants to unselect its current route. 19969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // The explicit flag indicates whether the change was explicitly requested by the 20069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // user or the application which may cause changes to propagate out to the rest 20169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // of the system. Should be false when the change is in response to a new globally 20269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // selected route or a default selection. 20369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 20469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit) { 20569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 20669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 20769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 20869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 20969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 21069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 21169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 21269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown setSelectedRouteLocked(client, routeId, explicit); 21369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 21469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 21569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 21669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 21769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 21869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 21969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 22069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 22169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void requestSetVolume(IMediaRouterClient client, String routeId, int volume) { 22269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 22369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 22469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 22569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeId == null) { 22669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("routeId must not be null"); 22769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 22869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 22969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 23069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 23169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 23269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown requestSetVolumeLocked(client, routeId, volume); 23369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 23469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 23569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 23669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 23769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 23869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 23969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 24069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 24169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction) { 24269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 24369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 24469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 24569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeId == null) { 24669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("routeId must not be null"); 24769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 24869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 24969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 25069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 25169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 25269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown requestUpdateVolumeLocked(client, routeId, direction); 25369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 25469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 25569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 25669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 25769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 25869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 25969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 26069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 26169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 262fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkey if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 26369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 26469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println("MEDIA ROUTER SERVICE (dumpsys media_router)"); 26569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(); 26669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println("Global state"); 26769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(" mCurrentUserId=" + mCurrentUserId); 26869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 26969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 27069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mUserRecords.size(); 27169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 27269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord userRecord = mUserRecords.valueAt(i); 27369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(); 27469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord.dump(pw, ""); 27569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 27969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void switchUser() { 28069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 28169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int userId = ActivityManager.getCurrentUser(); 28269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mCurrentUserId != userId) { 28369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int oldUserId = mCurrentUserId; 28469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCurrentUserId = userId; // do this first 28569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 28669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord oldUser = mUserRecords.get(oldUserId); 28769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (oldUser != null) { 28869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown oldUser.mHandler.sendEmptyMessage(UserHandler.MSG_STOP); 28969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown disposeUserIfNeededLocked(oldUser); // since no longer current user 29069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 29269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord newUser = mUserRecords.get(userId); 29369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (newUser != null) { 29469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newUser.mHandler.sendEmptyMessage(UserHandler.MSG_START); 29569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 30069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void clientDied(ClientRecord clientRecord) { 30169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 30269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unregisterClientLocked(clientRecord.mClient, true); 30369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 30469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 30569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 30669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void registerClientLocked(IMediaRouterClient client, 307af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown int pid, String packageName, int userId, boolean trusted) { 30869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IBinder binder = client.asBinder(); 30969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(binder); 31069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord == null) { 31169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean newUser = false; 31269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord userRecord = mUserRecords.get(userId); 31369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (userRecord == null) { 31469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord = new UserRecord(userId); 31569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newUser = true; 31669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 317af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown clientRecord = new ClientRecord(userRecord, client, pid, packageName, trusted); 31869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 31969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown binder.linkToDeath(clientRecord, 0); 32069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 32169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new RuntimeException("Media router client died prematurely.", ex); 32269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 32369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 32469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (newUser) { 32569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserRecords.put(userId, userRecord); 32669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown initializeUserLocked(userRecord); 32769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 32869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 32969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord.mClientRecords.add(clientRecord); 33069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mAllClientRecords.put(binder, clientRecord); 33169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown initializeClientLocked(clientRecord); 33269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 33369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 33469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 33569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void unregisterClientLocked(IMediaRouterClient client, boolean died) { 33669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder()); 33769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 33869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord userRecord = clientRecord.mUserRecord; 33969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord.mClientRecords.remove(clientRecord); 34069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown disposeClientLocked(clientRecord, died); 34169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown disposeUserIfNeededLocked(userRecord); // since client removed from user 34269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 34369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 34469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 34569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private MediaRouterClientState getStateLocked(IMediaRouterClient client) { 34669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); 34769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 348af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown return clientRecord.getState(); 34969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 35169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 35369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void setDiscoveryRequestLocked(IMediaRouterClient client, 35469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes, boolean activeScan) { 35569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IBinder binder = client.asBinder(); 35669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(binder); 35769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 358af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only let the system discover remote display routes for now. 359af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (!clientRecord.mTrusted) { 360af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown routeTypes &= ~MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY; 361af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 362af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 36369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord.mRouteTypes != routeTypes 36469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || clientRecord.mActiveScan != activeScan) { 36569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 36669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Set discovery request, routeTypes=0x" 36769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + Integer.toHexString(routeTypes) + ", activeScan=" + activeScan); 36869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mRouteTypes = routeTypes; 37069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mActiveScan = activeScan; 37169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.sendEmptyMessage( 37269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_UPDATE_DISCOVERY_REQUEST); 37369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void setSelectedRouteLocked(IMediaRouterClient client, 37869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String routeId, boolean explicit) { 37969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); 38069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 38169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String oldRouteId = clientRecord.mSelectedRouteId; 382e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(routeId, oldRouteId)) { 38369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 38469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Set selected route, routeId=" + routeId 38569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + ", oldRouteId=" + oldRouteId 38669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + ", explicit=" + explicit); 38769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 38969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mSelectedRouteId = routeId; 39069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (explicit) { 391af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Any app can disconnect from the globally selected route. 39269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (oldRouteId != null) { 39369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.obtainMessage( 39469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_UNSELECT_ROUTE, oldRouteId).sendToTarget(); 39569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 396af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Only let the system connect to new global routes for now. 397af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // A similar check exists in the display manager for wifi display. 398af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (routeId != null && clientRecord.mTrusted) { 39969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.obtainMessage( 40069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget(); 40169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 40769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void requestSetVolumeLocked(IMediaRouterClient client, 40869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String routeId, int volume) { 40969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IBinder binder = client.asBinder(); 41069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(binder); 41169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 41269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.obtainMessage( 41369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_REQUEST_SET_VOLUME, volume, 0, routeId).sendToTarget(); 41469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 41769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void requestUpdateVolumeLocked(IMediaRouterClient client, 41869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String routeId, int direction) { 41969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IBinder binder = client.asBinder(); 42069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(binder); 42169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 42269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.obtainMessage( 42369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_REQUEST_UPDATE_VOLUME, direction, 0, routeId).sendToTarget(); 42469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 42769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void initializeUserLocked(UserRecord userRecord) { 42869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 42969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, userRecord + ": Initialized"); 43069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (userRecord.mUserId == mCurrentUserId) { 43269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START); 43369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 43569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 43669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void disposeUserIfNeededLocked(UserRecord userRecord) { 43769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // If there are no records left and the user is no longer current then go ahead 43869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // and purge the user record and all of its associated state. If the user is current 43969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // then leave it alone since we might be connected to a route or want to query 44069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // the same route information again soon. 44169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (userRecord.mUserId != mCurrentUserId 44269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && userRecord.mClientRecords.isEmpty()) { 44369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 44469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, userRecord + ": Disposed"); 44569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserRecords.remove(userRecord.mUserId); 44769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Note: User already stopped (by switchUser) so no need to send stop message here. 44869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 45169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void initializeClientLocked(ClientRecord clientRecord) { 45269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 45369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Registered"); 45469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 45769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void disposeClientLocked(ClientRecord clientRecord, boolean died) { 45869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 45969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (died) { 46069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Died!"); 46169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 46269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Unregistered"); 46369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord.mRouteTypes != 0 || clientRecord.mActiveScan) { 46669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.sendEmptyMessage( 46769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_UPDATE_DISCOVERY_REQUEST); 46869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.dispose(); 47069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 47269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private boolean validatePackageName(int uid, String packageName) { 47369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (packageName != null) { 47469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); 47569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (packageNames != null) { 47669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (String n : packageNames) { 47769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (n.equals(packageName)) { 47869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return true; 47969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return false; 48469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 48569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 48669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 48769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Information about a particular client of the media router. 48869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * The contents of this object is guarded by mLock. 48969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 49069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class ClientRecord implements DeathRecipient { 49169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final UserRecord mUserRecord; 49269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final IMediaRouterClient mClient; 49369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final int mPid; 49469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final String mPackageName; 495af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown public final boolean mTrusted; 49669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 49769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public int mRouteTypes; 49869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean mActiveScan; 49969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String mSelectedRouteId; 50069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 50169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public ClientRecord(UserRecord userRecord, IMediaRouterClient client, 502af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown int pid, String packageName, boolean trusted) { 50369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserRecord = userRecord; 50469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = client; 50569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mPid = pid; 50669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mPackageName = packageName; 507af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown mTrusted = trusted; 50869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 50969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 51069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dispose() { 51169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient.asBinder().unlinkToDeath(this, 0); 51269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 51469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 51569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void binderDied() { 51669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientDied(this); 51769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 519af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown MediaRouterClientState getState() { 520af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown return mTrusted ? mUserRecord.mTrustedState : mUserRecord.mUntrustedState; 521af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 522af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 52369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(PrintWriter pw, String prefix) { 52469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + this); 52569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 52669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 527af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown pw.println(indent + "mTrusted=" + mTrusted); 52869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mRouteTypes=0x" + Integer.toHexString(mRouteTypes)); 52969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mActiveScan=" + mActiveScan); 53069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mSelectedRouteId=" + mSelectedRouteId); 53169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 53369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 53469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String toString() { 53569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return "Client " + mPackageName + " (pid " + mPid + ")"; 53669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 53869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 53969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 54069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Information about a particular user. 54169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * The contents of this object is guarded by mLock. 54269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 54369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class UserRecord { 54469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final int mUserId; 54569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final ArrayList<ClientRecord> mClientRecords = new ArrayList<ClientRecord>(); 54669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final UserHandler mHandler; 547af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown public MediaRouterClientState mTrustedState; 548af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown public MediaRouterClientState mUntrustedState; 54969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 55069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public UserRecord(int userId) { 55169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserId = userId; 55269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler = new UserHandler(MediaRouterService.this, this); 55369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 55569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(final PrintWriter pw, String prefix) { 55669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + this); 55769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 55869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 55969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int clientCount = mClientRecords.size(); 56069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientCount != 0) { 56169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < clientCount; i++) { 56269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientRecords.get(i).dump(pw, indent); 56369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 56569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "<no clients>"); 56669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 568af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown pw.println(indent + "State"); 569af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown pw.println(indent + "mTrustedState=" + mTrustedState); 570af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown pw.println(indent + "mUntrustedState=" + mUntrustedState); 571af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 57269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mHandler.runWithScissors(new Runnable() { 57369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 57469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void run() { 57569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.dump(pw, indent); 57669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 57769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }, 1000)) { 57869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "<could not dump handler state>"); 57969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 58269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 58369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String toString() { 58469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return "User " + mUserId; 58569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 58769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 58869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 58969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Media router handler 59069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * <p> 59169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Since remote display providers are designed to be single-threaded by nature, 59269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * this class encapsulates all of the associated functionality and exports state 59369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * to the service as it evolves. 59469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p><p> 59569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * One important task of this class is to keep track of the current globally selected 59669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * route id for certain routes that have global effects, such as remote displays. 59769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Global route selections override local selections made within apps. The change 59869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * is propagated to all apps so that they are all in sync. Synchronization works 59969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * both ways. Whenever the globally selected route is explicitly unselected by any 60069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * app, then it becomes unselected globally and all apps are informed. 60169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p><p> 60269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This class is currently hardcoded to work with remote display providers but 60369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * it is intended to be eventually extended to support more general route providers 60469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * similar to the support library media router. 60569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p> 60669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 60769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final class UserHandler extends Handler 60869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown implements RemoteDisplayProviderWatcher.Callback, 60969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayProviderProxy.Callback { 61069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_START = 1; 61169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_STOP = 2; 61269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_UPDATE_DISCOVERY_REQUEST = 3; 61369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_SELECT_ROUTE = 4; 61469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_UNSELECT_ROUTE = 5; 61569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_REQUEST_SET_VOLUME = 6; 61669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_REQUEST_UPDATE_VOLUME = 7; 61769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final int MSG_UPDATE_CLIENT_STATE = 8; 61869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final int MSG_CONNECTION_TIMED_OUT = 9; 61969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 62069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1; 62139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private static final int TIMEOUT_REASON_CONNECTION_LOST = 2; 62239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTING = 3; 62339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTED = 4; 62439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 62539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // The relative order of these constants is important and expresses progress 62639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // through the process of connecting to a route. 62739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private static final int PHASE_NOT_AVAILABLE = -1; 62839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private static final int PHASE_NOT_CONNECTED = 0; 62939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private static final int PHASE_CONNECTING = 1; 63039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private static final int PHASE_CONNECTED = 2; 63169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 63269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final MediaRouterService mService; 63369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final UserRecord mUserRecord; 63469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final RemoteDisplayProviderWatcher mWatcher; 63569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ArrayList<ProviderRecord> mProviderRecords = 63669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new ArrayList<ProviderRecord>(); 63769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ArrayList<IMediaRouterClient> mTempClients = 63869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new ArrayList<IMediaRouterClient>(); 63969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 64069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private boolean mRunning; 64169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int mDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE; 64269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private RouteRecord mGloballySelectedRouteRecord; 64339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private int mConnectionPhase = PHASE_NOT_AVAILABLE; 64469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int mConnectionTimeoutReason; 64569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private long mConnectionTimeoutStartTime; 64669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private boolean mClientStateUpdateScheduled; 64769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 64869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public UserHandler(MediaRouterService service, UserRecord userRecord) { 64969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown super(Looper.getMainLooper(), null, true); 65069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mService = service; 65169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserRecord = userRecord; 65269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mWatcher = new RemoteDisplayProviderWatcher(service.mContext, this, 65369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown this, mUserRecord.mUserId); 65469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 65569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 65669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 65769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void handleMessage(Message msg) { 65869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (msg.what) { 65969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_START: { 66069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown start(); 66169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 66269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 66369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_STOP: { 66469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown stop(); 66569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 66669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 66769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_UPDATE_DISCOVERY_REQUEST: { 66869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateDiscoveryRequest(); 66969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 67069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 67169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_SELECT_ROUTE: { 67269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRoute((String)msg.obj); 67369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 67469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 67569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_UNSELECT_ROUTE: { 67669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectRoute((String)msg.obj); 67769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 67869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 67969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_REQUEST_SET_VOLUME: { 68069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown requestSetVolume((String)msg.obj, msg.arg1); 68169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 68269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 68369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_REQUEST_UPDATE_VOLUME: { 68469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown requestUpdateVolume((String)msg.obj, msg.arg1); 68569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 68669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 68769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_UPDATE_CLIENT_STATE: { 68869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 68969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 69069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 69169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_CONNECTION_TIMED_OUT: { 69269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown connectionTimedOut(); 69369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 69469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 69569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 69669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 69769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 69869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(PrintWriter pw, String prefix) { 69969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + "Handler"); 70069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 70169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 70269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mRunning=" + mRunning); 70369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mDiscoveryMode=" + mDiscoveryMode); 70469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mGloballySelectedRouteRecord=" + mGloballySelectedRouteRecord); 70539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown pw.println(indent + "mConnectionPhase=" + mConnectionPhase); 70669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mConnectionTimeoutReason=" + mConnectionTimeoutReason); 70769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mConnectionTimeoutStartTime=" + (mConnectionTimeoutReason != 0 ? 70869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown TimeUtils.formatUptime(mConnectionTimeoutStartTime) : "<n/a>")); 70969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 71069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mWatcher.dump(pw, prefix); 71169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 71269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int providerCount = mProviderRecords.size(); 71369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (providerCount != 0) { 71469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < providerCount; i++) { 71569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviderRecords.get(i).dump(pw, prefix); 71669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 71769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 71869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "<no providers>"); 71969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 72069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 72169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 72269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void start() { 72369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mRunning) { 72469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRunning = true; 72569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mWatcher.start(); // also starts all providers 72669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 72769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 72869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 72969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void stop() { 73069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mRunning) { 73169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRunning = false; 73269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectGloballySelectedRoute(); 73369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mWatcher.stop(); // also stops all providers 73469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 73569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 73669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 73769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void updateDiscoveryRequest() { 73869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes = 0; 73969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScan = false; 74069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mService.mLock) { 74169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mUserRecord.mClientRecords.size(); 74269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 74369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mUserRecord.mClientRecords.get(i); 74469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= clientRecord.mRouteTypes; 74569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScan |= clientRecord.mActiveScan; 74669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 74769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 74869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 74969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int newDiscoveryMode; 750af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if ((routeTypes & MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY) != 0) { 75169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (activeScan) { 75269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_ACTIVE; 75369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 75469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_PASSIVE; 75569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 75669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 75769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE; 75869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 75969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 76069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mDiscoveryMode != newDiscoveryMode) { 76169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryMode = newDiscoveryMode; 76269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mProviderRecords.size(); 76369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 76469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviderRecords.get(i).getProvider().setDiscoveryMode(mDiscoveryMode); 76569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 76669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 76769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 76869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 76969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void selectRoute(String routeId) { 77069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeId != null 77169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && (mGloballySelectedRouteRecord == null 77269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || !routeId.equals(mGloballySelectedRouteRecord.getUniqueId()))) { 77369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord routeRecord = findRouteRecord(routeId); 77469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeRecord != null) { 77569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectGloballySelectedRoute(); 77669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 77769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Selected global route:" + routeRecord); 77869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord = routeRecord; 77969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown checkGloballySelectedRouteState(); 78069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeRecord.getProvider().setSelectedDisplay(routeRecord.getDescriptorId()); 78169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 78269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 78369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 78469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 78569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 78669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 78769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void unselectRoute(String routeId) { 78869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeId != null 78969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && mGloballySelectedRouteRecord != null 79069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) { 79169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectGloballySelectedRoute(); 79269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 79369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 79469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 79569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void unselectGloballySelectedRoute() { 79669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mGloballySelectedRouteRecord != null) { 79769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Unselected global route:" + mGloballySelectedRouteRecord); 79869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord.getProvider().setSelectedDisplay(null); 79969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord = null; 80069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown checkGloballySelectedRouteState(); 80169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 80269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 80369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 80469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 80569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 80669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void requestSetVolume(String routeId, int volume) { 80769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mGloballySelectedRouteRecord != null 80869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) { 80969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord.getProvider().setDisplayVolume(volume); 81069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 81169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 81269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 81369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void requestUpdateVolume(String routeId, int direction) { 81469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mGloballySelectedRouteRecord != null 81569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) { 81669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord.getProvider().adjustDisplayVolume(direction); 81769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 81869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 81969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 82069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 82169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void addProvider(RemoteDisplayProviderProxy provider) { 82269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setCallback(this); 82369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setDiscoveryMode(mDiscoveryMode); 82469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setSelectedDisplay(null); // just to be safe 82569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 82669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ProviderRecord providerRecord = new ProviderRecord(provider); 82769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviderRecords.add(providerRecord); 82869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown providerRecord.updateDescriptor(provider.getDisplayState()); 82969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 83069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 83169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 83269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 83369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 83469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void removeProvider(RemoteDisplayProviderProxy provider) { 83569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int index = findProviderRecord(provider); 83669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (index >= 0) { 83769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ProviderRecord providerRecord = mProviderRecords.remove(index); 83869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown providerRecord.updateDescriptor(null); // mark routes invalid 83969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setCallback(null); 84069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setDiscoveryMode(RemoteDisplayState.DISCOVERY_MODE_NONE); 84169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 84269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown checkGloballySelectedRouteState(); 84369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 84469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 84569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 84669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 84769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 84869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onDisplayStateChanged(RemoteDisplayProviderProxy provider, 84969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayState state) { 85069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateProvider(provider, state); 85169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 85269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 85369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void updateProvider(RemoteDisplayProviderProxy provider, 85469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayState state) { 85569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int index = findProviderRecord(provider); 85669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (index >= 0) { 85769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ProviderRecord providerRecord = mProviderRecords.get(index); 85869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (providerRecord.updateDescriptor(state)) { 85969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown checkGloballySelectedRouteState(); 86069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 86169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 86269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 86369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 86469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 86569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 86669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This function is called whenever the state of the globally selected route 86769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * may have changed. It checks the state and updates timeouts or unselects 86869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * the route as appropriate. 86969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 87069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void checkGloballySelectedRouteState() { 87169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Unschedule timeouts when the route is unselected. 87269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mGloballySelectedRouteRecord == null) { 87339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mConnectionPhase = PHASE_NOT_AVAILABLE; 87469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(0); 87569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return; 87669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 87769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 87869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Ensure that the route is still present and enabled. 87969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mGloballySelectedRouteRecord.isValid() 88069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || !mGloballySelectedRouteRecord.isEnabled()) { 88169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE); 88269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return; 88369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 88469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 88539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // Make sure we haven't lost our connection. 88639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown final int oldPhase = mConnectionPhase; 88739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown mConnectionPhase = getConnectionPhase(mGloballySelectedRouteRecord.getStatus()); 88839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (oldPhase >= PHASE_CONNECTING && mConnectionPhase < PHASE_CONNECTING) { 88939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown updateConnectionTimeout(TIMEOUT_REASON_CONNECTION_LOST); 89039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return; 89139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 89239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 89369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Check the route status. 89439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown switch (mConnectionPhase) { 89539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case PHASE_CONNECTED: 89639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (oldPhase != PHASE_CONNECTED) { 89769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Connected to global route: " 89869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + mGloballySelectedRouteRecord); 89969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 90069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(0); 90169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 90239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case PHASE_CONNECTING: 90339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown if (oldPhase != PHASE_CONNECTING) { 90469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Connecting to global route: " 90569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + mGloballySelectedRouteRecord); 90669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 90769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTED); 90869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 90939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case PHASE_NOT_CONNECTED: 91069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTING); 91169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 91239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case PHASE_NOT_AVAILABLE: 91369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown default: 91469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE); 91569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 91669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 91769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 91869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 91969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void updateConnectionTimeout(int reason) { 92069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (reason != mConnectionTimeoutReason) { 92169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mConnectionTimeoutReason != 0) { 92269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeMessages(MSG_CONNECTION_TIMED_OUT); 92369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 92469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mConnectionTimeoutReason = reason; 92569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mConnectionTimeoutStartTime = SystemClock.uptimeMillis(); 92669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (reason) { 92769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_NOT_AVAILABLE: 92839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case TIMEOUT_REASON_CONNECTION_LOST: 92939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // Route became unavailable or connection lost. 93039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown // Unselect it immediately. 93169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sendEmptyMessage(MSG_CONNECTION_TIMED_OUT); 93269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 93369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_WAITING_FOR_CONNECTING: 93469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Waiting for route to start connecting. 93569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTING_TIMEOUT); 93669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 93769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_WAITING_FOR_CONNECTED: 93869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Waiting for route to complete connection. 93969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTED_TIMEOUT); 94069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 94169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 94269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 94369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 94469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 94569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void connectionTimedOut() { 94669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mConnectionTimeoutReason == 0 || mGloballySelectedRouteRecord == null) { 94769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Shouldn't get here. There must be a bug somewhere. 94869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.wtf(TAG, "Handled connection timeout for no reason."); 94969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return; 95069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 95169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 95269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (mConnectionTimeoutReason) { 95369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_NOT_AVAILABLE: 95469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Global route no longer available: " 95569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + mGloballySelectedRouteRecord); 95669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 95739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case TIMEOUT_REASON_CONNECTION_LOST: 95839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown Slog.i(TAG, "Global route connection lost: " 95939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown + mGloballySelectedRouteRecord); 96039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown break; 96169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_WAITING_FOR_CONNECTING: 96269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Global route timed out while waiting for " 96369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + "connection attempt to begin after " 96469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime) 96569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + " ms: " + mGloballySelectedRouteRecord); 96669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 96769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_WAITING_FOR_CONNECTED: 96869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Global route timed out while connecting after " 96969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime) 97069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + " ms: " + mGloballySelectedRouteRecord); 97169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 97269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 97369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mConnectionTimeoutReason = 0; 97469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 97569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectGloballySelectedRoute(); 97669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 97769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 97869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void scheduleUpdateClientState() { 97969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mClientStateUpdateScheduled) { 98069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientStateUpdateScheduled = true; 98169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sendEmptyMessage(MSG_UPDATE_CLIENT_STATE); 98269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 98369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 98469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 98569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void updateClientState() { 98669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientStateUpdateScheduled = false; 98769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 988af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown final String globallySelectedRouteId = mGloballySelectedRouteRecord != null ? 98969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord.getUniqueId() : null; 990af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 991af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Build a new client state for trusted clients. 992af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown MediaRouterClientState trustedState = new MediaRouterClientState(); 993af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown trustedState.globallySelectedRouteId = globallySelectedRouteId; 99469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int providerCount = mProviderRecords.size(); 99569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < providerCount; i++) { 996af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown mProviderRecords.get(i).appendClientState(trustedState); 997af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown } 998af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown 999af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // Build a new client state for untrusted clients that can only see 1000af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown // the currently selected route. 1001af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown MediaRouterClientState untrustedState = new MediaRouterClientState(); 1002af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown untrustedState.globallySelectedRouteId = globallySelectedRouteId; 1003af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown if (globallySelectedRouteId != null) { 1004af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown untrustedState.routes.add(trustedState.getRoute(globallySelectedRouteId)); 100569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 100669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 100769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 100869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mService.mLock) { 100969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update the UserRecord. 1010af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown mUserRecord.mTrustedState = trustedState; 1011af574183c274f51d04487a9c8355e9f34a1150f2Jeff Brown mUserRecord.mUntrustedState = untrustedState; 101269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 101369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Collect all clients. 101469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mUserRecord.mClientRecords.size(); 101569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 101669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mTempClients.add(mUserRecord.mClientRecords.get(i).mClient); 101769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 101869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 101969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 102069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Notify all clients (outside of the lock). 102169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mTempClients.size(); 102269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 102369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 102469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mTempClients.get(i).onStateChanged(); 102569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 102669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // ignore errors, client probably died 102769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 102869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 102969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 103069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Clear the list in preparation for the next time. 103169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mTempClients.clear(); 103269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 103369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 103469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 103569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int findProviderRecord(RemoteDisplayProviderProxy provider) { 103669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mProviderRecords.size(); 103769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 103869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ProviderRecord record = mProviderRecords.get(i); 103969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (record.getProvider() == provider) { 104069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return i; 104169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 104269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 104369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return -1; 104469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 104569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 104669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private RouteRecord findRouteRecord(String uniqueId) { 104769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mProviderRecords.size(); 104869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 104969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord record = mProviderRecords.get(i).findRouteByUniqueId(uniqueId); 105069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (record != null) { 105169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return record; 105269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 105369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 105469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 105569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 105669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 105739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown private static int getConnectionPhase(int status) { 105839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown switch (status) { 105939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case MediaRouter.RouteInfo.STATUS_NONE: 106039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case MediaRouter.RouteInfo.STATUS_CONNECTED: 106139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return PHASE_CONNECTED; 106239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case MediaRouter.RouteInfo.STATUS_CONNECTING: 106339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return PHASE_CONNECTING; 106439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case MediaRouter.RouteInfo.STATUS_SCANNING: 106539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case MediaRouter.RouteInfo.STATUS_AVAILABLE: 106639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return PHASE_NOT_CONNECTED; 106739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE: 106839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown case MediaRouter.RouteInfo.STATUS_IN_USE: 106939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown default: 107039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown return PHASE_NOT_AVAILABLE; 107139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 107239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown } 107339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown 107469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final class ProviderRecord { 107569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final RemoteDisplayProviderProxy mProvider; 107669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final String mUniquePrefix; 107769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ArrayList<RouteRecord> mRoutes = new ArrayList<RouteRecord>(); 107869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private RemoteDisplayState mDescriptor; 107969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 108069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public ProviderRecord(RemoteDisplayProviderProxy provider) { 108169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProvider = provider; 108269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUniquePrefix = provider.getFlattenedComponentName() + ":"; 108369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 108469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 108569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public RemoteDisplayProviderProxy getProvider() { 108669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mProvider; 108769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 108869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 108969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String getUniquePrefix() { 109069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mUniquePrefix; 109169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 109269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 109369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean updateDescriptor(RemoteDisplayState descriptor) { 109469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 109569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mDescriptor != descriptor) { 109669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDescriptor = descriptor; 109769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 109869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update all existing routes and reorder them to match 109969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // the order of their descriptors. 110069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int targetIndex = 0; 110169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (descriptor != null) { 110269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (descriptor.isValid()) { 110369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final List<RemoteDisplayInfo> routeDescriptors = descriptor.displays; 110469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = routeDescriptors.size(); 110569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 110669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RemoteDisplayInfo routeDescriptor = 110769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeDescriptors.get(i); 110869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String descriptorId = routeDescriptor.id; 110969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int sourceIndex = findRouteByDescriptorId(descriptorId); 111069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (sourceIndex < 0) { 111169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Add the route to the provider. 111269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String uniqueId = assignRouteUniqueId(descriptorId); 111369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = 111469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new RouteRecord(this, descriptorId, uniqueId); 111569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRoutes.add(targetIndex++, route); 111669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.updateDescriptor(routeDescriptor); 111769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 111869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (sourceIndex < targetIndex) { 111969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Ignore route with duplicate id. 112069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.w(TAG, "Ignoring route descriptor with duplicate id: " 112169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + routeDescriptor); 112269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 112369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Reorder existing route within the list. 112469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = mRoutes.get(sourceIndex); 112569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Collections.swap(mRoutes, sourceIndex, targetIndex++); 112669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed |= route.updateDescriptor(routeDescriptor); 112769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 112869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 112969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 113069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.w(TAG, "Ignoring invalid descriptor from media route provider: " 113169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + mProvider.getFlattenedComponentName()); 113269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 113369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 113469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 113569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Dispose all remaining routes that do not have matching descriptors. 113669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = mRoutes.size() - 1; i >= targetIndex; i--) { 113769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = mRoutes.remove(i); 113869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.updateDescriptor(null); // mark route invalid 113969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 114069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 114169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 114269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return changed; 114369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 114469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 114569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void appendClientState(MediaRouterClientState state) { 114669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = mRoutes.size(); 114769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 114869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown state.routes.add(mRoutes.get(i).getInfo()); 114969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 115069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 115169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 115269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public RouteRecord findRouteByUniqueId(String uniqueId) { 115369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = mRoutes.size(); 115469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 115569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = mRoutes.get(i); 115669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.getUniqueId().equals(uniqueId)) { 115769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 115869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 115969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 116069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 116169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 116269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 116369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int findRouteByDescriptorId(String descriptorId) { 116469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = mRoutes.size(); 116569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 116669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = mRoutes.get(i); 116769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.getDescriptorId().equals(descriptorId)) { 116869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return i; 116969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 117069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 117169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return -1; 117269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 117369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 117469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(PrintWriter pw, String prefix) { 117569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + this); 117669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 117769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 117869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProvider.dump(pw, indent); 117969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 118069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = mRoutes.size(); 118169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeCount != 0) { 118269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 118369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRoutes.get(i).dump(pw, indent); 118469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 118569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 118669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "<no routes>"); 118769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 118869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 118969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 119069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 119169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String toString() { 119269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return "Provider " + mProvider.getFlattenedComponentName(); 119369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 119469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 119569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private String assignRouteUniqueId(String descriptorId) { 119669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mUniquePrefix + descriptorId; 119769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 119869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 119969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 120069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final class RouteRecord { 120169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ProviderRecord mProviderRecord; 120269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final String mDescriptorId; 120369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final MediaRouterClientState.RouteInfo mMutableInfo; 120469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private MediaRouterClientState.RouteInfo mImmutableInfo; 120569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private RemoteDisplayInfo mDescriptor; 120669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 120769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public RouteRecord(ProviderRecord providerRecord, 120869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String descriptorId, String uniqueId) { 120969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviderRecord = providerRecord; 121069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDescriptorId = descriptorId; 121169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo = new MediaRouterClientState.RouteInfo(uniqueId); 121269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 121369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 121469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public RemoteDisplayProviderProxy getProvider() { 121569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mProviderRecord.getProvider(); 121669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 121769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 121869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public ProviderRecord getProviderRecord() { 121969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mProviderRecord; 122069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 122169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 122269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String getDescriptorId() { 122369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mDescriptorId; 122469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 122569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 122669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String getUniqueId() { 122769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mMutableInfo.id; 122869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 122969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 123069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public MediaRouterClientState.RouteInfo getInfo() { 123169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mImmutableInfo == null) { 123269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mImmutableInfo = new MediaRouterClientState.RouteInfo(mMutableInfo); 123369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 123469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mImmutableInfo; 123569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 123669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 123769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean isValid() { 123869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mDescriptor != null; 123969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 124069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 124169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean isEnabled() { 124269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mMutableInfo.enabled; 124369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 124469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 124569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public int getStatus() { 124669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mMutableInfo.statusCode; 124769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 124869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 124969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean updateDescriptor(RemoteDisplayInfo descriptor) { 125069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 125169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mDescriptor != descriptor) { 125269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDescriptor = descriptor; 125369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (descriptor != null) { 125469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String name = computeName(descriptor); 1255e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(mMutableInfo.name, name)) { 125669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.name = name; 125769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 125869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 125969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String description = computeDescription(descriptor); 1260e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root if (!Objects.equals(mMutableInfo.description, description)) { 126169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.description = description; 126269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 126369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 126469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int supportedTypes = computeSupportedTypes(descriptor); 126569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.supportedTypes != supportedTypes) { 126669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.supportedTypes = supportedTypes; 126769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 126869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 126969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final boolean enabled = computeEnabled(descriptor); 127069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.enabled != enabled) { 127169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.enabled = enabled; 127269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 127369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 127469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int statusCode = computeStatusCode(descriptor); 127569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.statusCode != statusCode) { 127669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.statusCode = statusCode; 127769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 127869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 127969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int playbackType = computePlaybackType(descriptor); 128069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.playbackType != playbackType) { 128169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.playbackType = playbackType; 128269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 128369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 128469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int playbackStream = computePlaybackStream(descriptor); 128569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.playbackStream != playbackStream) { 128669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.playbackStream = playbackStream; 128769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 128869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 128969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volume = computeVolume(descriptor); 129069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.volume != volume) { 129169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.volume = volume; 129269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 129369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 129469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeMax = computeVolumeMax(descriptor); 129569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.volumeMax != volumeMax) { 129669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.volumeMax = volumeMax; 129769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 129869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 129969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeHandling = computeVolumeHandling(descriptor); 130069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.volumeHandling != volumeHandling) { 130169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.volumeHandling = volumeHandling; 130269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 130369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 130469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int presentationDisplayId = computePresentationDisplayId(descriptor); 130569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.presentationDisplayId != presentationDisplayId) { 130669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.presentationDisplayId = presentationDisplayId; 130769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 130869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 130969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 131069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 131169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (changed) { 131269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mImmutableInfo = null; 131369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 131469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return changed; 131569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 131669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 131769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(PrintWriter pw, String prefix) { 131869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + this); 131969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 132069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 132169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mMutableInfo=" + mMutableInfo); 132269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mDescriptorId=" + mDescriptorId); 132369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mDescriptor=" + mDescriptor); 132469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 132569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 132669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 132769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String toString() { 132869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return "Route " + mMutableInfo.name + " (" + mMutableInfo.id + ")"; 132969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 133069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 133169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static String computeName(RemoteDisplayInfo descriptor) { 133269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Note that isValid() already ensures the name is non-empty. 133369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return descriptor.name; 133469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 133569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 133669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static String computeDescription(RemoteDisplayInfo descriptor) { 133769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String description = descriptor.description; 133869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return TextUtils.isEmpty(description) ? null : description; 133969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 134069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 134169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeSupportedTypes(RemoteDisplayInfo descriptor) { 134269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.ROUTE_TYPE_LIVE_AUDIO 134369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | MediaRouter.ROUTE_TYPE_LIVE_VIDEO 134469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY; 134569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 134669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 134769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static boolean computeEnabled(RemoteDisplayInfo descriptor) { 134869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (descriptor.status) { 134969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_CONNECTED: 135069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_CONNECTING: 135169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_AVAILABLE: 135269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return true; 135369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown default: 135469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return false; 135569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 135669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 135769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 135869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeStatusCode(RemoteDisplayInfo descriptor) { 135969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (descriptor.status) { 136069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_NOT_AVAILABLE: 136169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE; 136269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_AVAILABLE: 136369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_AVAILABLE; 136469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_IN_USE: 136569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_IN_USE; 136669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_CONNECTING: 136769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_CONNECTING; 136869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_CONNECTED: 136969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_CONNECTED; 137069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown default: 137169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_NONE; 137269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 137369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 137469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 137569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computePlaybackType(RemoteDisplayInfo descriptor) { 137669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE; 137769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 137869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 137969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computePlaybackStream(RemoteDisplayInfo descriptor) { 138069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return AudioSystem.STREAM_MUSIC; 138169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 138269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 138369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeVolume(RemoteDisplayInfo descriptor) { 138469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volume = descriptor.volume; 138569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeMax = descriptor.volumeMax; 138669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (volume < 0) { 138769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return 0; 138869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (volume > volumeMax) { 138969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return volumeMax; 139069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 139169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return volume; 139269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 139369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 139469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeVolumeMax(RemoteDisplayInfo descriptor) { 139569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeMax = descriptor.volumeMax; 139669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return volumeMax > 0 ? volumeMax : 0; 139769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 139869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 139969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeVolumeHandling(RemoteDisplayInfo descriptor) { 140069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeHandling = descriptor.volumeHandling; 140169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (volumeHandling) { 140269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.PLAYBACK_VOLUME_VARIABLE: 140369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE; 140469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.PLAYBACK_VOLUME_FIXED: 140569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown default: 140669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED; 140769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 140869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 140969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 141069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computePresentationDisplayId(RemoteDisplayInfo descriptor) { 141169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // The MediaRouter class validates that the id corresponds to an extant 141269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // presentation display. So all we do here is canonicalize the null case. 141369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int displayId = descriptor.presentationDisplayId; 141469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return displayId < 0 ? -1 : displayId; 141569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 141669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 141769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 141869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown} 1419