blob: 57323170b327ab2ed519d96919d3996859eb5f73 [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
Jeff Browna7f9c962012-10-17 15:15:12 -070019import android.content.BroadcastReceiver;
Jeff Browncbad9762012-09-04 21:57:59 -070020import android.content.Context;
Jeff Browne08ae382012-09-07 20:36:36 -070021import android.content.Intent;
Jeff Browna7f9c962012-10-17 15:15:12 -070022import android.content.IntentFilter;
Tomasz Wasilczyk3f1588b2019-06-27 11:49:44 -070023import android.content.pm.PackageManager;
Jeff Browne08ae382012-09-07 20:36:36 -070024import android.hardware.display.DisplayManager;
25import android.hardware.display.WifiDisplay;
Chong Zhang1f3ecaa2013-05-03 15:55:36 -070026import android.hardware.display.WifiDisplaySessionInfo;
Jeff Browne08ae382012-09-07 20:36:36 -070027import android.hardware.display.WifiDisplayStatus;
Jeff Browncbad9762012-09-04 21:57:59 -070028import android.media.RemoteDisplay;
29import android.os.Handler;
30import android.os.IBinder;
Jeff Browna7f9c962012-10-17 15:15:12 -070031import android.os.Looper;
32import android.os.Message;
33import android.os.UserHandle;
Jeff Brownbc335452012-09-26 18:34:47 -070034import android.util.Slog;
Jeff Brown92130f62012-10-24 21:28:33 -070035import android.view.Display;
Dominik Laskowskidb845962019-01-27 21:20:00 -080036import android.view.DisplayAddress;
Jeff Browncbad9762012-09-04 21:57:59 -070037import android.view.Surface;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080038import android.view.SurfaceControl;
Jeff Browncbad9762012-09-04 21:57:59 -070039
Dominik Laskowskidb845962019-01-27 21:20:00 -080040import com.android.internal.util.DumpUtils;
41import com.android.internal.util.IndentingPrintWriter;
42
Jeff Browncbad9762012-09-04 21:57:59 -070043import java.io.PrintWriter;
Narayan Kamath607223f2018-02-19 14:09:02 +000044import java.util.ArrayList;
Jeff Browne08ae382012-09-07 20:36:36 -070045import java.util.Arrays;
Chong Zhangab87a632013-06-11 10:25:49 -070046import java.util.List;
Narayan Kamath607223f2018-02-19 14:09:02 +000047import java.util.Objects;
Jeff Brown74da1092012-11-07 16:02:13 -080048
Jeff Browncbad9762012-09-04 21:57:59 -070049/**
50 * Connects to Wifi displays that implement the Miracast protocol.
51 * <p>
52 * The Wifi display protocol relies on Wifi direct for discovering and pairing
53 * with the display. Once connected, the Media Server opens an RTSP socket and accepts
54 * a connection from the display. After session negotiation, the Media Server
55 * streams encoded buffers to the display.
56 * </p><p>
57 * This class is responsible for connecting to Wifi displays and mediating
58 * the interactions between Media Server, Surface Flinger and the Display Manager Service.
59 * </p><p>
60 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
61 * </p>
62 */
63final class WifiDisplayAdapter extends DisplayAdapter {
64 private static final String TAG = "WifiDisplayAdapter";
65
Jeff Brown2444ae72012-10-11 14:30:21 -070066 private static final boolean DEBUG = false;
67
Jeff Browna7f9c962012-10-17 15:15:12 -070068 private static final int MSG_SEND_STATUS_CHANGE_BROADCAST = 1;
Jeff Browna7f9c962012-10-17 15:15:12 -070069
70 private static final String ACTION_DISCONNECT = "android.server.display.wfd.DISCONNECT";
71
Wale Ogunwale361ca212014-11-20 11:42:38 -080072 // Unique id prefix for wifi displays
73 private static final String DISPLAY_NAME_PREFIX = "wifi:";
74
Jeff Browna7f9c962012-10-17 15:15:12 -070075 private final WifiDisplayHandler mHandler;
Jeff Brown77aebfd2012-10-01 21:07:03 -070076 private final PersistentDataStore mPersistentDataStore;
77 private final boolean mSupportsProtectedBuffers;
Jeff Brown89d55462012-09-19 11:33:42 -070078
Jeff Browncbad9762012-09-04 21:57:59 -070079 private WifiDisplayController mDisplayController;
Jeff Brownf8f0edd2012-09-11 17:05:11 -070080 private WifiDisplayDevice mDisplayDevice;
Jeff Browncbad9762012-09-04 21:57:59 -070081
Jeff Browne08ae382012-09-07 20:36:36 -070082 private WifiDisplayStatus mCurrentStatus;
Jeff Brown89d55462012-09-19 11:33:42 -070083 private int mFeatureState;
Jeff Brown180bbc72012-09-08 23:15:00 -070084 private int mScanState;
85 private int mActiveDisplayState;
86 private WifiDisplay mActiveDisplay;
Chong Zhangab87a632013-06-11 10:25:49 -070087 private WifiDisplay[] mDisplays = WifiDisplay.EMPTY_ARRAY;
Jeff Brown89d55462012-09-19 11:33:42 -070088 private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
89 private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
Chong Zhang1f3ecaa2013-05-03 15:55:36 -070090 private WifiDisplaySessionInfo mSessionInfo;
Jeff Browne08ae382012-09-07 20:36:36 -070091
92 private boolean mPendingStatusChangeBroadcast;
93
Jeff Brown66692502012-10-18 16:13:44 -070094 // Called with SyncRoot lock held.
Jeff Browncbad9762012-09-04 21:57:59 -070095 public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Jeff Brown89d55462012-09-19 11:33:42 -070096 Context context, Handler handler, Listener listener,
97 PersistentDataStore persistentDataStore) {
Jeff Browncbad9762012-09-04 21:57:59 -070098 super(syncRoot, context, handler, listener, TAG);
Tomasz Wasilczyk3f1588b2019-06-27 11:49:44 -070099
100 if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) {
101 throw new RuntimeException("WiFi display was requested, "
102 + "but there is no WiFi Direct feature");
103 }
104
Jeff Browna7f9c962012-10-17 15:15:12 -0700105 mHandler = new WifiDisplayHandler(handler.getLooper());
Jeff Brown89d55462012-09-19 11:33:42 -0700106 mPersistentDataStore = persistentDataStore;
Jeff Brown77aebfd2012-10-01 21:07:03 -0700107 mSupportsProtectedBuffers = context.getResources().getBoolean(
108 com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers);
Jeff Browncbad9762012-09-04 21:57:59 -0700109 }
110
111 @Override
112 public void dumpLocked(PrintWriter pw) {
113 super.dumpLocked(pw);
114
Jeff Browne08ae382012-09-07 20:36:36 -0700115 pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
Jeff Brown89d55462012-09-19 11:33:42 -0700116 pw.println("mFeatureState=" + mFeatureState);
Jeff Brown180bbc72012-09-08 23:15:00 -0700117 pw.println("mScanState=" + mScanState);
118 pw.println("mActiveDisplayState=" + mActiveDisplayState);
119 pw.println("mActiveDisplay=" + mActiveDisplay);
Chong Zhangab87a632013-06-11 10:25:49 -0700120 pw.println("mDisplays=" + Arrays.toString(mDisplays));
Jeff Brown89d55462012-09-19 11:33:42 -0700121 pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
122 pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
Jeff Browne08ae382012-09-07 20:36:36 -0700123 pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
Jeff Brown77aebfd2012-10-01 21:07:03 -0700124 pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
Andy McFaddene8b1aeb2014-06-13 14:05:40 -0700125
Jeff Browncbad9762012-09-04 21:57:59 -0700126 // Try to dump the controller state.
127 if (mDisplayController == null) {
128 pw.println("mDisplayController=null");
129 } else {
130 pw.println("mDisplayController:");
131 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
132 ipw.increaseIndent();
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800133 DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, "", 200);
Jeff Browncbad9762012-09-04 21:57:59 -0700134 }
135 }
136
137 @Override
138 public void registerLocked() {
139 super.registerLocked();
140
Jeff Brown89d55462012-09-19 11:33:42 -0700141 updateRememberedDisplaysLocked();
142
Jeff Browncbad9762012-09-04 21:57:59 -0700143 getHandler().post(new Runnable() {
144 @Override
145 public void run() {
146 mDisplayController = new WifiDisplayController(
147 getContext(), getHandler(), mWifiDisplayListener);
Jeff Brown66692502012-10-18 16:13:44 -0700148
149 getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
150 new IntentFilter(ACTION_DISCONNECT), null, mHandler);
Jeff Browncbad9762012-09-04 21:57:59 -0700151 }
152 });
153 }
154
Jeff Brownce468a32013-11-21 16:42:03 -0800155 public void requestStartScanLocked() {
Jeff Brown2444ae72012-10-11 14:30:21 -0700156 if (DEBUG) {
Jeff Brownce468a32013-11-21 16:42:03 -0800157 Slog.d(TAG, "requestStartScanLocked");
Jeff Brown2444ae72012-10-11 14:30:21 -0700158 }
159
Jeff Browne08ae382012-09-07 20:36:36 -0700160 getHandler().post(new Runnable() {
161 @Override
162 public void run() {
163 if (mDisplayController != null) {
Jeff Brownce468a32013-11-21 16:42:03 -0800164 mDisplayController.requestStartScan();
165 }
166 }
167 });
168 }
169
170 public void requestStopScanLocked() {
171 if (DEBUG) {
172 Slog.d(TAG, "requestStopScanLocked");
173 }
174
175 getHandler().post(new Runnable() {
176 @Override
177 public void run() {
178 if (mDisplayController != null) {
179 mDisplayController.requestStopScan();
Jeff Browne08ae382012-09-07 20:36:36 -0700180 }
181 }
182 });
Jeff Browncbad9762012-09-04 21:57:59 -0700183 }
184
Jeff Brownaf574182013-11-14 18:16:08 -0800185 public void requestConnectLocked(final String address) {
Jeff Brown2444ae72012-10-11 14:30:21 -0700186 if (DEBUG) {
Jeff Brownaf574182013-11-14 18:16:08 -0800187 Slog.d(TAG, "requestConnectLocked: address=" + address);
Jeff Brownbc335452012-09-26 18:34:47 -0700188 }
189
Jeff Browne08ae382012-09-07 20:36:36 -0700190 getHandler().post(new Runnable() {
191 @Override
192 public void run() {
193 if (mDisplayController != null) {
194 mDisplayController.requestConnect(address);
195 }
196 }
197 });
198 }
199
Chong Zhang1f3ecaa2013-05-03 15:55:36 -0700200 public void requestPauseLocked() {
201 if (DEBUG) {
202 Slog.d(TAG, "requestPauseLocked");
203 }
204
205 getHandler().post(new Runnable() {
206 @Override
207 public void run() {
208 if (mDisplayController != null) {
209 mDisplayController.requestPause();
210 }
211 }
212 });
213 }
214
215 public void requestResumeLocked() {
216 if (DEBUG) {
217 Slog.d(TAG, "requestResumeLocked");
218 }
219
220 getHandler().post(new Runnable() {
221 @Override
222 public void run() {
223 if (mDisplayController != null) {
224 mDisplayController.requestResume();
225 }
226 }
227 });
228 }
229
Jeff Browne08ae382012-09-07 20:36:36 -0700230 public void requestDisconnectLocked() {
Jeff Brown2444ae72012-10-11 14:30:21 -0700231 if (DEBUG) {
232 Slog.d(TAG, "requestDisconnectedLocked");
233 }
234
Jeff Browne08ae382012-09-07 20:36:36 -0700235 getHandler().post(new Runnable() {
236 @Override
237 public void run() {
238 if (mDisplayController != null) {
239 mDisplayController.requestDisconnect();
240 }
241 }
242 });
243 }
244
Jeff Brown89d55462012-09-19 11:33:42 -0700245 public void requestRenameLocked(String address, String alias) {
Jeff Brown2444ae72012-10-11 14:30:21 -0700246 if (DEBUG) {
247 Slog.d(TAG, "requestRenameLocked: address=" + address + ", alias=" + alias);
248 }
249
Jeff Brown89d55462012-09-19 11:33:42 -0700250 if (alias != null) {
251 alias = alias.trim();
Jeff Brown2444ae72012-10-11 14:30:21 -0700252 if (alias.isEmpty() || alias.equals(address)) {
Jeff Brown89d55462012-09-19 11:33:42 -0700253 alias = null;
254 }
255 }
256
Jeff Brown74da1092012-11-07 16:02:13 -0800257 WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address);
Narayan Kamath607223f2018-02-19 14:09:02 +0000258 if (display != null && !Objects.equals(display.getDeviceAlias(), alias)) {
Chong Zhangab87a632013-06-11 10:25:49 -0700259 display = new WifiDisplay(address, display.getDeviceName(), alias,
260 false, false, false);
Jeff Brown74da1092012-11-07 16:02:13 -0800261 if (mPersistentDataStore.rememberWifiDisplay(display)) {
262 mPersistentDataStore.saveIfNeeded();
263 updateRememberedDisplaysLocked();
264 scheduleStatusChangedBroadcastLocked();
265 }
Jeff Brown89d55462012-09-19 11:33:42 -0700266 }
Jeff Brownee4f0292012-10-15 15:31:59 -0700267
Jeff Brown74da1092012-11-07 16:02:13 -0800268 if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
269 renameDisplayDeviceLocked(mActiveDisplay.getFriendlyDisplayName());
Jeff Brownee4f0292012-10-15 15:31:59 -0700270 }
Jeff Brown89d55462012-09-19 11:33:42 -0700271 }
272
273 public void requestForgetLocked(String address) {
Jeff Brown2444ae72012-10-11 14:30:21 -0700274 if (DEBUG) {
275 Slog.d(TAG, "requestForgetLocked: address=" + address);
276 }
277
Jeff Brown89d55462012-09-19 11:33:42 -0700278 if (mPersistentDataStore.forgetWifiDisplay(address)) {
279 mPersistentDataStore.saveIfNeeded();
280 updateRememberedDisplaysLocked();
281 scheduleStatusChangedBroadcastLocked();
282 }
283
284 if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
285 requestDisconnectLocked();
286 }
287 }
288
Jeff Browne08ae382012-09-07 20:36:36 -0700289 public WifiDisplayStatus getWifiDisplayStatusLocked() {
290 if (mCurrentStatus == null) {
Jeff Brown89d55462012-09-19 11:33:42 -0700291 mCurrentStatus = new WifiDisplayStatus(
292 mFeatureState, mScanState, mActiveDisplayState,
Chong Zhang1f3ecaa2013-05-03 15:55:36 -0700293 mActiveDisplay, mDisplays, mSessionInfo);
Jeff Browne08ae382012-09-07 20:36:36 -0700294 }
Jeff Brown2444ae72012-10-11 14:30:21 -0700295
296 if (DEBUG) {
297 Slog.d(TAG, "getWifiDisplayStatusLocked: result=" + mCurrentStatus);
298 }
Jeff Browne08ae382012-09-07 20:36:36 -0700299 return mCurrentStatus;
300 }
301
Chong Zhangab87a632013-06-11 10:25:49 -0700302 private void updateDisplaysLocked() {
303 List<WifiDisplay> displays = new ArrayList<WifiDisplay>(
304 mAvailableDisplays.length + mRememberedDisplays.length);
305 boolean[] remembered = new boolean[mAvailableDisplays.length];
306 for (WifiDisplay d : mRememberedDisplays) {
307 boolean available = false;
308 for (int i = 0; i < mAvailableDisplays.length; i++) {
309 if (d.equals(mAvailableDisplays[i])) {
310 remembered[i] = available = true;
311 break;
312 }
313 }
314 if (!available) {
315 displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
316 d.getDeviceAlias(), false, false, true));
317 }
318 }
319 for (int i = 0; i < mAvailableDisplays.length; i++) {
320 WifiDisplay d = mAvailableDisplays[i];
321 displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
322 d.getDeviceAlias(), true, d.canConnect(), remembered[i]));
323 }
324 mDisplays = displays.toArray(WifiDisplay.EMPTY_ARRAY);
325 }
326
Jeff Brown89d55462012-09-19 11:33:42 -0700327 private void updateRememberedDisplaysLocked() {
328 mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
329 mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
330 mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
Chong Zhangab87a632013-06-11 10:25:49 -0700331 updateDisplaysLocked();
Jeff Brown89d55462012-09-19 11:33:42 -0700332 }
333
Jeff Brown74da1092012-11-07 16:02:13 -0800334 private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() {
335 // It may happen that a display name has changed since it was remembered.
336 // Consult the list of available displays and update the name if needed.
337 // We don't do anything special for the active display here. The display
338 // controller will send a separate event when it needs to be updates.
339 boolean changed = false;
340 for (int i = 0; i < mRememberedDisplays.length; i++) {
341 WifiDisplay rememberedDisplay = mRememberedDisplays[i];
342 WifiDisplay availableDisplay = findAvailableDisplayLocked(
343 rememberedDisplay.getDeviceAddress());
344 if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) {
345 if (DEBUG) {
346 Slog.d(TAG, "fixRememberedDisplayNamesFromAvailableDisplaysLocked: "
347 + "updating remembered display to " + availableDisplay);
348 }
349 mRememberedDisplays[i] = availableDisplay;
350 changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay);
351 }
352 }
353 if (changed) {
354 mPersistentDataStore.saveIfNeeded();
355 }
356 }
357
358 private WifiDisplay findAvailableDisplayLocked(String address) {
359 for (WifiDisplay display : mAvailableDisplays) {
360 if (display.getDeviceAddress().equals(address)) {
361 return display;
362 }
363 }
364 return null;
365 }
366
367 private void addDisplayDeviceLocked(WifiDisplay display,
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700368 Surface surface, int width, int height, int flags) {
Jeff Brown74da1092012-11-07 16:02:13 -0800369 removeDisplayDeviceLocked();
Jeff Browne08ae382012-09-07 20:36:36 -0700370
Jeff Brown89d55462012-09-19 11:33:42 -0700371 if (mPersistentDataStore.rememberWifiDisplay(display)) {
372 mPersistentDataStore.saveIfNeeded();
373 updateRememberedDisplaysLocked();
374 scheduleStatusChangedBroadcastLocked();
375 }
376
Jeff Brownf0681b32012-10-23 17:35:57 -0700377 boolean secure = (flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0;
Jeff Brown7d00aff2013-08-02 19:03:49 -0700378 int deviceFlags = DisplayDeviceInfo.FLAG_PRESENTATION;
Jeff Brownf0681b32012-10-23 17:35:57 -0700379 if (secure) {
Jeff Brown77aebfd2012-10-01 21:07:03 -0700380 deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
Jeff Brownf0681b32012-10-23 17:35:57 -0700381 if (mSupportsProtectedBuffers) {
382 deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
383 }
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700384 }
385
386 float refreshRate = 60.0f; // TODO: get this for real
387
Jeff Brown89d55462012-09-19 11:33:42 -0700388 String name = display.getFriendlyDisplayName();
Jeff Brown92130f62012-10-24 21:28:33 -0700389 String address = display.getDeviceAddress();
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800390 IBinder displayToken = SurfaceControl.createDisplay(name, secure);
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700391 mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
Jeff Brown92130f62012-10-24 21:28:33 -0700392 refreshRate, deviceFlags, address, surface);
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700393 sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
Jeff Browne08ae382012-09-07 20:36:36 -0700394 }
395
Jeff Brown74da1092012-11-07 16:02:13 -0800396 private void removeDisplayDeviceLocked() {
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700397 if (mDisplayDevice != null) {
Jesse Hall6a6bc212013-08-08 12:15:03 -0700398 mDisplayDevice.destroyLocked();
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700399 sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
400 mDisplayDevice = null;
Jeff Browncbad9762012-09-04 21:57:59 -0700401 }
402 }
403
Jeff Brown74da1092012-11-07 16:02:13 -0800404 private void renameDisplayDeviceLocked(String name) {
405 if (mDisplayDevice != null && !mDisplayDevice.getNameLocked().equals(name)) {
406 mDisplayDevice.setNameLocked(name);
407 sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
408 }
409 }
410
Jeff Browne08ae382012-09-07 20:36:36 -0700411 private void scheduleStatusChangedBroadcastLocked() {
Jeff Brown89d55462012-09-19 11:33:42 -0700412 mCurrentStatus = null;
Jeff Browne08ae382012-09-07 20:36:36 -0700413 if (!mPendingStatusChangeBroadcast) {
414 mPendingStatusChangeBroadcast = true;
Jeff Browna7f9c962012-10-17 15:15:12 -0700415 mHandler.sendEmptyMessage(MSG_SEND_STATUS_CHANGE_BROADCAST);
Jeff Browne08ae382012-09-07 20:36:36 -0700416 }
417 }
418
Jeff Browna7f9c962012-10-17 15:15:12 -0700419 // Runs on the handler.
420 private void handleSendStatusChangeBroadcast() {
421 final Intent intent;
422 synchronized (getSyncRoot()) {
423 if (!mPendingStatusChangeBroadcast) {
424 return;
Jeff Browne08ae382012-09-07 20:36:36 -0700425 }
426
Jeff Browna7f9c962012-10-17 15:15:12 -0700427 mPendingStatusChangeBroadcast = false;
428 intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
429 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
430 intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
431 getWifiDisplayStatusLocked());
432 }
433
434 // Send protected broadcast about wifi display status to registered receivers.
435 getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
436 }
437
Jeff Browna7f9c962012-10-17 15:15:12 -0700438 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
439 @Override
440 public void onReceive(Context context, Intent intent) {
441 if (intent.getAction().equals(ACTION_DISCONNECT)) {
442 synchronized (getSyncRoot()) {
443 requestDisconnectLocked();
444 }
445 }
Jeff Browne08ae382012-09-07 20:36:36 -0700446 }
447 };
448
Jeff Browncbad9762012-09-04 21:57:59 -0700449 private final WifiDisplayController.Listener mWifiDisplayListener =
450 new WifiDisplayController.Listener() {
451 @Override
Jeff Brown89d55462012-09-19 11:33:42 -0700452 public void onFeatureStateChanged(int featureState) {
Jeff Browncbad9762012-09-04 21:57:59 -0700453 synchronized (getSyncRoot()) {
Jeff Brown89d55462012-09-19 11:33:42 -0700454 if (mFeatureState != featureState) {
455 mFeatureState = featureState;
Jeff Browne08ae382012-09-07 20:36:36 -0700456 scheduleStatusChangedBroadcastLocked();
457 }
458 }
459 }
460
461 @Override
462 public void onScanStarted() {
463 synchronized (getSyncRoot()) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700464 if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700465 mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
Jeff Browne08ae382012-09-07 20:36:36 -0700466 scheduleStatusChangedBroadcastLocked();
467 }
468 }
469 }
470
Jeff Brown2444ae72012-10-11 14:30:21 -0700471 @Override
Jeff Brownce468a32013-11-21 16:42:03 -0800472 public void onScanResults(WifiDisplay[] availableDisplays) {
Jeff Browne08ae382012-09-07 20:36:36 -0700473 synchronized (getSyncRoot()) {
Jeff Brown89d55462012-09-19 11:33:42 -0700474 availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
475 availableDisplays);
476
Chong Zhangab87a632013-06-11 10:25:49 -0700477 boolean changed = !Arrays.equals(mAvailableDisplays, availableDisplays);
Jeff Brownce468a32013-11-21 16:42:03 -0800478
479 // Check whether any of the available displays changed canConnect status.
Chong Zhangab87a632013-06-11 10:25:49 -0700480 for (int i = 0; !changed && i<availableDisplays.length; i++) {
481 changed = availableDisplays[i].canConnect()
482 != mAvailableDisplays[i].canConnect();
483 }
484
Jeff Brownce468a32013-11-21 16:42:03 -0800485 if (changed) {
Jeff Brown89d55462012-09-19 11:33:42 -0700486 mAvailableDisplays = availableDisplays;
Jeff Brown74da1092012-11-07 16:02:13 -0800487 fixRememberedDisplayNamesFromAvailableDisplaysLocked();
Chong Zhangab87a632013-06-11 10:25:49 -0700488 updateDisplaysLocked();
Jeff Browne08ae382012-09-07 20:36:36 -0700489 scheduleStatusChangedBroadcastLocked();
490 }
491 }
492 }
493
494 @Override
Jeff Brownce468a32013-11-21 16:42:03 -0800495 public void onScanFinished() {
496 synchronized (getSyncRoot()) {
497 if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING) {
498 mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
499 scheduleStatusChangedBroadcastLocked();
500 }
501 }
502 }
503
504 @Override
Jeff Browne08ae382012-09-07 20:36:36 -0700505 public void onDisplayConnecting(WifiDisplay display) {
506 synchronized (getSyncRoot()) {
Jeff Brown89d55462012-09-19 11:33:42 -0700507 display = mPersistentDataStore.applyWifiDisplayAlias(display);
508
Jeff Brown180bbc72012-09-08 23:15:00 -0700509 if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
510 || mActiveDisplay == null
511 || !mActiveDisplay.equals(display)) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700512 mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
513 mActiveDisplay = display;
Jeff Browne08ae382012-09-07 20:36:36 -0700514 scheduleStatusChangedBroadcastLocked();
515 }
516 }
517 }
518
519 @Override
520 public void onDisplayConnectionFailed() {
521 synchronized (getSyncRoot()) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700522 if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
523 || mActiveDisplay != null) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700524 mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
525 mActiveDisplay = null;
Jeff Browne08ae382012-09-07 20:36:36 -0700526 scheduleStatusChangedBroadcastLocked();
527 }
528 }
529 }
530
531 @Override
Jeff Brownf8f0edd2012-09-11 17:05:11 -0700532 public void onDisplayConnected(WifiDisplay display, Surface surface,
533 int width, int height, int flags) {
Jeff Browne08ae382012-09-07 20:36:36 -0700534 synchronized (getSyncRoot()) {
Jeff Brown89d55462012-09-19 11:33:42 -0700535 display = mPersistentDataStore.applyWifiDisplayAlias(display);
Jeff Brown74da1092012-11-07 16:02:13 -0800536 addDisplayDeviceLocked(display, surface, width, height, flags);
Jeff Browne08ae382012-09-07 20:36:36 -0700537
Jeff Brown180bbc72012-09-08 23:15:00 -0700538 if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
539 || mActiveDisplay == null
540 || !mActiveDisplay.equals(display)) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700541 mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
542 mActiveDisplay = display;
Jeff Browne08ae382012-09-07 20:36:36 -0700543 scheduleStatusChangedBroadcastLocked();
544 }
Jeff Browncbad9762012-09-04 21:57:59 -0700545 }
546 }
547
548 @Override
Chong Zhang1f3ecaa2013-05-03 15:55:36 -0700549 public void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo) {
550 synchronized (getSyncRoot()) {
551 mSessionInfo = sessionInfo;
552 scheduleStatusChangedBroadcastLocked();
553 }
554 }
555
556 @Override
Jeff Brown74da1092012-11-07 16:02:13 -0800557 public void onDisplayChanged(WifiDisplay display) {
558 synchronized (getSyncRoot()) {
559 display = mPersistentDataStore.applyWifiDisplayAlias(display);
560 if (mActiveDisplay != null
561 && mActiveDisplay.hasSameAddress(display)
562 && !mActiveDisplay.equals(display)) {
563 mActiveDisplay = display;
564 renameDisplayDeviceLocked(display.getFriendlyDisplayName());
565 scheduleStatusChangedBroadcastLocked();
566 }
567 }
568 }
569
570 @Override
Jeff Browncbad9762012-09-04 21:57:59 -0700571 public void onDisplayDisconnected() {
572 // Stop listening.
573 synchronized (getSyncRoot()) {
Jeff Brown74da1092012-11-07 16:02:13 -0800574 removeDisplayDeviceLocked();
Jeff Browne08ae382012-09-07 20:36:36 -0700575
Jeff Brown180bbc72012-09-08 23:15:00 -0700576 if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
577 || mActiveDisplay != null) {
Jeff Brown180bbc72012-09-08 23:15:00 -0700578 mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
579 mActiveDisplay = null;
Jeff Browne08ae382012-09-07 20:36:36 -0700580 scheduleStatusChangedBroadcastLocked();
581 }
Jeff Browncbad9762012-09-04 21:57:59 -0700582 }
583 }
584 };
585
586 private final class WifiDisplayDevice extends DisplayDevice {
Jeff Brownee4f0292012-10-15 15:31:59 -0700587 private String mName;
Jeff Browncbad9762012-09-04 21:57:59 -0700588 private final int mWidth;
589 private final int mHeight;
590 private final float mRefreshRate;
591 private final int mFlags;
Dominik Laskowskidb845962019-01-27 21:20:00 -0800592 private final DisplayAddress mAddress;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700593 private final Display.Mode mMode;
Jeff Browncbad9762012-09-04 21:57:59 -0700594
595 private Surface mSurface;
596 private DisplayDeviceInfo mInfo;
597
598 public WifiDisplayDevice(IBinder displayToken, String name,
Jeff Brown92130f62012-10-24 21:28:33 -0700599 int width, int height, float refreshRate, int flags, String address,
Jeff Browncbad9762012-09-04 21:57:59 -0700600 Surface surface) {
Wale Ogunwale361ca212014-11-20 11:42:38 -0800601 super(WifiDisplayAdapter.this, displayToken, DISPLAY_NAME_PREFIX + address);
Jeff Browncbad9762012-09-04 21:57:59 -0700602 mName = name;
603 mWidth = width;
604 mHeight = height;
605 mRefreshRate = refreshRate;
606 mFlags = flags;
Dominik Laskowskidb845962019-01-27 21:20:00 -0800607 mAddress = DisplayAddress.fromMacAddress(address);
Jeff Browncbad9762012-09-04 21:57:59 -0700608 mSurface = surface;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700609 mMode = createMode(width, height, refreshRate);
Jeff Browncbad9762012-09-04 21:57:59 -0700610 }
611
Michael Wright1c9977b2016-07-12 13:30:10 -0700612 @Override
613 public boolean hasStableUniqueId() {
614 return true;
615 }
616
Jesse Hall6a6bc212013-08-08 12:15:03 -0700617 public void destroyLocked() {
618 if (mSurface != null) {
619 mSurface.release();
620 mSurface = null;
621 }
622 SurfaceControl.destroyDisplay(getDisplayTokenLocked());
Jeff Browncbad9762012-09-04 21:57:59 -0700623 }
624
Jeff Brownee4f0292012-10-15 15:31:59 -0700625 public void setNameLocked(String name) {
626 mName = name;
627 mInfo = null;
628 }
629
Jeff Browncbad9762012-09-04 21:57:59 -0700630 @Override
Robert Carrae606b42018-02-15 15:36:23 -0800631 public void performTraversalLocked(SurfaceControl.Transaction t) {
Jesse Hall6a6bc212013-08-08 12:15:03 -0700632 if (mSurface != null) {
Robert Carrae606b42018-02-15 15:36:23 -0800633 setSurfaceLocked(t, mSurface);
Jesse Hall6a6bc212013-08-08 12:15:03 -0700634 }
Jeff Browncbad9762012-09-04 21:57:59 -0700635 }
636
637 @Override
638 public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
639 if (mInfo == null) {
640 mInfo = new DisplayDeviceInfo();
641 mInfo.name = mName;
Wale Ogunwale361ca212014-11-20 11:42:38 -0800642 mInfo.uniqueId = getUniqueId();
Jeff Browncbad9762012-09-04 21:57:59 -0700643 mInfo.width = mWidth;
644 mInfo.height = mHeight;
P.Y. Laligand5c7773d2015-05-04 13:30:58 -0700645 mInfo.modeId = mMode.getModeId();
646 mInfo.defaultModeId = mMode.getModeId();
647 mInfo.supportedModes = new Display.Mode[] { mMode };
Andy McFaddene8b1aeb2014-06-13 14:05:40 -0700648 mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame
Jeff Browncbad9762012-09-04 21:57:59 -0700649 mInfo.flags = mFlags;
Jeff Brown92130f62012-10-24 21:28:33 -0700650 mInfo.type = Display.TYPE_WIFI;
651 mInfo.address = mAddress;
Jeff Brownd728bf52012-09-08 18:05:28 -0700652 mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
Jeff Browncbad9762012-09-04 21:57:59 -0700653 mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
Charles Chenb28fb722020-05-21 17:19:32 +0800654 // The display is trusted since it is created by system.
655 mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
Jeff Browncbad9762012-09-04 21:57:59 -0700656 }
657 return mInfo;
658 }
659 }
Jeff Browna7f9c962012-10-17 15:15:12 -0700660
661 private final class WifiDisplayHandler extends Handler {
662 public WifiDisplayHandler(Looper looper) {
663 super(looper, null, true /*async*/);
664 }
665
666 @Override
667 public void handleMessage(Message msg) {
668 switch (msg.what) {
669 case MSG_SEND_STATUS_CHANGE_BROADCAST:
670 handleSendStatusChangeBroadcast();
671 break;
Jeff Browna7f9c962012-10-17 15:15:12 -0700672 }
673 }
674 }
Jeff Browncbad9762012-09-04 21:57:59 -0700675}