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
19a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport com.android.internal.R;
20cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport com.android.internal.util.DumpUtils;
21cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport com.android.internal.util.IndentingPrintWriter;
22cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
23a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.app.Notification;
24a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.app.NotificationManager;
25a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.app.PendingIntent;
26a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.content.BroadcastReceiver;
27cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.content.Context;
28e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.content.Intent;
29a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.content.IntentFilter;
30a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.content.res.Resources;
31e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.DisplayManager;
32e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.WifiDisplay;
331f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhangimport android.hardware.display.WifiDisplaySessionInfo;
34e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.WifiDisplayStatus;
35cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.media.RemoteDisplay;
36cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.Handler;
37cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.IBinder;
38a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.os.Looper;
39a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.os.Message;
40a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.os.UserHandle;
41a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.provider.Settings;
42bc335457462a12434a9df6955de1dd693cdccac7Jeff Brownimport android.util.Slog;
4392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brownimport android.view.Display;
44cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.view.Surface;
453866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopianimport android.view.SurfaceControl;
46cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
47cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.io.PrintWriter;
48e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport java.util.Arrays;
49ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhangimport java.util.List;
50ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhangimport java.util.ArrayList;
51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
5274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brownimport libcore.util.Objects;
5374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Connects to Wifi displays that implement the Miracast protocol.
56cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p>
57cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The Wifi display protocol relies on Wifi direct for discovering and pairing
58cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * with the display.  Once connected, the Media Server opens an RTSP socket and accepts
59cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * a connection from the display.  After session negotiation, the Media Server
60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * streams encoded buffers to the display.
61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This class is responsible for connecting to Wifi displays and mediating
63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * the interactions between Media Server, Surface Flinger and the Display Manager Service.
64cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
65cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
66cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p>
67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
68cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayAdapter extends DisplayAdapter {
69cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final String TAG = "WifiDisplayAdapter";
70cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
712444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown    private static final boolean DEBUG = false;
722444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
73a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final int MSG_SEND_STATUS_CHANGE_BROADCAST = 1;
74a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final int MSG_UPDATE_NOTIFICATION = 2;
75a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
76a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final String ACTION_DISCONNECT = "android.server.display.wfd.DISCONNECT";
77a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
78a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final WifiDisplayHandler mHandler;
7977aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown    private final PersistentDataStore mPersistentDataStore;
8077aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown    private final boolean mSupportsProtectedBuffers;
81a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final NotificationManager mNotificationManager;
82a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
8366692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    private PendingIntent mSettingsPendingIntent;
8466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    private PendingIntent mDisconnectPendingIntent;
8589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
86cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiDisplayController mDisplayController;
87f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private WifiDisplayDevice mDisplayDevice;
88cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
89e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private WifiDisplayStatus mCurrentStatus;
9089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private int mFeatureState;
91180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mScanState;
92180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mActiveDisplayState;
93180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private WifiDisplay mActiveDisplay;
94ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang    private WifiDisplay[] mDisplays = WifiDisplay.EMPTY_ARRAY;
9589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
9689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
971f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    private WifiDisplaySessionInfo mSessionInfo;
98e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
99e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private boolean mPendingStatusChangeBroadcast;
100a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private boolean mPendingNotificationUpdate;
101e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
10266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    // Called with SyncRoot lock held.
103cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
10489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Context context, Handler handler, Listener listener,
10589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            PersistentDataStore persistentDataStore) {
106cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super(syncRoot, context, handler, listener, TAG);
107a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mHandler = new WifiDisplayHandler(handler.getLooper());
10889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mPersistentDataStore = persistentDataStore;
10977aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        mSupportsProtectedBuffers = context.getResources().getBoolean(
11077aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown                com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers);
111a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mNotificationManager = (NotificationManager)context.getSystemService(
112a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                Context.NOTIFICATION_SERVICE);
113cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
114cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
115cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
116cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void dumpLocked(PrintWriter pw) {
117cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.dumpLocked(pw);
118cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
119e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
12089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mFeatureState=" + mFeatureState);
121180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mScanState=" + mScanState);
122180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplayState=" + mActiveDisplayState);
123180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplay=" + mActiveDisplay);
124ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        pw.println("mDisplays=" + Arrays.toString(mDisplays));
12589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
12689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
127e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
128a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        pw.println("mPendingNotificationUpdate=" + mPendingNotificationUpdate);
12977aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
130ce468a35b388ca46578934706b38dbae94941643Jeff Brown
131cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Try to dump the controller state.
132cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDisplayController == null) {
133cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController=null");
134cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
135cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController:");
136cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
137cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            ipw.increaseIndent();
138cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200);
139cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
140cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
141cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
142cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
143cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void registerLocked() {
144cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.registerLocked();
145cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
14689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateRememberedDisplaysLocked();
14789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
148cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        getHandler().post(new Runnable() {
149cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
150cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void run() {
151cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mDisplayController = new WifiDisplayController(
152cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        getContext(), getHandler(), mWifiDisplayListener);
15366692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
15466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
15566692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        new IntentFilter(ACTION_DISCONNECT), null, mHandler);
156cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
157cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
158cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
159cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
160ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void requestStartScanLocked() {
1612444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
162ce468a35b388ca46578934706b38dbae94941643Jeff Brown            Slog.d(TAG, "requestStartScanLocked");
1632444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
1642444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
165e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
166e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
167e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
168e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
169ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mDisplayController.requestStartScan();
170e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
171e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
172e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
173e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
174e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
175ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void requestStopScanLocked() {
1762444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
177ce468a35b388ca46578934706b38dbae94941643Jeff Brown            Slog.d(TAG, "requestStopScanLocked");
178bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        }
179bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown
180e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
181e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
182e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
183e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
184ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mDisplayController.requestStopScan();
185e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
186e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
187e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
188e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
189e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
190ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void requestConnectLocked(final String address) {
191ce468a35b388ca46578934706b38dbae94941643Jeff Brown        if (DEBUG) {
192ce468a35b388ca46578934706b38dbae94941643Jeff Brown            Slog.d(TAG, "requestConnectLocked: address=" + address);
193bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        }
194ce468a35b388ca46578934706b38dbae94941643Jeff Brown
195ce468a35b388ca46578934706b38dbae94941643Jeff Brown        getHandler().post(new Runnable() {
196ce468a35b388ca46578934706b38dbae94941643Jeff Brown            @Override
197ce468a35b388ca46578934706b38dbae94941643Jeff Brown            public void run() {
198ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (mDisplayController != null) {
199ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mDisplayController.requestConnect(address);
200ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
201ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
202ce468a35b388ca46578934706b38dbae94941643Jeff Brown        });
203bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    }
204bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown
2051f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void requestPauseLocked() {
2061f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (DEBUG) {
2071f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            Slog.d(TAG, "requestPauseLocked");
2081f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
2091f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
2101f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        getHandler().post(new Runnable() {
2111f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            @Override
2121f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            public void run() {
2131f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                if (mDisplayController != null) {
2141f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                    mDisplayController.requestPause();
2151f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                }
2161f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            }
2171f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        });
2181f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang      }
2191f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
2201f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void requestResumeLocked() {
2211f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        if (DEBUG) {
2221f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            Slog.d(TAG, "requestResumeLocked");
2231f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
2241f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
2251f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        getHandler().post(new Runnable() {
2261f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            @Override
2271f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            public void run() {
2281f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                if (mDisplayController != null) {
2291f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                    mDisplayController.requestResume();
2301f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                }
2311f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            }
2321f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        });
2331f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
2341f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
235e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestDisconnectLocked() {
2362444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2372444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestDisconnectedLocked");
2382444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2392444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
240e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
241e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
242e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
243e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
244e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestDisconnect();
245e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
246e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
247e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
248e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
249e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
25089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestRenameLocked(String address, String alias) {
2512444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2522444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestRenameLocked: address=" + address + ", alias=" + alias);
2532444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2542444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
25589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (alias != null) {
25689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            alias = alias.trim();
2572444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            if (alias.isEmpty() || alias.equals(address)) {
25889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                alias = null;
25989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
26089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
26189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
26274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address);
26374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (display != null && !Objects.equal(display.getDeviceAlias(), alias)) {
264ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            display = new WifiDisplay(address, display.getDeviceName(), alias,
265ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    false, false, false);
26674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (mPersistentDataStore.rememberWifiDisplay(display)) {
26774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                mPersistentDataStore.saveIfNeeded();
26874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                updateRememberedDisplaysLocked();
26974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                scheduleStatusChangedBroadcastLocked();
27074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
27189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
272ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown
27374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
27474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            renameDisplayDeviceLocked(mActiveDisplay.getFriendlyDisplayName());
275ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        }
27689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
27789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
27889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestForgetLocked(String address) {
2792444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2802444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestForgetLocked: address=" + address);
2812444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2822444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
28389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.forgetWifiDisplay(address)) {
28489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
28589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
28689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
28789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
28889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
28989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
29089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            requestDisconnectLocked();
29189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
29289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
29389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
294e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatusLocked() {
295e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (mCurrentStatus == null) {
29689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mCurrentStatus = new WifiDisplayStatus(
29789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState, mScanState, mActiveDisplayState,
2981f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                    mActiveDisplay, mDisplays, mSessionInfo);
299e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
3002444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
3012444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
3022444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "getWifiDisplayStatusLocked: result=" + mCurrentStatus);
3032444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
304e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        return mCurrentStatus;
305e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
306cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
307ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang    private void updateDisplaysLocked() {
308ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        List<WifiDisplay> displays = new ArrayList<WifiDisplay>(
309ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                mAvailableDisplays.length + mRememberedDisplays.length);
310ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        boolean[] remembered = new boolean[mAvailableDisplays.length];
311ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        for (WifiDisplay d : mRememberedDisplays) {
312ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            boolean available = false;
313ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            for (int i = 0; i < mAvailableDisplays.length; i++) {
314ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                if (d.equals(mAvailableDisplays[i])) {
315ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    remembered[i] = available = true;
316ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    break;
317ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                }
318ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            }
319ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            if (!available) {
320ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
321ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                        d.getDeviceAlias(), false, false, true));
322ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            }
323ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        }
324ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        for (int i = 0; i < mAvailableDisplays.length; i++) {
325ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            WifiDisplay d = mAvailableDisplays[i];
326ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
327ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    d.getDeviceAlias(), true, d.canConnect(), remembered[i]));
328ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        }
329ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        mDisplays = displays.toArray(WifiDisplay.EMPTY_ARRAY);
330ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang    }
331ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang
33289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateRememberedDisplaysLocked() {
33389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
33489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
33589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
336ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        updateDisplaysLocked();
33789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
33889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
33974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() {
34074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // It may happen that a display name has changed since it was remembered.
34174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // Consult the list of available displays and update the name if needed.
34274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // We don't do anything special for the active display here.  The display
34374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // controller will send a separate event when it needs to be updates.
34474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        boolean changed = false;
34574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        for (int i = 0; i < mRememberedDisplays.length; i++) {
34674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            WifiDisplay rememberedDisplay = mRememberedDisplays[i];
34774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            WifiDisplay availableDisplay = findAvailableDisplayLocked(
34874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    rememberedDisplay.getDeviceAddress());
34974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) {
35074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                if (DEBUG) {
35174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    Slog.d(TAG, "fixRememberedDisplayNamesFromAvailableDisplaysLocked: "
35274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                            + "updating remembered display to " + availableDisplay);
35374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                }
35474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                mRememberedDisplays[i] = availableDisplay;
35574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay);
35674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
35774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
35874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (changed) {
35974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mPersistentDataStore.saveIfNeeded();
36074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
36174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
36274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
36374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private WifiDisplay findAvailableDisplayLocked(String address) {
36474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        for (WifiDisplay display : mAvailableDisplays) {
36574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (display.getDeviceAddress().equals(address)) {
36674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                return display;
36774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
36874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
36974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        return null;
37074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
37174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
37274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void addDisplayDeviceLocked(WifiDisplay display,
373f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Surface surface, int width, int height, int flags) {
37474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        removeDisplayDeviceLocked();
375e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
37689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.rememberWifiDisplay(display)) {
37789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
37889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
37989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
38089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
38189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
382f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown        boolean secure = (flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0;
3837d00affce6e25b22fd8fc135933b3bf6b547a0dcJeff Brown        int deviceFlags = DisplayDeviceInfo.FLAG_PRESENTATION;
384f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown        if (secure) {
38577aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown            deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
386f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown            if (mSupportsProtectedBuffers) {
387f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown                deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
388f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown            }
389f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        }
390f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
391f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        float refreshRate = 60.0f; // TODO: get this for real
392f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
39389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        String name = display.getFriendlyDisplayName();
39492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown        String address = display.getDeviceAddress();
3953866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian        IBinder displayToken = SurfaceControl.createDisplay(name, secure);
396f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
39792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                refreshRate, deviceFlags, address, surface);
398f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
399cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
400cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
40174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void removeDisplayDeviceLocked() {
402f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mDisplayDevice != null) {
4036a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall            mDisplayDevice.destroyLocked();
404f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
405f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mDisplayDevice = null;
406cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
407cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
408cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
40974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void renameDisplayDeviceLocked(String name) {
41074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mDisplayDevice != null && !mDisplayDevice.getNameLocked().equals(name)) {
41174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mDisplayDevice.setNameLocked(name);
41274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
41374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
41474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
41574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
416e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void scheduleStatusChangedBroadcastLocked() {
41789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mCurrentStatus = null;
418e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (!mPendingStatusChangeBroadcast) {
419e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mPendingStatusChangeBroadcast = true;
420a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mHandler.sendEmptyMessage(MSG_SEND_STATUS_CHANGE_BROADCAST);
421e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
422e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
423e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
424a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void scheduleUpdateNotificationLocked() {
425a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        if (!mPendingNotificationUpdate) {
426a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingNotificationUpdate = true;
427a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mHandler.sendEmptyMessage(MSG_UPDATE_NOTIFICATION);
428a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
429a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
430a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
431a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    // Runs on the handler.
432a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void handleSendStatusChangeBroadcast() {
433a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        final Intent intent;
434a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        synchronized (getSyncRoot()) {
435a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (!mPendingStatusChangeBroadcast) {
436a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                return;
437a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
438a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
439a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingStatusChangeBroadcast = false;
440a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
441a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
442a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
443a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    getWifiDisplayStatusLocked());
444a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
445e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
446a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        // Send protected broadcast about wifi display status to registered receivers.
447a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
448a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
449a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
450a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    // Runs on the handler.
451a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void handleUpdateNotification() {
452e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown        final int state;
453e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown        final WifiDisplay display;
454a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        synchronized (getSyncRoot()) {
455a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (!mPendingNotificationUpdate) {
456a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                return;
457e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
458e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
459a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingNotificationUpdate = false;
460e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown            state = mActiveDisplayState;
461e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown            display = mActiveDisplay;
462a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
463a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
46466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown        // Cancel the old notification if there is one.
465a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mNotificationManager.cancelAsUser(null,
466e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                R.string.wifi_display_notification_disconnect, UserHandle.ALL);
467a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
468e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown        if (state == WifiDisplayStatus.DISPLAY_STATE_CONNECTING
469e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                || state == WifiDisplayStatus.DISPLAY_STATE_CONNECTED) {
470a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Context context = getContext();
471a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
47266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            // Initialize pending intents for the notification outside of the lock because
47366692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            // creating a pending intent requires a call into the activity manager.
47466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            if (mSettingsPendingIntent == null) {
47566692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
47666692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
47766692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
47866692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        | Intent.FLAG_ACTIVITY_CLEAR_TOP);
47966692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                mSettingsPendingIntent = PendingIntent.getActivityAsUser(
48066692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        context, 0, settingsIntent, 0, null, UserHandle.CURRENT);
48166692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            }
48266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
48366692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            if (mDisconnectPendingIntent == null) {
48466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                Intent disconnectIntent = new Intent(ACTION_DISCONNECT);
48566692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                mDisconnectPendingIntent = PendingIntent.getBroadcastAsUser(
48666692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        context, 0, disconnectIntent, 0, UserHandle.CURRENT);
48766692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            }
48866692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
48966692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            // Post the notification.
490a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Resources r = context.getResources();
491e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown            Notification notification;
492e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown            if (state == WifiDisplayStatus.DISPLAY_STATE_CONNECTING) {
493e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                notification = new Notification.Builder(context)
494e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setContentTitle(r.getString(
495e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                R.string.wifi_display_notification_connecting_title))
496e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setContentText(r.getString(
497e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                R.string.wifi_display_notification_connecting_message,
498e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                display.getFriendlyDisplayName()))
499e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setContentIntent(mSettingsPendingIntent)
500e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setSmallIcon(R.drawable.ic_notification_cast_connecting)
501e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setOngoing(true)
502e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .addAction(android.R.drawable.ic_menu_close_clear_cancel,
503e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                r.getString(R.string.wifi_display_notification_disconnect),
504e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                mDisconnectPendingIntent)
505e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .build();
506e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown            } else {
507e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                notification = new Notification.Builder(context)
508e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setContentTitle(r.getString(
509e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                R.string.wifi_display_notification_connected_title))
510e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setContentText(r.getString(
511e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                R.string.wifi_display_notification_connected_message,
512e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                display.getFriendlyDisplayName()))
513e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setContentIntent(mSettingsPendingIntent)
514e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setSmallIcon(R.drawable.ic_notification_cast_on)
515e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .setOngoing(true)
516e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .addAction(android.R.drawable.ic_menu_close_clear_cancel,
517e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                r.getString(R.string.wifi_display_notification_disconnect),
518e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                                mDisconnectPendingIntent)
519e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                        .build();
520e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown            }
521a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mNotificationManager.notifyAsUser(null,
522e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                    R.string.wifi_display_notification_disconnect,
523a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    notification, UserHandle.ALL);
524a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
525a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
526a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
527a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
528a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        @Override
529a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public void onReceive(Context context, Intent intent) {
530a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (intent.getAction().equals(ACTION_DISCONNECT)) {
531a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                synchronized (getSyncRoot()) {
532a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    requestDisconnectLocked();
533a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                }
534a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
535e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
536e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    };
537e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
538cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final WifiDisplayController.Listener mWifiDisplayListener =
539cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            new WifiDisplayController.Listener() {
540cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
54189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        public void onFeatureStateChanged(int featureState) {
542e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
54389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                if (mFeatureState != featureState) {
54489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState = featureState;
545e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
546e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
547e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
548e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
549e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
550e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
551e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onScanStarted() {
552e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
553180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
554180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
555e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
556e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
557e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
558e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
559e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
5602444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        @Override
561ce468a35b388ca46578934706b38dbae94941643Jeff Brown        public void onScanResults(WifiDisplay[] availableDisplays) {
562e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
56389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
56489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        availableDisplays);
56589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
566ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                boolean changed = !Arrays.equals(mAvailableDisplays, availableDisplays);
567ce468a35b388ca46578934706b38dbae94941643Jeff Brown
568ce468a35b388ca46578934706b38dbae94941643Jeff Brown                // Check whether any of the available displays changed canConnect status.
569ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                for (int i = 0; !changed && i<availableDisplays.length; i++) {
570ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    changed = availableDisplays[i].canConnect()
571ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                            != mAvailableDisplays[i].canConnect();
572ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                }
573ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang
574ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (changed) {
57589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mAvailableDisplays = availableDisplays;
57674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    fixRememberedDisplayNamesFromAvailableDisplaysLocked();
577ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    updateDisplaysLocked();
578e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
579e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
580e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
581e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
582e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
583e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
584ce468a35b388ca46578934706b38dbae94941643Jeff Brown        public void onScanFinished() {
585ce468a35b388ca46578934706b38dbae94941643Jeff Brown            synchronized (getSyncRoot()) {
586ce468a35b388ca46578934706b38dbae94941643Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING) {
587ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
588ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    scheduleStatusChangedBroadcastLocked();
589ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
590ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
591ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
592ce468a35b388ca46578934706b38dbae94941643Jeff Brown
593ce468a35b388ca46578934706b38dbae94941643Jeff Brown        @Override
594e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnecting(WifiDisplay display) {
595e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
59689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
59789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
598180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
599180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
600180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
601180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
602180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
603e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
604e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                    scheduleUpdateNotificationLocked();
605e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
606e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
607e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
608e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
609e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
610e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnectionFailed() {
611e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
612180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
613180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
614180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
615180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
616e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
617e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                    scheduleUpdateNotificationLocked();
618e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
619e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
620e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
621e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
622e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
623f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        public void onDisplayConnected(WifiDisplay display, Surface surface,
624f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                int width, int height, int flags) {
625cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
62689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
62774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                addDisplayDeviceLocked(display, surface, width, height, flags);
628e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
629180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
630180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
631180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
632180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
633180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
634e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
635e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                    scheduleUpdateNotificationLocked();
636e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
637cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
638cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
639cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
640cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
6411f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        public void onDisplaySessionInfo(WifiDisplaySessionInfo sessionInfo) {
6421f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            synchronized (getSyncRoot()) {
6431f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                mSessionInfo = sessionInfo;
6441f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                scheduleStatusChangedBroadcastLocked();
6451f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            }
6461f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
6471f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
6481f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        @Override
64974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        public void onDisplayChanged(WifiDisplay display) {
65074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            synchronized (getSyncRoot()) {
65174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
65274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                if (mActiveDisplay != null
65374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        && mActiveDisplay.hasSameAddress(display)
65474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        && !mActiveDisplay.equals(display)) {
65574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    mActiveDisplay = display;
65674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    renameDisplayDeviceLocked(display.getFriendlyDisplayName());
65774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    scheduleStatusChangedBroadcastLocked();
658e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                    scheduleUpdateNotificationLocked();
65974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                }
66074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
66174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
66274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
66374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        @Override
664cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onDisplayDisconnected() {
665cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            // Stop listening.
666cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
66774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                removeDisplayDeviceLocked();
668e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
669180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
670180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
671180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
672180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
673e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
674e7ae644522f692c204d0233f91e77c7841bdfe53Jeff Brown                    scheduleUpdateNotificationLocked();
675e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
676cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
677cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
678cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
679cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
680cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final class WifiDisplayDevice extends DisplayDevice {
681ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        private String mName;
682cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mWidth;
683cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mHeight;
684cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final float mRefreshRate;
685cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mFlags;
68692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown        private final String mAddress;
687cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
688cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private Surface mSurface;
689cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private DisplayDeviceInfo mInfo;
690cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
691cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public WifiDisplayDevice(IBinder displayToken, String name,
69292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                int width, int height, float refreshRate, int flags, String address,
693cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Surface surface) {
694cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            super(WifiDisplayAdapter.this, displayToken);
695cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mName = name;
696cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWidth = width;
697cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mHeight = height;
698cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mRefreshRate = refreshRate;
699cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mFlags = flags;
70092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown            mAddress = address;
701cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = surface;
702cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
703cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
7046a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall        public void destroyLocked() {
7056a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall            if (mSurface != null) {
7066a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall                mSurface.release();
7076a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall                mSurface = null;
7086a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall            }
7096a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall            SurfaceControl.destroyDisplay(getDisplayTokenLocked());
710cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
711cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
712ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        public void setNameLocked(String name) {
713ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mName = name;
714ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mInfo = null;
715ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        }
716ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown
717cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
718cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void performTraversalInTransactionLocked() {
7196a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall            if (mSurface != null) {
7206a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall                setSurfaceInTransactionLocked(mSurface);
7216a6bc216d15293886ad088bb0ca99aadb7df85dcJesse Hall            }
722cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
723cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
724cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
725cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
726cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mInfo == null) {
727cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo = new DisplayDeviceInfo();
728cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.name = mName;
729cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.width = mWidth;
730cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.height = mHeight;
731cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.refreshRate = mRefreshRate;
732cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.flags = mFlags;
73392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                mInfo.type = Display.TYPE_WIFI;
73492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                mInfo.address = mAddress;
735d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown                mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
736cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
737cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
738cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return mInfo;
739cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
740cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
741a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
742a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final class WifiDisplayHandler extends Handler {
743a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public WifiDisplayHandler(Looper looper) {
744a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            super(looper, null, true /*async*/);
745a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
746a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
747a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        @Override
748a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public void handleMessage(Message msg) {
749a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            switch (msg.what) {
750a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                case MSG_SEND_STATUS_CHANGE_BROADCAST:
751a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    handleSendStatusChangeBroadcast();
752a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    break;
753a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
754a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                case MSG_UPDATE_NOTIFICATION:
755a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    handleUpdateNotification();
756a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    break;
757a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
758a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
759a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
760cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
761