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