blob: 85af346aa88a7fa21eafd326cfc714cc05cb0fa9 [file] [log] [blame]
Kyunglyul Hyund51666d2019-04-11 04:08:40 +00001/*
2 * Copyright 2019 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 com.android.server.media;
18
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +090019import android.annotation.NonNull;
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000020import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.content.ServiceConnection;
Hyundo Moon56337492020-02-16 16:19:54 +090024import android.media.IMediaRoute2ProviderService;
25import android.media.IMediaRoute2ProviderServiceCallback;
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +090026import android.media.MediaRoute2ProviderInfo;
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000027import android.media.MediaRoute2ProviderService;
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +090028import android.media.RouteDiscoveryPreference;
Hyundo Moonf829e6f2020-01-11 19:31:35 +090029import android.media.RoutingSessionInfo;
Hyundo Moon84e027d2020-01-16 17:39:05 +090030import android.os.Bundle;
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000031import android.os.Handler;
32import android.os.IBinder;
33import android.os.IBinder.DeathRecipient;
Hyundo Moon56337492020-02-16 16:19:54 +090034import android.os.Looper;
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000035import android.os.RemoteException;
36import android.os.UserHandle;
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +090037import android.text.TextUtils;
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000038import android.util.Log;
39import android.util.Slog;
40
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +090041import com.android.internal.annotations.GuardedBy;
42
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000043import java.io.PrintWriter;
44import java.lang.ref.WeakReference;
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +090045import java.util.ArrayList;
46import java.util.List;
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +090047import java.util.Objects;
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000048
49/**
Hyundo Moon56337492020-02-16 16:19:54 +090050 * Maintains a connection to a particular {@link MediaRoute2ProviderService}.
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000051 */
Hyundo Moon56337492020-02-16 16:19:54 +090052final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
53 implements ServiceConnection {
54 private static final String TAG = "MR2ProviderSvcProxy";
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000055 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
56
57 private final Context mContext;
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000058 private final int mUserId;
59 private final Handler mHandler;
60
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000061 // Connection state
62 private boolean mRunning;
63 private boolean mBound;
64 private Connection mActiveConnection;
65 private boolean mConnectionReady;
66
Kyunglyul Hyunf2b19c8b2020-05-18 18:29:11 +090067 private RouteDiscoveryPreference mLastDiscoveryPreference = null;
Kyunglyul Hyunbab0cda2020-03-10 20:59:49 +090068
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +090069 @GuardedBy("mLock")
70 final List<RoutingSessionInfo> mReleasingSessions = new ArrayList<>();
71
Hyundo Moon56337492020-02-16 16:19:54 +090072 MediaRoute2ProviderServiceProxy(@NonNull Context context, @NonNull ComponentName componentName,
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +090073 int userId) {
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000074 super(componentName);
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +090075 mContext = Objects.requireNonNull(context, "Context must not be null.");
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000076 mUserId = userId;
Hyundo Moon56337492020-02-16 16:19:54 +090077 mHandler = new Handler(Looper.myLooper());
Kyunglyul Hyund51666d2019-04-11 04:08:40 +000078 }
79
80 public void dump(PrintWriter pw, String prefix) {
81 pw.println(prefix + "Proxy");
82 pw.println(prefix + " mUserId=" + mUserId);
83 pw.println(prefix + " mRunning=" + mRunning);
84 pw.println(prefix + " mBound=" + mBound);
85 pw.println(prefix + " mActiveConnection=" + mActiveConnection);
86 pw.println(prefix + " mConnectionReady=" + mConnectionReady);
87 }
88
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +000089 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +090090 public void requestCreateSession(long requestId, String packageName, String routeId,
Hyundo Moon84e027d2020-01-16 17:39:05 +090091 Bundle sessionHints) {
Hyundo Moon63a05402019-12-19 20:13:56 +090092 if (mConnectionReady) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +090093 mActiveConnection.requestCreateSession(requestId, packageName, routeId, sessionHints);
Hyundo Moon63a05402019-12-19 20:13:56 +090094 updateBinding();
95 }
96 }
97
98 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +090099 public void releaseSession(long requestId, String sessionId) {
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000100 if (mConnectionReady) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900101 mActiveConnection.releaseSession(requestId, sessionId);
Kyunglyul Hyuna0d47412019-07-01 11:14:24 +0900102 updateBinding();
103 }
104 }
105
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000106 @Override
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +0900107 public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
Kyunglyul Hyunf2b19c8b2020-05-18 18:29:11 +0900108 mLastDiscoveryPreference = discoveryPreference;
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +0900109 if (mConnectionReady) {
110 mActiveConnection.updateDiscoveryPreference(discoveryPreference);
111 updateBinding();
112 }
113 }
114
115 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900116 public void selectRoute(long requestId, String sessionId, String routeId) {
Kyunglyul Hyuna0d47412019-07-01 11:14:24 +0900117 if (mConnectionReady) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900118 mActiveConnection.selectRoute(requestId, sessionId, routeId);
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900119 }
120 }
121
122 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900123 public void deselectRoute(long requestId, String sessionId, String routeId) {
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900124 if (mConnectionReady) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900125 mActiveConnection.deselectRoute(requestId, sessionId, routeId);
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900126 }
127 }
128
129 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900130 public void transferToRoute(long requestId, String sessionId, String routeId) {
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900131 if (mConnectionReady) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900132 mActiveConnection.transferToRoute(requestId, sessionId, routeId);
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000133 }
134 }
135
Kyunglyul Hyun0332e9a22019-11-20 01:39:25 +0000136 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900137 public void setRouteVolume(long requestId, String routeId, int volume) {
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900138 if (mConnectionReady) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900139 mActiveConnection.setRouteVolume(requestId, routeId, volume);
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900140 updateBinding();
141 }
142 }
143
144 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900145 public void setSessionVolume(long requestId, String sessionId, int volume) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900146 if (mConnectionReady) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900147 mActiveConnection.setSessionVolume(requestId, sessionId, volume);
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900148 updateBinding();
149 }
150 }
151
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900152 @Override
153 public void prepareReleaseSession(@NonNull String sessionId) {
154 synchronized (mLock) {
155 for (RoutingSessionInfo session : mSessionInfos) {
156 if (TextUtils.equals(session.getId(), sessionId)) {
157 mSessionInfos.remove(session);
158 mReleasingSessions.add(session);
159 break;
160 }
161 }
162 }
163 }
164
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000165 public boolean hasComponentName(String packageName, String className) {
166 return mComponentName.getPackageName().equals(packageName)
167 && mComponentName.getClassName().equals(className);
168 }
169
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000170 public void start() {
171 if (!mRunning) {
172 if (DEBUG) {
173 Slog.d(TAG, this + ": Starting");
174 }
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000175 mRunning = true;
176 updateBinding();
177 }
178 }
179
180 public void stop() {
181 if (mRunning) {
182 if (DEBUG) {
183 Slog.d(TAG, this + ": Stopping");
184 }
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000185 mRunning = false;
186 updateBinding();
187 }
188 }
189
190 public void rebindIfDisconnected() {
Kyunglyul Hyun89e2ee92020-04-10 20:17:04 +0900191 //TODO: When we are connecting to the service, calling this will unbind and bind again.
192 // We'd better not unbind if we are connecting.
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000193 if (mActiveConnection == null && shouldBind()) {
194 unbind();
195 bind();
196 }
197 }
198
199 private void updateBinding() {
200 if (shouldBind()) {
201 bind();
202 } else {
203 unbind();
204 }
205 }
206
207 private boolean shouldBind() {
Kyunglyul Hyun6c5d7dc2019-04-24 15:57:07 +0900208 //TODO: Binding could be delayed until it's necessary.
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000209 if (mRunning) {
210 return true;
211 }
212 return false;
213 }
214
215 private void bind() {
216 if (!mBound) {
217 if (DEBUG) {
218 Slog.d(TAG, this + ": Binding");
219 }
220
221 Intent service = new Intent(MediaRoute2ProviderService.SERVICE_INTERFACE);
222 service.setComponent(mComponentName);
223 try {
224 mBound = mContext.bindServiceAsUser(service, this,
225 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
226 new UserHandle(mUserId));
227 if (!mBound && DEBUG) {
228 Slog.d(TAG, this + ": Bind failed");
229 }
230 } catch (SecurityException ex) {
231 if (DEBUG) {
232 Slog.d(TAG, this + ": Bind failed", ex);
233 }
234 }
235 }
236 }
237
238 private void unbind() {
239 if (mBound) {
240 if (DEBUG) {
241 Slog.d(TAG, this + ": Unbinding");
242 }
243
244 mBound = false;
245 disconnect();
246 mContext.unbindService(this);
247 }
248 }
249
250 @Override
251 public void onServiceConnected(ComponentName name, IBinder service) {
252 if (DEBUG) {
253 Slog.d(TAG, this + ": Connected");
254 }
255
256 if (mBound) {
257 disconnect();
Hyundo Moon56337492020-02-16 16:19:54 +0900258 IMediaRoute2ProviderService serviceBinder =
259 IMediaRoute2ProviderService.Stub.asInterface(service);
260 if (serviceBinder != null) {
261 Connection connection = new Connection(serviceBinder);
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000262 if (connection.register()) {
263 mActiveConnection = connection;
264 } else {
265 if (DEBUG) {
266 Slog.d(TAG, this + ": Registration failed");
267 }
268 }
269 } else {
Hyundo Moon56337492020-02-16 16:19:54 +0900270 Slog.e(TAG, this + ": Service returned invalid binder");
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000271 }
272 }
273 }
274
275 @Override
276 public void onServiceDisconnected(ComponentName name) {
277 if (DEBUG) {
278 Slog.d(TAG, this + ": Service disconnected");
279 }
280 disconnect();
281 }
282
Hyundo Moon7294e5f2020-01-29 13:26:14 +0900283 @Override
284 public void onBindingDied(ComponentName name) {
285 if (DEBUG) {
286 Slog.d(TAG, this + ": Service binding died");
287 }
Hyundo Moon7294e5f2020-01-29 13:26:14 +0900288 if (shouldBind()) {
289 unbind();
290 bind();
291 }
292 }
293
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000294 private void onConnectionReady(Connection connection) {
295 if (mActiveConnection == connection) {
296 mConnectionReady = true;
Kyunglyul Hyunf2b19c8b2020-05-18 18:29:11 +0900297 if (mLastDiscoveryPreference != null) {
298 updateDiscoveryPreference(mLastDiscoveryPreference);
Kyunglyul Hyunbab0cda2020-03-10 20:59:49 +0900299 }
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000300 }
301 }
302
303 private void onConnectionDied(Connection connection) {
304 if (mActiveConnection == connection) {
305 if (DEBUG) {
306 Slog.d(TAG, this + ": Service connection died");
307 }
308 disconnect();
309 }
310 }
311
Kyunglyul Hyunefe43742019-12-31 18:32:28 +0900312 private void onProviderStateUpdated(Connection connection,
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900313 MediaRoute2ProviderInfo providerInfo) {
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +0900314 if (mActiveConnection != connection) {
315 return;
316 }
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +0900317 if (DEBUG) {
318 Slog.d(TAG, this + ": State changed ");
319 }
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900320 setAndNotifyProviderState(providerInfo);
Kyunglyul Hyun23b3aaa2019-08-06 11:17:16 +0900321 }
322
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900323 private void onSessionCreated(Connection connection, long requestId,
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900324 RoutingSessionInfo newSession) {
Hyundo Moon63a05402019-12-19 20:13:56 +0900325 if (mActiveConnection != connection) {
326 return;
327 }
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900328
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900329 if (newSession == null) {
330 Slog.w(TAG, "onSessionCreated: Ignoring null session sent from " + mComponentName);
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900331 return;
Kyunglyul Hyun138246e2020-01-02 18:19:52 +0900332 }
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900333
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900334 newSession = assignProviderIdForSession(newSession);
335 String newSessionId = newSession.getId();
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900336
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900337 synchronized (mLock) {
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900338 if (mSessionInfos.stream()
339 .anyMatch(session -> TextUtils.equals(session.getId(), newSessionId))
340 || mReleasingSessions.stream()
341 .anyMatch(session -> TextUtils.equals(session.getId(), newSessionId))) {
342 Slog.w(TAG, "onSessionCreated: Duplicate session already exists. Ignoring.");
343 return;
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900344 }
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900345 mSessionInfos.add(newSession);
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900346 }
347
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900348 mCallback.onSessionCreated(this, requestId, newSession);
Hyundo Moon63a05402019-12-19 20:13:56 +0900349 }
350
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900351 private void onSessionUpdated(Connection connection, RoutingSessionInfo updatedSession) {
Hyundo Moon0a926572019-12-28 15:01:21 +0900352 if (mActiveConnection != connection) {
353 return;
354 }
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900355 if (updatedSession == null) {
356 Slog.w(TAG, "onSessionUpdated: Ignoring null session sent from "
Hyundo Moon0a926572019-12-28 15:01:21 +0900357 + mComponentName);
358 return;
359 }
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900360
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900361 updatedSession = assignProviderIdForSession(updatedSession);
Hyundo Moonb26c4b22020-01-08 19:44:43 +0900362
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900363 boolean found = false;
364 synchronized (mLock) {
365 for (int i = 0; i < mSessionInfos.size(); i++) {
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900366 if (mSessionInfos.get(i).getId().equals(updatedSession.getId())) {
367 mSessionInfos.set(i, updatedSession);
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900368 found = true;
369 break;
370 }
371 }
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900372
373 if (!found) {
374 for (RoutingSessionInfo releasingSession : mReleasingSessions) {
375 if (TextUtils.equals(releasingSession.getId(), updatedSession.getId())) {
376 return;
377 }
378 }
379 Slog.w(TAG, "onSessionUpdated: Matching session info not found");
380 return;
381 }
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900382 }
383
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900384 mCallback.onSessionUpdated(this, updatedSession);
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900385 }
386
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900387 private void onSessionReleased(Connection connection, RoutingSessionInfo releaedSession) {
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900388 if (mActiveConnection != connection) {
389 return;
390 }
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900391 if (releaedSession == null) {
392 Slog.w(TAG, "onSessionReleased: Ignoring null session sent from " + mComponentName);
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900393 return;
394 }
395
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900396 releaedSession = assignProviderIdForSession(releaedSession);
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900397
398 boolean found = false;
399 synchronized (mLock) {
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900400 for (RoutingSessionInfo session : mSessionInfos) {
401 if (TextUtils.equals(session.getId(), releaedSession.getId())) {
402 mSessionInfos.remove(session);
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900403 found = true;
404 break;
405 }
406 }
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900407 if (!found) {
408 for (RoutingSessionInfo session : mReleasingSessions) {
409 if (TextUtils.equals(session.getId(), releaedSession.getId())) {
410 mReleasingSessions.remove(session);
411 return;
412 }
413 }
414 }
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900415 }
416
417 if (!found) {
418 Slog.w(TAG, "onSessionReleased: Matching session info not found");
419 return;
420 }
421
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900422 mCallback.onSessionReleased(this, releaedSession);
Hyundo Moon0a926572019-12-28 15:01:21 +0900423 }
424
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900425 private RoutingSessionInfo assignProviderIdForSession(RoutingSessionInfo sessionInfo) {
Kyunglyul Hyune2dbbf72020-04-29 22:40:59 +0900426 return new RoutingSessionInfo.Builder(sessionInfo)
427 .setOwnerPackageName(mComponentName.getPackageName())
428 .setProviderId(getUniqueId())
429 .build();
430 }
431
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900432 private void onRequestFailed(Connection connection, long requestId, int reason) {
433 if (mActiveConnection != connection) {
434 return;
435 }
436
437 if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
438 Slog.w(TAG, "onRequestFailed: Ignoring requestId REQUEST_ID_NONE");
439 return;
440 }
441
442 mCallback.onRequestFailed(this, requestId, reason);
443 }
444
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000445 private void disconnect() {
446 if (mActiveConnection != null) {
447 mConnectionReady = false;
448 mActiveConnection.dispose();
449 mActiveConnection = null;
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900450 setAndNotifyProviderState(null);
Kyunglyul Hyun47d289e2020-02-07 19:24:08 +0900451 synchronized (mLock) {
452 for (RoutingSessionInfo sessionInfo : mSessionInfos) {
453 mCallback.onSessionReleased(this, sessionInfo);
454 }
455 mSessionInfos.clear();
Kyunglyul Hyun6a2f1d62020-05-19 23:00:17 +0900456 mReleasingSessions.clear();
Kyunglyul Hyun47d289e2020-02-07 19:24:08 +0900457 }
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000458 }
459 }
460
461 @Override
462 public String toString() {
463 return "Service connection " + mComponentName.flattenToShortString();
464 }
465
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000466 private final class Connection implements DeathRecipient {
Hyundo Moon56337492020-02-16 16:19:54 +0900467 private final IMediaRoute2ProviderService mService;
468 private final ServiceCallbackStub mCallbackStub;
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000469
Hyundo Moon56337492020-02-16 16:19:54 +0900470 Connection(IMediaRoute2ProviderService serviceBinder) {
471 mService = serviceBinder;
472 mCallbackStub = new ServiceCallbackStub(this);
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000473 }
474
475 public boolean register() {
476 try {
Hyundo Moon56337492020-02-16 16:19:54 +0900477 mService.asBinder().linkToDeath(this, 0);
478 mService.setCallback(mCallbackStub);
Kyunglyul Hyuna0d47412019-07-01 11:14:24 +0900479 mHandler.post(() -> onConnectionReady(Connection.this));
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000480 return true;
481 } catch (RemoteException ex) {
482 binderDied();
483 }
484 return false;
485 }
486
487 public void dispose() {
Hyundo Moon56337492020-02-16 16:19:54 +0900488 mService.asBinder().unlinkToDeath(this, 0);
489 mCallbackStub.dispose();
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000490 }
491
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900492 public void requestCreateSession(long requestId, String packageName, String routeId,
Hyundo Moon84e027d2020-01-16 17:39:05 +0900493 Bundle sessionHints) {
Hyundo Moon63a05402019-12-19 20:13:56 +0900494 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900495 mService.requestCreateSession(requestId, packageName, routeId, sessionHints);
Hyundo Moon63a05402019-12-19 20:13:56 +0900496 } catch (RemoteException ex) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900497 Slog.e(TAG, "requestCreateSession: Failed to deliver request.");
Hyundo Moon63a05402019-12-19 20:13:56 +0900498 }
499 }
500
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900501 public void releaseSession(long requestId, String sessionId) {
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000502 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900503 mService.releaseSession(requestId, sessionId);
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000504 } catch (RemoteException ex) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900505 Slog.e(TAG, "releaseSession: Failed to deliver request.");
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000506 }
507 }
508
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +0900509 public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
510 try {
Hyundo Moon56337492020-02-16 16:19:54 +0900511 mService.updateDiscoveryPreference(discoveryPreference);
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +0900512 } catch (RemoteException ex) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900513 Slog.e(TAG, "updateDiscoveryPreference: Failed to deliver request.");
Kyunglyul Hyun1866d8a2020-01-31 11:56:34 +0900514 }
515 }
516
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900517 public void selectRoute(long requestId, String sessionId, String routeId) {
Kyunglyul Hyuncaae8dc2019-04-29 15:45:23 +0900518 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900519 mService.selectRoute(requestId, sessionId, routeId);
Kyunglyul Hyuna0d47412019-07-01 11:14:24 +0900520 } catch (RemoteException ex) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900521 Slog.e(TAG, "selectRoute: Failed to deliver request.", ex);
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900522 }
523 }
524
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900525 public void deselectRoute(long requestId, String sessionId, String routeId) {
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900526 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900527 mService.deselectRoute(requestId, sessionId, routeId);
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900528 } catch (RemoteException ex) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900529 Slog.e(TAG, "deselectRoute: Failed to deliver request.", ex);
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900530 }
531 }
532
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900533 public void transferToRoute(long requestId, String sessionId, String routeId) {
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900534 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900535 mService.transferToRoute(requestId, sessionId, routeId);
Kyunglyul Hyuncb8894d2019-12-27 14:24:46 +0900536 } catch (RemoteException ex) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900537 Slog.e(TAG, "transferToRoute: Failed to deliver request.", ex);
Kyunglyul Hyuna0d47412019-07-01 11:14:24 +0900538 }
539 }
540
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900541 public void setRouteVolume(long requestId, String routeId, int volume) {
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900542 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900543 mService.setRouteVolume(requestId, routeId, volume);
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900544 } catch (RemoteException ex) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900545 Slog.e(TAG, "setRouteVolume: Failed to deliver request.", ex);
546 }
547 }
548
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900549 public void setSessionVolume(long requestId, String sessionId, int volume) {
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900550 try {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900551 mService.setSessionVolume(requestId, sessionId, volume);
Kyunglyul Hyun5161b372020-02-05 18:45:35 +0900552 } catch (RemoteException ex) {
553 Slog.e(TAG, "setSessionVolume: Failed to deliver request.", ex);
Kyunglyul Hyun5a8dedc2019-10-10 14:09:44 +0900554 }
555 }
556
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000557 @Override
558 public void binderDied() {
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +0900559 mHandler.post(() -> onConnectionDied(Connection.this));
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000560 }
561
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900562 void postProviderStateUpdated(MediaRoute2ProviderInfo providerInfo) {
563 mHandler.post(() -> onProviderStateUpdated(Connection.this, providerInfo));
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000564 }
Kyunglyul Hyunf7d5e042019-11-11 13:56:28 +0900565
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900566 void postSessionCreated(long requestId, RoutingSessionInfo sessionInfo) {
567 mHandler.post(() -> onSessionCreated(Connection.this, requestId, sessionInfo));
Hyundo Moon63a05402019-12-19 20:13:56 +0900568 }
Hyundo Moon0a926572019-12-28 15:01:21 +0900569
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900570 void postSessionUpdated(RoutingSessionInfo sessionInfo) {
571 mHandler.post(() -> onSessionUpdated(Connection.this, sessionInfo));
572 }
573
574 void postSessionReleased(RoutingSessionInfo sessionInfo) {
575 mHandler.post(() -> onSessionReleased(Connection.this, sessionInfo));
Hyundo Moon0a926572019-12-28 15:01:21 +0900576 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900577
Hyundo Moon7c2059c2020-02-27 19:01:52 +0900578 void postRequestFailed(long requestId, int reason) {
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900579 mHandler.post(() -> onRequestFailed(Connection.this, requestId, reason));
580 }
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000581 }
582
Hyundo Moon56337492020-02-16 16:19:54 +0900583 private static final class ServiceCallbackStub extends
584 IMediaRoute2ProviderServiceCallback.Stub {
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000585 private final WeakReference<Connection> mConnectionRef;
586
Hyundo Moon56337492020-02-16 16:19:54 +0900587 ServiceCallbackStub(Connection connection) {
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +0900588 mConnectionRef = new WeakReference<>(connection);
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000589 }
590
591 public void dispose() {
592 mConnectionRef.clear();
593 }
594
595 @Override
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900596 public void updateState(MediaRoute2ProviderInfo providerInfo) {
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +0900597 Connection connection = mConnectionRef.get();
598 if (connection != null) {
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900599 connection.postProviderStateUpdated(providerInfo);
Kyunglyul Hyun3aedf022019-04-15 16:38:19 +0900600 }
601 }
Kyunglyul Hyunf7d5e042019-11-11 13:56:28 +0900602
603 @Override
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900604 public void notifySessionCreated(long requestId, RoutingSessionInfo sessionInfo) {
Hyundo Moon63a05402019-12-19 20:13:56 +0900605 Connection connection = mConnectionRef.get();
606 if (connection != null) {
Hyundo Moonf8e49f4b2020-03-06 17:19:42 +0900607 connection.postSessionCreated(requestId, sessionInfo);
Hyundo Moon63a05402019-12-19 20:13:56 +0900608 }
609 }
Hyundo Moon0a926572019-12-28 15:01:21 +0900610
611 @Override
Hyundo Moon6e30f1b2020-01-13 19:50:27 +0900612 public void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
613 Connection connection = mConnectionRef.get();
614 if (connection != null) {
615 connection.postSessionUpdated(sessionInfo);
616 }
617 }
618
619 @Override
620 public void notifySessionReleased(RoutingSessionInfo sessionInfo) {
621 Connection connection = mConnectionRef.get();
622 if (connection != null) {
623 connection.postSessionReleased(sessionInfo);
Hyundo Moon0a926572019-12-28 15:01:21 +0900624 }
625 }
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900626
627 @Override
628 public void notifyRequestFailed(long requestId, int reason) {
629 Connection connection = mConnectionRef.get();
630 if (connection != null) {
Hyundo Moon7c2059c2020-02-27 19:01:52 +0900631 connection.postRequestFailed(requestId, reason);
Hyundo Moon0fa60e82020-02-14 11:44:45 +0900632 }
633 }
Kyunglyul Hyund51666d2019-04-11 04:08:40 +0000634 }
635}