MediaRouterService.java revision 69b07161bebdb2c726e3a826c2268866f1a94517
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.internal.util.Objects; 2069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport com.android.server.Watchdog; 2169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 2269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.Manifest; 2369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.app.ActivityManager; 2469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.BroadcastReceiver; 2569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.Context; 2669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.Intent; 2769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.IntentFilter; 2869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.pm.PackageManager; 2969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.AudioSystem; 3069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.IMediaRouterClient; 3169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.IMediaRouterService; 3269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.MediaRouter; 3369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.MediaRouterClientState; 3469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.RemoteDisplayState; 3569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.RemoteDisplayState.RemoteDisplayInfo; 3669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Binder; 3769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Handler; 3869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.IBinder; 3969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Looper; 4069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Message; 4169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.RemoteException; 4269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.SystemClock; 4369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.text.TextUtils; 4469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.ArrayMap; 4569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.Log; 4669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.Slog; 4769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.SparseArray; 4869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.TimeUtils; 4969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 5069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.io.FileDescriptor; 5169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.io.PrintWriter; 5269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.util.ArrayList; 5369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.util.Collections; 5469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.util.List; 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); 13169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 13269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 13369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 13469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown registerClientLocked(client, pid, packageName, resolvedUserId); 13569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 13669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 13769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 13869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 13969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 14069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 14169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 14269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 14369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void unregisterClient(IMediaRouterClient client) { 14469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 14569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 14669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 14769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 14869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 14969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 15069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 15169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unregisterClientLocked(client, false); 15269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 15369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 15469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 15569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 15669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 15769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 15869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 15969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 16069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public MediaRouterClientState getState(IMediaRouterClient client) { 16169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 16269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 16369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 16469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 16569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 16669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 16769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 16869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return getStateLocked(client); 16969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 17069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 17169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 17269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 17369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 17469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 17569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 17669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 17769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void setDiscoveryRequest(IMediaRouterClient client, 17869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes, boolean activeScan) { 17969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 18069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 18169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 18269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 18369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 18469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 18569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 18669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown setDiscoveryRequestLocked(client, routeTypes, activeScan); 18769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 18869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 18969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 19069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 19169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 19269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 19369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 19469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // A null routeId means that the client wants to unselect its current route. 19569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // The explicit flag indicates whether the change was explicitly requested by the 19669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // user or the application which may cause changes to propagate out to the rest 19769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // of the system. Should be false when the change is in response to a new globally 19869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // selected route or a default selection. 19969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 20069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit) { 20169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 20269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 20369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 20469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 20569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 20669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 20769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 20869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown setSelectedRouteLocked(client, routeId, explicit); 20969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 21069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 21169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 21269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 21369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 21469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 21569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 21669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 21769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void requestSetVolume(IMediaRouterClient client, String routeId, int volume) { 21869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 21969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 22069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 22169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeId == null) { 22269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("routeId must not be null"); 22369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 22469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 22569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 22669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 22769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 22869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown requestSetVolumeLocked(client, routeId, volume); 22969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 23069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 23169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 23269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 23369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 23469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 23569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 23669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 23769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction) { 23869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (client == null) { 23969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("client must not be null"); 24069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 24169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeId == null) { 24269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new IllegalArgumentException("routeId must not be null"); 24369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 24469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 24569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final long token = Binder.clearCallingIdentity(); 24669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 24769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 24869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown requestUpdateVolumeLocked(client, routeId, direction); 24969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 25069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 25169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Binder.restoreCallingIdentity(token); 25269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 25369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 25469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 25569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Binder call 25669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 25769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 25869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 25969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown != PackageManager.PERMISSION_GRANTED) { 26069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println("Permission Denial: can't dump MediaRouterService from from pid=" 26169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + Binder.getCallingPid() 26269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + ", uid=" + Binder.getCallingUid()); 26369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return; 26469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 26569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 26669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println("MEDIA ROUTER SERVICE (dumpsys media_router)"); 26769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(); 26869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println("Global state"); 26969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(" mCurrentUserId=" + mCurrentUserId); 27069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 27169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 27269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mUserRecords.size(); 27369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 27469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord userRecord = mUserRecords.valueAt(i); 27569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(); 27669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord.dump(pw, ""); 27769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 27969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 28069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 28169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void switchUser() { 28269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 28369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int userId = ActivityManager.getCurrentUser(); 28469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mCurrentUserId != userId) { 28569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int oldUserId = mCurrentUserId; 28669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mCurrentUserId = userId; // do this first 28769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 28869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord oldUser = mUserRecords.get(oldUserId); 28969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (oldUser != null) { 29069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown oldUser.mHandler.sendEmptyMessage(UserHandler.MSG_STOP); 29169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown disposeUserIfNeededLocked(oldUser); // since no longer current user 29269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 29469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord newUser = mUserRecords.get(userId); 29569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (newUser != null) { 29669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newUser.mHandler.sendEmptyMessage(UserHandler.MSG_START); 29769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 29969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 30069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 30169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 30269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown void clientDied(ClientRecord clientRecord) { 30369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mLock) { 30469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unregisterClientLocked(clientRecord.mClient, true); 30569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 30669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 30769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 30869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void registerClientLocked(IMediaRouterClient client, 30969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int pid, String packageName, int userId) { 31069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IBinder binder = client.asBinder(); 31169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(binder); 31269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord == null) { 31369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean newUser = false; 31469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord userRecord = mUserRecords.get(userId); 31569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (userRecord == null) { 31669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord = new UserRecord(userId); 31769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newUser = true; 31869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 31969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord = new ClientRecord(userRecord, client, pid, packageName); 32069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 32169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown binder.linkToDeath(clientRecord, 0); 32269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 32369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown throw new RuntimeException("Media router client died prematurely.", ex); 32469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 32569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 32669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (newUser) { 32769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserRecords.put(userId, userRecord); 32869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown initializeUserLocked(userRecord); 32969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 33069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 33169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord.mClientRecords.add(clientRecord); 33269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mAllClientRecords.put(binder, clientRecord); 33369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown initializeClientLocked(clientRecord); 33469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 33569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 33669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 33769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void unregisterClientLocked(IMediaRouterClient client, boolean died) { 33869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder()); 33969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 34069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserRecord userRecord = clientRecord.mUserRecord; 34169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord.mClientRecords.remove(clientRecord); 34269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown disposeClientLocked(clientRecord, died); 34369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown disposeUserIfNeededLocked(userRecord); // since client removed from user 34469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 34569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 34669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 34769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private MediaRouterClientState getStateLocked(IMediaRouterClient client) { 34869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); 34969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 35069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return clientRecord.mUserRecord.mState; 35169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 35369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 35469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 35569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void setDiscoveryRequestLocked(IMediaRouterClient client, 35669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes, boolean activeScan) { 35769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IBinder binder = client.asBinder(); 35869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(binder); 35969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 36069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord.mRouteTypes != routeTypes 36169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || clientRecord.mActiveScan != activeScan) { 36269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 36369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Set discovery request, routeTypes=0x" 36469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + Integer.toHexString(routeTypes) + ", activeScan=" + activeScan); 36569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 36669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mRouteTypes = routeTypes; 36769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mActiveScan = activeScan; 36869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.sendEmptyMessage( 36969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_UPDATE_DISCOVERY_REQUEST); 37069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 37369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 37469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void setSelectedRouteLocked(IMediaRouterClient client, 37569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String routeId, boolean explicit) { 37669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); 37769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 37869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String oldRouteId = clientRecord.mSelectedRouteId; 37969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!Objects.equal(routeId, oldRouteId)) { 38069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 38169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Set selected route, routeId=" + routeId 38269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + ", oldRouteId=" + oldRouteId 38369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + ", explicit=" + explicit); 38469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 38569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 38669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mSelectedRouteId = routeId; 38769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (explicit) { 38869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (oldRouteId != null) { 38969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.obtainMessage( 39069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_UNSELECT_ROUTE, oldRouteId).sendToTarget(); 39169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeId != null) { 39369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.obtainMessage( 39469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget(); 39569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 39969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 40169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void requestSetVolumeLocked(IMediaRouterClient client, 40269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String routeId, int volume) { 40369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IBinder binder = client.asBinder(); 40469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(binder); 40569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 40669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.obtainMessage( 40769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_REQUEST_SET_VOLUME, volume, 0, routeId).sendToTarget(); 40869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 40969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 41169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void requestUpdateVolumeLocked(IMediaRouterClient client, 41269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String routeId, int direction) { 41369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final IBinder binder = client.asBinder(); 41469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mAllClientRecords.get(binder); 41569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord != null) { 41669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.obtainMessage( 41769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_REQUEST_UPDATE_VOLUME, direction, 0, routeId).sendToTarget(); 41869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 41969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 42169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void initializeUserLocked(UserRecord userRecord) { 42269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 42369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, userRecord + ": Initialized"); 42469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (userRecord.mUserId == mCurrentUserId) { 42669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START); 42769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 42969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 43069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void disposeUserIfNeededLocked(UserRecord userRecord) { 43169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // If there are no records left and the user is no longer current then go ahead 43269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // and purge the user record and all of its associated state. If the user is current 43369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // then leave it alone since we might be connected to a route or want to query 43469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // the same route information again soon. 43569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (userRecord.mUserId != mCurrentUserId 43669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && userRecord.mClientRecords.isEmpty()) { 43769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 43869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, userRecord + ": Disposed"); 43969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserRecords.remove(userRecord.mUserId); 44169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Note: User already stopped (by switchUser) so no need to send stop message here. 44269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 44569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void initializeClientLocked(ClientRecord clientRecord) { 44669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 44769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Registered"); 44869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 44969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 45169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void disposeClientLocked(ClientRecord clientRecord, boolean died) { 45269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (DEBUG) { 45369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (died) { 45469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Died!"); 45569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 45669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.d(TAG, clientRecord + ": Unregistered"); 45769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 45969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientRecord.mRouteTypes != 0 || clientRecord.mActiveScan) { 46069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.mUserRecord.mHandler.sendEmptyMessage( 46169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown UserHandler.MSG_UPDATE_DISCOVERY_REQUEST); 46269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientRecord.dispose(); 46469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 46569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 46669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private boolean validatePackageName(int uid, String packageName) { 46769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (packageName != null) { 46869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); 46969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (packageNames != null) { 47069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (String n : packageNames) { 47169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (n.equals(packageName)) { 47269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return true; 47369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return false; 47869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 47969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 48069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 48169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Information about a particular client of the media router. 48269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * The contents of this object is guarded by mLock. 48369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 48469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class ClientRecord implements DeathRecipient { 48569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final UserRecord mUserRecord; 48669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final IMediaRouterClient mClient; 48769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final int mPid; 48869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final String mPackageName; 48969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 49069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public int mRouteTypes; 49169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean mActiveScan; 49269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String mSelectedRouteId; 49369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 49469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public ClientRecord(UserRecord userRecord, IMediaRouterClient client, 49569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int pid, String packageName) { 49669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserRecord = userRecord; 49769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient = client; 49869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mPid = pid; 49969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mPackageName = packageName; 50069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 50169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 50269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dispose() { 50369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClient.asBinder().unlinkToDeath(this, 0); 50469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 50569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 50669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 50769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void binderDied() { 50869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown clientDied(this); 50969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 51169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(PrintWriter pw, String prefix) { 51269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + this); 51369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 51469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 51569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mRouteTypes=0x" + Integer.toHexString(mRouteTypes)); 51669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mActiveScan=" + mActiveScan); 51769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mSelectedRouteId=" + mSelectedRouteId); 51869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 51969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 52069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 52169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String toString() { 52269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return "Client " + mPackageName + " (pid " + mPid + ")"; 52369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 52569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 52669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 52769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Information about a particular user. 52869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * The contents of this object is guarded by mLock. 52969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 53069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final class UserRecord { 53169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final int mUserId; 53269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final ArrayList<ClientRecord> mClientRecords = new ArrayList<ClientRecord>(); 53369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public final UserHandler mHandler; 53469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public MediaRouterClientState mState; 53569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 53669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public UserRecord(int userId) { 53769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserId = userId; 53869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler = new UserHandler(MediaRouterService.this, this); 53969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 54069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 54169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(final PrintWriter pw, String prefix) { 54269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + this); 54369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 54469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 54569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int clientCount = mClientRecords.size(); 54669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (clientCount != 0) { 54769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < clientCount; i++) { 54869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientRecords.get(i).dump(pw, indent); 54969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 55169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "<no clients>"); 55269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 55469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mHandler.runWithScissors(new Runnable() { 55569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 55669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void run() { 55769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mHandler.dump(pw, indent); 55869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 55969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown }, 1000)) { 56069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "<could not dump handler state>"); 56169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 56469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 56569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String toString() { 56669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return "User " + mUserId; 56769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 56969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 57069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 57169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Media router handler 57269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * <p> 57369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Since remote display providers are designed to be single-threaded by nature, 57469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * this class encapsulates all of the associated functionality and exports state 57569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * to the service as it evolves. 57669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p><p> 57769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * One important task of this class is to keep track of the current globally selected 57869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * route id for certain routes that have global effects, such as remote displays. 57969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Global route selections override local selections made within apps. The change 58069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * is propagated to all apps so that they are all in sync. Synchronization works 58169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * both ways. Whenever the globally selected route is explicitly unselected by any 58269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * app, then it becomes unselected globally and all apps are informed. 58369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p><p> 58469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This class is currently hardcoded to work with remote display providers but 58569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * it is intended to be eventually extended to support more general route providers 58669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * similar to the support library media router. 58769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * </p> 58869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 58969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final class UserHandler extends Handler 59069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown implements RemoteDisplayProviderWatcher.Callback, 59169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayProviderProxy.Callback { 59269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_START = 1; 59369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_STOP = 2; 59469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_UPDATE_DISCOVERY_REQUEST = 3; 59569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_SELECT_ROUTE = 4; 59669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_UNSELECT_ROUTE = 5; 59769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_REQUEST_SET_VOLUME = 6; 59869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public static final int MSG_REQUEST_UPDATE_VOLUME = 7; 59969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final int MSG_UPDATE_CLIENT_STATE = 8; 60069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final int MSG_CONNECTION_TIMED_OUT = 9; 60169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 60269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1; 60369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTING = 2; 60469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTED = 3; 60569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 60669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final MediaRouterService mService; 60769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final UserRecord mUserRecord; 60869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final RemoteDisplayProviderWatcher mWatcher; 60969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ArrayList<ProviderRecord> mProviderRecords = 61069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new ArrayList<ProviderRecord>(); 61169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ArrayList<IMediaRouterClient> mTempClients = 61269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new ArrayList<IMediaRouterClient>(); 61369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 61469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private boolean mRunning; 61569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int mDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE; 61669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private RouteRecord mGloballySelectedRouteRecord; 61769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int mConnectionTimeoutReason; 61869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private long mConnectionTimeoutStartTime; 61969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private boolean mClientStateUpdateScheduled; 62069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 62169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public UserHandler(MediaRouterService service, UserRecord userRecord) { 62269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown super(Looper.getMainLooper(), null, true); 62369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mService = service; 62469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserRecord = userRecord; 62569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mWatcher = new RemoteDisplayProviderWatcher(service.mContext, this, 62669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown this, mUserRecord.mUserId); 62769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 62869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 62969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 63069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void handleMessage(Message msg) { 63169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (msg.what) { 63269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_START: { 63369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown start(); 63469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 63569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 63669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_STOP: { 63769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown stop(); 63869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 63969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 64069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_UPDATE_DISCOVERY_REQUEST: { 64169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateDiscoveryRequest(); 64269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 64369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 64469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_SELECT_ROUTE: { 64569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown selectRoute((String)msg.obj); 64669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 64769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 64869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_UNSELECT_ROUTE: { 64969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectRoute((String)msg.obj); 65069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 65169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 65269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_REQUEST_SET_VOLUME: { 65369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown requestSetVolume((String)msg.obj, msg.arg1); 65469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 65569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 65669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_REQUEST_UPDATE_VOLUME: { 65769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown requestUpdateVolume((String)msg.obj, msg.arg1); 65869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 65969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 66069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_UPDATE_CLIENT_STATE: { 66169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateClientState(); 66269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 66369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 66469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MSG_CONNECTION_TIMED_OUT: { 66569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown connectionTimedOut(); 66669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 66769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 66869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 66969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 67069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 67169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(PrintWriter pw, String prefix) { 67269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + "Handler"); 67369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 67469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 67569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mRunning=" + mRunning); 67669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mDiscoveryMode=" + mDiscoveryMode); 67769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mGloballySelectedRouteRecord=" + mGloballySelectedRouteRecord); 67869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mConnectionTimeoutReason=" + mConnectionTimeoutReason); 67969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mConnectionTimeoutStartTime=" + (mConnectionTimeoutReason != 0 ? 68069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown TimeUtils.formatUptime(mConnectionTimeoutStartTime) : "<n/a>")); 68169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 68269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mWatcher.dump(pw, prefix); 68369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 68469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int providerCount = mProviderRecords.size(); 68569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (providerCount != 0) { 68669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < providerCount; i++) { 68769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviderRecords.get(i).dump(pw, prefix); 68869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 68969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 69069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "<no providers>"); 69169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 69269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 69369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 69469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void start() { 69569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mRunning) { 69669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRunning = true; 69769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mWatcher.start(); // also starts all providers 69869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 69969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 70069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 70169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void stop() { 70269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mRunning) { 70369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRunning = false; 70469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectGloballySelectedRoute(); 70569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mWatcher.stop(); // also stops all providers 70669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 70769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 70869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 70969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void updateDiscoveryRequest() { 71069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int routeTypes = 0; 71169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean activeScan = false; 71269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mService.mLock) { 71369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mUserRecord.mClientRecords.size(); 71469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 71569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ClientRecord clientRecord = mUserRecord.mClientRecords.get(i); 71669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeTypes |= clientRecord.mRouteTypes; 71769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown activeScan |= clientRecord.mActiveScan; 71869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 71969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 72069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 72169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int newDiscoveryMode; 72269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if ((routeTypes & (MediaRouter.ROUTE_TYPE_LIVE_VIDEO 72369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) != 0) { 72469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (activeScan) { 72569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_ACTIVE; 72669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 72769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_PASSIVE; 72869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 72969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 73069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE; 73169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 73269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 73369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mDiscoveryMode != newDiscoveryMode) { 73469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDiscoveryMode = newDiscoveryMode; 73569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mProviderRecords.size(); 73669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 73769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviderRecords.get(i).getProvider().setDiscoveryMode(mDiscoveryMode); 73869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 73969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 74069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 74169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 74269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void selectRoute(String routeId) { 74369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeId != null 74469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && (mGloballySelectedRouteRecord == null 74569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || !routeId.equals(mGloballySelectedRouteRecord.getUniqueId()))) { 74669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord routeRecord = findRouteRecord(routeId); 74769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeRecord != null) { 74869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectGloballySelectedRoute(); 74969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 75069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Selected global route:" + routeRecord); 75169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord = routeRecord; 75269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown checkGloballySelectedRouteState(); 75369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeRecord.getProvider().setSelectedDisplay(routeRecord.getDescriptorId()); 75469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 75569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 75669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 75769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 75869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 75969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 76069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void unselectRoute(String routeId) { 76169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeId != null 76269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && mGloballySelectedRouteRecord != null 76369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) { 76469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectGloballySelectedRoute(); 76569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 76669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 76769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 76869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void unselectGloballySelectedRoute() { 76969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mGloballySelectedRouteRecord != null) { 77069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Unselected global route:" + mGloballySelectedRouteRecord); 77169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord.getProvider().setSelectedDisplay(null); 77269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord = null; 77369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown checkGloballySelectedRouteState(); 77469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 77569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 77669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 77769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 77869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 77969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void requestSetVolume(String routeId, int volume) { 78069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mGloballySelectedRouteRecord != null 78169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) { 78269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord.getProvider().setDisplayVolume(volume); 78369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 78469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 78569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 78669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void requestUpdateVolume(String routeId, int direction) { 78769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mGloballySelectedRouteRecord != null 78869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) { 78969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord.getProvider().adjustDisplayVolume(direction); 79069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 79169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 79269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 79369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 79469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void addProvider(RemoteDisplayProviderProxy provider) { 79569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setCallback(this); 79669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setDiscoveryMode(mDiscoveryMode); 79769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setSelectedDisplay(null); // just to be safe 79869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 79969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ProviderRecord providerRecord = new ProviderRecord(provider); 80069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviderRecords.add(providerRecord); 80169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown providerRecord.updateDescriptor(provider.getDisplayState()); 80269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 80369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 80469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 80569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 80669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 80769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void removeProvider(RemoteDisplayProviderProxy provider) { 80869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int index = findProviderRecord(provider); 80969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (index >= 0) { 81069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ProviderRecord providerRecord = mProviderRecords.remove(index); 81169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown providerRecord.updateDescriptor(null); // mark routes invalid 81269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setCallback(null); 81369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown provider.setDiscoveryMode(RemoteDisplayState.DISCOVERY_MODE_NONE); 81469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 81569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown checkGloballySelectedRouteState(); 81669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 81769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 81869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 81969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 82069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 82169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void onDisplayStateChanged(RemoteDisplayProviderProxy provider, 82269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayState state) { 82369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateProvider(provider, state); 82469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 82569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 82669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void updateProvider(RemoteDisplayProviderProxy provider, 82769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RemoteDisplayState state) { 82869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int index = findProviderRecord(provider); 82969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (index >= 0) { 83069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ProviderRecord providerRecord = mProviderRecords.get(index); 83169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (providerRecord.updateDescriptor(state)) { 83269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown checkGloballySelectedRouteState(); 83369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown scheduleUpdateClientState(); 83469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 83569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 83669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 83769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 83869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown /** 83969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * This function is called whenever the state of the globally selected route 84069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * may have changed. It checks the state and updates timeouts or unselects 84169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * the route as appropriate. 84269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */ 84369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void checkGloballySelectedRouteState() { 84469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Unschedule timeouts when the route is unselected. 84569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mGloballySelectedRouteRecord == null) { 84669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(0); 84769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return; 84869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 84969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 85069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Ensure that the route is still present and enabled. 85169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mGloballySelectedRouteRecord.isValid() 85269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown || !mGloballySelectedRouteRecord.isEnabled()) { 85369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE); 85469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return; 85569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 85669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 85769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Check the route status. 85869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (mGloballySelectedRouteRecord.getStatus()) { 85969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MediaRouter.RouteInfo.STATUS_NONE: 86069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MediaRouter.RouteInfo.STATUS_CONNECTED: 86169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mConnectionTimeoutReason != 0) { 86269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Connected to global route: " 86369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + mGloballySelectedRouteRecord); 86469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 86569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(0); 86669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 86769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MediaRouter.RouteInfo.STATUS_CONNECTING: 86869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mConnectionTimeoutReason != 0) { 86969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Connecting to global route: " 87069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + mGloballySelectedRouteRecord); 87169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 87269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTED); 87369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 87469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MediaRouter.RouteInfo.STATUS_SCANNING: 87569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MediaRouter.RouteInfo.STATUS_AVAILABLE: 87669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTING); 87769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 87869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE: 87969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case MediaRouter.RouteInfo.STATUS_IN_USE: 88069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown default: 88169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE); 88269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 88369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 88469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 88569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 88669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void updateConnectionTimeout(int reason) { 88769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (reason != mConnectionTimeoutReason) { 88869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mConnectionTimeoutReason != 0) { 88969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown removeMessages(MSG_CONNECTION_TIMED_OUT); 89069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 89169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mConnectionTimeoutReason = reason; 89269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mConnectionTimeoutStartTime = SystemClock.uptimeMillis(); 89369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (reason) { 89469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_NOT_AVAILABLE: 89569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Route became unavailable. Unselect it immediately. 89669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sendEmptyMessage(MSG_CONNECTION_TIMED_OUT); 89769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 89869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_WAITING_FOR_CONNECTING: 89969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Waiting for route to start connecting. 90069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTING_TIMEOUT); 90169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 90269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_WAITING_FOR_CONNECTED: 90369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Waiting for route to complete connection. 90469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTED_TIMEOUT); 90569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 90669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 90769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 90869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 90969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 91069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void connectionTimedOut() { 91169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mConnectionTimeoutReason == 0 || mGloballySelectedRouteRecord == null) { 91269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Shouldn't get here. There must be a bug somewhere. 91369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Log.wtf(TAG, "Handled connection timeout for no reason."); 91469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return; 91569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 91669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 91769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (mConnectionTimeoutReason) { 91869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_NOT_AVAILABLE: 91969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Global route no longer available: " 92069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + mGloballySelectedRouteRecord); 92169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 92269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_WAITING_FOR_CONNECTING: 92369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Global route timed out while waiting for " 92469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + "connection attempt to begin after " 92569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime) 92669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + " ms: " + mGloballySelectedRouteRecord); 92769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 92869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case TIMEOUT_REASON_WAITING_FOR_CONNECTED: 92969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.i(TAG, "Global route timed out while connecting after " 93069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime) 93169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + " ms: " + mGloballySelectedRouteRecord); 93269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown break; 93369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 93469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mConnectionTimeoutReason = 0; 93569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 93669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown unselectGloballySelectedRoute(); 93769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 93869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 93969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void scheduleUpdateClientState() { 94069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!mClientStateUpdateScheduled) { 94169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientStateUpdateScheduled = true; 94269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown sendEmptyMessage(MSG_UPDATE_CLIENT_STATE); 94369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 94469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 94569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 94669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private void updateClientState() { 94769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mClientStateUpdateScheduled = false; 94869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 94969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Build a new client state. 95069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown MediaRouterClientState state = new MediaRouterClientState(); 95169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown state.globallySelectedRouteId = mGloballySelectedRouteRecord != null ? 95269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mGloballySelectedRouteRecord.getUniqueId() : null; 95369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int providerCount = mProviderRecords.size(); 95469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < providerCount; i++) { 95569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviderRecords.get(i).appendClientState(state); 95669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 95769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 95869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 95969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown synchronized (mService.mLock) { 96069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update the UserRecord. 96169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUserRecord.mState = state; 96269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 96369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Collect all clients. 96469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mUserRecord.mClientRecords.size(); 96569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 96669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mTempClients.add(mUserRecord.mClientRecords.get(i).mClient); 96769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 96869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 96969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 97069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Notify all clients (outside of the lock). 97169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mTempClients.size(); 97269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 97369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown try { 97469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mTempClients.get(i).onStateChanged(); 97569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } catch (RemoteException ex) { 97669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // ignore errors, client probably died 97769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 97869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 97969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } finally { 98069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Clear the list in preparation for the next time. 98169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mTempClients.clear(); 98269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 98369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 98469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 98569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int findProviderRecord(RemoteDisplayProviderProxy provider) { 98669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mProviderRecords.size(); 98769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 98869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown ProviderRecord record = mProviderRecords.get(i); 98969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (record.getProvider() == provider) { 99069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return i; 99169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 99269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 99369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return -1; 99469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 99569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 99669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private RouteRecord findRouteRecord(String uniqueId) { 99769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int count = mProviderRecords.size(); 99869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < count; i++) { 99969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord record = mProviderRecords.get(i).findRouteByUniqueId(uniqueId); 100069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (record != null) { 100169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return record; 100269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 100369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 100469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 100569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 100669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 100769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final class ProviderRecord { 100869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final RemoteDisplayProviderProxy mProvider; 100969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final String mUniquePrefix; 101069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ArrayList<RouteRecord> mRoutes = new ArrayList<RouteRecord>(); 101169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private RemoteDisplayState mDescriptor; 101269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 101369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public ProviderRecord(RemoteDisplayProviderProxy provider) { 101469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProvider = provider; 101569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mUniquePrefix = provider.getFlattenedComponentName() + ":"; 101669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 101769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 101869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public RemoteDisplayProviderProxy getProvider() { 101969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mProvider; 102069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 102169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 102269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String getUniquePrefix() { 102369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mUniquePrefix; 102469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 102569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 102669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean updateDescriptor(RemoteDisplayState descriptor) { 102769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 102869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mDescriptor != descriptor) { 102969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDescriptor = descriptor; 103069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 103169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Update all existing routes and reorder them to match 103269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // the order of their descriptors. 103369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown int targetIndex = 0; 103469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (descriptor != null) { 103569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (descriptor.isValid()) { 103669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final List<RemoteDisplayInfo> routeDescriptors = descriptor.displays; 103769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = routeDescriptors.size(); 103869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 103969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final RemoteDisplayInfo routeDescriptor = 104069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown routeDescriptors.get(i); 104169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String descriptorId = routeDescriptor.id; 104269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int sourceIndex = findRouteByDescriptorId(descriptorId); 104369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (sourceIndex < 0) { 104469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Add the route to the provider. 104569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String uniqueId = assignRouteUniqueId(descriptorId); 104669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = 104769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown new RouteRecord(this, descriptorId, uniqueId); 104869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRoutes.add(targetIndex++, route); 104969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.updateDescriptor(routeDescriptor); 105069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 105169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (sourceIndex < targetIndex) { 105269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Ignore route with duplicate id. 105369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.w(TAG, "Ignoring route descriptor with duplicate id: " 105469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + routeDescriptor); 105569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 105669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Reorder existing route within the list. 105769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = mRoutes.get(sourceIndex); 105869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Collections.swap(mRoutes, sourceIndex, targetIndex++); 105969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed |= route.updateDescriptor(routeDescriptor); 106069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 106169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 106269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 106369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown Slog.w(TAG, "Ignoring invalid descriptor from media route provider: " 106469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown + mProvider.getFlattenedComponentName()); 106569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 106669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 106769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 106869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Dispose all remaining routes that do not have matching descriptors. 106969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = mRoutes.size() - 1; i >= targetIndex; i--) { 107069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = mRoutes.remove(i); 107169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown route.updateDescriptor(null); // mark route invalid 107269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 107369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 107469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 107569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return changed; 107669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 107769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 107869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void appendClientState(MediaRouterClientState state) { 107969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = mRoutes.size(); 108069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 108169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown state.routes.add(mRoutes.get(i).getInfo()); 108269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 108369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 108469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 108569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public RouteRecord findRouteByUniqueId(String uniqueId) { 108669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = mRoutes.size(); 108769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 108869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = mRoutes.get(i); 108969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.getUniqueId().equals(uniqueId)) { 109069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return route; 109169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 109269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 109369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return null; 109469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 109569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 109669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private int findRouteByDescriptorId(String descriptorId) { 109769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = mRoutes.size(); 109869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 109969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown RouteRecord route = mRoutes.get(i); 110069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (route.getDescriptorId().equals(descriptorId)) { 110169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return i; 110269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 110369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 110469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return -1; 110569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 110669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 110769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(PrintWriter pw, String prefix) { 110869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + this); 110969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 111069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 111169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProvider.dump(pw, indent); 111269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 111369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int routeCount = mRoutes.size(); 111469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (routeCount != 0) { 111569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown for (int i = 0; i < routeCount; i++) { 111669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mRoutes.get(i).dump(pw, indent); 111769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 111869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else { 111969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "<no routes>"); 112069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 112169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 112269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 112369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 112469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String toString() { 112569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return "Provider " + mProvider.getFlattenedComponentName(); 112669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 112769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 112869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private String assignRouteUniqueId(String descriptorId) { 112969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mUniquePrefix + descriptorId; 113069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 113169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 113269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 113369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown static final class RouteRecord { 113469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final ProviderRecord mProviderRecord; 113569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final String mDescriptorId; 113669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private final MediaRouterClientState.RouteInfo mMutableInfo; 113769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private MediaRouterClientState.RouteInfo mImmutableInfo; 113869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private RemoteDisplayInfo mDescriptor; 113969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 114069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public RouteRecord(ProviderRecord providerRecord, 114169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown String descriptorId, String uniqueId) { 114269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mProviderRecord = providerRecord; 114369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDescriptorId = descriptorId; 114469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo = new MediaRouterClientState.RouteInfo(uniqueId); 114569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 114669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 114769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public RemoteDisplayProviderProxy getProvider() { 114869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mProviderRecord.getProvider(); 114969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 115069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 115169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public ProviderRecord getProviderRecord() { 115269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mProviderRecord; 115369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 115469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 115569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String getDescriptorId() { 115669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mDescriptorId; 115769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 115869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 115969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String getUniqueId() { 116069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mMutableInfo.id; 116169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 116269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 116369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public MediaRouterClientState.RouteInfo getInfo() { 116469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mImmutableInfo == null) { 116569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mImmutableInfo = new MediaRouterClientState.RouteInfo(mMutableInfo); 116669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 116769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mImmutableInfo; 116869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 116969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 117069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean isValid() { 117169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mDescriptor != null; 117269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 117369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 117469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean isEnabled() { 117569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mMutableInfo.enabled; 117669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 117769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 117869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public int getStatus() { 117969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return mMutableInfo.statusCode; 118069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 118169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 118269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public boolean updateDescriptor(RemoteDisplayInfo descriptor) { 118369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown boolean changed = false; 118469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mDescriptor != descriptor) { 118569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mDescriptor = descriptor; 118669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (descriptor != null) { 118769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String name = computeName(descriptor); 118869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!Objects.equal(mMutableInfo.name, name)) { 118969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.name = name; 119069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 119169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 119269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String description = computeDescription(descriptor); 119369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (!Objects.equal(mMutableInfo.description, description)) { 119469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.description = description; 119569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 119669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 119769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int supportedTypes = computeSupportedTypes(descriptor); 119869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.supportedTypes != supportedTypes) { 119969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.supportedTypes = supportedTypes; 120069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 120169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 120269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final boolean enabled = computeEnabled(descriptor); 120369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.enabled != enabled) { 120469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.enabled = enabled; 120569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 120669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 120769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int statusCode = computeStatusCode(descriptor); 120869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.statusCode != statusCode) { 120969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.statusCode = statusCode; 121069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 121169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 121269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int playbackType = computePlaybackType(descriptor); 121369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.playbackType != playbackType) { 121469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.playbackType = playbackType; 121569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 121669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 121769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int playbackStream = computePlaybackStream(descriptor); 121869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.playbackStream != playbackStream) { 121969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.playbackStream = playbackStream; 122069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 122169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 122269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volume = computeVolume(descriptor); 122369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.volume != volume) { 122469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.volume = volume; 122569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 122669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 122769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeMax = computeVolumeMax(descriptor); 122869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.volumeMax != volumeMax) { 122969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.volumeMax = volumeMax; 123069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 123169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 123269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeHandling = computeVolumeHandling(descriptor); 123369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.volumeHandling != volumeHandling) { 123469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.volumeHandling = volumeHandling; 123569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 123669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 123769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int presentationDisplayId = computePresentationDisplayId(descriptor); 123869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (mMutableInfo.presentationDisplayId != presentationDisplayId) { 123969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mMutableInfo.presentationDisplayId = presentationDisplayId; 124069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown changed = true; 124169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 124269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 124369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 124469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (changed) { 124569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown mImmutableInfo = null; 124669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 124769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return changed; 124869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 124969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 125069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public void dump(PrintWriter pw, String prefix) { 125169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(prefix + this); 125269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 125369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String indent = prefix + " "; 125469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mMutableInfo=" + mMutableInfo); 125569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mDescriptorId=" + mDescriptorId); 125669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown pw.println(indent + "mDescriptor=" + mDescriptor); 125769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 125869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 125969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown @Override 126069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown public String toString() { 126169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return "Route " + mMutableInfo.name + " (" + mMutableInfo.id + ")"; 126269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 126369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 126469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static String computeName(RemoteDisplayInfo descriptor) { 126569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // Note that isValid() already ensures the name is non-empty. 126669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return descriptor.name; 126769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 126869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 126969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static String computeDescription(RemoteDisplayInfo descriptor) { 127069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final String description = descriptor.description; 127169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return TextUtils.isEmpty(description) ? null : description; 127269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 127369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 127469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeSupportedTypes(RemoteDisplayInfo descriptor) { 127569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.ROUTE_TYPE_LIVE_AUDIO 127669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | MediaRouter.ROUTE_TYPE_LIVE_VIDEO 127769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY; 127869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 127969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 128069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static boolean computeEnabled(RemoteDisplayInfo descriptor) { 128169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (descriptor.status) { 128269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_CONNECTED: 128369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_CONNECTING: 128469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_AVAILABLE: 128569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return true; 128669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown default: 128769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return false; 128869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 128969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 129069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 129169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeStatusCode(RemoteDisplayInfo descriptor) { 129269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (descriptor.status) { 129369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_NOT_AVAILABLE: 129469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE; 129569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_AVAILABLE: 129669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_AVAILABLE; 129769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_IN_USE: 129869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_IN_USE; 129969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_CONNECTING: 130069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_CONNECTING; 130169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.STATUS_CONNECTED: 130269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_CONNECTED; 130369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown default: 130469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.STATUS_NONE; 130569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 130669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 130769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 130869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computePlaybackType(RemoteDisplayInfo descriptor) { 130969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE; 131069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 131169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 131269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computePlaybackStream(RemoteDisplayInfo descriptor) { 131369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return AudioSystem.STREAM_MUSIC; 131469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 131569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 131669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeVolume(RemoteDisplayInfo descriptor) { 131769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volume = descriptor.volume; 131869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeMax = descriptor.volumeMax; 131969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown if (volume < 0) { 132069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return 0; 132169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } else if (volume > volumeMax) { 132269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return volumeMax; 132369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 132469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return volume; 132569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 132669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 132769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeVolumeMax(RemoteDisplayInfo descriptor) { 132869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeMax = descriptor.volumeMax; 132969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return volumeMax > 0 ? volumeMax : 0; 133069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 133169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 133269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computeVolumeHandling(RemoteDisplayInfo descriptor) { 133369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int volumeHandling = descriptor.volumeHandling; 133469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown switch (volumeHandling) { 133569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.PLAYBACK_VOLUME_VARIABLE: 133669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE; 133769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown case RemoteDisplayInfo.PLAYBACK_VOLUME_FIXED: 133869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown default: 133969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED; 134069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 134169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 134269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown 134369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown private static int computePresentationDisplayId(RemoteDisplayInfo descriptor) { 134469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // The MediaRouter class validates that the id corresponds to an extant 134569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown // presentation display. So all we do here is canonicalize the null case. 134669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown final int displayId = descriptor.presentationDisplayId; 134769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown return displayId < 0 ? -1 : displayId; 134869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 134969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 135069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown } 135169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown} 1352