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