RegisteredMediaRouteProvider.java revision fa326a4649d9d0e8113e315f6c8251fe686abce4
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 17fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownpackage android.support.v4.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; 31fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.support.v4.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; 37fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 38fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/** 39fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Maintains a connection to a particular media route provider service. 40fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 41fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownfinal class RegisteredMediaRouteProvider extends MediaRouteProvider 42fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown implements ServiceConnection { 43fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private static final String TAG = "RegisteredMediaRouteProvider"; 44fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private static final boolean DEBUG = true; 45fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 46fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ComponentName mComponentName; 47fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final PrivateHandler mPrivateHandler; 48fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<Controller> mControllers = new ArrayList<Controller>(); 49fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 50fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mBound; 51fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private Connection mActiveConnection; 52fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mConnectionReady; 53fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 54fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public RegisteredMediaRouteProvider(Context context, ComponentName componentName) { 55fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown super(context, new ProviderMetadata(componentName.getPackageName())); 56fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 57fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mComponentName = componentName; 58fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPrivateHandler = new PrivateHandler(); 59fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 60fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 61fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 62fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public RouteController onCreateRouteController(String routeId) { 63fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderDescriptor descriptor = getDescriptor(); 64fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (descriptor != null) { 65fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RouteDescriptor[] routes = descriptor.getRoutes(); 66fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < routes.length; i++) { 67fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (routes[i].getId().equals(routeId)) { 68fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Controller controller = new Controller(routeId); 69fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.add(controller); 70fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnectionReady) { 71fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown controller.attachConnection(mActiveConnection); 72fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 73fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return controller; 74fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 75fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 76fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 77fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return null; 78fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 79fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 80fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean hasComponentName(String packageName, String className) { 81fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mComponentName.getPackageName().equals(packageName) 82fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown && mComponentName.getClassName().equals(className); 83fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 84fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 85fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void bind() { 86fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 87fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Binding"); 88fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 89fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 90fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Intent service = new Intent(MediaRouteProviderService.SERVICE_INTERFACE); 91fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown service.setComponent(mComponentName); 92fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 93fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // TODO: Should this use BIND_ALLOW_OOM_MANAGEMENT? 94fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mBound = getContext().bindService(service, this, Context.BIND_AUTO_CREATE); 95fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!mBound && DEBUG) { 96fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Bind failed"); 97fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 98fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (SecurityException ex) { 99fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 100fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Bind failed", ex); 101fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 102fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 103fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 104fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 105fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void unbind() { 106fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 107fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Unbinding"); 108fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 109fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 110fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown disconnect(); 111fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mBound) { 112fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mBound = false; 113fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown getContext().unbindService(this); 114fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 115fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 116fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 117fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void rebindIfDisconnected() { 118fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == null) { 119fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unbind(); 120fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown bind(); 121fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 122fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 123fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 124fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 125fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onServiceConnected(ComponentName name, IBinder service) { 126fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 127fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Connected"); 128fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 129fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 130fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mBound) { 131fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown disconnect(); 132fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 133fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Messenger messenger = (service != null ? new Messenger(service) : null); 134fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (MediaRouteProviderService.isValidRemoteMessenger(messenger)) { 135fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Connection connection = new Connection(messenger); 136fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (connection.register()) { 137fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mActiveConnection = connection; 138fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 139fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 140fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Registration failed"); 141fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 142fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 143fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 144fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.e(TAG, this + ": Service returned invalid messenger binder"); 145fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 146fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 147fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 148fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 149fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 150fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void onServiceDisconnected(ComponentName name) { 151fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 152fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Service disconnected"); 153fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 154fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown disconnect(); 155fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 156fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 157fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onConnectionReady(Connection connection) { 158fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 159fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionReady = true; 160fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown attachControllersToConnection(); 161fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 163fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 164fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onConnectionDied(Connection connection) { 165fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 166fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 167fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Service connection died"); 168fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 169fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown disconnect(); 170fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 171fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 172fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 173fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onConnectionError(Connection connection, String error) { 174fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 175fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 176fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Service connection error - " + error); 177fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 178fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unbind(); 179fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 180fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 181fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 182fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onConnectionDescriptorChanged(Connection connection, 183fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderDescriptor descriptor) { 184fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 185fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 186fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Descriptor changed, descriptor=" + descriptor); 187fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 188fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown setDescriptor(descriptor); 189fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 190fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 191fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 192fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void disconnect() { 193fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection != null) { 194fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown setDescriptor(null); 195fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionReady = false; 196fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown detachControllersFromConnection(); 197fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mActiveConnection.dispose(); 198fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mActiveConnection = null; 199fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 200fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 201fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 202fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void onControllerReleased(Controller controller) { 203fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.remove(controller); 204fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown controller.detachConnection(); 205fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 206fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 207fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void attachControllersToConnection() { 208fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControllers.size(); 209fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 210fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.get(i).attachConnection(mActiveConnection); 211fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 212fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 213fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 214fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void detachControllersFromConnection() { 215fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControllers.size(); 216fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 217fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.get(i).detachConnection(); 218fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 219fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 220fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 221fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 222fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public String toString() { 223fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return "Service connection " + mComponentName.flattenToShortString(); 224fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 225fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 226fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final class Controller extends RouteController { 227fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final String mRouteId; 228fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 229fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mSelected; 230fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mPendingSetVolume = -1; 231fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mPendingUpdateVolumeDelta; 232fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 233fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private Connection mConnection; 234fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mControllerId; 235fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 236fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public Controller(String routeId) { 237fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mRouteId = routeId; 238fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 239fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 240fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void attachConnection(Connection connection) { 241fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection = connection; 242fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllerId = connection.createRouteController(mRouteId); 243fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mSelected) { 244fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.selectRoute(mControllerId); 245fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPendingSetVolume >= 0) { 246fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.setVolume(mControllerId, mPendingSetVolume); 247fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingSetVolume = -1; 248fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 249fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPendingUpdateVolumeDelta != 0) { 250fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.updateVolume(mControllerId, mPendingUpdateVolumeDelta); 251fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingUpdateVolumeDelta = 0; 252fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 253fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 254fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 255fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 256fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void detachConnection() { 257fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 258fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.releaseRouteController(mControllerId); 259fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection = null; 260fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllerId = 0; 261fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 262fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 263fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 264fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 265fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void release() { 266fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onControllerReleased(this); 267fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 268fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 269fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 270fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void select() { 271fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSelected = true; 272fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 273fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.selectRoute(mControllerId); 274fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 275fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 276fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 277fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 278fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void unselect() { 279fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSelected = false; 280fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 281fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.unselectRoute(mControllerId); 282fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 283fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 284fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 285fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 286fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void setVolume(int volume) { 287fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 288fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.setVolume(mControllerId, volume); 289fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 290fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingSetVolume = volume; 291fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingUpdateVolumeDelta = 0; 292fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 293fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 294fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 295fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 296fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void updateVolume(int delta) { 297fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 298fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.updateVolume(mControllerId, delta); 299fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 300fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingUpdateVolumeDelta += delta; 301fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 302fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 303fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 304fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 305fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean sendControlRequest(Intent intent, ControlRequestCallback callback) { 306fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 307fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mConnection.sendControlRequest(mControllerId, intent, callback); 308fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 309fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 310fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 311fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 312fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 313fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final class Connection implements DeathRecipient { 314fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final Messenger mServiceMessenger; 315fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ReceiveHandler mReceiveHandler; 316fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final Messenger mReceiveMessenger; 317fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 318fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mNextRequestId = 1; 319fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mNextControllerId = 1; 320fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mServiceVersion; // non-zero when registration complete 321fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 322fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mPendingRegisterRequestId; 323fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final SparseArray<ControlRequestCallback> mPendingCallbacks = 324fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown new SparseArray<ControlRequestCallback>(); 325fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 326fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public Connection(Messenger serviceMessenger) { 327fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger = serviceMessenger; 328fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mReceiveHandler = new ReceiveHandler(this); 329fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mReceiveMessenger = new Messenger(mReceiveHandler); 330fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 331fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 332fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean register() { 333fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId = mNextRequestId++; 334fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!sendRequest(MediaRouteProviderService.CLIENT_MSG_REGISTER, 335fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId, 336fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown MediaRouteProviderService.CLIENT_VERSION_CURRENT, null, null)) { 337fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 338fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 339fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 340fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 341fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger.getBinder().linkToDeath(this, 0); 342fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 343fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (RemoteException ex) { 344fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown binderDied(); 345fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 346fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 347fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 348fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 349fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void dispose() { 350fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sendRequest(MediaRouteProviderService.CLIENT_MSG_UNREGISTER, 0, 0, null, null); 351fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mReceiveHandler.dispose(); 352fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger.getBinder().unlinkToDeath(this, 0); 353fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 354fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPrivateHandler.post(new Runnable() { 355fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 356fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void run() { 357fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown failPendingCallbacks(); 358fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 359fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown }); 360fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 361fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 362fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void failPendingCallbacks() { 363fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = 0; 364fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < mPendingCallbacks.size(); i++) { 365fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.get(i).onResult(ControlRequestCallback.REQUEST_FAILED, null); 366fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 367fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.clear(); 368fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 369fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 370fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onGenericFailure(int requestId) { 371fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (requestId == mPendingRegisterRequestId) { 372fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId = 0; 373fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionError(this, "Registation failed"); 374fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 375fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ControlRequestCallback callback = mPendingCallbacks.get(requestId); 376fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 377fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.remove(requestId); 378fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown callback.onResult(ControlRequestCallback.REQUEST_FAILED, null); 379fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 380fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 381fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 382fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 383fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onGenericSuccess(int requestId) { 384fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 385fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 386fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 387fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onRegistered(int requestId, int serviceVersion, 388fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle descriptorBundle) { 389fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mServiceVersion == 0 390fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown && requestId == mPendingRegisterRequestId 391fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown && serviceVersion >= MediaRouteProviderService.SERVICE_VERSION_1) { 392fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId = 0; 393fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceVersion = serviceVersion; 394fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionDescriptorChanged(this, 395fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderDescriptor.fromBundle(descriptorBundle)); 396fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionReady(this); 397fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 398fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 399fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 400fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 401fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 402fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onDescriptorChanged(Bundle descriptorBundle) { 403fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mServiceVersion != 0) { 404fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionDescriptorChanged(this, 405fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ProviderDescriptor.fromBundle(descriptorBundle)); 406fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 407fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 408fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 409fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 410fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 411fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onControlRequestResult(int requestId, int resultCode, 412fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle resultData) { 413fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ControlRequestCallback callback = mPendingCallbacks.get(requestId); 414fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 415fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.remove(requestId); 416fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown callback.onResult(resultCode, resultData); 417fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 418fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 419fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 420fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 421fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 422fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 423fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void binderDied() { 424fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPrivateHandler.post(new Runnable() { 425fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 426fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void run() { 427fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionDied(Connection.this); 428fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 429fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown }); 430fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 431fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 432fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public int createRouteController(String routeId) { 433fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int controllerId = mNextControllerId++; 434fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle data = new Bundle(); 435fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown data.putString(MediaRouteProviderService.CLIENT_DATA_ROUTE_ID, routeId); 436fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sendRequest(MediaRouteProviderService.CLIENT_MSG_CREATE_ROUTE_CONTROLLER, 437fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, data); 438fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return controllerId; 439fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 440fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 441fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void releaseRouteController(int controllerId) { 442fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sendRequest(MediaRouteProviderService.CLIENT_MSG_RELEASE_ROUTE_CONTROLLER, 443fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, null); 444fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 445fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 446fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void selectRoute(int controllerId) { 447fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sendRequest(MediaRouteProviderService.CLIENT_MSG_SELECT_ROUTE, 448fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, null); 449fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 450fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 451fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void unselectRoute(int controllerId) { 452fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sendRequest(MediaRouteProviderService.CLIENT_MSG_UNSELECT_ROUTE, 453fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, null); 454fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 455fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 456fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void setVolume(int controllerId, int volume) { 457fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle data = new Bundle(); 458fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown data.putInt(MediaRouteProviderService.CLIENT_DATA_VOLUME, volume); 459fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sendRequest(MediaRouteProviderService.CLIENT_MSG_SET_ROUTE_VOLUME, 460fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, data); 461fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 462fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 463fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void updateVolume(int controllerId, int delta) { 464fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle data = new Bundle(); 465fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown data.putInt(MediaRouteProviderService.CLIENT_DATA_VOLUME, delta); 466fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown sendRequest(MediaRouteProviderService.CLIENT_MSG_UPDATE_ROUTE_VOLUME, 467fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, data); 468fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 469fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 470fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean sendControlRequest(int controllerId, Intent intent, 471fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ControlRequestCallback callback) { 472fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int requestId = mNextRequestId++; 473fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (sendRequest(MediaRouteProviderService.CLIENT_MSG_ROUTE_CONTROL_REQUEST, 474fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown requestId, controllerId, intent, null)) { 475fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 476fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.put(requestId, callback); 477fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 478fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 479fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 480fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 481fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 482fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 483fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean sendRequest(int what, int requestId, int arg, Object obj, Bundle data) { 484fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Message msg = Message.obtain(); 485fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.what = what; 486fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.arg1 = requestId; 487fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.arg2 = arg; 488fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.obj = obj; 489fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.setData(data); 490fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.replyTo = mReceiveMessenger; 491fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 492fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger.send(msg); 493fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 494fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (DeadObjectException ex) { 495fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // The service died. 496fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (RemoteException ex) { 497fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (what != MediaRouteProviderService.CLIENT_MSG_UNREGISTER) { 498fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.e(TAG, "Could not send message to service.", ex); 499fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 500fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 501fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 502fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 503fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 504fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 505fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final class PrivateHandler extends Handler { 506fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 507fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 508fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 509fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Handler that receives messages from the server. 510fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <p> 511fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This inner class is static and only retains a weak reference to the connection 512fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * to prevent the client from being leaked in case the service is holding an 513fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * active reference to the client's messenger. 514fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p><p> 515fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This handler should not be used to handle any messages other than those 516fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * that come from the service. 517fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p> 518fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 519fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private static final class ReceiveHandler extends Handler { 520fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final WeakReference<Connection> mConnectionRef; 521fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 522fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public ReceiveHandler(Connection connection) { 523fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionRef = new WeakReference<Connection>(connection); 524fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 525fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 526fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void dispose() { 527fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionRef.clear(); 528fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 529fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 530fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 531fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void handleMessage(Message msg) { 532fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int what = msg.what; 533fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int requestId = msg.arg1; 534fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final int arg = msg.arg2; 535fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown final Object obj = msg.obj; 536fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (!processMessage(what, requestId, arg, obj)) { 537fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 538fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, "Unhandled message from server: " + msg); 539fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 540fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 541fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 542fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 543fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean processMessage(int what, int requestId, int arg, Object obj) { 544fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Connection connection = mConnectionRef.get(); 545fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (connection != null) { 546fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown switch (what) { 547fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown case MediaRouteProviderService.SERVICE_MSG_GENERIC_FAILURE: 548fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.onGenericFailure(requestId); 549fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 550fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 551fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown case MediaRouteProviderService.SERVICE_MSG_GENERIC_SUCCESS: 552fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.onGenericSuccess(requestId); 553fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 554fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 555fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown case MediaRouteProviderService.SERVICE_MSG_REGISTERED: 556fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (obj instanceof Bundle) { 557fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return connection.onRegistered(requestId, arg, (Bundle)obj); 558fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 559fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown break; 560fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 561fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown case MediaRouteProviderService.SERVICE_MSG_DESCRIPTOR_CHANGED: 562fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (obj instanceof Bundle) { 563fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return connection.onDescriptorChanged((Bundle)obj); 564fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 565fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown break; 566fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 567fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown case MediaRouteProviderService.SERVICE_MSG_CONTROL_RESULT: 568fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (obj == null || obj instanceof Bundle) { 569fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return connection.onControlRequestResult( 570fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown requestId, arg, (Bundle)obj); 571fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 572fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown break; 573fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 574fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 575fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 576fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 577fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 578fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown} 579