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 17package android.media; 18 19import dalvik.system.CloseGuard; 20 21import android.os.Handler; 22import android.view.Surface; 23 24/** 25 * Listens for Wifi remote display connections managed by the media server. 26 * 27 * @hide 28 */ 29public 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 44 private native long nativeListen(String iface, String opPackageName); 45 private native void nativeDispose(long ptr); 46 private native void nativePause(long ptr); 47 private native void nativeResume(long ptr); 48 49 private RemoteDisplay(Listener listener, Handler handler, String opPackageName) { 50 mListener = listener; 51 mHandler = handler; 52 mOpPackageName = opPackageName; 53 } 54 55 @Override 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 */ 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 */ 91 public void dispose() { 92 dispose(false); 93 } 94 95 public void pause() { 96 nativePause(mPtr); 97 } 98 99 public void resume() { 100 nativeResume(mPtr); 101 } 102 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 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. 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. 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. 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 { 162 void onDisplayConnected(Surface surface, 163 int width, int height, int flags, int session); 164 void onDisplayDisconnected(); 165 void onDisplayError(int error); 166 } 167} 168