1cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/*
2cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Copyright (C) 2012 The Android Open Source Project
3cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown *
4cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * you may not use this file except in compliance with the License.
6cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * You may obtain a copy of the License at
7cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown *
8cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown *
10cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Unless required by applicable law or agreed to in writing, software
11cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * See the License for the specific language governing permissions and
14cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * limitations under the License.
15cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
16cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
17cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownpackage android.media;
18cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
19cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport dalvik.system.CloseGuard;
20cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
21cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.Handler;
22cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.view.Surface;
23cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
24cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
25cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Listens for Wifi remote display connections managed by the media server.
26cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown *
27cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * @hide
28cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
29cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownpublic final class RemoteDisplay {
30cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /* these constants must be kept in sync with IRemoteDisplayClient.h */
31cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
32cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public static final int DISPLAY_FLAG_SECURE = 1 << 0;
33cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
34cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public static final int DISPLAY_ERROR_UNKOWN = 1;
35cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public static final int DISPLAY_ERROR_CONNECTION_DROPPED = 2;
36cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
37cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final CloseGuard mGuard = CloseGuard.get();
38cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Listener mListener;
39cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final Handler mHandler;
40cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
41075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    private long mPtr;
42cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
43075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    private native long nativeListen(String iface);
44075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    private native void nativeDispose(long ptr);
45075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    private native void nativePause(long ptr);
46075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    private native void nativeResume(long ptr);
47cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
48cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private RemoteDisplay(Listener listener, Handler handler) {
49cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mListener = listener;
50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mHandler = handler;
51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
52cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
53cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    protected void finalize() throws Throwable {
55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        try {
56cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            dispose(true);
57cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } finally {
58cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            super.finalize();
59cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /**
63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * Starts listening for displays to be connected on the specified interface.
64cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     *
65cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * @param iface The interface address and port in the form "x.x.x.x:y".
66cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * @param listener The listener to invoke when displays are connected or disconnected.
67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * @param handler The handler on which to invoke the listener.
68cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     */
69cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public static RemoteDisplay listen(String iface, Listener listener, Handler handler) {
70cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (iface == null) {
71cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            throw new IllegalArgumentException("iface must not be null");
72cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
73cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (listener == null) {
74cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            throw new IllegalArgumentException("listener must not be null");
75cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
76cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (handler == null) {
77cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            throw new IllegalArgumentException("handler must not be null");
78cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
79cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
80cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        RemoteDisplay display = new RemoteDisplay(listener, handler);
81cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        display.startListening(iface);
82cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return display;
83cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
84cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
85cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /**
86cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * Disconnects the remote display and stops listening for new connections.
87cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     */
88cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void dispose() {
89cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        dispose(false);
90cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
91cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
921f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void pause() {
931f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        nativePause(mPtr);
941f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
951f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
961f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void resume() {
971f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        nativeResume(mPtr);
981f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
991f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
100cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void dispose(boolean finalized) {
101cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mPtr != 0) {
102cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mGuard != null) {
103cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                if (finalized) {
104cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    mGuard.warnIfOpen();
105cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                } else {
106cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    mGuard.close();
107cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                }
108cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
109cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
110cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            nativeDispose(mPtr);
111cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mPtr = 0;
112cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
113cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
114cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
115cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void startListening(String iface) {
116cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mPtr = nativeListen(iface);
117cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mPtr == 0) {
118cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            throw new IllegalStateException("Could not start listening for "
119cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    + "remote display connection on \"" + iface + "\"");
120cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
121cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mGuard.open("dispose");
122cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
123cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
124cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // Called from native.
125cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void notifyDisplayConnected(final Surface surface,
1261f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            final int width, final int height, final int flags, final int session) {
127cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mHandler.post(new Runnable() {
128cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
129cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void run() {
1301f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                mListener.onDisplayConnected(surface, width, height, flags, session);
131cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
132cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
133cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
134cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
135cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // Called from native.
136cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void notifyDisplayDisconnected() {
137cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mHandler.post(new Runnable() {
138cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
139cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void run() {
140cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mListener.onDisplayDisconnected();
141cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
142cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
143cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
144cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
145cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    // Called from native.
146cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private void notifyDisplayError(final int error) {
147cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mHandler.post(new Runnable() {
148cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
149cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void run() {
150cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mListener.onDisplayError(error);
151cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
152cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
153cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
154cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
155cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    /**
156cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     * Listener invoked when the remote display connection changes state.
157cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown     */
158cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public interface Listener {
1591f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        void onDisplayConnected(Surface surface,
1601f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                int width, int height, int flags, int session);
161cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        void onDisplayDisconnected();
162cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        void onDisplayError(int error);
163cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
164cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
165