MediaRouteProviderService.java revision ae161a4d000a10dafd844d17145de631933f21f3
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v7.media;
18
19import android.app.Service;
20import android.content.Intent;
21import android.os.Handler;
22import android.os.IBinder;
23import android.os.IBinder.DeathRecipient;
24import android.os.Bundle;
25import android.os.DeadObjectException;
26import android.os.Message;
27import android.os.Messenger;
28import android.os.RemoteException;
29import android.util.Log;
30import android.util.SparseArray;
31
32import java.lang.ref.WeakReference;
33import java.util.ArrayList;
34
35/**
36 * Base class for media route provider services.
37 * <p>
38 * To implement your own media route provider service, extend this class and
39 * override the {@link #onCreateMediaRouteProvider} method to return an
40 * instance of your {@link MediaRouteProvider}.
41 * </p><p>
42 * Declare your media route provider service in your application manifest
43 * like this:
44 * </p>
45 * <pre>
46 *   &lt;service android:name=".MyMediaRouteProviderService"
47 *           android:label="@string/my_media_route_provider_service">
48 *       &lt;intent-filter>
49 *           &lt;action android:name="android.media.MediaRouteProviderService" />
50 *       &lt;/intent-filter>
51 *   &lt;/service>
52 * </pre>
53 */
54public abstract class MediaRouteProviderService extends Service {
55    private static final String TAG = "MediaRouteProviderSrv"; // max. 23 chars
56    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
57
58    private final ArrayList<ClientRecord> mClients = new ArrayList<ClientRecord>();
59    private final ReceiveHandler mReceiveHandler;
60    private final Messenger mReceiveMessenger;
61    private final PrivateHandler mPrivateHandler;
62    private final ProviderCallback mProviderCallback;
63
64    private MediaRouteProvider mProvider;
65    private MediaRouteDiscoveryRequest mCompositeDiscoveryRequest;
66
67    /**
68     * The {@link Intent} that must be declared as handled by the service.
69     * Put this in your manifest.
70     */
71    public static final String SERVICE_INTERFACE =
72            "android.media.MediaRouteProviderService";
73
74    /*
75     * Messages sent from the client to the service.
76     * DO NOT RENUMBER THESE!
77     */
78
79    /** (client v1)
80     * Register client.
81     * - replyTo : client messenger
82     * - arg1    : request id
83     * - arg2    : client version
84     */
85    static final int CLIENT_MSG_REGISTER = 1;
86
87    /** (client v1)
88     * Unregister client.
89     * - replyTo : client messenger
90     * - arg1    : request id
91     */
92    static final int CLIENT_MSG_UNREGISTER = 2;
93
94    /** (client v1)
95     * Create route controller.
96     * - replyTo : client messenger
97     * - arg1    : request id
98     * - arg2    : route controller id
99     * - CLIENT_DATA_ROUTE_ID : route id string
100     */
101    static final int CLIENT_MSG_CREATE_ROUTE_CONTROLLER = 3;
102
103    /** (client v1)
104     * Release route controller.
105     * - replyTo : client messenger
106     * - arg1    : request id
107     * - arg2    : route controller id
108     */
109    static final int CLIENT_MSG_RELEASE_ROUTE_CONTROLLER = 4;
110
111    /** (client v1)
112     * Select route.
113     * - replyTo : client messenger
114     * - arg1    : request id
115     * - arg2    : route controller id
116     */
117    static final int CLIENT_MSG_SELECT_ROUTE = 5;
118
119    /** (client v1)
120     * Unselect route.
121     * - replyTo : client messenger
122     * - arg1    : request id
123     * - arg2    : route controller id
124     */
125    static final int CLIENT_MSG_UNSELECT_ROUTE = 6;
126
127    /** (client v1)
128     * Set route volume.
129     * - replyTo : client messenger
130     * - arg1    : request id
131     * - arg2    : route controller id
132     * - CLIENT_DATA_VOLUME : volume integer
133     */
134    static final int CLIENT_MSG_SET_ROUTE_VOLUME = 7;
135
136    /** (client v1)
137     * Update route volume.
138     * - replyTo : client messenger
139     * - arg1    : request id
140     * - arg2    : route controller id
141     * - CLIENT_DATA_VOLUME : volume delta integer
142     */
143    static final int CLIENT_MSG_UPDATE_ROUTE_VOLUME = 8;
144
145    /** (client v1)
146     * Route control request.
147     * - replyTo : client messenger
148     * - arg1    : request id
149     * - arg2    : route controller id
150     * - obj     : media control intent
151     */
152    static final int CLIENT_MSG_ROUTE_CONTROL_REQUEST = 9;
153
154    /** (client v1)
155     * Sets the discovery request.
156     * - replyTo : client messenger
157     * - arg1    : request id
158     * - obj     : discovery request bundle, or null if none
159     */
160    static final int CLIENT_MSG_SET_DISCOVERY_REQUEST = 10;
161
162    static final String CLIENT_DATA_ROUTE_ID = "routeId";
163    static final String CLIENT_DATA_VOLUME = "volume";
164
165    /*
166     * Messages sent from the service to the client.
167     * DO NOT RENUMBER THESE!
168     */
169
170    /** (service v1)
171     * Generic failure sent in response to any unrecognized or malformed request.
172     * - arg1    : request id
173     */
174    static final int SERVICE_MSG_GENERIC_FAILURE = 0;
175
176    /** (service v1)
177     * Generic failure sent in response to a successful message.
178     * - arg1    : request id
179     */
180    static final int SERVICE_MSG_GENERIC_SUCCESS = 1;
181
182    /** (service v1)
183     * Registration succeeded.
184     * - arg1    : request id
185     * - arg2    : server version
186     * - obj     : route provider descriptor bundle, or null
187     */
188    static final int SERVICE_MSG_REGISTERED = 2;
189
190    /** (service v1)
191     * Route control request success result.
192     * - arg1    : request id
193     * - obj     : result data bundle, or null
194     */
195    static final int SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED = 3;
196
197    /** (service v1)
198     * Route control request failure result.
199     * - arg1    : request id
200     * - obj     : result data bundle, or null
201     * - SERVICE_DATA_ERROR: error message
202     */
203    static final int SERVICE_MSG_CONTROL_REQUEST_FAILED = 4;
204
205    /** (service v1)
206     * Route provider descriptor changed.  (unsolicited event)
207     * - arg1    : reserved (0)
208     * - obj     : route provider descriptor bundle, or null
209     */
210    static final int SERVICE_MSG_DESCRIPTOR_CHANGED = 5;
211
212    static final String SERVICE_DATA_ERROR = "error";
213
214    /*
215     * Recognized client version numbers.  (Reserved for future use.)
216     * DO NOT RENUMBER THESE!
217     */
218
219    static final int CLIENT_VERSION_1 = 1;
220    static final int CLIENT_VERSION_CURRENT = CLIENT_VERSION_1;
221
222    /*
223     * Recognized server version numbers.  (Reserved for future use.)
224     * DO NOT RENUMBER THESE!
225     */
226
227    static final int SERVICE_VERSION_1 = 1;
228    static final int SERVICE_VERSION_CURRENT = SERVICE_VERSION_1;
229
230    /*
231     * Private messages used internally.  (Yes, you can renumber these.)
232     */
233
234    private static final int PRIVATE_MSG_CLIENT_DIED = 1;
235
236    /**
237     * Creates a media route provider service.
238     */
239    public MediaRouteProviderService() {
240        mReceiveHandler = new ReceiveHandler(this);
241        mReceiveMessenger = new Messenger(mReceiveHandler);
242        mPrivateHandler = new PrivateHandler();
243        mProviderCallback = new ProviderCallback();
244    }
245
246    /**
247     * Called by the system when it is time to create the media route provider.
248     *
249     * @return The media route provider offered by this service, or null if
250     * this service has decided not to offer a media route provider.
251     */
252    public abstract MediaRouteProvider onCreateMediaRouteProvider();
253
254    /**
255     * Gets the media route provider offered by this service.
256     *
257     * @return The media route provider offered by this service, or null if
258     * it has not yet been created.
259     *
260     * @see #onCreateMediaRouteProvider()
261     */
262    public MediaRouteProvider getMediaRouteProvider() {
263        return mProvider;
264    }
265
266    @Override
267    public IBinder onBind(Intent intent) {
268        if (intent.getAction().equals(SERVICE_INTERFACE)) {
269            if (mProvider == null) {
270                MediaRouteProvider provider = onCreateMediaRouteProvider();
271                if (provider != null) {
272                    String providerPackage = provider.getMetadata().getPackageName();
273                    if (!providerPackage.equals(getPackageName())) {
274                        throw new IllegalStateException("onCreateMediaRouteProvider() returned "
275                                + "a provider whose package name does not match the package "
276                                + "name of the service.  A media route provider service can "
277                                + "only export its own media route providers.  "
278                                + "Provider package name: " + providerPackage
279                                + ".  Service package name: " + getPackageName() + ".");
280                    }
281                    mProvider = provider;
282                    mProvider.setCallback(mProviderCallback);
283                }
284            }
285            if (mProvider != null) {
286                return mReceiveMessenger.getBinder();
287            }
288        }
289        return null;
290    }
291
292    private boolean onRegisterClient(Messenger messenger, int requestId, int version) {
293        if (version >= CLIENT_VERSION_1) {
294            int index = findClient(messenger);
295            if (index < 0) {
296                ClientRecord client = new ClientRecord(messenger, version);
297                if (client.register()) {
298                    mClients.add(client);
299                    if (DEBUG) {
300                        Log.d(TAG, client + ": Registered, version=" + version);
301                    }
302                    if (requestId != 0) {
303                        MediaRouteProviderDescriptor descriptor = mProvider.getDescriptor();
304                        sendReply(messenger, SERVICE_MSG_REGISTERED,
305                                requestId, SERVICE_VERSION_CURRENT,
306                                descriptor != null ? descriptor.asBundle() : null, null);
307                    }
308                    return true;
309                }
310            }
311        }
312        return false;
313    }
314
315    private boolean onUnregisterClient(Messenger messenger, int requestId) {
316        int index = findClient(messenger);
317        if (index >= 0) {
318            ClientRecord client = mClients.remove(index);
319            if (DEBUG) {
320                Log.d(TAG, client + ": Unregistered");
321            }
322            client.dispose();
323            sendGenericSuccess(messenger, requestId);
324            return true;
325        }
326        return false;
327    }
328
329    private void onBinderDied(Messenger messenger) {
330        int index = findClient(messenger);
331        if (index >= 0) {
332            ClientRecord client = mClients.remove(index);
333            if (DEBUG) {
334                Log.d(TAG, client + ": Binder died");
335            }
336            client.dispose();
337        }
338    }
339
340    private boolean onCreateRouteController(Messenger messenger, int requestId,
341            int controllerId, String routeId) {
342        ClientRecord client = getClient(messenger);
343        if (client != null) {
344            if (client.createRouteController(routeId, controllerId)) {
345                if (DEBUG) {
346                    Log.d(TAG, client + ": Route controller created"
347                            + ", controllerId=" + controllerId + ", routeId=" + routeId);
348                }
349                sendGenericSuccess(messenger, requestId);
350                return true;
351            }
352        }
353        return false;
354    }
355
356    private boolean onReleaseRouteController(Messenger messenger, int requestId,
357            int controllerId) {
358        ClientRecord client = getClient(messenger);
359        if (client != null) {
360            if (client.releaseRouteController(controllerId)) {
361                if (DEBUG) {
362                    Log.d(TAG, client + ": Route controller released"
363                            + ", controllerId=" + controllerId);
364                }
365                sendGenericSuccess(messenger, requestId);
366                return true;
367            }
368        }
369        return false;
370    }
371
372    private boolean onSelectRoute(Messenger messenger, int requestId,
373            int controllerId) {
374        ClientRecord client = getClient(messenger);
375        if (client != null) {
376            MediaRouteProvider.RouteController controller =
377                    client.getRouteController(controllerId);
378            if (controller != null) {
379                controller.onSelect();
380                if (DEBUG) {
381                    Log.d(TAG, client + ": Route selected"
382                            + ", controllerId=" + controllerId);
383                }
384                sendGenericSuccess(messenger, requestId);
385                return true;
386            }
387        }
388        return false;
389    }
390
391    private boolean onUnselectRoute(Messenger messenger, int requestId,
392            int controllerId) {
393        ClientRecord client = getClient(messenger);
394        if (client != null) {
395            MediaRouteProvider.RouteController controller =
396                    client.getRouteController(controllerId);
397            if (controller != null) {
398                controller.onUnselect();
399                if (DEBUG) {
400                    Log.d(TAG, client + ": Route unselected"
401                            + ", controllerId=" + controllerId);
402                }
403                sendGenericSuccess(messenger, requestId);
404                return true;
405            }
406        }
407        return false;
408    }
409
410    private boolean onSetRouteVolume(Messenger messenger, int requestId,
411            int controllerId, int volume) {
412        ClientRecord client = getClient(messenger);
413        if (client != null) {
414            MediaRouteProvider.RouteController controller =
415                    client.getRouteController(controllerId);
416            if (controller != null) {
417                controller.onSetVolume(volume);
418                if (DEBUG) {
419                    Log.d(TAG, client + ": Route volume changed"
420                            + ", controllerId=" + controllerId + ", volume=" + volume);
421                }
422                sendGenericSuccess(messenger, requestId);
423                return true;
424            }
425        }
426        return false;
427    }
428
429    private boolean onUpdateRouteVolume(Messenger messenger, int requestId,
430            int controllerId, int delta) {
431        ClientRecord client = getClient(messenger);
432        if (client != null) {
433            MediaRouteProvider.RouteController controller =
434                    client.getRouteController(controllerId);
435            if (controller != null) {
436                controller.onUpdateVolume(delta);
437                if (DEBUG) {
438                    Log.d(TAG, client + ": Route volume updated"
439                            + ", controllerId=" + controllerId + ", delta=" + delta);
440                }
441                sendGenericSuccess(messenger, requestId);
442                return true;
443            }
444        }
445        return false;
446    }
447
448    private boolean onRouteControlRequest(final Messenger messenger, final int requestId,
449            final int controllerId, final Intent intent) {
450        final ClientRecord client = getClient(messenger);
451        if (client != null) {
452            MediaRouteProvider.RouteController controller =
453                    client.getRouteController(controllerId);
454            if (controller != null) {
455                MediaRouter.ControlRequestCallback callback = null;
456                if (requestId != 0) {
457                    callback = new MediaRouter.ControlRequestCallback() {
458                        @Override
459                        public void onResult(Bundle data) {
460                            if (DEBUG) {
461                                Log.d(TAG, client + ": Route control request succeeded"
462                                        + ", controllerId=" + controllerId
463                                        + ", intent=" + intent
464                                        + ", data=" + data);
465                            }
466                            if (findClient(messenger) >= 0) {
467                                sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED,
468                                        requestId, 0, data, null);
469                            }
470                        }
471
472                        @Override
473                        public void onError(String error, Bundle data) {
474                            if (DEBUG) {
475                                Log.d(TAG, client + ": Route control request failed"
476                                        + ", controllerId=" + controllerId
477                                        + ", intent=" + intent
478                                        + ", error=" + error + ", data=" + data);
479                            }
480                            if (findClient(messenger) >= 0) {
481                                if (error != null) {
482                                    Bundle bundle = new Bundle();
483                                    bundle.putString(SERVICE_DATA_ERROR, error);
484                                    sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
485                                            requestId, 0, data, bundle);
486                                } else {
487                                    sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
488                                            requestId, 0, data, null);
489                                }
490                            }
491                        }
492                    };
493                }
494                if (controller.onControlRequest(intent, callback)) {
495                    if (DEBUG) {
496                        Log.d(TAG, client + ": Route control request delivered"
497                                + ", controllerId=" + controllerId + ", intent=" + intent);
498                    }
499                    return true;
500                }
501            }
502        }
503        return false;
504    }
505
506    private boolean onSetDiscoveryRequest(Messenger messenger, int requestId,
507            MediaRouteDiscoveryRequest request) {
508        ClientRecord client = getClient(messenger);
509        if (client != null) {
510            boolean actuallyChanged = client.setDiscoveryRequest(request);
511            if (DEBUG) {
512                Log.d(TAG, client + ": Set discovery request, request=" + request
513                        + ", actuallyChanged=" + actuallyChanged
514                        + ", compositeDiscoveryRequest=" + mCompositeDiscoveryRequest);
515            }
516            sendGenericSuccess(messenger, requestId);
517            return true;
518        }
519        return false;
520    }
521
522    private void sendDescriptorChanged(MediaRouteProviderDescriptor descriptor) {
523        Bundle descriptorBundle = descriptor != null ? descriptor.asBundle() : null;
524        final int count = mClients.size();
525        for (int i = 0; i < count; i++) {
526            ClientRecord client = mClients.get(i);
527            sendReply(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
528                    descriptorBundle, null);
529            if (DEBUG) {
530                Log.d(TAG, client + ": Sent descriptor change event, descriptor=" + descriptor);
531            }
532        }
533    }
534
535    private boolean updateCompositeDiscoveryRequest() {
536        MediaRouteDiscoveryRequest composite = null;
537        MediaRouteSelector.Builder selectorBuilder = null;
538        boolean activeScan = false;
539        final int count = mClients.size();
540        for (int i = 0; i < count; i++) {
541            MediaRouteDiscoveryRequest request = mClients.get(i).mDiscoveryRequest;
542            if (request != null
543                    && (!request.getSelector().isEmpty() || request.isActiveScan())) {
544                activeScan |= request.isActiveScan();
545                if (composite == null) {
546                    composite = request;
547                } else {
548                    if (selectorBuilder == null) {
549                        selectorBuilder = new MediaRouteSelector.Builder(composite.getSelector());
550                    }
551                    selectorBuilder.addSelector(request.getSelector());
552                }
553            }
554        }
555        if (selectorBuilder != null) {
556            composite = new MediaRouteDiscoveryRequest(selectorBuilder.build(), activeScan);
557        }
558        if (mCompositeDiscoveryRequest != composite
559                && (mCompositeDiscoveryRequest == null
560                        || !mCompositeDiscoveryRequest.equals(composite))) {
561            mCompositeDiscoveryRequest = composite;
562            mProvider.setDiscoveryRequest(composite);
563            return true;
564        }
565        return false;
566    }
567
568    private ClientRecord getClient(Messenger messenger) {
569        int index = findClient(messenger);
570        return index >= 0 ? mClients.get(index) : null;
571    }
572
573    private int findClient(Messenger messenger) {
574        final int count = mClients.size();
575        for (int i = 0; i < count; i++) {
576            ClientRecord client = mClients.get(i);
577            if (client.hasMessenger(messenger)) {
578                return i;
579            }
580        }
581        return -1;
582    }
583
584    private static void sendGenericFailure(Messenger messenger, int requestId) {
585        if (requestId != 0) {
586            sendReply(messenger, SERVICE_MSG_GENERIC_FAILURE, requestId, 0, null, null);
587        }
588    }
589
590    private static void sendGenericSuccess(Messenger messenger, int requestId) {
591        if (requestId != 0) {
592            sendReply(messenger, SERVICE_MSG_GENERIC_SUCCESS, requestId, 0, null, null);
593        }
594    }
595
596    private static void sendReply(Messenger messenger, int what,
597            int requestId, int arg, Object obj, Bundle data) {
598        Message msg = Message.obtain();
599        msg.what = what;
600        msg.arg1 = requestId;
601        msg.arg2 = arg;
602        msg.obj = obj;
603        msg.setData(data);
604        try {
605            messenger.send(msg);
606        } catch (DeadObjectException ex) {
607            // The client died.
608        } catch (RemoteException ex) {
609            Log.e(TAG, "Could not send message to " + getClientId(messenger), ex);
610        }
611    }
612
613    private static String getClientId(Messenger messenger) {
614        return "Client connection " + messenger.getBinder().toString();
615    }
616
617    /**
618     * Returns true if the messenger object is valid.
619     * <p>
620     * The messenger constructor and unparceling code does not check whether the
621     * provided IBinder is a valid IMessenger object.  As a result, it's possible
622     * for a peer to send an invalid IBinder that will result in crashes downstream.
623     * This method checks that the messenger is in a valid state.
624     * </p>
625     */
626    static boolean isValidRemoteMessenger(Messenger messenger) {
627        try {
628            return messenger != null && messenger.getBinder() != null;
629        } catch (NullPointerException ex) {
630            // If the messenger was constructed with a binder interface other than
631            // IMessenger then the call to getBinder() will crash with an NPE.
632            return false;
633        }
634    }
635
636    private final class PrivateHandler extends Handler {
637        @Override
638        public void handleMessage(Message msg) {
639            switch (msg.what) {
640                case PRIVATE_MSG_CLIENT_DIED:
641                    onBinderDied((Messenger)msg.obj);
642                    break;
643            }
644        }
645    }
646
647    private final class ProviderCallback extends MediaRouteProvider.Callback {
648        @Override
649        public void onDescriptorChanged(MediaRouteProvider provider,
650                MediaRouteProviderDescriptor descriptor) {
651            sendDescriptorChanged(descriptor);
652        }
653    }
654
655    private final class ClientRecord implements DeathRecipient {
656        public final Messenger mMessenger;
657        public final int mVersion;
658        public MediaRouteDiscoveryRequest mDiscoveryRequest;
659
660        private final SparseArray<MediaRouteProvider.RouteController> mControllers =
661                new SparseArray<MediaRouteProvider.RouteController>();
662
663        public ClientRecord(Messenger messenger, int version) {
664            mMessenger = messenger;
665            mVersion = version;
666        }
667
668        public boolean register() {
669            try {
670                mMessenger.getBinder().linkToDeath(this, 0);
671                return true;
672            } catch (RemoteException ex) {
673                binderDied();
674            }
675            return false;
676        }
677
678        public void dispose() {
679            int count = mControllers.size();
680            for (int i = 0; i < count; i++) {
681                mControllers.valueAt(i).onRelease();
682            }
683            mControllers.clear();
684
685            mMessenger.getBinder().unlinkToDeath(this, 0);
686
687            setDiscoveryRequest(null);
688        }
689
690        public boolean hasMessenger(Messenger other) {
691            return mMessenger.getBinder() == other.getBinder();
692        }
693
694        public boolean createRouteController(String routeId, int controllerId) {
695            if (mControllers.indexOfKey(controllerId) < 0) {
696                MediaRouteProvider.RouteController controller =
697                        mProvider.onCreateRouteController(routeId);
698                if (controller != null) {
699                    mControllers.put(controllerId, controller);
700                    return true;
701                }
702            }
703            return false;
704        }
705
706        public boolean releaseRouteController(int controllerId) {
707            MediaRouteProvider.RouteController controller = mControllers.get(controllerId);
708            if (controller != null) {
709                mControllers.remove(controllerId);
710                controller.onRelease();
711                return true;
712            }
713            return false;
714        }
715
716        public MediaRouteProvider.RouteController getRouteController(int controllerId) {
717            return mControllers.get(controllerId);
718        }
719
720        public boolean setDiscoveryRequest(MediaRouteDiscoveryRequest request) {
721            if (mDiscoveryRequest != request
722                    && (mDiscoveryRequest == null || !mDiscoveryRequest.equals(request))) {
723                mDiscoveryRequest = request;
724                return updateCompositeDiscoveryRequest();
725            }
726            return false;
727        }
728
729        // Runs on a binder thread.
730        @Override
731        public void binderDied() {
732            mPrivateHandler.obtainMessage(PRIVATE_MSG_CLIENT_DIED, mMessenger).sendToTarget();
733        }
734
735        @Override
736        public String toString() {
737            return getClientId(mMessenger);
738        }
739    }
740
741    /**
742     * Handler that receives messages from clients.
743     * <p>
744     * This inner class is static and only retains a weak reference to the service
745     * to prevent the service from being leaked in case one of the clients is holding an
746     * active reference to the server's messenger.
747     * </p><p>
748     * This handler should not be used to handle any messages other than those
749     * that come from the client.
750     * </p>
751     */
752    private static final class ReceiveHandler extends Handler {
753        private final WeakReference<MediaRouteProviderService> mServiceRef;
754
755        public ReceiveHandler(MediaRouteProviderService service) {
756            mServiceRef = new WeakReference<MediaRouteProviderService>(service);
757        }
758
759        @Override
760        public void handleMessage(Message msg) {
761            final Messenger messenger = msg.replyTo;
762            if (isValidRemoteMessenger(messenger)) {
763                final int what = msg.what;
764                final int requestId = msg.arg1;
765                final int arg = msg.arg2;
766                final Object obj = msg.obj;
767                final Bundle data = msg.peekData();
768                if (!processMessage(what, messenger, requestId, arg, obj, data)) {
769                    if (DEBUG) {
770                        Log.d(TAG, getClientId(messenger) + ": Message failed, what=" + what
771                                + ", requestId=" + requestId + ", arg=" + arg
772                                + ", obj=" + obj + ", data=" + data);
773                    }
774                    sendGenericFailure(messenger, requestId);
775                }
776            } else {
777                if (DEBUG) {
778                    Log.d(TAG, "Ignoring message without valid reply messenger.");
779                }
780            }
781        }
782
783        private boolean processMessage(int what,
784                Messenger messenger, int requestId, int arg, Object obj, Bundle data) {
785            MediaRouteProviderService service = mServiceRef.get();
786            if (service != null) {
787                switch (what) {
788                    case CLIENT_MSG_REGISTER:
789                        return service.onRegisterClient(messenger, requestId, arg);
790
791                    case CLIENT_MSG_UNREGISTER:
792                        return service.onUnregisterClient(messenger, requestId);
793
794                    case CLIENT_MSG_CREATE_ROUTE_CONTROLLER: {
795                        String routeId = data.getString(CLIENT_DATA_ROUTE_ID);
796                        if (routeId != null) {
797                            return service.onCreateRouteController(
798                                    messenger, requestId, arg, routeId);
799                        }
800                        break;
801                    }
802
803                    case CLIENT_MSG_RELEASE_ROUTE_CONTROLLER:
804                        return service.onReleaseRouteController(messenger, requestId, arg);
805
806                    case CLIENT_MSG_SELECT_ROUTE:
807                        return service.onSelectRoute(messenger, requestId, arg);
808
809                    case CLIENT_MSG_UNSELECT_ROUTE:
810                        return service.onUnselectRoute(messenger, requestId, arg);
811
812                    case CLIENT_MSG_SET_ROUTE_VOLUME: {
813                        int volume = data.getInt(CLIENT_DATA_VOLUME, -1);
814                        if (volume >= 0) {
815                            return service.onSetRouteVolume(
816                                    messenger, requestId, arg, volume);
817                        }
818                        break;
819                    }
820
821                    case CLIENT_MSG_UPDATE_ROUTE_VOLUME: {
822                        int delta = data.getInt(CLIENT_DATA_VOLUME, 0);
823                        if (delta != 0) {
824                            return service.onUpdateRouteVolume(
825                                    messenger, requestId, arg, delta);
826                        }
827                        break;
828                    }
829
830                    case CLIENT_MSG_ROUTE_CONTROL_REQUEST:
831                        if (obj instanceof Intent) {
832                            return service.onRouteControlRequest(
833                                    messenger, requestId, arg, (Intent)obj);
834                        }
835                        break;
836
837                    case CLIENT_MSG_SET_DISCOVERY_REQUEST: {
838                        if (obj == null || obj instanceof Bundle) {
839                            MediaRouteDiscoveryRequest request =
840                                    MediaRouteDiscoveryRequest.fromBundle((Bundle)obj);
841                            return service.onSetDiscoveryRequest(
842                                    messenger, requestId,
843                                    request != null && request.isValid() ? request : null);
844                        }
845                    }
846                }
847            }
848            return false;
849        }
850    }
851}
852