1 /*
2  * Copyright (C) 2012 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 
17 package android.media;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 import android.os.Handler;
21 import android.view.Surface;
22 
23 import dalvik.system.CloseGuard;
24 
25 /**
26  * Listens for Wifi remote display connections managed by the media server.
27  *
28  * @hide
29  */
30 public final class RemoteDisplay {
31     /* these constants must be kept in sync with IRemoteDisplayClient.h */
32 
33     public static final int DISPLAY_FLAG_SECURE = 1 << 0;
34 
35     public static final int DISPLAY_ERROR_UNKOWN = 1;
36     public static final int DISPLAY_ERROR_CONNECTION_DROPPED = 2;
37 
38     private final CloseGuard mGuard = CloseGuard.get();
39     private final Listener mListener;
40     private final Handler mHandler;
41     private final String mOpPackageName;
42 
43     private long mPtr;
44 
nativeListen(String iface, String opPackageName)45     private native long nativeListen(String iface, String opPackageName);
nativeDispose(long ptr)46     private native void nativeDispose(long ptr);
nativePause(long ptr)47     private native void nativePause(long ptr);
nativeResume(long ptr)48     private native void nativeResume(long ptr);
49 
RemoteDisplay(Listener listener, Handler handler, String opPackageName)50     private RemoteDisplay(Listener listener, Handler handler, String opPackageName) {
51         mListener = listener;
52         mHandler = handler;
53         mOpPackageName = opPackageName;
54     }
55 
56     @Override
finalize()57     protected void finalize() throws Throwable {
58         try {
59             dispose(true);
60         } finally {
61             super.finalize();
62         }
63     }
64 
65     /**
66      * Starts listening for displays to be connected on the specified interface.
67      *
68      * @param iface The interface address and port in the form "x.x.x.x:y".
69      * @param listener The listener to invoke when displays are connected or disconnected.
70      * @param handler The handler on which to invoke the listener.
71      */
listen(String iface, Listener listener, Handler handler, String opPackageName)72     public static RemoteDisplay listen(String iface, Listener listener, Handler handler,
73             String opPackageName) {
74         if (iface == null) {
75             throw new IllegalArgumentException("iface must not be null");
76         }
77         if (listener == null) {
78             throw new IllegalArgumentException("listener must not be null");
79         }
80         if (handler == null) {
81             throw new IllegalArgumentException("handler must not be null");
82         }
83 
84         RemoteDisplay display = new RemoteDisplay(listener, handler, opPackageName);
85         display.startListening(iface);
86         return display;
87     }
88 
89     /**
90      * Disconnects the remote display and stops listening for new connections.
91      */
92     @UnsupportedAppUsage
dispose()93     public void dispose() {
94         dispose(false);
95     }
96 
pause()97     public void pause() {
98         nativePause(mPtr);
99     }
100 
resume()101     public void resume() {
102         nativeResume(mPtr);
103     }
104 
dispose(boolean finalized)105     private void dispose(boolean finalized) {
106         if (mPtr != 0) {
107             if (mGuard != null) {
108                 if (finalized) {
109                     mGuard.warnIfOpen();
110                 } else {
111                     mGuard.close();
112                 }
113             }
114 
115             nativeDispose(mPtr);
116             mPtr = 0;
117         }
118     }
119 
startListening(String iface)120     private void startListening(String iface) {
121         mPtr = nativeListen(iface, mOpPackageName);
122         if (mPtr == 0) {
123             throw new IllegalStateException("Could not start listening for "
124                     + "remote display connection on \"" + iface + "\"");
125         }
126         mGuard.open("dispose");
127     }
128 
129     // Called from native.
130     @UnsupportedAppUsage
notifyDisplayConnected(final Surface surface, final int width, final int height, final int flags, final int session)131     private void notifyDisplayConnected(final Surface surface,
132             final int width, final int height, final int flags, final int session) {
133         mHandler.post(new Runnable() {
134             @Override
135             public void run() {
136                 mListener.onDisplayConnected(surface, width, height, flags, session);
137             }
138         });
139     }
140 
141     // Called from native.
142     @UnsupportedAppUsage
notifyDisplayDisconnected()143     private void notifyDisplayDisconnected() {
144         mHandler.post(new Runnable() {
145             @Override
146             public void run() {
147                 mListener.onDisplayDisconnected();
148             }
149         });
150     }
151 
152     // Called from native.
153     @UnsupportedAppUsage
notifyDisplayError(final int error)154     private void notifyDisplayError(final int error) {
155         mHandler.post(new Runnable() {
156             @Override
157             public void run() {
158                 mListener.onDisplayError(error);
159             }
160         });
161     }
162 
163     /**
164      * Listener invoked when the remote display connection changes state.
165      */
166     public interface Listener {
onDisplayConnected(Surface surface, int width, int height, int flags, int session)167         void onDisplayConnected(Surface surface,
168                 int width, int height, int flags, int session);
onDisplayDisconnected()169         void onDisplayDisconnected();
onDisplayError(int error)170         void onDisplayError(int error);
171     }
172 }
173