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 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.mediarouter.media; 18fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_DATA_ROUTE_ID; 20ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_DATA_ROUTE_LIBRARY_GROUP; 21ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_DATA_UNSELECT_REASON; 22ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_DATA_VOLUME; 23ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol 248e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas .CLIENT_MSG_CREATE_ROUTE_CONTROLLER; 25ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_REGISTER; 26ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol 278e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas .CLIENT_MSG_RELEASE_ROUTE_CONTROLLER; 28f2d1695bf23114f2a5d6bfc9e092a4bfcb5b2701Aurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol 29f2d1695bf23114f2a5d6bfc9e092a4bfcb5b2701Aurimas Liutikas .CLIENT_MSG_ROUTE_CONTROL_REQUEST; 30ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_SELECT_ROUTE; 31f2d1695bf23114f2a5d6bfc9e092a4bfcb5b2701Aurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol 32f2d1695bf23114f2a5d6bfc9e092a4bfcb5b2701Aurimas Liutikas .CLIENT_MSG_SET_DISCOVERY_REQUEST; 33ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_SET_ROUTE_VOLUME; 34ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_UNREGISTER; 35ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_UNSELECT_ROUTE; 36ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_UPDATE_ROUTE_VOLUME; 37ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.CLIENT_VERSION_CURRENT; 38ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_DATA_ERROR; 39ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol 408e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas .SERVICE_MSG_CONTROL_REQUEST_FAILED; 41ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol 428e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas .SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED; 43ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_DESCRIPTOR_CHANGED; 44ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_FAILURE; 45ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_SUCCESS; 46ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_REGISTERED; 47ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_VERSION_1; 48ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.mediarouter.media.MediaRouteProviderProtocol.isValidRemoteMessenger; 498e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas 50fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.ComponentName; 51fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.Context; 52fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.Intent; 53fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.ServiceConnection; 54fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Bundle; 55fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.DeadObjectException; 56fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Handler; 57fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.IBinder; 58fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.IBinder.DeathRecipient; 59fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Message; 60fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.os.Messenger; 618e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport android.os.RemoteException; 62fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.util.Log; 63fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.util.SparseArray; 64fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 65f2d1695bf23114f2a5d6bfc9e092a4bfcb5b2701Aurimas Liutikasimport androidx.annotation.NonNull; 66f2d1695bf23114f2a5d6bfc9e092a4bfcb5b2701Aurimas Liutikasimport androidx.mediarouter.media.MediaRouter.ControlRequestCallback; 67f2d1695bf23114f2a5d6bfc9e092a4bfcb5b2701Aurimas Liutikas 68fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.lang.ref.WeakReference; 69fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.util.ArrayList; 7011417b1cfde8f1749905f2d735623af9214148afJeff Brownimport java.util.List; 71fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 72fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/** 73fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Maintains a connection to a particular media route provider service. 74fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 75fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownfinal class RegisteredMediaRouteProvider extends MediaRouteProvider 76fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown implements ServiceConnection { 77e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas static final String TAG = "MediaRouteProviderProxy"; // max. 23 chars 78e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 79fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 80fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ComponentName mComponentName; 81e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas final PrivateHandler mPrivateHandler; 82fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<Controller> mControllers = new ArrayList<Controller>(); 83fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 84f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private boolean mStarted; 85fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mBound; 86fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private Connection mActiveConnection; 87fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mConnectionReady; 88fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 89fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public RegisteredMediaRouteProvider(Context context, ComponentName componentName) { 90adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown super(context, new ProviderMetadata(componentName)); 91fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 92fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mComponentName = componentName; 93fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPrivateHandler = new PrivateHandler(); 94fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 95fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 96fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 972f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim public RouteController onCreateRouteController(@NonNull String routeId) { 982f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim if (routeId == null) { 992f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim throw new IllegalArgumentException("routeId cannot be null"); 100fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1012f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim return createRouteController(routeId, null); 1022f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim } 1032f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim 1042f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim @Override 1052f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim public RouteController onCreateRouteController( 1062f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim @NonNull String routeId, @NonNull String routeGroupId) { 1072f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim if (routeId == null) { 1082f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim throw new IllegalArgumentException("routeId cannot be null"); 1092f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim } 1102f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim if (routeGroupId == null) { 1112f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim throw new IllegalArgumentException("routeGroupId cannot be null"); 1122f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim } 1132f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim return createRouteController(routeId, routeGroupId); 114fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 115fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 11628520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown @Override 11711417b1cfde8f1749905f2d735623af9214148afJeff Brown public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) { 11828520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown if (mConnectionReady) { 11911417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveConnection.setDiscoveryRequest(request); 12028520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 121f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown updateBinding(); 12228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 12328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 1242a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim @Override 1252a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim public void onServiceConnected(ComponentName name, IBinder service) { 1262a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim if (DEBUG) { 1272a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim Log.d(TAG, this + ": Connected"); 1282a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } 1292a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim 1302a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim if (mBound) { 1312a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim disconnect(); 1322a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim 1332a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim Messenger messenger = (service != null ? new Messenger(service) : null); 1342a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim if (isValidRemoteMessenger(messenger)) { 1352a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim Connection connection = new Connection(messenger); 1362a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim if (connection.register()) { 1372a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim mActiveConnection = connection; 1382a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } else { 1392a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim if (DEBUG) { 1402a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim Log.d(TAG, this + ": Registration failed"); 1412a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } 1422a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } 1432a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } else { 1442a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim Log.e(TAG, this + ": Service returned invalid messenger binder"); 1452a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } 1462a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } 1472a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } 1482a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim 1492a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim @Override 1502a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim public void onServiceDisconnected(ComponentName name) { 1512a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim if (DEBUG) { 1522a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim Log.d(TAG, this + ": Service disconnected"); 1532a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } 1542a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim disconnect(); 1552a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } 1562a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim 1572a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim @Override 1582a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim public String toString() { 1592a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim return "Service connection " + mComponentName.flattenToShortString(); 1602a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim } 1612a67dc6d2e1c788bd14e4a9bd685ee4d924de8bbSungsoo Lim 162fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean hasComponentName(String packageName, String className) { 163fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mComponentName.getPackageName().equals(packageName) 164fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown && mComponentName.getClassName().equals(className); 165fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 166fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 167f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown public void start() { 168f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!mStarted) { 169fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 170f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Starting"); 171fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 172f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 173f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown mStarted = true; 174f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown updateBinding(); 175fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 176fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 177fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 178f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown public void stop() { 179f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (mStarted) { 180f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 181f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Stopping"); 182f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 183fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 184f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown mStarted = false; 185f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown updateBinding(); 186fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 187fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 188fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 189fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void rebindIfDisconnected() { 190f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (mActiveConnection == null && shouldBind()) { 191fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unbind(); 192fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown bind(); 193fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 194fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 195fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 196f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private void updateBinding() { 197f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (shouldBind()) { 198f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown bind(); 199f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } else { 200f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown unbind(); 201f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 202f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 203f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 204f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private boolean shouldBind() { 205f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (mStarted) { 206f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown // Bind whenever there is a discovery request. 207f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (getDiscoveryRequest() != null) { 208f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return true; 209f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 210f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 211f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown // Bind whenever the application has an active route controller. 212f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown // This means that one of this provider's routes is selected. 213f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!mControllers.isEmpty()) { 214f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return true; 215f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 216f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 217f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return false; 218f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 219f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 220f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private void bind() { 221f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!mBound) { 222f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 223f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Binding"); 224f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 225f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 2263efa63d3b896244713e84acbb5945562dce41d77Jeff Brown Intent service = new Intent(MediaRouteProviderProtocol.SERVICE_INTERFACE); 227f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown service.setComponent(mComponentName); 228f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown try { 229f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown mBound = getContext().bindService(service, this, Context.BIND_AUTO_CREATE); 230f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!mBound && DEBUG) { 231f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Bind failed"); 232f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 233f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } catch (SecurityException ex) { 234f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 235f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Bind failed", ex); 236f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 237f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 238f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 239f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 240f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 241f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private void unbind() { 242f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (mBound) { 243f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 244f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, this + ": Unbinding"); 245f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 246f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 247f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown mBound = false; 248f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown disconnect(); 249f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown getContext().unbindService(this); 250f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 251f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 252f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 2532f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim private RouteController createRouteController(String routeId, String routeGroupId) { 2542f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim MediaRouteProviderDescriptor descriptor = getDescriptor(); 2552f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim if (descriptor != null) { 2562f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim List<MediaRouteDescriptor> routes = descriptor.getRoutes(); 2572f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim final int count = routes.size(); 2582f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim for (int i = 0; i < count; i++) { 2592f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim final MediaRouteDescriptor route = routes.get(i); 2602f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim if (route.getId().equals(routeId)) { 2612f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim Controller controller = new Controller(routeId, routeGroupId); 2622f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim mControllers.add(controller); 2632f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim if (mConnectionReady) { 2642f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim controller.attachConnection(mActiveConnection); 2652f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim } 2662f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim updateBinding(); 2672f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim return controller; 2682f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim } 2692f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim } 2702f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim } 2712f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim return null; 2722f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim } 2732f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim 274e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas void onConnectionReady(Connection connection) { 275fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 276fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionReady = true; 277fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown attachControllersToConnection(); 27811417b1cfde8f1749905f2d735623af9214148afJeff Brown 27911417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteDiscoveryRequest request = getDiscoveryRequest(); 28011417b1cfde8f1749905f2d735623af9214148afJeff Brown if (request != null) { 28111417b1cfde8f1749905f2d735623af9214148afJeff Brown mActiveConnection.setDiscoveryRequest(request); 28228520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 283fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 284fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 285fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 286e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas void onConnectionDied(Connection connection) { 287fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 288fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 289fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Service connection died"); 290fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 291fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown disconnect(); 292fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 293fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 294fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 295e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas void onConnectionError(Connection connection, String error) { 296fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 297fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 298fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Service connection error - " + error); 299fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 300fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown unbind(); 301fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 302fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 303fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 304e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas void onConnectionDescriptorChanged(Connection connection, 30511417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor descriptor) { 306fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection == connection) { 307fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (DEBUG) { 308fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.d(TAG, this + ": Descriptor changed, descriptor=" + descriptor); 309fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 310fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown setDescriptor(descriptor); 311fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 312fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 313fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 314fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void disconnect() { 315fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mActiveConnection != null) { 316fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown setDescriptor(null); 317fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionReady = false; 318fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown detachControllersFromConnection(); 319fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mActiveConnection.dispose(); 320fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mActiveConnection = null; 321fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 322fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 323fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 324e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas void onControllerReleased(Controller controller) { 325fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.remove(controller); 326fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown controller.detachConnection(); 327f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown updateBinding(); 328fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 329fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 330fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void attachControllersToConnection() { 331fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControllers.size(); 332fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 333fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.get(i).attachConnection(mActiveConnection); 334fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 335fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 336fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 337fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void detachControllersFromConnection() { 338fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mControllers.size(); 339fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 340fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllers.get(i).detachConnection(); 341fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 342fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 343fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 344fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final class Controller extends RouteController { 345fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final String mRouteId; 3462f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim private final String mRouteGroupId; 347fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 348fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean mSelected; 349fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mPendingSetVolume = -1; 350fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mPendingUpdateVolumeDelta; 351fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 352fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private Connection mConnection; 353fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mControllerId; 354fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 3552f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim public Controller(String routeId, String routeGroupId) { 356fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mRouteId = routeId; 3572f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim mRouteGroupId = routeGroupId; 358fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 359fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 360fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void attachConnection(Connection connection) { 361fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection = connection; 3622f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim mControllerId = connection.createRouteController(mRouteId, mRouteGroupId); 363fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mSelected) { 364fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.selectRoute(mControllerId); 365fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPendingSetVolume >= 0) { 366fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.setVolume(mControllerId, mPendingSetVolume); 367fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingSetVolume = -1; 368fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 369fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mPendingUpdateVolumeDelta != 0) { 370fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown connection.updateVolume(mControllerId, mPendingUpdateVolumeDelta); 371fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingUpdateVolumeDelta = 0; 372fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 373fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 374fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 375fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 376fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void detachConnection() { 377fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 378fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.releaseRouteController(mControllerId); 379fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection = null; 380fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mControllerId = 0; 381fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 382fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 383fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 384fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 385129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onRelease() { 386fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onControllerReleased(this); 387fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 388fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 389fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 390129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onSelect() { 391fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSelected = true; 392fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 393fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.selectRoute(mControllerId); 394fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 395fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 396fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 397fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 398129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onUnselect() { 39994be6100218126ce6a08bf1f56209578500b361fRoboErik onUnselect(MediaRouter.UNSELECT_REASON_UNKNOWN); 40094be6100218126ce6a08bf1f56209578500b361fRoboErik } 40194be6100218126ce6a08bf1f56209578500b361fRoboErik 40294be6100218126ce6a08bf1f56209578500b361fRoboErik @Override 40394be6100218126ce6a08bf1f56209578500b361fRoboErik public void onUnselect(int reason) { 404fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mSelected = false; 405fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 40694be6100218126ce6a08bf1f56209578500b361fRoboErik mConnection.unselectRoute(mControllerId, reason); 407fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 408fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 409fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 410fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 411129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onSetVolume(int volume) { 412fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 413fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.setVolume(mControllerId, volume); 414fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 415fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingSetVolume = volume; 416fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingUpdateVolumeDelta = 0; 417fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 418fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 419fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 420fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 421129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public void onUpdateVolume(int delta) { 422fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 423fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnection.updateVolume(mControllerId, delta); 424fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else { 425fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingUpdateVolumeDelta += delta; 426fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 427fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 428fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 429fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 430129abf73ce9be1bc172b945263c7975ad1a3006fJeff Brown public boolean onControlRequest(Intent intent, ControlRequestCallback callback) { 431fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mConnection != null) { 432fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return mConnection.sendControlRequest(mControllerId, intent, callback); 433fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 434fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 435fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 436fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 437fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 438fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final class Connection implements DeathRecipient { 439fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final Messenger mServiceMessenger; 440fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ReceiveHandler mReceiveHandler; 441fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final Messenger mReceiveMessenger; 442fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 443fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mNextRequestId = 1; 444fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mNextControllerId = 1; 445fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mServiceVersion; // non-zero when registration complete 446fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 447fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int mPendingRegisterRequestId; 448fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final SparseArray<ControlRequestCallback> mPendingCallbacks = 449fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown new SparseArray<ControlRequestCallback>(); 450fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 451fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public Connection(Messenger serviceMessenger) { 452fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger = serviceMessenger; 453fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mReceiveHandler = new ReceiveHandler(this); 454fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mReceiveMessenger = new Messenger(mReceiveHandler); 455fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 456fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 457fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean register() { 458fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId = mNextRequestId++; 4593efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (!sendRequest(CLIENT_MSG_REGISTER, 460fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId, 4613efa63d3b896244713e84acbb5945562dce41d77Jeff Brown CLIENT_VERSION_CURRENT, null, null)) { 462fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 463fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 464fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 465fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 466fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger.getBinder().linkToDeath(this, 0); 467fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 468fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (RemoteException ex) { 469fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown binderDied(); 470fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 471fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 472fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 473fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 474fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void dispose() { 4753efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_UNREGISTER, 0, 0, null, null); 476fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mReceiveHandler.dispose(); 477fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger.getBinder().unlinkToDeath(this, 0); 478fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 479fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPrivateHandler.post(new Runnable() { 480fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 481fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void run() { 482fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown failPendingCallbacks(); 483fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 484fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown }); 485fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 486fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 487e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas void failPendingCallbacks() { 488fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = 0; 489fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < mPendingCallbacks.size(); i++) { 49037da34e71d13376b3542b28d19c7356c622d6747Jeff Brown mPendingCallbacks.valueAt(i).onError(null, null); 491fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 492fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.clear(); 493fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 494fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 495fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onGenericFailure(int requestId) { 496fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (requestId == mPendingRegisterRequestId) { 497fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId = 0; 498c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas onConnectionError(this, "Registration failed"); 499fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 500fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ControlRequestCallback callback = mPendingCallbacks.get(requestId); 501fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 502fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.remove(requestId); 5033d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown callback.onError(null, null); 504fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 505fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 506fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 507fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 508fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onGenericSuccess(int requestId) { 509fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 510fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 511fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 512fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onRegistered(int requestId, int serviceVersion, 513fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle descriptorBundle) { 514fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mServiceVersion == 0 515fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown && requestId == mPendingRegisterRequestId 5163efa63d3b896244713e84acbb5945562dce41d77Jeff Brown && serviceVersion >= SERVICE_VERSION_1) { 517fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingRegisterRequestId = 0; 518fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceVersion = serviceVersion; 519fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionDescriptorChanged(this, 52011417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor.fromBundle(descriptorBundle)); 521fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionReady(this); 522fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 523fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 524fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 525fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 526fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 527fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean onDescriptorChanged(Bundle descriptorBundle) { 528fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (mServiceVersion != 0) { 529fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionDescriptorChanged(this, 53011417b1cfde8f1749905f2d735623af9214148afJeff Brown MediaRouteProviderDescriptor.fromBundle(descriptorBundle)); 531fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 532fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 533fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 534fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 535fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 5363d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown public boolean onControlRequestSucceeded(int requestId, Bundle data) { 537fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ControlRequestCallback callback = mPendingCallbacks.get(requestId); 538fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 539fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.remove(requestId); 5403d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown callback.onResult(data); 5413d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown return true; 5423d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown } 5433d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown return false; 5443d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown } 5453d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown 5463d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown public boolean onControlRequestFailed(int requestId, String error, Bundle data) { 5473d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown ControlRequestCallback callback = mPendingCallbacks.get(requestId); 5483d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown if (callback != null) { 5493d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown mPendingCallbacks.remove(requestId); 5503d4c9459ed77f732dd3ba602713af6ebf9280c8cJeff Brown callback.onError(error, data); 551fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 552fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 553fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 554fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 555fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 556fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 557fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void binderDied() { 558fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPrivateHandler.post(new Runnable() { 559fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 560fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void run() { 561fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown onConnectionDied(Connection.this); 562fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 563fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown }); 564fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 565fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 5662f829125aef3796ca674d0ca5fccf9bd37b8417bSungsoo Lim public int createRouteController(String routeId, String routeGroupId) { 567fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int controllerId = mNextControllerId++; 568fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle data = new Bundle(); 5693efa63d3b896244713e84acbb5945562dce41d77Jeff Brown data.putString(CLIENT_DATA_ROUTE_ID, routeId); 5708e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas data.putString(CLIENT_DATA_ROUTE_LIBRARY_GROUP, routeGroupId); 5713efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_CREATE_ROUTE_CONTROLLER, 572fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, data); 573fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return controllerId; 574fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 575fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 576fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void releaseRouteController(int controllerId) { 5773efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_RELEASE_ROUTE_CONTROLLER, 578fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, null); 579fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 580fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 581fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void selectRoute(int controllerId) { 5823efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_SELECT_ROUTE, 583fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, null); 584fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 585fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 58694be6100218126ce6a08bf1f56209578500b361fRoboErik public void unselectRoute(int controllerId, int reason) { 58794be6100218126ce6a08bf1f56209578500b361fRoboErik Bundle extras = new Bundle(); 58894be6100218126ce6a08bf1f56209578500b361fRoboErik extras.putInt(CLIENT_DATA_UNSELECT_REASON, reason); 5893efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_UNSELECT_ROUTE, 59094be6100218126ce6a08bf1f56209578500b361fRoboErik mNextRequestId++, controllerId, null, extras); 591fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 592fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 593fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void setVolume(int controllerId, int volume) { 594fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle data = new Bundle(); 5953efa63d3b896244713e84acbb5945562dce41d77Jeff Brown data.putInt(CLIENT_DATA_VOLUME, volume); 5963efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_SET_ROUTE_VOLUME, 597fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, data); 598fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 599fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 600fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void updateVolume(int controllerId, int delta) { 601fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Bundle data = new Bundle(); 6023efa63d3b896244713e84acbb5945562dce41d77Jeff Brown data.putInt(CLIENT_DATA_VOLUME, delta); 6033efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_UPDATE_ROUTE_VOLUME, 604fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mNextRequestId++, controllerId, null, data); 605fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 606fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 607fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public boolean sendControlRequest(int controllerId, Intent intent, 608fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ControlRequestCallback callback) { 609fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int requestId = mNextRequestId++; 6103efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (sendRequest(CLIENT_MSG_ROUTE_CONTROL_REQUEST, 611fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown requestId, controllerId, intent, null)) { 612fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (callback != null) { 613fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPendingCallbacks.put(requestId, callback); 614fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 615fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 616fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 617fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 618fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 619fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 62011417b1cfde8f1749905f2d735623af9214148afJeff Brown public void setDiscoveryRequest(MediaRouteDiscoveryRequest request) { 6213efa63d3b896244713e84acbb5945562dce41d77Jeff Brown sendRequest(CLIENT_MSG_SET_DISCOVERY_REQUEST, 62211417b1cfde8f1749905f2d735623af9214148afJeff Brown mNextRequestId++, 0, request != null ? request.asBundle() : null, null); 62328520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown } 62428520a15611522424b52cf88e4a2dbeb1a9be42bJeff Brown 625fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private boolean sendRequest(int what, int requestId, int arg, Object obj, Bundle data) { 626fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Message msg = Message.obtain(); 627fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.what = what; 628fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.arg1 = requestId; 629fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.arg2 = arg; 630fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.obj = obj; 631fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.setData(data); 632fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown msg.replyTo = mReceiveMessenger; 633fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown try { 634fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mServiceMessenger.send(msg); 635fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return true; 636fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (DeadObjectException ex) { 637fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // The service died. 638fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } catch (RemoteException ex) { 6393efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (what != CLIENT_MSG_UNREGISTER) { 640fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Log.e(TAG, "Could not send message to service.", ex); 641fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 642fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 643fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 644fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 645fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 646fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 64798ec0d5b378c8417156037af6389e90f0074a26eAurimas Liutikas private static final class PrivateHandler extends Handler { 648e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas PrivateHandler() { 649e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas } 650fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 651fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 652fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown /** 653fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Handler that receives messages from the server. 654fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * <p> 655fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This inner class is static and only retains a weak reference to the connection 656fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * to prevent the client from being leaked in case the service is holding an 657fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * active reference to the client's messenger. 658fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p><p> 659fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * This handler should not be used to handle any messages other than those 660fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * that come from the service. 661fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * </p> 662fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 663fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private static final class ReceiveHandler extends Handler { 664fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final WeakReference<Connection> mConnectionRef; 665fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 666fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public ReceiveHandler(Connection connection) { 667fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionRef = new WeakReference<Connection>(connection); 668fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 669fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 670fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void dispose() { 671fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mConnectionRef.clear(); 672fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 673fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 674fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown @Override 675fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void handleMessage(Message msg) { 676f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Connection connection = mConnectionRef.get(); 677f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (connection != null) { 678f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final int what = msg.what; 679f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final int requestId = msg.arg1; 680f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final int arg = msg.arg2; 681f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final Object obj = msg.obj; 682f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown final Bundle data = msg.peekData(); 683f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (!processMessage(connection, what, requestId, arg, obj, data)) { 684f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (DEBUG) { 685f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown Log.d(TAG, "Unhandled message from server: " + msg); 686f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 687fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 688fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 689fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 690fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 691f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown private boolean processMessage(Connection connection, 692f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown int what, int requestId, int arg, Object obj, Bundle data) { 693f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown switch (what) { 6943efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_GENERIC_FAILURE: 695f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown connection.onGenericFailure(requestId); 696f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return true; 697f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 6983efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_GENERIC_SUCCESS: 699f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown connection.onGenericSuccess(requestId); 700f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return true; 701f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 7023efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_REGISTERED: 703f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (obj == null || obj instanceof Bundle) { 704f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return connection.onRegistered(requestId, arg, (Bundle)obj); 705f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 706f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown break; 707f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 7083efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_DESCRIPTOR_CHANGED: 709f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (obj == null || obj instanceof Bundle) { 710f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return connection.onDescriptorChanged((Bundle)obj); 711f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 712f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown break; 713f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 7143efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED: 715f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (obj == null || obj instanceof Bundle) { 716f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return connection.onControlRequestSucceeded( 717f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown requestId, (Bundle)obj); 718f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 719f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown break; 720f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown 7213efa63d3b896244713e84acbb5945562dce41d77Jeff Brown case SERVICE_MSG_CONTROL_REQUEST_FAILED: 722f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown if (obj == null || obj instanceof Bundle) { 7237c5516660ad65c3f2a1a63ead6ffd2ae1879dd45Jeff Brown String error = (data == null ? null : 7243efa63d3b896244713e84acbb5945562dce41d77Jeff Brown data.getString(SERVICE_DATA_ERROR)); 725f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown return connection.onControlRequestFailed( 726f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown requestId, error, (Bundle)obj); 727f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown } 728f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown break; 729fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 730fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return false; 731fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 732fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 733fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown} 734