1fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/* 2fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Copyright (C) 2013 The Android Open Source Project 3fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 4fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 5fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * you may not use this file except in compliance with the License. 6fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * You may obtain a copy of the License at 7fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 8fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 9fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 10fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Unless required by applicable law or agreed to in writing, software 11fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 12fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * See the License for the specific language governing permissions and 14fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * limitations under the License. 15fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 16fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 17b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownpackage android.support.v7.media; 18fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 19fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.ComponentName; 20fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.Context; 21fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.Intent; 22fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.ServiceConnection; 23fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Bundle; 24fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.DeadObjectException; 25fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Handler; 26fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.IBinder; 27fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.RemoteException; 28fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.IBinder.DeathRecipient; 29fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Message; 30fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Messenger; 31b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownimport android.support.v7.media.MediaRouter.ControlRequestCallback; 32fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.util.Log; 33fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.util.SparseArray; 34fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 35fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.lang.ref.WeakReference; 36fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.util.ArrayList; 3711417b1cfde8f1749905f2d735623af9214148afJeff Brownimport java.util.List; 38fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 393efa63d3b896244713e84acbb5945562dce41d77Jeff Brownimport static android.support.v7.media.MediaRouteProviderProtocol.*; 403efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 41fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/** 42fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Maintains a connection to a particular media route provider service. 43fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 44fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownfinal class RegisteredMediaRouteProvider extends MediaRouteProvider 45fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown implements ServiceConnection { 46f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private static final String TAG = "MediaRouteProviderProxy"; // max. 23 chars 47f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 48fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 49fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ComponentName mComponentName; 50fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final PrivateHandler mPrivateHandler; 51fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<Controller> mControllers = new ArrayList<Controller>(); 52fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 53f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private boolean mStarted; 54fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mBound; 55fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private Connection mActiveConnection; 56fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mConnectionReady; 57fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 58fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public RegisteredMediaRouteProvider(Context context, ComponentName componentName) { 59adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown super(context, new ProviderMetadata(componentName)); 60fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 61fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mComponentName = componentName; 62fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPrivateHandler = new PrivateHandler(); 63fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 64fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 65fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 66fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public RouteController onCreateRouteController(String routeId) { 6711417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor descriptor = getDescriptor(); 68fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (descriptor != null) { 6911417b1cfde8f1749905f2d735623af9214148afJeff Brown List<MediaRouteDescriptor> routes = descriptor.getRoutes(); 7011417b1cfde8f1749905f2d735623af9214148afJeff Brown final int count = routes.size(); 7111417b1cfde8f1749905f2d735623af9214148afJeff Brown for (int i = 0; i < count; i++) { 7211417b1cfde8f1749905f2d735623af9214148afJeff Brown final MediaRouteDescriptor route = routes.get(i); 7311417b1cfde8f1749905f2d735623af9214148afJeff Brown if (route.getId().equals(routeId)) { 74fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Controller controller = new Controller(routeId); 75fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.add(controller); 76fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnectionReady) { 77fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown controller.attachConnection(mActiveConnection); 78fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 79f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown updateBinding(); 80fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return controller; 81fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 82fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 83fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 84fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return null; 85fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 86fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 8728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown @Override 8811417b1cfde8f1749905f2d735623af9214148afJeff Brown public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) { 8928520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (mConnectionReady) { 9011417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveConnection.setDiscoveryRequest(request); 9128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 92f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown updateBinding(); 9328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 9428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 95fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean hasComponentName(String packageName, String className) { 96fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mComponentName.getPackageName().equals(packageName) 97fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown && mComponentName.getClassName().equals(className); 98fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 99fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 100f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown public void start() { 101f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!mStarted) { 102fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 103f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Starting"); 104fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 105f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 106f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown mStarted = true; 107f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown updateBinding(); 108fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 109fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 110fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 111f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown public void stop() { 112f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (mStarted) { 113f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 114f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Stopping"); 115f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 116fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 117f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown mStarted = false; 118f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown updateBinding(); 119fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 120fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 121fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 122fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void rebindIfDisconnected() { 123f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (mActiveConnection == null && shouldBind()) { 124fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unbind(); 125fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown bind(); 126fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 127fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 128fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 129f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private void updateBinding() { 130f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (shouldBind()) { 131f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown bind(); 132f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } else { 133f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown unbind(); 134f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 135f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 136f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 137f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private boolean shouldBind() { 138f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (mStarted) { 139f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown // Bind whenever there is a discovery request. 140f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (getDiscoveryRequest() != null) { 141f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return true; 142f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 143f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 144f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown // Bind whenever the application has an active route controller. 145f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown // This means that one of this provider's routes is selected. 146f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!mControllers.isEmpty()) { 147f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return true; 148f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 149f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 150f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return false; 151f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 152f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 153f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private void bind() { 154f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!mBound) { 155f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 156f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Binding"); 157f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 158f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 1593efa63d3b896244713e84acbb5945562dce41d77Jeff Brown Intent service = new Intent(MediaRouteProviderProtocol.SERVICE_INTERFACE); 160f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown service.setComponent(mComponentName); 161f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown try { 162f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown mBound = getContext().bindService(service, this, Context.BIND_AUTO_CREATE); 163f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!mBound && DEBUG) { 164f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Bind failed"); 165f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 166f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } catch (SecurityException ex) { 167f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 168f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Bind failed", ex); 169f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 170f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 171f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 172f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 173f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 174f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private void unbind() { 175f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (mBound) { 176f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 177f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Unbinding"); 178f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 179f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 180f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown mBound = false; 181f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown disconnect(); 182f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown getContext().unbindService(this); 183f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 184f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 185f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 186fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 187fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onServiceConnected(ComponentName name, IBinder service) { 188fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 189fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Connected"); 190fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 191fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 192fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mBound) { 193fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown disconnect(); 194fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 195fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Messenger messenger = (service != null ? new Messenger(service) : null); 1963efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (isValidRemoteMessenger(messenger)) { 197fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Connection connection = new Connection(messenger); 198fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (connection.register()) { 199fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mActiveConnection = connection; 200fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 201fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 202fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Registration failed"); 203fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 204fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 205fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 206fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.e(TAG, this + ": Service returned invalid messenger binder"); 207fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 208fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 209fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 210fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 211fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 212fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onServiceDisconnected(ComponentName name) { 213fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 214fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Service disconnected"); 215fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 216fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown disconnect(); 217fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 218fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 219fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onConnectionReady(Connection connection) { 220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 221fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionReady = true; 222fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown attachControllersToConnection(); 22311417b1cfde8f1749905f2d735623af9214148afJeff Brown 22411417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteDiscoveryRequest request = getDiscoveryRequest(); 22511417b1cfde8f1749905f2d735623af9214148afJeff Brown if (request != null) { 22611417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveConnection.setDiscoveryRequest(request); 22728520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 228fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 229fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 230fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 231fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onConnectionDied(Connection connection) { 232fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 233fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 234fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Service connection died"); 235fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 236fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown disconnect(); 237fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 238fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 239fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 240fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onConnectionError(Connection connection, String error) { 241fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 242fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 243fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Service connection error - " + error); 244fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 245fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unbind(); 246fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 247fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 248fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 249fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onConnectionDescriptorChanged(Connection connection, 25011417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor descriptor) { 251fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 252fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 253fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Descriptor changed, descriptor=" + descriptor); 254fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 255fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown setDescriptor(descriptor); 256fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 257fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 258fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 259fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void disconnect() { 260fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection != null) { 261fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown setDescriptor(null); 262fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionReady = false; 263fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown detachControllersFromConnection(); 264fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mActiveConnection.dispose(); 265fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mActiveConnection = null; 266fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 267fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 268fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 269fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onControllerReleased(Controller controller) { 270fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.remove(controller); 271fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown controller.detachConnection(); 272f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown updateBinding(); 273fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 274fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 275fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void attachControllersToConnection() { 276fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControllers.size(); 277fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 278fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.get(i).attachConnection(mActiveConnection); 279fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 280fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 281fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 282fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void detachControllersFromConnection() { 283fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControllers.size(); 284fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 285fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.get(i).detachConnection(); 286fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 287fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 288fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 289fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 290fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public String toString() { 291fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return "Service connection " + mComponentName.flattenToShortString(); 292fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 293fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 294fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final class Controller extends RouteController { 295fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final String mRouteId; 296fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 297fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mSelected; 298fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mPendingSetVolume = -1; 299fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mPendingUpdateVolumeDelta; 300fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 301fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private Connection mConnection; 302fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mControllerId; 303fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 304fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public Controller(String routeId) { 305fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mRouteId = routeId; 306fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 307fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 308fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void attachConnection(Connection connection) { 309fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection = connection; 310fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllerId = connection.createRouteController(mRouteId); 311fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mSelected) { 312fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.selectRoute(mControllerId); 313fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPendingSetVolume >= 0) { 314fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.setVolume(mControllerId, mPendingSetVolume); 315fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingSetVolume = -1; 316fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 317fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPendingUpdateVolumeDelta != 0) { 318fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.updateVolume(mControllerId, mPendingUpdateVolumeDelta); 319fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingUpdateVolumeDelta = 0; 320fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 321fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 322fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 323fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 324fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void detachConnection() { 325fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 326fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.releaseRouteController(mControllerId); 327fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection = null; 328fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllerId = 0; 329fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 330fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 331fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 332fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 333129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onRelease() { 334fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onControllerReleased(this); 335fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 336fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 337fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 338129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onSelect() { 339fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSelected = true; 340fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 341fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.selectRoute(mControllerId); 342fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 343fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 344fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 345fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 346129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onUnselect() { 34794be6100218126ce6a08bf1f56209578500b361fRoboErik onUnselect(MediaRouter.UNSELECT_REASON_UNKNOWN); 34894be6100218126ce6a08bf1f56209578500b361fRoboErik } 34994be6100218126ce6a08bf1f56209578500b361fRoboErik 35094be6100218126ce6a08bf1f56209578500b361fRoboErik @Override 35194be6100218126ce6a08bf1f56209578500b361fRoboErik public void onUnselect(int reason) { 352fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSelected = false; 353fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 35494be6100218126ce6a08bf1f56209578500b361fRoboErik mConnection.unselectRoute(mControllerId, reason); 355fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 356fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 357fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 358fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 359129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onSetVolume(int volume) { 360fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 361fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.setVolume(mControllerId, volume); 362fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 363fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingSetVolume = volume; 364fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingUpdateVolumeDelta = 0; 365fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 366fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 367fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 368fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 369129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onUpdateVolume(int delta) { 370fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 371fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.updateVolume(mControllerId, delta); 372fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 373fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingUpdateVolumeDelta += delta; 374fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 375fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 376fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 377fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 378129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public boolean onControlRequest(Intent intent, ControlRequestCallback callback) { 379fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 380fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mConnection.sendControlRequest(mControllerId, intent, callback); 381fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 382fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 383fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 384fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 385fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 386fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final class Connection implements DeathRecipient { 387fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final Messenger mServiceMessenger; 388fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ReceiveHandler mReceiveHandler; 389fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final Messenger mReceiveMessenger; 390fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 391fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mNextRequestId = 1; 392fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mNextControllerId = 1; 393fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mServiceVersion; // non-zero when registration complete 394fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 395fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mPendingRegisterRequestId; 396fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final SparseArray<ControlRequestCallback> mPendingCallbacks = 397fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown new SparseArray<ControlRequestCallback>(); 398fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 399fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public Connection(Messenger serviceMessenger) { 400fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger = serviceMessenger; 401fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mReceiveHandler = new ReceiveHandler(this); 402fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mReceiveMessenger = new Messenger(mReceiveHandler); 403fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 404fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 405fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean register() { 406fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId = mNextRequestId++; 4073efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (!sendRequest(CLIENT_MSG_REGISTER, 408fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId, 4093efa63d3b896244713e84acbb5945562dce41d77Jeff Brown CLIENT_VERSION_CURRENT, null, null)) { 410fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 411fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 412fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 413fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 414fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger.getBinder().linkToDeath(this, 0); 415fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 416fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (RemoteException ex) { 417fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown binderDied(); 418fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 419fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 420fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 421fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 422fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void dispose() { 4233efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_UNREGISTER, 0, 0, null, null); 424fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mReceiveHandler.dispose(); 425fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger.getBinder().unlinkToDeath(this, 0); 426fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 427fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPrivateHandler.post(new Runnable() { 428fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 429fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void run() { 430fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown failPendingCallbacks(); 431fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 432fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown }); 433fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 434fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 435fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void failPendingCallbacks() { 436fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = 0; 437fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < mPendingCallbacks.size(); i++) { 43837da34e71d13376b3542b28d19c7356c622d6747Jeff Brown mPendingCallbacks.valueAt(i).onError(null, null); 439fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 440fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.clear(); 441fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 442fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 443fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onGenericFailure(int requestId) { 444fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (requestId == mPendingRegisterRequestId) { 445fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId = 0; 446fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionError(this, "Registation failed"); 447fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 448fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ControlRequestCallback callback = mPendingCallbacks.get(requestId); 449fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 450fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.remove(requestId); 4513d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown callback.onError(null, null); 452fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 453fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 454fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 455fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 456fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onGenericSuccess(int requestId) { 457fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 458fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 459fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 460fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onRegistered(int requestId, int serviceVersion, 461fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle descriptorBundle) { 462fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mServiceVersion == 0 463fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown && requestId == mPendingRegisterRequestId 4643efa63d3b896244713e84acbb5945562dce41d77Jeff Brown && serviceVersion >= SERVICE_VERSION_1) { 465fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId = 0; 466fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceVersion = serviceVersion; 467fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionDescriptorChanged(this, 46811417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor.fromBundle(descriptorBundle)); 469fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionReady(this); 470fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 471fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 472fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 473fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 474fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 475fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onDescriptorChanged(Bundle descriptorBundle) { 476fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mServiceVersion != 0) { 477fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionDescriptorChanged(this, 47811417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor.fromBundle(descriptorBundle)); 479fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 480fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 481fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 482fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 483fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 4843d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown public boolean onControlRequestSucceeded(int requestId, Bundle data) { 485fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ControlRequestCallback callback = mPendingCallbacks.get(requestId); 486fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 487fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.remove(requestId); 4883d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown callback.onResult(data); 4893d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown return true; 4903d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown } 4913d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown return false; 4923d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown } 4933d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown 4943d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown public boolean onControlRequestFailed(int requestId, String error, Bundle data) { 4953d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown ControlRequestCallback callback = mPendingCallbacks.get(requestId); 4963d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown if (callback != null) { 4973d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown mPendingCallbacks.remove(requestId); 4983d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown callback.onError(error, data); 499fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 500fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 501fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 502fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 503fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 504fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 505fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void binderDied() { 506fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPrivateHandler.post(new Runnable() { 507fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 508fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void run() { 509fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionDied(Connection.this); 510fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 511fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown }); 512fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 513fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 514fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public int createRouteController(String routeId) { 515fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int controllerId = mNextControllerId++; 516fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle data = new Bundle(); 5173efa63d3b896244713e84acbb5945562dce41d77Jeff Brown data.putString(CLIENT_DATA_ROUTE_ID, routeId); 5183efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_CREATE_ROUTE_CONTROLLER, 519fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, data); 520fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return controllerId; 521fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 522fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 523fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void releaseRouteController(int controllerId) { 5243efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_RELEASE_ROUTE_CONTROLLER, 525fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, null); 526fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 527fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 528fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void selectRoute(int controllerId) { 5293efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_SELECT_ROUTE, 530fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, null); 531fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 532fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 53394be6100218126ce6a08bf1f56209578500b361fRoboErik public void unselectRoute(int controllerId, int reason) { 53494be6100218126ce6a08bf1f56209578500b361fRoboErik Bundle extras = new Bundle(); 53594be6100218126ce6a08bf1f56209578500b361fRoboErik extras.putInt(CLIENT_DATA_UNSELECT_REASON, reason); 5363efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_UNSELECT_ROUTE, 53794be6100218126ce6a08bf1f56209578500b361fRoboErik mNextRequestId++, controllerId, null, extras); 538fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 539fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 540fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void setVolume(int controllerId, int volume) { 541fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle data = new Bundle(); 5423efa63d3b896244713e84acbb5945562dce41d77Jeff Brown data.putInt(CLIENT_DATA_VOLUME, volume); 5433efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_SET_ROUTE_VOLUME, 544fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, data); 545fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 546fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 547fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void updateVolume(int controllerId, int delta) { 548fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle data = new Bundle(); 5493efa63d3b896244713e84acbb5945562dce41d77Jeff Brown data.putInt(CLIENT_DATA_VOLUME, delta); 5503efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_UPDATE_ROUTE_VOLUME, 551fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, data); 552fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 553fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 554fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean sendControlRequest(int controllerId, Intent intent, 555fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ControlRequestCallback callback) { 556fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int requestId = mNextRequestId++; 5573efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (sendRequest(CLIENT_MSG_ROUTE_CONTROL_REQUEST, 558fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown requestId, controllerId, intent, null)) { 559fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 560fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.put(requestId, callback); 561fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 562fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 563fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 564fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 565fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 566fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 56711417b1cfde8f1749905f2d735623af9214148afJeff Brown public void setDiscoveryRequest(MediaRouteDiscoveryRequest request) { 5683efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_SET_DISCOVERY_REQUEST, 56911417b1cfde8f1749905f2d735623af9214148afJeff Brown mNextRequestId++, 0, request != null ? request.asBundle() : null, null); 57028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 57128520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 572fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean sendRequest(int what, int requestId, int arg, Object obj, Bundle data) { 573fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Message msg = Message.obtain(); 574fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.what = what; 575fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.arg1 = requestId; 576fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.arg2 = arg; 577fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.obj = obj; 578fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.setData(data); 579fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.replyTo = mReceiveMessenger; 580fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 581fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger.send(msg); 582fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 583fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (DeadObjectException ex) { 584fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // The service died. 585fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (RemoteException ex) { 5863efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (what != CLIENT_MSG_UNREGISTER) { 587fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.e(TAG, "Could not send message to service.", ex); 588fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 589fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 590fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 591fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 592fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 593fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 594fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final class PrivateHandler extends Handler { 595fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 596fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 597fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 598fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Handler that receives messages from the server. 599fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <p> 600fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This inner class is static and only retains a weak reference to the connection 601fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * to prevent the client from being leaked in case the service is holding an 602fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * active reference to the client's messenger. 603fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p><p> 604fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This handler should not be used to handle any messages other than those 605fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * that come from the service. 606fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p> 607fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 608fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private static final class ReceiveHandler extends Handler { 609fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final WeakReference<Connection> mConnectionRef; 610fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 611fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public ReceiveHandler(Connection connection) { 612fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionRef = new WeakReference<Connection>(connection); 613fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 614fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 615fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void dispose() { 616fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionRef.clear(); 617fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 618fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 619fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 620fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void handleMessage(Message msg) { 621f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Connection connection = mConnectionRef.get(); 622f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (connection != null) { 623f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final int what = msg.what; 624f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final int requestId = msg.arg1; 625f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final int arg = msg.arg2; 626f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final Object obj = msg.obj; 627f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final Bundle data = msg.peekData(); 628f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!processMessage(connection, what, requestId, arg, obj, data)) { 629f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 630f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, "Unhandled message from server: " + msg); 631f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 632fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 633fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 634fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 635fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 636f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private boolean processMessage(Connection connection, 637f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown int what, int requestId, int arg, Object obj, Bundle data) { 638f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown switch (what) { 6393efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_GENERIC_FAILURE: 640f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown connection.onGenericFailure(requestId); 641f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return true; 642f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 6433efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_GENERIC_SUCCESS: 644f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown connection.onGenericSuccess(requestId); 645f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return true; 646f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 6473efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_REGISTERED: 648f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (obj == null || obj instanceof Bundle) { 649f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return connection.onRegistered(requestId, arg, (Bundle)obj); 650f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 651f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown break; 652f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 6533efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_DESCRIPTOR_CHANGED: 654f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (obj == null || obj instanceof Bundle) { 655f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return connection.onDescriptorChanged((Bundle)obj); 656f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 657f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown break; 658f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 6593efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED: 660f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (obj == null || obj instanceof Bundle) { 661f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return connection.onControlRequestSucceeded( 662f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown requestId, (Bundle)obj); 663f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 664f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown break; 665f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 6663efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_CONTROL_REQUEST_FAILED: 667f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (obj == null || obj instanceof Bundle) { 6687c5516660ad65c3f2a1a63ead6ffd2ae1879dd45Jeff Brown String error = (data == null ? null : 6693efa63d3b896244713e84acbb5945562dce41d77Jeff Brown data.getString(SERVICE_DATA_ERROR)); 670f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return connection.onControlRequestFailed( 671f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown requestId, error, (Bundle)obj); 672f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 673f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown break; 674fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 675fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 676fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 677fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 678fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown} 679