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