WifiDisplayAdapter.java revision 92130f6407dc51c58b3b941d28a6daf4e04b8d62
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;
44cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
45cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.io.PrintWriter;
46e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport java.util.Arrays;
47cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
48cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
49cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Connects to Wifi displays that implement the Miracast protocol.
50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p>
51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The Wifi display protocol relies on Wifi direct for discovering and pairing
52cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * with the display.  Once connected, the Media Server opens an RTSP socket and accepts
53cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * a connection from the display.  After session negotiation, the Media Server
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * streams encoded buffers to the display.
55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
56cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This class is responsible for connecting to Wifi displays and mediating
57cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * the interactions between Media Server, Surface Flinger and the Display Manager Service.
58cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
59cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p>
61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayAdapter extends DisplayAdapter {
63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final String TAG = "WifiDisplayAdapter";
64cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
652444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown    private static final boolean DEBUG = false;
662444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
67a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final int MSG_SEND_STATUS_CHANGE_BROADCAST = 1;
68a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final int MSG_UPDATE_NOTIFICATION = 2;
69a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
70a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final String ACTION_DISCONNECT = "android.server.display.wfd.DISCONNECT";
71a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
72a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final WifiDisplayHandler mHandler;
7377aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown    private final PersistentDataStore mPersistentDataStore;
7477aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown    private final boolean mSupportsProtectedBuffers;
75a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final NotificationManager mNotificationManager;
76a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
7766692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    private PendingIntent mSettingsPendingIntent;
7866692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    private PendingIntent mDisconnectPendingIntent;
7989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
80cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiDisplayController mDisplayController;
81f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private WifiDisplayDevice mDisplayDevice;
82cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
83e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private WifiDisplayStatus mCurrentStatus;
8489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private int mFeatureState;
85180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mScanState;
86180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mActiveDisplayState;
87180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private WifiDisplay mActiveDisplay;
8889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
8989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
90e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
91e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private boolean mPendingStatusChangeBroadcast;
92a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private boolean mPendingNotificationUpdate;
93e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
9466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    // Called with SyncRoot lock held.
95cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
9689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Context context, Handler handler, Listener listener,
9789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            PersistentDataStore persistentDataStore) {
98cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super(syncRoot, context, handler, listener, TAG);
99a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mHandler = new WifiDisplayHandler(handler.getLooper());
10089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mPersistentDataStore = persistentDataStore;
10177aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        mSupportsProtectedBuffers = context.getResources().getBoolean(
10277aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown                com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers);
103a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mNotificationManager = (NotificationManager)context.getSystemService(
104a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                Context.NOTIFICATION_SERVICE);
105cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
106cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
107cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
108cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void dumpLocked(PrintWriter pw) {
109cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.dumpLocked(pw);
110cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
111e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
11289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mFeatureState=" + mFeatureState);
113180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mScanState=" + mScanState);
114180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplayState=" + mActiveDisplayState);
115180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplay=" + mActiveDisplay);
11689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
11789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
118e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
119a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        pw.println("mPendingNotificationUpdate=" + mPendingNotificationUpdate);
12077aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
121e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
122cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Try to dump the controller state.
123cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDisplayController == null) {
124cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController=null");
125cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
126cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController:");
127cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
128cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            ipw.increaseIndent();
129cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200);
130cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
131cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
132cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
133cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
134cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void registerLocked() {
135cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.registerLocked();
136cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
13789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateRememberedDisplaysLocked();
13889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
139cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        getHandler().post(new Runnable() {
140cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
141cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void run() {
142cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mDisplayController = new WifiDisplayController(
143cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        getContext(), getHandler(), mWifiDisplayListener);
14466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
14566692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
14666692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        new IntentFilter(ACTION_DISCONNECT), null, mHandler);
147cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
148cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
149cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
150cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
151e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestScanLocked() {
1522444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
1532444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestScanLocked");
1542444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
1552444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
156e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
157e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
158e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
159e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
160e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestScan();
161e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
162e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
163e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
164e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
165e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
166bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    public void requestConnectLocked(final String address, final boolean trusted) {
1672444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
1682444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestConnectLocked: address=" + address + ", trusted=" + trusted);
1692444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
1702444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
171bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        if (!trusted) {
172bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            synchronized (getSyncRoot()) {
173bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                if (!isRememberedDisplayLocked(address)) {
174bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                    Slog.w(TAG, "Ignoring request by an untrusted client to connect to "
175bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                            + "an unknown wifi display: " + address);
176bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                    return;
177bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                }
178bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            }
179bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        }
180bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown
181e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
182e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
183e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
184e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
185e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestConnect(address);
186e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
187e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
188e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
189e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
190e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
191bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    private boolean isRememberedDisplayLocked(String address) {
192bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        for (WifiDisplay display : mRememberedDisplays) {
193bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            if (display.getDeviceAddress().equals(address)) {
194bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                return true;
195bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            }
196bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        }
197bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        return false;
198bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    }
199bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown
200e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestDisconnectLocked() {
2012444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2022444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestDisconnectedLocked");
2032444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2042444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
205e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
206e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
207e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
208e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
209e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestDisconnect();
210e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
211e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
212e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
213e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
214e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
21589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestRenameLocked(String address, String alias) {
2162444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2172444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestRenameLocked: address=" + address + ", alias=" + alias);
2182444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2192444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
22089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (alias != null) {
22189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            alias = alias.trim();
2222444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            if (alias.isEmpty() || alias.equals(address)) {
22389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                alias = null;
22489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
22589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
22689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
22789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.renameWifiDisplay(address, alias)) {
22889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
22989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
23089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
23189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
232ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown
233ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)
234ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown                && mDisplayDevice != null) {
235ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mDisplayDevice.setNameLocked(mActiveDisplay.getFriendlyDisplayName());
236ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
237ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        }
23889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
23989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
24089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestForgetLocked(String address) {
2412444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2422444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestForgetLocked: address=" + address);
2432444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2442444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
24589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.forgetWifiDisplay(address)) {
24689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
24789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
24889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
24989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
25089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
25189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
25289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            requestDisconnectLocked();
25389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
25489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
25589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
256e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatusLocked() {
257e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (mCurrentStatus == null) {
25889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mCurrentStatus = new WifiDisplayStatus(
25989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState, mScanState, mActiveDisplayState,
26089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mActiveDisplay, mAvailableDisplays, mRememberedDisplays);
261e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
2622444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
2632444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2642444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "getWifiDisplayStatusLocked: result=" + mCurrentStatus);
2652444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
266e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        return mCurrentStatus;
267e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
268cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
26989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateRememberedDisplaysLocked() {
27089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
27189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
27289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
27389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
27489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
275f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private void handleConnectLocked(WifiDisplay display,
276f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Surface surface, int width, int height, int flags) {
277e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        handleDisconnectLocked();
278e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
27989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.rememberWifiDisplay(display)) {
28089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
28189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
28289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
28389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
28489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
285f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown        boolean secure = (flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0;
286f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        int deviceFlags = 0;
287f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown        if (secure) {
28877aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown            deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
289f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown            if (mSupportsProtectedBuffers) {
290f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown                deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
291f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown            }
292f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        }
293f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
294f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        float refreshRate = 60.0f; // TODO: get this for real
295f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
29689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        String name = display.getFriendlyDisplayName();
29792130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown        String address = display.getDeviceAddress();
298f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown        IBinder displayToken = Surface.createDisplay(name, secure);
299f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
30092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                refreshRate, deviceFlags, address, surface);
301f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
302a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
303a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        scheduleUpdateNotificationLocked();
304cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
305cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
306e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void handleDisconnectLocked() {
307f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mDisplayDevice != null) {
308f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mDisplayDevice.clearSurfaceLocked();
309f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
310f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mDisplayDevice = null;
311a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
312a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            scheduleUpdateNotificationLocked();
313cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
314cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
315cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
316e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void scheduleStatusChangedBroadcastLocked() {
31789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mCurrentStatus = null;
318e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (!mPendingStatusChangeBroadcast) {
319e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mPendingStatusChangeBroadcast = true;
320a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mHandler.sendEmptyMessage(MSG_SEND_STATUS_CHANGE_BROADCAST);
321e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
322e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
323e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
324a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void scheduleUpdateNotificationLocked() {
325a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        if (!mPendingNotificationUpdate) {
326a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingNotificationUpdate = true;
327a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mHandler.sendEmptyMessage(MSG_UPDATE_NOTIFICATION);
328a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
329a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
330a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
331a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    // Runs on the handler.
332a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void handleSendStatusChangeBroadcast() {
333a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        final Intent intent;
334a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        synchronized (getSyncRoot()) {
335a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (!mPendingStatusChangeBroadcast) {
336a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                return;
337a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
338a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
339a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingStatusChangeBroadcast = false;
340a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
341a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
342a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
343a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    getWifiDisplayStatusLocked());
344a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
345e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
346a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        // Send protected broadcast about wifi display status to registered receivers.
347a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
348a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
349a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
350a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    // Runs on the handler.
351a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void handleUpdateNotification() {
352a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        final boolean isConnected;
353a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        synchronized (getSyncRoot()) {
354a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (!mPendingNotificationUpdate) {
355a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                return;
356e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
357e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
358a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingNotificationUpdate = false;
359a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            isConnected = (mDisplayDevice != null);
360a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
361a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
36266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown        // Cancel the old notification if there is one.
363a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mNotificationManager.cancelAsUser(null,
364a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                R.string.wifi_display_notification_title, UserHandle.ALL);
365a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
366a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        if (isConnected) {
367a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Context context = getContext();
368a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
36966692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            // Initialize pending intents for the notification outside of the lock because
37066692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            // creating a pending intent requires a call into the activity manager.
37166692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            if (mSettingsPendingIntent == null) {
37266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
37366692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
37466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
37566692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        | Intent.FLAG_ACTIVITY_CLEAR_TOP);
37666692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                mSettingsPendingIntent = PendingIntent.getActivityAsUser(
37766692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        context, 0, settingsIntent, 0, null, UserHandle.CURRENT);
37866692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            }
37966692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
38066692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            if (mDisconnectPendingIntent == null) {
38166692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                Intent disconnectIntent = new Intent(ACTION_DISCONNECT);
38266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                mDisconnectPendingIntent = PendingIntent.getBroadcastAsUser(
38366692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown                        context, 0, disconnectIntent, 0, UserHandle.CURRENT);
38466692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            }
38566692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
38666692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown            // Post the notification.
387a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Resources r = context.getResources();
388a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Notification notification = new Notification.Builder(context)
389a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setContentTitle(r.getString(
390a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            R.string.wifi_display_notification_title))
391a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setContentText(r.getString(
392a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            R.string.wifi_display_notification_message))
393a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setContentIntent(mSettingsPendingIntent)
394a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setSmallIcon(R.drawable.ic_notify_wifidisplay)
395a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setOngoing(true)
396a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .addAction(android.R.drawable.ic_menu_close_clear_cancel,
397a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            r.getString(R.string.wifi_display_notification_disconnect),
398a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            mDisconnectPendingIntent)
399a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .build();
400a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mNotificationManager.notifyAsUser(null,
401a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    R.string.wifi_display_notification_title,
402a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    notification, UserHandle.ALL);
403a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
404a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
405a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
406a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
407a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        @Override
408a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public void onReceive(Context context, Intent intent) {
409a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (intent.getAction().equals(ACTION_DISCONNECT)) {
410a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                synchronized (getSyncRoot()) {
411a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    requestDisconnectLocked();
412a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                }
413a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
414e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
415e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    };
416e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
417cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final WifiDisplayController.Listener mWifiDisplayListener =
418cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            new WifiDisplayController.Listener() {
419cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
42089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        public void onFeatureStateChanged(int featureState) {
421e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
42289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                if (mFeatureState != featureState) {
42389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState = featureState;
424e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
425e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
426e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
427e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
428e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
429e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
430e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onScanStarted() {
431e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
432180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
433180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
434e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
435e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
436e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
437e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
438e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
4392444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        @Override
44089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        public void onScanFinished(WifiDisplay[] availableDisplays) {
441e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
44289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
44389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        availableDisplays);
44489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
445180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING
44689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        || !Arrays.equals(mAvailableDisplays, availableDisplays)) {
447180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
44889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mAvailableDisplays = availableDisplays;
449e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
450e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
451e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
452e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
453e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
454e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
455e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnecting(WifiDisplay display) {
456e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
45789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
45889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
459180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
460180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
461180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
462180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
463180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
464e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
465e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
466e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
467e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
468e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
469e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
470e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnectionFailed() {
471e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
472180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
473180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
474180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
475180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
476e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
477e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
478e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
479e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
480e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
481e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
482f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        public void onDisplayConnected(WifiDisplay display, Surface surface,
483f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                int width, int height, int flags) {
484cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
48589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
486f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                handleConnectLocked(display, surface, width, height, flags);
487e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
488180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
489180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
490180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
491180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
492180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
493e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
494e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
495cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
496cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
497cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
498cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
499cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onDisplayDisconnected() {
500cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            // Stop listening.
501cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
502e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                handleDisconnectLocked();
503e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
504180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
505180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
506180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
507180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
508e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
509e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
510cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
511cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
512cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
513cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
514cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final class WifiDisplayDevice extends DisplayDevice {
515ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        private String mName;
516cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mWidth;
517cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mHeight;
518cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final float mRefreshRate;
519cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mFlags;
52092130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown        private final String mAddress;
521cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
522cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private Surface mSurface;
523cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private DisplayDeviceInfo mInfo;
524cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
525cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public WifiDisplayDevice(IBinder displayToken, String name,
52692130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                int width, int height, float refreshRate, int flags, String address,
527cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Surface surface) {
528cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            super(WifiDisplayAdapter.this, displayToken);
529cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mName = name;
530cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWidth = width;
531cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mHeight = height;
532cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mRefreshRate = refreshRate;
533cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mFlags = flags;
53492130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown            mAddress = address;
535cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = surface;
536cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
537cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
538cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void clearSurfaceLocked() {
539cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = null;
540cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            sendTraversalRequestLocked();
541cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
542cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
543ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        public void setNameLocked(String name) {
544ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mName = name;
545ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mInfo = null;
546ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        }
547ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown
548cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
549cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void performTraversalInTransactionLocked() {
550cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            setSurfaceInTransactionLocked(mSurface);
551cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
552cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
553cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
554cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
555cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mInfo == null) {
556cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo = new DisplayDeviceInfo();
557cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.name = mName;
558cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.width = mWidth;
559cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.height = mHeight;
560cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.refreshRate = mRefreshRate;
561cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.flags = mFlags;
56292130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                mInfo.type = Display.TYPE_WIFI;
56392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                mInfo.address = mAddress;
564d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown                mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
565cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
566cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
567cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return mInfo;
568cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
569cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
570a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
571a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final class WifiDisplayHandler extends Handler {
572a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public WifiDisplayHandler(Looper looper) {
573a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            super(looper, null, true /*async*/);
574a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
575a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
576a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        @Override
577a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public void handleMessage(Message msg) {
578a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            switch (msg.what) {
579a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                case MSG_SEND_STATUS_CHANGE_BROADCAST:
580a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    handleSendStatusChangeBroadcast();
581a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    break;
582a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
583a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                case MSG_UPDATE_NOTIFICATION:
584a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    handleUpdateNotification();
585a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    break;
586a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
587a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
588a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
589cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
590