blob: 08c0a1ad8219d047ee1a0e560da0f952ba86c3cf [file] [log] [blame]
Jeff Browncbad9762012-09-04 21:57:59 -07001/*
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 com.android.server.display;
18
19import com.android.internal.util.DumpUtils;
20import com.android.internal.util.IndentingPrintWriter;
21
Jeff Browna7f9c962012-10-17 15:15:12 -070022import android.content.BroadcastReceiver;
Jeff Browncbad9762012-09-04 21:57:59 -070023import android.content.Context;
Jeff Browne08ae382012-09-07 20:36:36 -070024import android.content.Intent;
Jeff Browna7f9c962012-10-17 15:15:12 -070025import android.content.IntentFilter;
Jeff Browne08ae382012-09-07 20:36:36 -070026import android.hardware.display.DisplayManager;
27import android.hardware.display.WifiDisplay;
Chong Zhang1f3ecaa2013-05-03 15:55:36 -070028import android.hardware.display.WifiDisplaySessionInfo;
Jeff Browne08ae382012-09-07 20:36:36 -070029import android.hardware.display.WifiDisplayStatus;
Jeff Browncbad9762012-09-04 21:57:59 -070030import android.media.RemoteDisplay;
31import android.os.Handler;
32import android.os.IBinder;
Jeff Browna7f9c962012-10-17 15:15:12 -070033import android.os.Looper;
34import android.os.Message;
35import android.os.UserHandle;
Jeff Brownbc335452012-09-26 18:34:47 -070036import android.util.Slog;
Jeff Brown92130f62012-10-24 21:28:33 -070037import android.view.Display;
Jeff Browncbad9762012-09-04 21:57:59 -070038import android.view.Surface;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080039import android.view.SurfaceControl;
Jeff Browncbad9762012-09-04 21:57:59 -070040
41import java.io.PrintWriter;
Jeff Browne08ae382012-09-07 20:36:36 -070042import java.util.Arrays;
Chong Zhangab87a632013-06-11 10:25:49 -070043import java.util.List;
44import java.util.ArrayList;
Jeff Browncbad9762012-09-04 21:57:59 -070045
Jeff Brown74da1092012-11-07 16:02:13 -080046import libcore.util.Objects;
47
Jeff Browncbad9762012-09-04 21:57:59 -070048/**
49 * Connects to Wifi displays that implement the Miracast protocol.
50 * <p>
51 * The Wifi display protocol relies on Wifi direct for discovering and pairing
52 * with the display. Once connected, the Media Server opens an RTSP socket and accepts
53 * a connection from the display. After session negotiation, the Media Server
54 * streams encoded buffers to the display.
55 * </p><p>
56 * This class is responsible for connecting to Wifi displays and mediating
57 * the interactions between Media Server, Surface Flinger and the Display Manager Service.
58 * </p><p>
59 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
60 * </p>
61 */
62final class WifiDisplayAdapter extends DisplayAdapter {
63 private static final String TAG = "WifiDisplayAdapter";
64
Jeff Brown2444ae72012-10-11 14:30:21 -070065 private static final boolean DEBUG = false;
66
Jeff Browna7f9c962012-10-17 15:15:12 -070067 private static final int MSG_SEND_STATUS_CHANGE_BROADCAST = 1;
Jeff Browna7f9c962012-10-17 15:15:12 -070068
69 private static final String ACTION_DISCONNECT = "android.server.display.wfd.DISCONNECT";
70
Wale Ogunwale361ca212014-11-20 11:42:38 -080071 // Unique id prefix for wifi displays
72 private static final String DISPLAY_NAME_PREFIX = "wifi:";
73
Jeff Browna7f9c962012-10-17 15:15:12 -070074 private final WifiDisplayHandler mHandler;
Jeff Brown77aebfd2012-10-01 21:07:03 -070075 private final PersistentDataStore mPersistentDataStore;
76 private final boolean mSupportsProtectedBuffers;
Jeff Brown89d55462012-09-19 11:33:42 -070077
Jeff Browncbad9762012-09-04 21:57:59 -070078 private WifiDisplayController mDisplayController;
Jeff Brownf8f0edd2012-09-11 17:05:11 -070079 private WifiDisplayDevice mDisplayDevice;
Jeff Browncbad9762012-09-04 21:57:59 -070080
Jeff Browne08ae382012-09-07 20:36:36 -070081 private WifiDisplayStatus mCurrentStatus;
Jeff Brown89d55462012-09-19 11:33:42 -070082 private int mFeatureState;
Jeff Brown180bbc72012-09-08 23:15:00 -070083 private int mScanState;
84 private int mActiveDisplayState;
85 private WifiDisplay mActiveDisplay;
Chong Zhangab87a632013-06-11 10:25:49 -070086 private WifiDisplay[] mDisplays = WifiDisplay.EMPTY_ARRAY;
Jeff Brown89d55462012-09-19 11:33:42 -070087 private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
88 private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
Chong Zhang1f3ecaa2013-05-03 15:55:36 -070089 private WifiDisplaySessionInfo mSessionInfo;
Jeff Browne08ae382012-09-07 20:36:36 -070090
91 private boolean mPendingStatusChangeBroadcast;
92
Jeff Brown66692502012-10-18 16:13:44 -070093 // Called with SyncRoot lock held.
Jeff Browncbad9762012-09-04 21:57:59 -070094 public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Jeff Brown89d55462012-09-19 11:33:42 -070095 Context context, Handler handler, Listener listener,
96 PersistentDataStore persistentDataStore) {
Jeff Browncbad9762012-09-04 21:57:59 -070097 super(syncRoot, context, handler, listener, TAG);
Jeff Browna7f9c962012-10-17 15:15:12 -070098 mHandler = new WifiDisplayHandler(handler.getLooper());
Jeff Brown89d55462012-09-19 11:33:42 -070099 mPersistentDataStore = persistentDataStore;
Jeff Brown77aebfd2012-10-01 21:07:03 -0700100 mSupportsProtectedBuffers = context.getResources().getBoolean(
101 com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers);
Jeff Browncbad9762012-09-04 21:57:59 -0700102 }
103
104 @Override
105 public void dumpLocked(PrintWriter pw) {
106 super.dumpLocked(pw);
107
Jeff Browne08ae382012-09-07 20:36:36 -0700108 pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
Jeff Brown89d55462012-09-19 11:33:42 -0700109 pw.println("mFeatureState=" + mFeatureState);
Jeff Brown180bbc72012-09-08 23:15:00 -0700110 pw.println("mScanState=" + mScanState);
111 pw.println("mActiveDisplayState=" + mActiveDisplayState);
112 pw.println("mActiveDisplay=" + mActiveDisplay);
Chong Zhangab87a632013-06-11 10:25:49 -0700113 pw.println("mDisplays=" + Arrays.toString(mDisplays));
Jeff Brown89d55462012-09-19 11:33:42 -0700114 pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
115 pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
Jeff Browne08ae382012-09-07 20:36:36 -0700116 pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
Jeff Brown77aebfd2012-10-01 21:07:03 -0700117 pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
Andy McFaddene8b1aeb2014-06-13 14:05:40 -0700118
Jeff Browncbad9762012-09-04 21:57:59 -0700119 // Try to dump the controller state.
120 if (mDisplayController == null) {
121 pw.println("mDisplayController=null");
122 } else {
123 pw.println("mDisplayController:");
124 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
125 ipw.increaseIndent();
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800126 DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, "", 200);
Jeff Browncbad9762012-09-04 21:57:59 -0700127 }
128 }
129
130 @Override
131 public void registerLocked() {
132 super.registerLocked();
133
Jeff Brown89d55462012-09-19 11:33:42 -0700134 updateRememberedDisplaysLocked();
135
Jeff Browncbad9762012-09-04 21:57:59 -0700136 getHandler().post(new Runnable() {
137 @Override
138 public void run() {
139 mDisplayController = new WifiDisplayController(
140 getContext(), getHandler(), mWifiDisplayListener);
Jeff Brown66692502012-10-18 16:13:44 -0700141
142 getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
143 new IntentFilter(ACTION_DISCONNECT), null, mHandler);
Jeff Browncbad9762012-09-04 21:57:59 -0700144 }
145 });
146 }
147
Jeff Brownce468a32013-11-21 16:42:03 -0800148 public void requestStartScanLocked() {
Jeff Brown2444ae72012-10-11 14:30:21 -0700149 if (DEBUG) {
Jeff Brownce468a32013-11-21 16:42:03 -0800150 Slog.d(TAG, "requestStartScanLocked");
Jeff Brown2444ae72012-10-11 14:30:21 -0700151 }
152
Jeff Browne08ae382012-09-07 20:36:36 -0700153 getHandler().post(new Runnable() {
154 @Override
155 public void run() {
156 if (mDisplayController != null) {
Jeff Brownce468a32013-11-21 16:42:03 -0800157 mDisplayController.requestStartScan();
158 }
159 }
160 });
161 }
162
163 public void requestStopScanLocked() {
164 if (DEBUG) {
165 Slog.d(TAG, "requestStopScanLocked");
166 }
167
168 getHandler().post(new Runnable() {
169 @Override
170 public void run() {
171 if (mDisplayController != null) {
172 mDisplayController.requestStopScan();
Jeff Browne08ae382012-09-07 20:36:36 -0700173 }
174 }
175 });
Jeff Browncbad9762012-09-04 21:57:59 -0700176 }
177
Jeff Brownaf574182013-11-14 18:16:08 -0800178 public void requestConnectLocked(final String address) {
Jeff Brown2444ae72012-10-11 14:30:21 -0700179 if (DEBUG) {
Jeff Brownaf574182013-11-14 18:16:08 -0800180 Slog.d(TAG, "requestConnectLocked: address=" + address);
Jeff Brownbc335452012-09-26 18:34:47 -0700181 }
182
Jeff Browne08ae382012-09-07 20:36:36 -0700183 getHandler().post(new Runnable() {
184 @Override
185 public void run() {
186 if (mDisplayController != null) {
187 mDisplayController.requestConnect(address);
188 }
189 }
190 });
191 }
192
Chong Zhang1f3ecaa2013-05-03 15:55:36 -0700193 public void requestPauseLocked() {
194 if (DEBUG) {
195 Slog.d(TAG, "requestPauseLocked");
196 }
197
198 getHandler().post(new Runnable() {
199 @Override
200 public void run() {
201 if (mDisplayController != null) {
202 mDisplayController.requestPause();
203 }
204 }
205 });
206 }
207
208 public void requestResumeLocked() {
209 if (DEBUG) {
210 Slog.d(TAG, "requestResumeLocked");
211 }
212
213 getHandler().post(new Runnable() {
214 @Override
215 public void run() {
216 if (mDisplayController != null) {
217 mDisplayController.requestResume();
218 }
219 }
220 });
221 }
222
Jeff Browne08ae382012-09-07 20:36:36 -0700223 public void requestDisconnectLocked() {
Jeff Brown2444ae72012-10-11 14:30:21 -0700224 if (DEBUG) {
225 Slog.d(TAG, "requestDisconnectedLocked");
226 }
227
Jeff Browne08ae382012-09-07 20:36:36 -0700228 getHandler().post(new Runnable() {
229 @Override
230 public void run() {
231 if (mDisplayController != null) {
232 mDisplayController.requestDisconnect();
233 }
234 }
235 });
236 }
237
Jeff Brown89d55462012-09-19 11:33:42 -0700238 public void requestRenameLocked(String address, String alias) {
Jeff Brown2444ae72012-10-11 14:30:21 -0700239 if (DEBUG) {
240 Slog.d(TAG, "requestRenameLocked: address=" + address + ", alias=" + alias);
241 }
242
Jeff Brown89d55462012-09-19 11:33:42 -0700243 if (alias != null) {
244 alias = alias.trim();
Jeff Brown2444ae72012-10-11 14:30:21 -0700245 if (alias.isEmpty() || alias.equals(address)) {
Jeff Brown89d55462012-09-19 11:33:42 -0700246 alias = null;
247 }
248 }
249
Jeff Brown74da1092012-11-07 16:02:13 -0800250 WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address);
251 if (display != null && !Objects.equal(display.getDeviceAlias(), alias)) {
Chong Zhangab87a632013-06-11 10:25:49 -0700252 display = new WifiDisplay(address, display.getDeviceName(), alias,
253 false, false, false);
Jeff Brown74da1092012-11-07 16:02:13 -0800254 if (mPersistentDataStore.rememberWifiDisplay(display)) {
255 mPersistentDataStore.saveIfNeeded();
256 updateRememberedDisplaysLocked();
257 scheduleStatusChangedBroadcastLocked();
258 }
Jeff Brown89d55462012-09-19 11:33:42 -0700259 }
Jeff Brownee4f0292012-10-15 15:31:59 -0700260
Jeff Brown74da1092012-11-07 16:02:13 -0800261 if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
262 renameDisplayDeviceLocked(mActiveDisplay.getFriendlyDisplayName());
Jeff Brownee4f0292012-10-15 15:31:59 -0700263 }
Jeff Brown89d55462012-09-19 11:33:42 -0700264 }
265
266 public void requestForgetLocked(String address) {
Jeff Brown2444ae72012-10-11 14:30:21 -0700267 if (DEBUG) {
268 Slog.d(TAG, "requestForgetLocked: address=" + address);
269 }
270
Jeff Brown89d55462012-09-19 11:33:42 -0700271 if (mPersistentDataStore.forgetWifiDisplay(address)) {
272 mPersistentDataStore.saveIfNeeded();
273 updateRememberedDisplaysLocked();
274 scheduleStatusChangedBroadcastLocked();
275 }
276
277 if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
278 requestDisconnectLocked();
279 }
280 }
281
Jeff Browne08ae382012-09-07 20:36:36 -0700282 public WifiDisplayStatus getWifiDisplayStatusLocked() {
283 if (mCurrentStatus == null) {
Jeff Brown89d55462012-09-19 11:33:42 -0700284 mCurrentStatus = new WifiDisplayStatus(
285 mFeatureState, mScanState, mActiveDisplayState,
Chong Zhang1f3ecaa2013-05-03 15:55:36 -0700286 mActiveDisplay, mDisplays, mSessionInfo);
Jeff Browne08ae382012-09-07 20:36:36 -0700287 }
Jeff Brown2444ae72012-10-11 14:30:21 -0700288
289 if (DEBUG) {
290 Slog.d(TAG, "getWifiDisplayStatusLocked: result=" + mCurrentStatus);
291 }
Jeff Browne08ae382012-09-07 20:36:36 -0700292 return mCurrentStatus;
293 }
294
Chong Zhangab87a632013-06-11 10:25:49 -0700295 private void updateDisplaysLocked() {
296 List<WifiDisplay> displays = new ArrayList<WifiDisplay>(
297 mAvailableDisplays.length + mRememberedDisplays.length);
298 boolean[] remembered = new boolean[mAvailableDisplays.length];
299 for (WifiDisplay d : mRememberedDisplays) {
300 boolean available = false;
301 for (int i = 0; i < mAvailableDisplays.length; i++) {
302 if (d.equals(mAvailableDisplays[i])) {
303 remembered[i] = available = true;
304 break;
305 }
306 }
307 if (!available) {
308 displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
309 d.getDeviceAlias(), false, false, true));
310 }
311 }
312 for (int i = 0; i < mAvailableDisplays.length; i++) {
313 WifiDisplay d = mAvailableDisplays[i];
314 displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
315 d.getDeviceAlias(), true, d.canConnect(), remembered[i]));
316 }
317 mDisplays = displays.toArray(WifiDisplay.EMPTY_ARRAY);
318 }
319
Jeff Brown89d55462012-09-19 11:33:42 -0700320 private void updateRememberedDisplaysLocked() {
321 mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
322 mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
323 mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
Chong Zhangab87a632013-06-11 10:25:49 -0700324 updateDisplaysLocked();
Jeff Brown89d55462012-09-19 11:33:42 -0700325 }
326
Jeff Brown74da1092012-11-07 16:02:13 -0800327 private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() {
328 // It may happen that a display name has changed since it was remembered.
329 // Consult the list of available displays and update the name if needed.
330 // We don't do anything special for the active display here. The display
331 // controller will send a separate event when it needs to be updates.
332 boolean changed = false;
333 for (int i = 0; i < mRememberedDisplays.length; i++) {
334 WifiDisplay rememberedDisplay = mRememberedDisplays[i];
335 WifiDisplay availableDisplay = findAvailableDisplayLocked(
336 rememberedDisplay.getDeviceAddress());
337 if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) {
338 if (DEBUG) {
339 Slog.d(TAG, "fixRememberedDisplayNamesFromAvailableDisplaysLocked: "
340 + "updating remembered display to " + availableDisplay);
341 }
342 mRememberedDisplays[i] = availableDisplay;
343 changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay);
344 }
345 }
346 if (changed) {
347 mPersistentDataStore.saveIfNeeded();
348 }
349 }
350
351 private WifiDisplay findAvailableDisplayLocked(String address) {
352 for (WifiDisplay display : mAvailableDisplays) {
353 if (display.getDeviceAddress().equals(address)) {
354 return display;
355 }
356 }
357 return null;
358 }
359
360 private void addDisplayDeviceLocked(WifiDisplay display,
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700361 Surface surface, int width, int height, int flags) {
Jeff Brown74da1092012-11-07 16:02:13 -0800362 removeDisplayDeviceLocked();
Jeff Browne08ae382012-09-07 20:36:36 -0700363
Jeff Brown89d55462012-09-19 11:33:42 -0700364 if (mPersistentDataStore.rememberWifiDisplay(display)) {
365 mPersistentDataStore.saveIfNeeded();
366 updateRememberedDisplaysLocked();
367 scheduleStatusChangedBroadcastLocked();
368 }
369
Jeff Brownf0681b32012-10-23 17:35:57 -0700370 boolean secure = (flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0;
Jeff Brown7d00aff2013-08-02 19:03:49 -0700371 int deviceFlags = DisplayDeviceInfo.FLAG_PRESENTATION;
Jeff Brownf0681b32012-10-23 17:35:57 -0700372 if (secure) {
Jeff Brown77aebfd2012-10-01 21:07:03 -0700373 deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700374 if (mSupportsProtectedBuffers) {
375 deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
376 }
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700377 }
378
379 float refreshRate = 60.0f; // TODO: get this for real
380
Jeff Brown89d55462012-09-19 11:33:42 -0700381 String name = display.getFriendlyDisplayName();
Jeff Brown92130f62012-10-24 21:28:33 -0700382 String address = display.getDeviceAddress();
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800383 IBinder displayToken = SurfaceControl.createDisplay(name, secure);
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700384 mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
Jeff Brown92130f62012-10-24 21:28:33 -0700385 refreshRate, deviceFlags, address, surface);
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700386 sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
Jeff Browne08ae382012-09-07 20:36:36 -0700387 }
388
Jeff Brown74da1092012-11-07 16:02:13 -0800389 private void removeDisplayDeviceLocked() {
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700390 if (mDisplayDevice != null) {
Jesse Hall6a6bc212013-08-08 12:15:03 -0700391 mDisplayDevice.destroyLocked();
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700392 sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
393 mDisplayDevice = null;
Jeff Browncbad9762012-09-04 21:57:59 -0700394 }
395 }
396
Jeff Brown74da1092012-11-07 16:02:13 -0800397 private void renameDisplayDeviceLocked(String name) {
398 if (mDisplayDevice != null && !mDisplayDevice.getNameLocked().equals(name)) {
399 mDisplayDevice.setNameLocked(name);
400 sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
401 }
402 }
403
Jeff Browne08ae382012-09-07 20:36:36 -0700404 private void scheduleStatusChangedBroadcastLocked() {
Jeff Brown89d55462012-09-19 11:33:42 -0700405 mCurrentStatus = null;
Jeff Browne08ae382012-09-07 20:36:36 -0700406 if (!mPendingStatusChangeBroadcast) {
407 mPendingStatusChangeBroadcast = true;
Jeff Browna7f9c962012-10-17 15:15:12 -0700408 mHandler.sendEmptyMessage(MSG_SEND_STATUS_CHANGE_BROADCAST);
Jeff Browne08ae382012-09-07 20:36:36 -0700409 }
410 }
411
Jeff Browna7f9c962012-10-17 15:15:12 -0700412 // Runs on the handler.
413 private void handleSendStatusChangeBroadcast() {
414 final Intent intent;
415 synchronized (getSyncRoot()) {
416 if (!mPendingStatusChangeBroadcast) {
417 return;
Jeff Browne08ae382012-09-07 20:36:36 -0700418 }
419
Jeff Browna7f9c962012-10-17 15:15:12 -0700420 mPendingStatusChangeBroadcast = false;
421 intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
422 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
423 intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
424 getWifiDisplayStatusLocked());
425 }
426
427 // Send protected broadcast about wifi display status to registered receivers.
428 getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
429 }
430
Jeff Browna7f9c962012-10-17 15:15:12 -0700431 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
432 @Override
433 public void onReceive(Context context, Intent intent) {
434 if (intent.getAction().equals(ACTION_DISCONNECT)) {
435 synchronized (getSyncRoot()) {
436 requestDisconnectLocked();
437 }
438 }
Jeff Browne08ae382012-09-07 20:36:36 -0700439 }
440 };
441
Jeff Browncbad9762012-09-04 21:57:59 -0700442 private final WifiDisplayController.Listener mWifiDisplayListener =
443 new WifiDisplayController.Listener() {
444 @Override
Jeff Brown89d55462012-09-19 11:33:42 -0700445 public void onFeatureStateChanged(int featureState) {
Jeff Browncbad9762012-09-04 21:57:59 -0700446 synchronized (getSyncRoot()) {
Jeff Brown89d55462012-09-19 11:33:42 -0700447 if (mFeatureState != featureState) {
448 mFeatureState = featureState;
Jeff Browne08ae382012-09-07 20:36:36 -0700449 scheduleStatusChangedBroadcastLocked();
450 }
451 }
452 }
453
454 @Override
455 public void onScanStarted() {
456 synchronized (getSyncRoot()) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700457 if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700458 mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
Jeff Browne08ae382012-09-07 20:36:36 -0700459 scheduleStatusChangedBroadcastLocked();
460 }
461 }
462 }
463
Jeff Brown2444ae72012-10-11 14:30:21 -0700464 @Override
Jeff Brownce468a32013-11-21 16:42:03 -0800465 public void onScanResults(WifiDisplay[] availableDisplays) {
Jeff Browne08ae382012-09-07 20:36:36 -0700466 synchronized (getSyncRoot()) {
Jeff Brown89d55462012-09-19 11:33:42 -0700467 availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
468 availableDisplays);
469
Chong Zhangab87a632013-06-11 10:25:49 -0700470 boolean changed = !Arrays.equals(mAvailableDisplays, availableDisplays);
Jeff Brownce468a32013-11-21 16:42:03 -0800471
472 // Check whether any of the available displays changed canConnect status.
Chong Zhangab87a632013-06-11 10:25:49 -0700473 for (int i = 0; !changed && i<availableDisplays.length; i++) {
474 changed = availableDisplays[i].canConnect()
475 != mAvailableDisplays[i].canConnect();
476 }
477
Jeff Brownce468a32013-11-21 16:42:03 -0800478 if (changed) {
Jeff Brown89d55462012-09-19 11:33:42 -0700479 mAvailableDisplays = availableDisplays;
Jeff Brown74da1092012-11-07 16:02:13 -0800480 fixRememberedDisplayNamesFromAvailableDisplaysLocked();
Chong Zhangab87a632013-06-11 10:25:49 -0700481 updateDisplaysLocked();
Jeff Browne08ae382012-09-07 20:36:36 -0700482 scheduleStatusChangedBroadcastLocked();
483 }
484 }
485 }
486
487 @Override
Jeff Brownce468a32013-11-21 16:42:03 -0800488 public void onScanFinished() {
489 synchronized (getSyncRoot()) {
490 if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING) {
491 mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
492 scheduleStatusChangedBroadcastLocked();
493 }
494 }
495 }
496
497 @Override
Jeff Browne08ae382012-09-07 20:36:36 -0700498 public void onDisplayConnecting(WifiDisplay display) {
499 synchronized (getSyncRoot()) {
Jeff Brown89d55462012-09-19 11:33:42 -0700500 display = mPersistentDataStore.applyWifiDisplayAlias(display);
501
Jeff Brown180bbc72012-09-08 23:15:00 -0700502 if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
503 || mActiveDisplay == null
504 || !mActiveDisplay.equals(display)) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700505 mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
506 mActiveDisplay = display;
Jeff Browne08ae382012-09-07 20:36:36 -0700507 scheduleStatusChangedBroadcastLocked();
508 }
509 }
510 }
511
512 @Override
513 public void onDisplayConnectionFailed() {
514 synchronized (getSyncRoot()) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700515 if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
516 || mActiveDisplay != null) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700517 mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
518 mActiveDisplay = null;
Jeff Browne08ae382012-09-07 20:36:36 -0700519 scheduleStatusChangedBroadcastLocked();
520 }
521 }
522 }
523
524 @Override
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700525 public void onDisplayConnected(WifiDisplay display, Surface surface,
526 int width, int height, int flags) {
Jeff Browne08ae382012-09-07 20:36:36 -0700527 synchronized (getSyncRoot()) {
Jeff Brown89d55462012-09-19 11:33:42 -0700528 display = mPersistentDataStore.applyWifiDisplayAlias(display);
Jeff Brown74da1092012-11-07 16:02:13 -0800529 addDisplayDeviceLocked(display, surface, width, height, flags);
Jeff Browne08ae382012-09-07 20:36:36 -0700530
Jeff Brown180bbc72012-09-08 23:15:00 -0700531 if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
532 || mActiveDisplay == null
533 || !mActiveDisplay.equals(display)) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700534 mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
535 mActiveDisplay = display;
Jeff Browne08ae382012-09-07 20:36:36 -0700536 scheduleStatusChangedBroadcastLocked();
537 }
Jeff Browncbad9762012-09-04 21:57:59 -0700538 }
539 }
540
541 @Override
Chong Zhang1f3ecaa2013-05-03 15:55:36 -0700542 public void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo) {
543 synchronized (getSyncRoot()) {
544 mSessionInfo = sessionInfo;
545 scheduleStatusChangedBroadcastLocked();
546 }
547 }
548
549 @Override
Jeff Brown74da1092012-11-07 16:02:13 -0800550 public void onDisplayChanged(WifiDisplay display) {
551 synchronized (getSyncRoot()) {
552 display = mPersistentDataStore.applyWifiDisplayAlias(display);
553 if (mActiveDisplay != null
554 && mActiveDisplay.hasSameAddress(display)
555 && !mActiveDisplay.equals(display)) {
556 mActiveDisplay = display;
557 renameDisplayDeviceLocked(display.getFriendlyDisplayName());
558 scheduleStatusChangedBroadcastLocked();
559 }
560 }
561 }
562
563 @Override
Jeff Browncbad9762012-09-04 21:57:59 -0700564 public void onDisplayDisconnected() {
565 // Stop listening.
566 synchronized (getSyncRoot()) {
Jeff Brown74da1092012-11-07 16:02:13 -0800567 removeDisplayDeviceLocked();
Jeff Browne08ae382012-09-07 20:36:36 -0700568
Jeff Brown180bbc72012-09-08 23:15:00 -0700569 if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
570 || mActiveDisplay != null) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700571 mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
572 mActiveDisplay = null;
Jeff Browne08ae382012-09-07 20:36:36 -0700573 scheduleStatusChangedBroadcastLocked();
574 }
Jeff Browncbad9762012-09-04 21:57:59 -0700575 }
576 }
577 };
578
579 private final class WifiDisplayDevice extends DisplayDevice {
Jeff Brownee4f0292012-10-15 15:31:59 -0700580 private String mName;
Jeff Browncbad9762012-09-04 21:57:59 -0700581 private final int mWidth;
582 private final int mHeight;
583 private final float mRefreshRate;
584 private final int mFlags;
Jeff Brown92130f62012-10-24 21:28:33 -0700585 private final String mAddress;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700586 private final Display.Mode mMode;
Jeff Browncbad9762012-09-04 21:57:59 -0700587
588 private Surface mSurface;
589 private DisplayDeviceInfo mInfo;
590
591 public WifiDisplayDevice(IBinder displayToken, String name,
Jeff Brown92130f62012-10-24 21:28:33 -0700592 int width, int height, float refreshRate, int flags, String address,
Jeff Browncbad9762012-09-04 21:57:59 -0700593 Surface surface) {
Wale Ogunwale361ca212014-11-20 11:42:38 -0800594 super(WifiDisplayAdapter.this, displayToken, DISPLAY_NAME_PREFIX + address);
Jeff Browncbad9762012-09-04 21:57:59 -0700595 mName = name;
596 mWidth = width;
597 mHeight = height;
598 mRefreshRate = refreshRate;
599 mFlags = flags;
Jeff Brown92130f62012-10-24 21:28:33 -0700600 mAddress = address;
Jeff Browncbad9762012-09-04 21:57:59 -0700601 mSurface = surface;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700602 mMode = createMode(width, height, refreshRate);
Jeff Browncbad9762012-09-04 21:57:59 -0700603 }
604
Michael Wright1c9977b2016-07-12 13:30:10 -0700605 @Override
606 public boolean hasStableUniqueId() {
607 return true;
608 }
609
Jesse Hall6a6bc212013-08-08 12:15:03 -0700610 public void destroyLocked() {
611 if (mSurface != null) {
612 mSurface.release();
613 mSurface = null;
614 }
615 SurfaceControl.destroyDisplay(getDisplayTokenLocked());
Jeff Browncbad9762012-09-04 21:57:59 -0700616 }
617
Jeff Brownee4f0292012-10-15 15:31:59 -0700618 public void setNameLocked(String name) {
619 mName = name;
620 mInfo = null;
621 }
622
Jeff Browncbad9762012-09-04 21:57:59 -0700623 @Override
624 public void performTraversalInTransactionLocked() {
Jesse Hall6a6bc212013-08-08 12:15:03 -0700625 if (mSurface != null) {
626 setSurfaceInTransactionLocked(mSurface);
627 }
Jeff Browncbad9762012-09-04 21:57:59 -0700628 }
629
630 @Override
631 public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
632 if (mInfo == null) {
633 mInfo = new DisplayDeviceInfo();
634 mInfo.name = mName;
Wale Ogunwale361ca212014-11-20 11:42:38 -0800635 mInfo.uniqueId = getUniqueId();
Jeff Browncbad9762012-09-04 21:57:59 -0700636 mInfo.width = mWidth;
637 mInfo.height = mHeight;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700638 mInfo.modeId = mMode.getModeId();
639 mInfo.defaultModeId = mMode.getModeId();
640 mInfo.supportedModes = new Display.Mode[] { mMode };
Andy McFaddene8b1aeb2014-06-13 14:05:40 -0700641 mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame
Jeff Browncbad9762012-09-04 21:57:59 -0700642 mInfo.flags = mFlags;
Jeff Brown92130f62012-10-24 21:28:33 -0700643 mInfo.type = Display.TYPE_WIFI;
644 mInfo.address = mAddress;
Jeff Brownd728bf52012-09-08 18:05:28 -0700645 mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
Jeff Browncbad9762012-09-04 21:57:59 -0700646 mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
647 }
648 return mInfo;
649 }
650 }
Jeff Browna7f9c962012-10-17 15:15:12 -0700651
652 private final class WifiDisplayHandler extends Handler {
653 public WifiDisplayHandler(Looper looper) {
654 super(looper, null, true /*async*/);
655 }
656
657 @Override
658 public void handleMessage(Message msg) {
659 switch (msg.what) {
660 case MSG_SEND_STATUS_CHANGE_BROADCAST:
661 handleSendStatusChangeBroadcast();
662 break;
Jeff Browna7f9c962012-10-17 15:15:12 -0700663 }
664 }
665 }
Jeff Browncbad9762012-09-04 21:57:59 -0700666}