WifiDisplayAdapter.java revision a7f9c966bc90e52baaf0cf0c165463e5f44354c5
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;
42cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.view.Surface;
43cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
44cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.io.PrintWriter;
45e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport java.util.Arrays;
46cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
47cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
48cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Connects to Wifi displays that implement the Miracast protocol.
49cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p>
50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The Wifi display protocol relies on Wifi direct for discovering and pairing
51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * with the display.  Once connected, the Media Server opens an RTSP socket and accepts
52cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * a connection from the display.  After session negotiation, the Media Server
53cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * streams encoded buffers to the display.
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This class is responsible for connecting to Wifi displays and mediating
56cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * the interactions between Media Server, Surface Flinger and the Display Manager Service.
57cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
58cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
59cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p>
60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayAdapter extends DisplayAdapter {
62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final String TAG = "WifiDisplayAdapter";
63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
642444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown    private static final boolean DEBUG = false;
652444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
66a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final int MSG_SEND_STATUS_CHANGE_BROADCAST = 1;
67a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final int MSG_UPDATE_NOTIFICATION = 2;
68a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
69a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private static final String ACTION_DISCONNECT = "android.server.display.wfd.DISCONNECT";
70a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
71a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final WifiDisplayHandler mHandler;
7277aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown    private final PersistentDataStore mPersistentDataStore;
7377aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown    private final boolean mSupportsProtectedBuffers;
74a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final NotificationManager mNotificationManager;
75a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
76a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final PendingIntent mSettingsPendingIntent;
77a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final PendingIntent mDisconnectPendingIntent;
7889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
79cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiDisplayController mDisplayController;
80f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private WifiDisplayDevice mDisplayDevice;
81cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
82e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private WifiDisplayStatus mCurrentStatus;
8389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private int mFeatureState;
84180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mScanState;
85180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mActiveDisplayState;
86180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private WifiDisplay mActiveDisplay;
8789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
8889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
89e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
90e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private boolean mPendingStatusChangeBroadcast;
91a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private boolean mPendingNotificationUpdate;
92e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
93cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
9489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Context context, Handler handler, Listener listener,
9589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            PersistentDataStore persistentDataStore) {
96cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super(syncRoot, context, handler, listener, TAG);
97a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mHandler = new WifiDisplayHandler(handler.getLooper());
9889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mPersistentDataStore = persistentDataStore;
9977aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        mSupportsProtectedBuffers = context.getResources().getBoolean(
10077aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown                com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers);
101a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mNotificationManager = (NotificationManager)context.getSystemService(
102a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                Context.NOTIFICATION_SERVICE);
103a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
104a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
105a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
106a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
107a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
108a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mSettingsPendingIntent = PendingIntent.getActivityAsUser(
109a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                context, 0, settingsIntent, 0, null, UserHandle.CURRENT);
110a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
111a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        Intent disconnectIntent = new Intent(ACTION_DISCONNECT);
112a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mDisconnectPendingIntent = PendingIntent.getBroadcastAsUser(
113a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                context, 0, disconnectIntent, 0, UserHandle.CURRENT);
114a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
115a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
116a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                new IntentFilter(ACTION_DISCONNECT), null, mHandler);
117cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
118cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
119cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
120cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void dumpLocked(PrintWriter pw) {
121cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.dumpLocked(pw);
122cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
123e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
12489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mFeatureState=" + mFeatureState);
125180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mScanState=" + mScanState);
126180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplayState=" + mActiveDisplayState);
127180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplay=" + mActiveDisplay);
12889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
12989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
130e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
131a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        pw.println("mPendingNotificationUpdate=" + mPendingNotificationUpdate);
13277aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
133e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
134cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Try to dump the controller state.
135cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDisplayController == null) {
136cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController=null");
137cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
138cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController:");
139cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
140cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            ipw.increaseIndent();
141cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200);
142cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
143cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
144cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
145cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
146cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void registerLocked() {
147cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.registerLocked();
148cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
14989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateRememberedDisplaysLocked();
15089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
151cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        getHandler().post(new Runnable() {
152cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
153cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void run() {
154cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mDisplayController = new WifiDisplayController(
155cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        getContext(), getHandler(), mWifiDisplayListener);
156cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
157cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
158cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
159cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
160e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestScanLocked() {
1612444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
1622444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestScanLocked");
1632444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
1642444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
165e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
166e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
167e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
168e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
169e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestScan();
170e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
171e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
172e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
173e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
174e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
175bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    public void requestConnectLocked(final String address, final boolean trusted) {
1762444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
1772444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestConnectLocked: address=" + address + ", trusted=" + trusted);
1782444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
1792444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
180bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        if (!trusted) {
181bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            synchronized (getSyncRoot()) {
182bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                if (!isRememberedDisplayLocked(address)) {
183bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                    Slog.w(TAG, "Ignoring request by an untrusted client to connect to "
184bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                            + "an unknown wifi display: " + address);
185bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                    return;
186bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                }
187bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            }
188bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        }
189bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown
190e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
191e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
192e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
193e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
194e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestConnect(address);
195e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
196e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
197e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
198e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
199e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
200bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    private boolean isRememberedDisplayLocked(String address) {
201bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        for (WifiDisplay display : mRememberedDisplays) {
202bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            if (display.getDeviceAddress().equals(address)) {
203bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown                return true;
204bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown            }
205bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        }
206bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown        return false;
207bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown    }
208bc335457462a12434a9df6955de1dd693cdccac7Jeff Brown
209e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestDisconnectLocked() {
2102444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2112444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestDisconnectedLocked");
2122444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2132444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
214e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
215e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
216e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
217e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
218e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestDisconnect();
219e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
220e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
221e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
222e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
223e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
22489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestRenameLocked(String address, String alias) {
2252444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2262444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestRenameLocked: address=" + address + ", alias=" + alias);
2272444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2282444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
22989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (alias != null) {
23089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            alias = alias.trim();
2312444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            if (alias.isEmpty() || alias.equals(address)) {
23289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                alias = null;
23389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
23489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
23589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
23689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.renameWifiDisplay(address, alias)) {
23789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
23889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
23989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
24089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
241ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown
242ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)
243ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown                && mDisplayDevice != null) {
244ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mDisplayDevice.setNameLocked(mActiveDisplay.getFriendlyDisplayName());
245ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
246ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        }
24789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
24889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
24989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestForgetLocked(String address) {
2502444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2512444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "requestForgetLocked: address=" + address);
2522444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
2532444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
25489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.forgetWifiDisplay(address)) {
25589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
25689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
25789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
25889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
25989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
26089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
26189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            requestDisconnectLocked();
26289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
26389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
26489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
265e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatusLocked() {
266e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (mCurrentStatus == null) {
26789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mCurrentStatus = new WifiDisplayStatus(
26889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState, mScanState, mActiveDisplayState,
26989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mActiveDisplay, mAvailableDisplays, mRememberedDisplays);
270e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
2712444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown
2722444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        if (DEBUG) {
2732444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown            Slog.d(TAG, "getWifiDisplayStatusLocked: result=" + mCurrentStatus);
2742444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        }
275e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        return mCurrentStatus;
276e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
277cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
27889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateRememberedDisplaysLocked() {
27989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
28089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
28189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
28289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
28389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
284f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private void handleConnectLocked(WifiDisplay display,
285f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Surface surface, int width, int height, int flags) {
286e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        handleDisconnectLocked();
287e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
28889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.rememberWifiDisplay(display)) {
28989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
29089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
29189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
29289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
29389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
294f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        int deviceFlags = 0;
295f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
29677aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown            deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
29777aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        }
29877aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown        if (mSupportsProtectedBuffers) {
29977aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown            deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
300f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        }
301f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
302f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        float refreshRate = 60.0f; // TODO: get this for real
303f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
30489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        String name = display.getFriendlyDisplayName();
305f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        IBinder displayToken = Surface.createDisplay(name);
306f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
307f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                refreshRate, deviceFlags, surface);
308f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
309a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
310a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        scheduleUpdateNotificationLocked();
311cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
312cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
313e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void handleDisconnectLocked() {
314f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mDisplayDevice != null) {
315f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mDisplayDevice.clearSurfaceLocked();
316f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
317f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mDisplayDevice = null;
318a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
319a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            scheduleUpdateNotificationLocked();
320cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
321cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
322cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
323e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void scheduleStatusChangedBroadcastLocked() {
32489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mCurrentStatus = null;
325e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (!mPendingStatusChangeBroadcast) {
326e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mPendingStatusChangeBroadcast = true;
327a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mHandler.sendEmptyMessage(MSG_SEND_STATUS_CHANGE_BROADCAST);
328e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
329e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
330e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
331a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void scheduleUpdateNotificationLocked() {
332a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        if (!mPendingNotificationUpdate) {
333a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingNotificationUpdate = true;
334a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mHandler.sendEmptyMessage(MSG_UPDATE_NOTIFICATION);
335a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
336a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
337a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
338a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    // Runs on the handler.
339a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void handleSendStatusChangeBroadcast() {
340a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        final Intent intent;
341a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        synchronized (getSyncRoot()) {
342a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (!mPendingStatusChangeBroadcast) {
343a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                return;
344a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
345a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
346a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingStatusChangeBroadcast = false;
347a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
348a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
349a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
350a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    getWifiDisplayStatusLocked());
351a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
352e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
353a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        // Send protected broadcast about wifi display status to registered receivers.
354a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
355a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
356a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
357a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    // Runs on the handler.
358a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private void handleUpdateNotification() {
359a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        final boolean isConnected;
360a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        synchronized (getSyncRoot()) {
361a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (!mPendingNotificationUpdate) {
362a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                return;
363e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
364e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
365a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mPendingNotificationUpdate = false;
366a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            isConnected = (mDisplayDevice != null);
367a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
368a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
369a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        mNotificationManager.cancelAsUser(null,
370a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                R.string.wifi_display_notification_title, UserHandle.ALL);
371a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
372a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        if (isConnected) {
373a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Context context = getContext();
374a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
375a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Resources r = context.getResources();
376a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            Notification notification = new Notification.Builder(context)
377a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setContentTitle(r.getString(
378a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            R.string.wifi_display_notification_title))
379a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setContentText(r.getString(
380a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            R.string.wifi_display_notification_message))
381a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setContentIntent(mSettingsPendingIntent)
382a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setSmallIcon(R.drawable.ic_notify_wifidisplay)
383a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .setOngoing(true)
384a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .addAction(android.R.drawable.ic_menu_close_clear_cancel,
385a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            r.getString(R.string.wifi_display_notification_disconnect),
386a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                            mDisconnectPendingIntent)
387a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    .build();
388a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            mNotificationManager.notifyAsUser(null,
389a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    R.string.wifi_display_notification_title,
390a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    notification, UserHandle.ALL);
391a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
392a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
393a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
394a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
395a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        @Override
396a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public void onReceive(Context context, Intent intent) {
397a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            if (intent.getAction().equals(ACTION_DISCONNECT)) {
398a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                synchronized (getSyncRoot()) {
399a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    requestDisconnectLocked();
400a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                }
401a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
402e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
403e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    };
404e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
405cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final WifiDisplayController.Listener mWifiDisplayListener =
406cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            new WifiDisplayController.Listener() {
407cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
40889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        public void onFeatureStateChanged(int featureState) {
409e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
41089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                if (mFeatureState != featureState) {
41189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState = featureState;
412e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
413e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
414e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
415e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
416e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
417e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
418e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onScanStarted() {
419e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
420180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
421180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
422e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
423e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
424e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
425e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
426e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
4272444ae7e2b8658a4a90f996e678423558744b4a2Jeff Brown        @Override
42889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        public void onScanFinished(WifiDisplay[] availableDisplays) {
429e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
43089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
43189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        availableDisplays);
43289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
433180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING
43489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        || !Arrays.equals(mAvailableDisplays, availableDisplays)) {
435180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
43689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mAvailableDisplays = availableDisplays;
437e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
438e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
439e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
440e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
441e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
442e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
443e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnecting(WifiDisplay display) {
444e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
44589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
44689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
447180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
448180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
449180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
450180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
451180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
452e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
453e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
454e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
455e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
456e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
457e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
458e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnectionFailed() {
459e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
460180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
461180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
462180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
463180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
464e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
465e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
466e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
467e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
468e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
469e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
470f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        public void onDisplayConnected(WifiDisplay display, Surface surface,
471f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                int width, int height, int flags) {
472cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
47389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
474f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                handleConnectLocked(display, surface, width, height, flags);
475e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
476180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
477180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
478180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
479180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
480180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
481e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
482e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
483cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
484cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
485cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
486cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
487cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onDisplayDisconnected() {
488cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            // Stop listening.
489cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
490e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                handleDisconnectLocked();
491e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
492180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
493180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
494180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
495180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
496e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
497e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
498cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
499cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
500cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
501cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
502cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final class WifiDisplayDevice extends DisplayDevice {
503ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        private String mName;
504cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mWidth;
505cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mHeight;
506cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final float mRefreshRate;
507cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mFlags;
508cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
509cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private Surface mSurface;
510cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private DisplayDeviceInfo mInfo;
511cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
512cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public WifiDisplayDevice(IBinder displayToken, String name,
513cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                int width, int height, float refreshRate, int flags,
514cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Surface surface) {
515cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            super(WifiDisplayAdapter.this, displayToken);
516cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mName = name;
517cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWidth = width;
518cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mHeight = height;
519cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mRefreshRate = refreshRate;
520cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mFlags = flags;
521cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = surface;
522cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
523cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
524cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void clearSurfaceLocked() {
525cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = null;
526cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            sendTraversalRequestLocked();
527cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
528cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
529ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        public void setNameLocked(String name) {
530ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mName = name;
531ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown            mInfo = null;
532ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown        }
533ee4f029ff4905abbdbc1ce47db2cf2c3510949e9Jeff Brown
534cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
535cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void performTraversalInTransactionLocked() {
536cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            setSurfaceInTransactionLocked(mSurface);
537cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
538cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
539cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
540cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
541cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mInfo == null) {
542cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo = new DisplayDeviceInfo();
543cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.name = mName;
544cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.width = mWidth;
545cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.height = mHeight;
546cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.refreshRate = mRefreshRate;
547cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.flags = mFlags;
548d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown                mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
549cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
550cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
551cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return mInfo;
552cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
553cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
554a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
555a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    private final class WifiDisplayHandler extends Handler {
556a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public WifiDisplayHandler(Looper looper) {
557a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            super(looper, null, true /*async*/);
558a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
559a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
560a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        @Override
561a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        public void handleMessage(Message msg) {
562a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            switch (msg.what) {
563a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                case MSG_SEND_STATUS_CHANGE_BROADCAST:
564a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    handleSendStatusChangeBroadcast();
565a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    break;
566a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown
567a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                case MSG_UPDATE_NOTIFICATION:
568a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    handleUpdateNotification();
569a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown                    break;
570a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown            }
571a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown        }
572a7f9c966bc90e52baaf0cf0c165463e5f44354c5Jeff Brown    }
573cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
574