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