WifiDisplayAdapter.java revision 180bbc71810496e280e9993177bfeddb3ad1f558
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 com.android.server.display;
18cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
19cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport com.android.internal.util.DumpUtils;
20cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport com.android.internal.util.IndentingPrintWriter;
21cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
22cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.content.Context;
23e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.content.Intent;
24e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.DisplayManager;
25e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.WifiDisplay;
26e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.WifiDisplayStatus;
27cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.media.RemoteDisplay;
28cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.Handler;
29cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.IBinder;
30cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.util.Slog;
31cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.view.Surface;
32cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
33cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.io.PrintWriter;
34e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport java.util.Arrays;
35cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
36cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
37cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Connects to Wifi displays that implement the Miracast protocol.
38cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p>
39cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The Wifi display protocol relies on Wifi direct for discovering and pairing
40cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * with the display.  Once connected, the Media Server opens an RTSP socket and accepts
41cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * a connection from the display.  After session negotiation, the Media Server
42cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * streams encoded buffers to the display.
43cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
44cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This class is responsible for connecting to Wifi displays and mediating
45cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * the interactions between Media Server, Surface Flinger and the Display Manager Service.
46cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
47cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
48cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p>
49cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayAdapter extends DisplayAdapter {
51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final String TAG = "WifiDisplayAdapter";
52cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
53cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiDisplayHandle mDisplayHandle;
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiDisplayController mDisplayController;
55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
56e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private WifiDisplayStatus mCurrentStatus;
57e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private boolean mEnabled;
58180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mScanState;
59180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mActiveDisplayState;
60180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private WifiDisplay mActiveDisplay;
61e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private WifiDisplay[] mKnownDisplays = WifiDisplay.EMPTY_ARRAY;
62e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
63e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private boolean mPendingStatusChangeBroadcast;
64e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
65cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
66cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Context context, Handler handler, Listener listener) {
67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super(syncRoot, context, handler, listener, TAG);
68cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
69cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
70cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
71cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void dumpLocked(PrintWriter pw) {
72cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.dumpLocked(pw);
73cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
74cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDisplayHandle == null) {
75cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayHandle=null");
76cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
77cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayHandle:");
78cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mDisplayHandle.dumpLocked(pw);
79cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
80cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
81e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
82e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mEnabled=" + mEnabled);
83180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mScanState=" + mScanState);
84180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplayState=" + mActiveDisplayState);
85180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplay=" + mActiveDisplay);
86e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mKnownDisplays=" + Arrays.toString(mKnownDisplays));
87e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
88e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
89cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Try to dump the controller state.
90cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDisplayController == null) {
91cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController=null");
92cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
93cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController:");
94cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
95cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            ipw.increaseIndent();
96cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200);
97cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
98cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
99cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
100cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
101cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void registerLocked() {
102cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.registerLocked();
103cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
104cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        getHandler().post(new Runnable() {
105cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
106cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void run() {
107cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mDisplayController = new WifiDisplayController(
108cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        getContext(), getHandler(), mWifiDisplayListener);
109cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
110cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
111cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
112cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
113e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestScanLocked() {
114e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
115e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
116e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
117e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
118e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestScan();
119e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
120e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
121e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
122e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
123e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
124e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestConnectLocked(final String address) {
125e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
126e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
127e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
128e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
129e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestConnect(address);
130e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
131e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
132e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
133e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
134e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
135e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestDisconnectLocked() {
136e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
137e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
138e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
139e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
140e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestDisconnect();
141e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
142e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
143e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
144e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
145e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
146e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatusLocked() {
147e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (mCurrentStatus == null) {
148180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown            mCurrentStatus = new WifiDisplayStatus(mEnabled, mScanState, mActiveDisplayState,
149180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay, mKnownDisplays);
150e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
151e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        return mCurrentStatus;
152e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
153cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
154e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void handleConnectLocked(WifiDisplay display, String iface) {
155e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        handleDisconnectLocked();
156e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
157e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        mDisplayHandle = new WifiDisplayHandle(display.getDeviceName(), iface);
158cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
159cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
160e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void handleDisconnectLocked() {
161cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDisplayHandle != null) {
162cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mDisplayHandle.disposeLocked();
163cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mDisplayHandle = null;
164cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
165cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
166cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
167e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void scheduleStatusChangedBroadcastLocked() {
168e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (!mPendingStatusChangeBroadcast) {
169e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mPendingStatusChangeBroadcast = true;
170e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            getHandler().post(mStatusChangeBroadcast);
171e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
172e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
173e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
174e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private final Runnable mStatusChangeBroadcast = new Runnable() {
175e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
176e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void run() {
177e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            final Intent intent;
178e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
179e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (!mPendingStatusChangeBroadcast) {
180e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    return;
181e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
182e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
183e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                mPendingStatusChangeBroadcast = false;
184e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
185e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
186e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
187e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                        getWifiDisplayStatusLocked());
188e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
189e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
190e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            // Send protected broadcast about wifi display status to receivers that
191e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            // have the required permission.
192e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            getContext().sendBroadcast(intent,
193e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    android.Manifest.permission.CONFIGURE_WIFI_DISPLAY);
194e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
195e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    };
196e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
197cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final WifiDisplayController.Listener mWifiDisplayListener =
198cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            new WifiDisplayController.Listener() {
199cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
200e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onEnablementChanged(boolean enabled) {
201e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
202e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mEnabled != enabled) {
203e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mCurrentStatus = null;
204e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mEnabled = enabled;
205e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
206e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
207e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
208e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
209e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
210e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
211e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onScanStarted() {
212e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
213180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
214e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mCurrentStatus = null;
215180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
216e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
217e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
218e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
219e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
220e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
221e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onScanFinished(WifiDisplay[] knownDisplays) {
222e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
223180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING
224180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !Arrays.equals(mKnownDisplays, knownDisplays)) {
225e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mCurrentStatus = null;
226180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
227e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mKnownDisplays = knownDisplays;
228e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
229e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
230e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
231e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
232e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
233e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
234e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnecting(WifiDisplay display) {
235e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
236180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
237180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
238180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
239e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mCurrentStatus = null;
240180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
241180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
242e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
243e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
244e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
245e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
246e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
247e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
248e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnectionFailed() {
249e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
250180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
251180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
252e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mCurrentStatus = null;
253180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
254180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
255e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
256e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
257e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
258e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
259e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
260e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
261e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnected(WifiDisplay display, String iface) {
262cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
263e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                handleConnectLocked(display, iface);
264e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
265180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
266180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
267180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
268e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mCurrentStatus = null;
269180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
270180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
271e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
272e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
273cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
274cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
275cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
276cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
277cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onDisplayDisconnected() {
278cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            // Stop listening.
279cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
280e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                handleDisconnectLocked();
281e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
282180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
283180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
284e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mCurrentStatus = null;
285180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
286180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
287e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
288e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
289cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
290cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
291cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
292cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
293cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final class WifiDisplayDevice extends DisplayDevice {
294cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final String mName;
295cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mWidth;
296cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mHeight;
297cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final float mRefreshRate;
298cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mFlags;
299cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
300cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private Surface mSurface;
301cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private DisplayDeviceInfo mInfo;
302cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
303cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public WifiDisplayDevice(IBinder displayToken, String name,
304cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                int width, int height, float refreshRate, int flags,
305cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Surface surface) {
306cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            super(WifiDisplayAdapter.this, displayToken);
307cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mName = name;
308cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWidth = width;
309cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mHeight = height;
310cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mRefreshRate = refreshRate;
311cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mFlags = flags;
312cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = surface;
313cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
314cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
315cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void clearSurfaceLocked() {
316cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = null;
317cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            sendTraversalRequestLocked();
318cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
319cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
320cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
321cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void performTraversalInTransactionLocked() {
322cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            setSurfaceInTransactionLocked(mSurface);
323cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
324cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
325cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
326cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
327cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mInfo == null) {
328cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo = new DisplayDeviceInfo();
329cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.name = mName;
330cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.width = mWidth;
331cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.height = mHeight;
332cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.refreshRate = mRefreshRate;
333cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.flags = mFlags;
334d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown                mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
335cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
336cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
337cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return mInfo;
338cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
339cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
340cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
341cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final class WifiDisplayHandle implements RemoteDisplay.Listener {
342cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final String mName;
343cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final String mIface;
344cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final RemoteDisplay mRemoteDisplay;
345cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
346cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private WifiDisplayDevice mDevice;
347cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private int mLastError;
348cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
349cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public WifiDisplayHandle(String name, String iface) {
350cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mName = name;
351cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mIface = iface;
352cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mRemoteDisplay = RemoteDisplay.listen(iface, this, getHandler());
353cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
354cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Listening for Wifi display connections on " + iface
355cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    + " from " + mName);
356cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
357cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
358cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void disposeLocked() {
359cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            Slog.i(TAG, "Stopped listening for Wifi display connections on " + mIface
360cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    + " from " + mName);
361cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
362cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            removeDisplayLocked();
363cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mRemoteDisplay.dispose();
364cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
365cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
366cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void dumpLocked(PrintWriter pw) {
367cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("  " + mName + ": " + (mDevice != null ? "connected" : "disconnected"));
368cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("    mIface=" + mIface);
369cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("    mLastError=" + mLastError);
370cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
371cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
372cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Called on the handler thread.
373cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
374cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onDisplayConnected(Surface surface, int width, int height, int flags) {
375cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
376cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mLastError = 0;
377cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                removeDisplayLocked();
378cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                addDisplayLocked(surface, width, height, flags);
379cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
380cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.i(TAG, "Wifi display connected: " + mName);
381cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
382cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
383cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
384cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Called on the handler thread.
385cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
386cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onDisplayDisconnected() {
387cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
388cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mLastError = 0;
389cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                removeDisplayLocked();
390cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
391cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.i(TAG, "Wifi display disconnected: " + mName);
392cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
393cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
394cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
395cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Called on the handler thread.
396cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
397cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onDisplayError(int error) {
398cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
399cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mLastError = error;
400cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                removeDisplayLocked();
401cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
402cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Slog.i(TAG, "Wifi display disconnected due to error " + error + ": " + mName);
403cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
404cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
405cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
406cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private void addDisplayLocked(Surface surface, int width, int height, int flags) {
407cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            int deviceFlags = 0;
408cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
409cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
410cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
411cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
412cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            float refreshRate = 60.0f; // TODO: get this for real
413cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
414cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            IBinder displayToken = Surface.createDisplay(mName);
415cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mDevice = new WifiDisplayDevice(displayToken, mName, width, height,
416cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    refreshRate, deviceFlags, surface);
417cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
418cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
419cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
420cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private void removeDisplayLocked() {
421cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mDevice != null) {
422cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mDevice.clearSurfaceLocked();
423cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
424cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mDevice = null;
425cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
426cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
427cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
428cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
429