Roll android_tools support library to 25.1.0
[android_tools.git] / sdk / sources / android-23 / com / android / server / media / RemoteDisplayProviderProxy.java
blobba98a0a9fd4e82d13e3296b7fd5febcc614c4f78
1 /*
2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.media;
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.ServiceConnection;
23 import android.media.IRemoteDisplayCallback;
24 import android.media.IRemoteDisplayProvider;
25 import android.media.RemoteDisplayState;
26 import android.os.Handler;
27 import android.os.IBinder;
28 import android.os.RemoteException;
29 import android.os.IBinder.DeathRecipient;
30 import android.os.UserHandle;
31 import android.util.Log;
32 import android.util.Slog;
34 import java.io.PrintWriter;
35 import java.lang.ref.WeakReference;
36 import java.util.Objects;
38 /**
39 * Maintains a connection to a particular remote display provider service.
41 final class RemoteDisplayProviderProxy implements ServiceConnection {
42 private static final String TAG = "RemoteDisplayProvider"; // max. 23 chars
43 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
45 private final Context mContext;
46 private final ComponentName mComponentName;
47 private final int mUserId;
48 private final Handler mHandler;
50 private Callback mDisplayStateCallback;
52 // Connection state
53 private boolean mRunning;
54 private boolean mBound;
55 private Connection mActiveConnection;
56 private boolean mConnectionReady;
58 // Logical state
59 private int mDiscoveryMode;
60 private String mSelectedDisplayId;
61 private RemoteDisplayState mDisplayState;
62 private boolean mScheduledDisplayStateChangedCallback;
64 public RemoteDisplayProviderProxy(Context context, ComponentName componentName,
65 int userId) {
66 mContext = context;
67 mComponentName = componentName;
68 mUserId = userId;
69 mHandler = new Handler();
72 public void dump(PrintWriter pw, String prefix) {
73 pw.println(prefix + "Proxy");
74 pw.println(prefix + " mUserId=" + mUserId);
75 pw.println(prefix + " mRunning=" + mRunning);
76 pw.println(prefix + " mBound=" + mBound);
77 pw.println(prefix + " mActiveConnection=" + mActiveConnection);
78 pw.println(prefix + " mConnectionReady=" + mConnectionReady);
79 pw.println(prefix + " mDiscoveryMode=" + mDiscoveryMode);
80 pw.println(prefix + " mSelectedDisplayId=" + mSelectedDisplayId);
81 pw.println(prefix + " mDisplayState=" + mDisplayState);
84 public void setCallback(Callback callback) {
85 mDisplayStateCallback = callback;
88 public RemoteDisplayState getDisplayState() {
89 return mDisplayState;
92 public void setDiscoveryMode(int mode) {
93 if (mDiscoveryMode != mode) {
94 mDiscoveryMode = mode;
95 if (mConnectionReady) {
96 mActiveConnection.setDiscoveryMode(mode);
98 updateBinding();
102 public void setSelectedDisplay(String id) {
103 if (!Objects.equals(mSelectedDisplayId, id)) {
104 if (mConnectionReady && mSelectedDisplayId != null) {
105 mActiveConnection.disconnect(mSelectedDisplayId);
107 mSelectedDisplayId = id;
108 if (mConnectionReady && id != null) {
109 mActiveConnection.connect(id);
111 updateBinding();
115 public void setDisplayVolume(int volume) {
116 if (mConnectionReady && mSelectedDisplayId != null) {
117 mActiveConnection.setVolume(mSelectedDisplayId, volume);
121 public void adjustDisplayVolume(int delta) {
122 if (mConnectionReady && mSelectedDisplayId != null) {
123 mActiveConnection.adjustVolume(mSelectedDisplayId, delta);
127 public boolean hasComponentName(String packageName, String className) {
128 return mComponentName.getPackageName().equals(packageName)
129 && mComponentName.getClassName().equals(className);
132 public String getFlattenedComponentName() {
133 return mComponentName.flattenToShortString();
136 public void start() {
137 if (!mRunning) {
138 if (DEBUG) {
139 Slog.d(TAG, this + ": Starting");
142 mRunning = true;
143 updateBinding();
147 public void stop() {
148 if (mRunning) {
149 if (DEBUG) {
150 Slog.d(TAG, this + ": Stopping");
153 mRunning = false;
154 updateBinding();
158 public void rebindIfDisconnected() {
159 if (mActiveConnection == null && shouldBind()) {
160 unbind();
161 bind();
165 private void updateBinding() {
166 if (shouldBind()) {
167 bind();
168 } else {
169 unbind();
173 private boolean shouldBind() {
174 if (mRunning) {
175 // Bind whenever there is a discovery request or selected display.
176 if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE
177 || mSelectedDisplayId != null) {
178 return true;
181 return false;
184 private void bind() {
185 if (!mBound) {
186 if (DEBUG) {
187 Slog.d(TAG, this + ": Binding");
190 Intent service = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
191 service.setComponent(mComponentName);
192 try {
193 mBound = mContext.bindServiceAsUser(service, this,
194 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
195 new UserHandle(mUserId));
196 if (!mBound && DEBUG) {
197 Slog.d(TAG, this + ": Bind failed");
199 } catch (SecurityException ex) {
200 if (DEBUG) {
201 Slog.d(TAG, this + ": Bind failed", ex);
207 private void unbind() {
208 if (mBound) {
209 if (DEBUG) {
210 Slog.d(TAG, this + ": Unbinding");
213 mBound = false;
214 disconnect();
215 mContext.unbindService(this);
219 @Override
220 public void onServiceConnected(ComponentName name, IBinder service) {
221 if (DEBUG) {
222 Slog.d(TAG, this + ": Connected");
225 if (mBound) {
226 disconnect();
228 IRemoteDisplayProvider provider = IRemoteDisplayProvider.Stub.asInterface(service);
229 if (provider != null) {
230 Connection connection = new Connection(provider);
231 if (connection.register()) {
232 mActiveConnection = connection;
233 } else {
234 if (DEBUG) {
235 Slog.d(TAG, this + ": Registration failed");
238 } else {
239 Slog.e(TAG, this + ": Service returned invalid remote display provider binder");
244 @Override
245 public void onServiceDisconnected(ComponentName name) {
246 if (DEBUG) {
247 Slog.d(TAG, this + ": Service disconnected");
249 disconnect();
252 private void onConnectionReady(Connection connection) {
253 if (mActiveConnection == connection) {
254 mConnectionReady = true;
256 if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE) {
257 mActiveConnection.setDiscoveryMode(mDiscoveryMode);
259 if (mSelectedDisplayId != null) {
260 mActiveConnection.connect(mSelectedDisplayId);
265 private void onConnectionDied(Connection connection) {
266 if (mActiveConnection == connection) {
267 if (DEBUG) {
268 Slog.d(TAG, this + ": Service connection died");
270 disconnect();
274 private void onDisplayStateChanged(Connection connection, RemoteDisplayState state) {
275 if (mActiveConnection == connection) {
276 if (DEBUG) {
277 Slog.d(TAG, this + ": State changed, state=" + state);
279 setDisplayState(state);
283 private void disconnect() {
284 if (mActiveConnection != null) {
285 if (mSelectedDisplayId != null) {
286 mActiveConnection.disconnect(mSelectedDisplayId);
288 mConnectionReady = false;
289 mActiveConnection.dispose();
290 mActiveConnection = null;
291 setDisplayState(null);
295 private void setDisplayState(RemoteDisplayState state) {
296 if (!Objects.equals(mDisplayState, state)) {
297 mDisplayState = state;
298 if (!mScheduledDisplayStateChangedCallback) {
299 mScheduledDisplayStateChangedCallback = true;
300 mHandler.post(mDisplayStateChanged);
305 @Override
306 public String toString() {
307 return "Service connection " + mComponentName.flattenToShortString();
310 private final Runnable mDisplayStateChanged = new Runnable() {
311 @Override
312 public void run() {
313 mScheduledDisplayStateChangedCallback = false;
314 if (mDisplayStateCallback != null) {
315 mDisplayStateCallback.onDisplayStateChanged(
316 RemoteDisplayProviderProxy.this, mDisplayState);
321 public interface Callback {
322 void onDisplayStateChanged(RemoteDisplayProviderProxy provider, RemoteDisplayState state);
325 private final class Connection implements DeathRecipient {
326 private final IRemoteDisplayProvider mProvider;
327 private final ProviderCallback mCallback;
329 public Connection(IRemoteDisplayProvider provider) {
330 mProvider = provider;
331 mCallback = new ProviderCallback(this);
334 public boolean register() {
335 try {
336 mProvider.asBinder().linkToDeath(this, 0);
337 mProvider.setCallback(mCallback);
338 mHandler.post(new Runnable() {
339 @Override
340 public void run() {
341 onConnectionReady(Connection.this);
344 return true;
345 } catch (RemoteException ex) {
346 binderDied();
348 return false;
351 public void dispose() {
352 mProvider.asBinder().unlinkToDeath(this, 0);
353 mCallback.dispose();
356 public void setDiscoveryMode(int mode) {
357 try {
358 mProvider.setDiscoveryMode(mode);
359 } catch (RemoteException ex) {
360 Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex);
364 public void connect(String id) {
365 try {
366 mProvider.connect(id);
367 } catch (RemoteException ex) {
368 Slog.e(TAG, "Failed to deliver request to connect to display.", ex);
372 public void disconnect(String id) {
373 try {
374 mProvider.disconnect(id);
375 } catch (RemoteException ex) {
376 Slog.e(TAG, "Failed to deliver request to disconnect from display.", ex);
380 public void setVolume(String id, int volume) {
381 try {
382 mProvider.setVolume(id, volume);
383 } catch (RemoteException ex) {
384 Slog.e(TAG, "Failed to deliver request to set display volume.", ex);
388 public void adjustVolume(String id, int volume) {
389 try {
390 mProvider.adjustVolume(id, volume);
391 } catch (RemoteException ex) {
392 Slog.e(TAG, "Failed to deliver request to adjust display volume.", ex);
396 @Override
397 public void binderDied() {
398 mHandler.post(new Runnable() {
399 @Override
400 public void run() {
401 onConnectionDied(Connection.this);
406 void postStateChanged(final RemoteDisplayState state) {
407 mHandler.post(new Runnable() {
408 @Override
409 public void run() {
410 onDisplayStateChanged(Connection.this, state);
417 * Receives callbacks from the service.
418 * <p>
419 * This inner class is static and only retains a weak reference to the connection
420 * to prevent the client from being leaked in case the service is holding an
421 * active reference to the client's callback.
422 * </p>
424 private static final class ProviderCallback extends IRemoteDisplayCallback.Stub {
425 private final WeakReference<Connection> mConnectionRef;
427 public ProviderCallback(Connection connection) {
428 mConnectionRef = new WeakReference<Connection>(connection);
431 public void dispose() {
432 mConnectionRef.clear();
435 @Override
436 public void onStateChanged(RemoteDisplayState state) throws RemoteException {
437 Connection connection = mConnectionRef.get();
438 if (connection != null) {
439 connection.postStateChanged(state);