WifiDisplayAdapter.java revision ab87a63997a7dc771acfd0dcd7efda990dc3d5fe
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;
33e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.WifiDisplayStatus;
34cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.media.RemoteDisplay;
35cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.Handler;
36cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.IBinder;
37a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.os.Looper;
38a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.os.Message;
39a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.os.UserHandle;
40a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brownimport android.provider.Settings;
41bc335457462a12434a9df6955de1dd693cdccac7Jeff Brownimport android.util.Slog;
4292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brownimport android.view.Display;
43cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.view.Surface;
443866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopianimport android.view.SurfaceControl;
45cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
46cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.io.PrintWriter;
47e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport java.util.Arrays;
48ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhangimport java.util.List;
49ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhangimport java.util.ArrayList;
50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
5174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brownimport libcore.util.Objects;
5274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
53cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Connects to Wifi displays that implement the Miracast protocol.
55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p>
56cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The Wifi display protocol relies on Wifi direct for discovering and pairing
57cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * with the display.  Once connected, the Media Server opens an RTSP socket and accepts
58cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * a connection from the display.  After session negotiation, the Media Server
59cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * streams encoded buffers to the display.
60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This class is responsible for connecting to Wifi displays and mediating
62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * the interactions between Media Server, Surface Flinger and the Display Manager Service.
63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
64cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
65cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p>
66cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayAdapter extends DisplayAdapter {
68cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final String TAG = "WifiDisplayAdapter";
69cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
702444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown    private static final boolean DEBUG = false;
712444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
72a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final int MSG_SEND_STATUS_CHANGE_BROADCAST = 1;
73a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final int MSG_UPDATE_NOTIFICATION = 2;
74a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
75a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final String ACTION_DISCONNECT = "android.server.display.wfd.DISCONNECT";
76a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
77a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final WifiDisplayHandler mHandler;
7877aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown    private final PersistentDataStore mPersistentDataStore;
7977aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown    private final boolean mSupportsProtectedBuffers;
80a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final NotificationManager mNotificationManager;
81a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
8266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    private PendingIntent mSettingsPendingIntent;
8366692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    private PendingIntent mDisconnectPendingIntent;
8489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
85cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiDisplayController mDisplayController;
86f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private WifiDisplayDevice mDisplayDevice;
87cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
88e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private WifiDisplayStatus mCurrentStatus;
8989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private int mFeatureState;
90180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mScanState;
91180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mActiveDisplayState;
92180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private WifiDisplay mActiveDisplay;
93ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang    private WifiDisplay[] mDisplays = WifiDisplay.EMPTY_ARRAY;
9489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
9589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
96e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
97e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private boolean mPendingStatusChangeBroadcast;
98a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private boolean mPendingNotificationUpdate;
99e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
10066692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    // Called with SyncRoot lock held.
101cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
10289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Context context, Handler handler, Listener listener,
10389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            PersistentDataStore persistentDataStore) {
104cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super(syncRoot, context, handler, listener, TAG);
105a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mHandler = new WifiDisplayHandler(handler.getLooper());
10689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mPersistentDataStore = persistentDataStore;
10777aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        mSupportsProtectedBuffers = context.getResources().getBoolean(
10877aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown                com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers);
109a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mNotificationManager = (NotificationManager)context.getSystemService(
110a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                Context.NOTIFICATION_SERVICE);
111cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
112cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
113cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
114cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void dumpLocked(PrintWriter pw) {
115cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.dumpLocked(pw);
116cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
117e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
11889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mFeatureState=" + mFeatureState);
119180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mScanState=" + mScanState);
120180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplayState=" + mActiveDisplayState);
121180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplay=" + mActiveDisplay);
122ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        pw.println("mDisplays=" + Arrays.toString(mDisplays));
12389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
12489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
125e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
126a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        pw.println("mPendingNotificationUpdate=" + mPendingNotificationUpdate);
12777aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
128e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
129cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Try to dump the controller state.
130cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDisplayController == null) {
131cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController=null");
132cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
133cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController:");
134cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
135cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            ipw.increaseIndent();
136cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200);
137cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
138cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
139cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
140cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
141cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void registerLocked() {
142cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.registerLocked();
143cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
14489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateRememberedDisplaysLocked();
14589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
146cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        getHandler().post(new Runnable() {
147cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
148cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void run() {
149cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mDisplayController = new WifiDisplayController(
150cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        getContext(), getHandler(), mWifiDisplayListener);
15166692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
15266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
15366692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        new IntentFilter(ACTION_DISCONNECT), null, mHandler);
154cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
155cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
156cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
157cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
158e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestScanLocked() {
1592444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
1602444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestScanLocked");
1612444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
1622444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
163e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
164e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
165e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
166e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
167e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestScan();
168e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
169e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
170e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
171e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
172e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
173bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    public void requestConnectLocked(final String address, final boolean trusted) {
1742444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
1752444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestConnectLocked: address=" + address + ", trusted=" + trusted);
1762444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
1772444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
178bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        if (!trusted) {
179bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            synchronized (getSyncRoot()) {
180bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                if (!isRememberedDisplayLocked(address)) {
181bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                    Slog.w(TAG, "Ignoring request by an untrusted client to connect to "
182bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                            + "an unknown wifi display: " + address);
183bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                    return;
184bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                }
185bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            }
186bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        }
187bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown
188e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
189e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
190e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
191e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
192e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestConnect(address);
193e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
194e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
195e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
196e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
197e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
198bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    private boolean isRememberedDisplayLocked(String address) {
199bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        for (WifiDisplay display : mRememberedDisplays) {
200bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            if (display.getDeviceAddress().equals(address)) {
201bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                return true;
202bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            }
203bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        }
204bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        return false;
205bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    }
206bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown
207e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestDisconnectLocked() {
2082444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2092444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestDisconnectedLocked");
2102444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2112444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
212e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
213e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
214e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
215e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
216e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestDisconnect();
217e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
218e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
219e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
220e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
221e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
22289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestRenameLocked(String address, String alias) {
2232444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2242444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestRenameLocked: address=" + address + ", alias=" + alias);
2252444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2262444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
22789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (alias != null) {
22889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            alias = alias.trim();
2292444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            if (alias.isEmpty() || alias.equals(address)) {
23089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                alias = null;
23189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
23289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
23389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
23474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address);
23574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (display != null && !Objects.equal(display.getDeviceAlias(), alias)) {
236ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            display = new WifiDisplay(address, display.getDeviceName(), alias,
237ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    false, false, false);
23874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (mPersistentDataStore.rememberWifiDisplay(display)) {
23974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                mPersistentDataStore.saveIfNeeded();
24074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                updateRememberedDisplaysLocked();
24174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                scheduleStatusChangedBroadcastLocked();
24274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
24389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
244ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown
24574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
24674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            renameDisplayDeviceLocked(mActiveDisplay.getFriendlyDisplayName());
247ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        }
24889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
24989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
25089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestForgetLocked(String address) {
2512444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2522444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestForgetLocked: address=" + address);
2532444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2542444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
25589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.forgetWifiDisplay(address)) {
25689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
25789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
25889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
25989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
26089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
26189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
26289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            requestDisconnectLocked();
26389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
26489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
26589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
266e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatusLocked() {
267e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (mCurrentStatus == null) {
26889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mCurrentStatus = new WifiDisplayStatus(
26989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState, mScanState, mActiveDisplayState,
270ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    mActiveDisplay, mDisplays);
271e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
2722444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
2732444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2742444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "getWifiDisplayStatusLocked: result=" + mCurrentStatus);
2752444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
276e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        return mCurrentStatus;
277e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
278cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
279ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang    private void updateDisplaysLocked() {
280ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        List<WifiDisplay> displays = new ArrayList<WifiDisplay>(
281ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                mAvailableDisplays.length + mRememberedDisplays.length);
282ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        boolean[] remembered = new boolean[mAvailableDisplays.length];
283ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        for (WifiDisplay d : mRememberedDisplays) {
284ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            boolean available = false;
285ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            for (int i = 0; i < mAvailableDisplays.length; i++) {
286ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                if (d.equals(mAvailableDisplays[i])) {
287ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    remembered[i] = available = true;
288ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    break;
289ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                }
290ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            }
291ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            if (!available) {
292ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
293ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                        d.getDeviceAlias(), false, false, true));
294ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            }
295ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        }
296ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        for (int i = 0; i < mAvailableDisplays.length; i++) {
297ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            WifiDisplay d = mAvailableDisplays[i];
298ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang            displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(),
299ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    d.getDeviceAlias(), true, d.canConnect(), remembered[i]));
300ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        }
301ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        mDisplays = displays.toArray(WifiDisplay.EMPTY_ARRAY);
302ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang    }
303ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang
30489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateRememberedDisplaysLocked() {
30589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
30689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
30789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
308ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang        updateDisplaysLocked();
30989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
31089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
31174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() {
31274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // It may happen that a display name has changed since it was remembered.
31374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // Consult the list of available displays and update the name if needed.
31474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // We don't do anything special for the active display here.  The display
31574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        // controller will send a separate event when it needs to be updates.
31674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        boolean changed = false;
31774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        for (int i = 0; i < mRememberedDisplays.length; i++) {
31874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            WifiDisplay rememberedDisplay = mRememberedDisplays[i];
31974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            WifiDisplay availableDisplay = findAvailableDisplayLocked(
32074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    rememberedDisplay.getDeviceAddress());
32174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) {
32274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                if (DEBUG) {
32374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    Slog.d(TAG, "fixRememberedDisplayNamesFromAvailableDisplaysLocked: "
32474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                            + "updating remembered display to " + availableDisplay);
32574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                }
32674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                mRememberedDisplays[i] = availableDisplay;
32774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay);
32874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
32974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
33074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (changed) {
33174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mPersistentDataStore.saveIfNeeded();
33274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
33374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
33474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
33574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private WifiDisplay findAvailableDisplayLocked(String address) {
33674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        for (WifiDisplay display : mAvailableDisplays) {
33774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            if (display.getDeviceAddress().equals(address)) {
33874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                return display;
33974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
34074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
34174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        return null;
34274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
34374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
34474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void addDisplayDeviceLocked(WifiDisplay display,
345f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Surface surface, int width, int height, int flags) {
34674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        removeDisplayDeviceLocked();
347e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
34889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.rememberWifiDisplay(display)) {
34989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
35089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
35189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
35289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
35389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
354f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown        boolean secure = (flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0;
355f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        int deviceFlags = 0;
356f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown        if (secure) {
35777aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown            deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
358f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown            if (mSupportsProtectedBuffers) {
359f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown                deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
360f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown            }
361f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        }
362f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
363f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        float refreshRate = 60.0f; // TODO: get this for real
364f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
36589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        String name = display.getFriendlyDisplayName();
36692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown        String address = display.getDeviceAddress();
3673866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian        IBinder displayToken = SurfaceControl.createDisplay(name, secure);
368f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
36992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                refreshRate, deviceFlags, address, surface);
370f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
371a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
372a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        scheduleUpdateNotificationLocked();
373cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
374cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
37574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void removeDisplayDeviceLocked() {
376f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mDisplayDevice != null) {
377f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mDisplayDevice.clearSurfaceLocked();
378f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
379f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mDisplayDevice = null;
380a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
381a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            scheduleUpdateNotificationLocked();
382cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
383cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
384cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
38574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    private void renameDisplayDeviceLocked(String name) {
38674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        if (mDisplayDevice != null && !mDisplayDevice.getNameLocked().equals(name)) {
38774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            mDisplayDevice.setNameLocked(name);
38874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
38974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
39074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown    }
39174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
392e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void scheduleStatusChangedBroadcastLocked() {
39389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mCurrentStatus = null;
394e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (!mPendingStatusChangeBroadcast) {
395e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mPendingStatusChangeBroadcast = true;
396a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mHandler.sendEmptyMessage(MSG_SEND_STATUS_CHANGE_BROADCAST);
397e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
398e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
399e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
400a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void scheduleUpdateNotificationLocked() {
401a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        if (!mPendingNotificationUpdate) {
402a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingNotificationUpdate = true;
403a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mHandler.sendEmptyMessage(MSG_UPDATE_NOTIFICATION);
404a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
405a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
406a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
407a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    // Runs on the handler.
408a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void handleSendStatusChangeBroadcast() {
409a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        final Intent intent;
410a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        synchronized (getSyncRoot()) {
411a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (!mPendingStatusChangeBroadcast) {
412a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                return;
413a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
414a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
415a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingStatusChangeBroadcast = false;
416a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
417a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
418a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
419a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    getWifiDisplayStatusLocked());
420a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
421e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
422a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        // Send protected broadcast about wifi display status to registered receivers.
423a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
424a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
425a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
426a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    // Runs on the handler.
427a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void handleUpdateNotification() {
428a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        final boolean isConnected;
429a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        synchronized (getSyncRoot()) {
430a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (!mPendingNotificationUpdate) {
431a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                return;
432e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
433e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
434a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingNotificationUpdate = false;
435a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            isConnected = (mDisplayDevice != null);
436a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
437a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
43866692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown        // Cancel the old notification if there is one.
439a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mNotificationManager.cancelAsUser(null,
440a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                R.string.wifi_display_notification_title, UserHandle.ALL);
441a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
442a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        if (isConnected) {
443a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Context context = getContext();
444a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
44566692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            // Initialize pending intents for the notification outside of the lock because
44666692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            // creating a pending intent requires a call into the activity manager.
44766692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            if (mSettingsPendingIntent == null) {
44866692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
44966692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
45066692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
45166692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        | Intent.FLAG_ACTIVITY_CLEAR_TOP);
45266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                mSettingsPendingIntent = PendingIntent.getActivityAsUser(
45366692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        context, 0, settingsIntent, 0, null, UserHandle.CURRENT);
45466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            }
45566692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
45666692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            if (mDisconnectPendingIntent == null) {
45766692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                Intent disconnectIntent = new Intent(ACTION_DISCONNECT);
45866692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                mDisconnectPendingIntent = PendingIntent.getBroadcastAsUser(
45966692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        context, 0, disconnectIntent, 0, UserHandle.CURRENT);
46066692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            }
46166692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
46266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            // Post the notification.
463a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Resources r = context.getResources();
464a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Notification notification = new Notification.Builder(context)
465a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setContentTitle(r.getString(
466a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            R.string.wifi_display_notification_title))
467a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setContentText(r.getString(
468a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            R.string.wifi_display_notification_message))
469a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setContentIntent(mSettingsPendingIntent)
470a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setSmallIcon(R.drawable.ic_notify_wifidisplay)
471a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setOngoing(true)
472a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .addAction(android.R.drawable.ic_menu_close_clear_cancel,
473a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            r.getString(R.string.wifi_display_notification_disconnect),
474a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            mDisconnectPendingIntent)
475a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .build();
476a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mNotificationManager.notifyAsUser(null,
477a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    R.string.wifi_display_notification_title,
478a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    notification, UserHandle.ALL);
479a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
480a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
481a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
482a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
483a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        @Override
484a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public void onReceive(Context context, Intent intent) {
485a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (intent.getAction().equals(ACTION_DISCONNECT)) {
486a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                synchronized (getSyncRoot()) {
487a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    requestDisconnectLocked();
488a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                }
489a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
490e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
491e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    };
492e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
493cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final WifiDisplayController.Listener mWifiDisplayListener =
494cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            new WifiDisplayController.Listener() {
495cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
49689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        public void onFeatureStateChanged(int featureState) {
497e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
49889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                if (mFeatureState != featureState) {
49989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState = featureState;
500e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
501e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
502e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
503e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
504e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
505e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
506e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onScanStarted() {
507e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
508180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
509180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
510e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
511e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
512e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
513e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
514e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
5152444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        @Override
51689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        public void onScanFinished(WifiDisplay[] availableDisplays) {
517e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
51889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
51989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        availableDisplays);
52089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
521ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                // check if any of the available displays changed canConnect status
522ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                boolean changed = !Arrays.equals(mAvailableDisplays, availableDisplays);
523ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                for (int i = 0; !changed && i<availableDisplays.length; i++) {
524ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    changed = availableDisplays[i].canConnect()
525ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                            != mAvailableDisplays[i].canConnect();
526ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                }
527ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang
528ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING || changed) {
529180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
53089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mAvailableDisplays = availableDisplays;
53174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    fixRememberedDisplayNamesFromAvailableDisplaysLocked();
532ab87a63997a7dc771acfd0dcd7efda990dc3d5feChong Zhang                    updateDisplaysLocked();
533e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
534e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
535e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
536e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
537e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
538e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
539e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnecting(WifiDisplay display) {
540e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
54189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
54289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
543180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
544180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
545180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
546180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
547180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
548e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
549e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
550e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
551e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
552e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
553e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
554e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnectionFailed() {
555e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
556180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
557180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
558180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
559180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
560e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
561e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
562e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
563e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
564e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
565e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
566f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        public void onDisplayConnected(WifiDisplay display, Surface surface,
567f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                int width, int height, int flags) {
568cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
56989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
57074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                addDisplayDeviceLocked(display, surface, width, height, flags);
571e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
572180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
573180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
574180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
575180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
576180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
577e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
578e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
579cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
580cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
581cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
582cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
58374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        public void onDisplayChanged(WifiDisplay display) {
58474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            synchronized (getSyncRoot()) {
58574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
58674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                if (mActiveDisplay != null
58774da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        && mActiveDisplay.hasSameAddress(display)
58874da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                        && !mActiveDisplay.equals(display)) {
58974da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    mActiveDisplay = display;
59074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    renameDisplayDeviceLocked(display.getFriendlyDisplayName());
59174da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                    scheduleStatusChangedBroadcastLocked();
59274da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                }
59374da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown            }
59474da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        }
59574da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown
59674da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown        @Override
597cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onDisplayDisconnected() {
598cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            // Stop listening.
599cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
60074da109102864f19b3dcdb30cd1d92c46fb12f2fJeff Brown                removeDisplayDeviceLocked();
601e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
602180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
603180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
604180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
605180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
606e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
607e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
608cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
609cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
610cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
611cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
612cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final class WifiDisplayDevice extends DisplayDevice {
613ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        private String mName;
614cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mWidth;
615cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mHeight;
616cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final float mRefreshRate;
617cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mFlags;
61892130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown        private final String mAddress;
619cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
620cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private Surface mSurface;
621cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private DisplayDeviceInfo mInfo;
622cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
623cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public WifiDisplayDevice(IBinder displayToken, String name,
62492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                int width, int height, float refreshRate, int flags, String address,
625cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Surface surface) {
626cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            super(WifiDisplayAdapter.this, displayToken);
627cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mName = name;
628cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWidth = width;
629cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mHeight = height;
630cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mRefreshRate = refreshRate;
631cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mFlags = flags;
63292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown            mAddress = address;
633cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = surface;
634cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
635cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
636cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void clearSurfaceLocked() {
637cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = null;
638cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            sendTraversalRequestLocked();
639cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
640cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
641ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        public void setNameLocked(String name) {
642ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mName = name;
643ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mInfo = null;
644ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        }
645ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown
646cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
647cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void performTraversalInTransactionLocked() {
648cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            setSurfaceInTransactionLocked(mSurface);
649cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
650cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
651cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
652cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
653cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mInfo == null) {
654cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo = new DisplayDeviceInfo();
655cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.name = mName;
656cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.width = mWidth;
657cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.height = mHeight;
658cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.refreshRate = mRefreshRate;
659cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.flags = mFlags;
66092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                mInfo.type = Display.TYPE_WIFI;
66192130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                mInfo.address = mAddress;
662d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown                mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
663cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
664cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
665cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return mInfo;
666cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
667cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
668a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
669a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final class WifiDisplayHandler extends Handler {
670a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public WifiDisplayHandler(Looper looper) {
671a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            super(looper, null, true /*async*/);
672a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
673a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
674a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        @Override
675a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public void handleMessage(Message msg) {
676a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            switch (msg.what) {
677a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                case MSG_SEND_STATUS_CHANGE_BROADCAST:
678a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    handleSendStatusChangeBroadcast();
679a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    break;
680a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
681a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                case MSG_UPDATE_NOTIFICATION:
682a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    handleUpdateNotification();
683a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    break;
684a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
685a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
686a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
687cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
688