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