WifiDisplayAdapter.java revision 89d5546d7fd3a3bb19820c42e8b4527013dd6545
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
19cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport com.android.internal.util.DumpUtils;
20cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport com.android.internal.util.IndentingPrintWriter;
21cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
22cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.content.Context;
23e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.content.Intent;
24e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.DisplayManager;
25e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.WifiDisplay;
26e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport android.hardware.display.WifiDisplayStatus;
27cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.media.RemoteDisplay;
28cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.Handler;
29cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.os.IBinder;
30cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport android.view.Surface;
31cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
32cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownimport java.io.PrintWriter;
33e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brownimport java.util.Arrays;
34cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
35cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/**
36cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Connects to Wifi displays that implement the Miracast protocol.
37cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * <p>
38cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * The Wifi display protocol relies on Wifi direct for discovering and pairing
39cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * with the display.  Once connected, the Media Server opens an RTSP socket and accepts
40cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * a connection from the display.  After session negotiation, the Media Server
41cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * streams encoded buffers to the display.
42cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
43cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * This class is responsible for connecting to Wifi displays and mediating
44cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * the interactions between Media Server, Surface Flinger and the Display Manager Service.
45cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p><p>
46cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
47cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * </p>
48cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
49cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownfinal class WifiDisplayAdapter extends DisplayAdapter {
50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private static final String TAG = "WifiDisplayAdapter";
51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
5289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private PersistentDataStore mPersistentDataStore;
5389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private WifiDisplayController mDisplayController;
55f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private WifiDisplayDevice mDisplayDevice;
56cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
57e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private WifiDisplayStatus mCurrentStatus;
5889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private int mFeatureState;
59180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mScanState;
60180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private int mActiveDisplayState;
61180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown    private WifiDisplay mActiveDisplay;
6289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
6389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
64e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
65e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private boolean mPendingStatusChangeBroadcast;
66e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
6889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Context context, Handler handler, Listener listener,
6989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            PersistentDataStore persistentDataStore) {
70cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super(syncRoot, context, handler, listener, TAG);
7189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mPersistentDataStore = persistentDataStore;
72cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
73cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
74cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
75cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void dumpLocked(PrintWriter pw) {
76cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.dumpLocked(pw);
77cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
78e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
7989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mFeatureState=" + mFeatureState);
80180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mScanState=" + mScanState);
81180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplayState=" + mActiveDisplayState);
82180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown        pw.println("mActiveDisplay=" + mActiveDisplay);
8389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
8489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
85e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
86e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
87cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        // Try to dump the controller state.
88cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (mDisplayController == null) {
89cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController=null");
90cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        } else {
91cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            pw.println("mDisplayController:");
92cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
93cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            ipw.increaseIndent();
94cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200);
95cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
96cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
97cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
98cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    @Override
99cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    public void registerLocked() {
100cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        super.registerLocked();
101cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
10289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        updateRememberedDisplaysLocked();
10389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
104cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        getHandler().post(new Runnable() {
105cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            @Override
106cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            public void run() {
107cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mDisplayController = new WifiDisplayController(
108cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                        getContext(), getHandler(), mWifiDisplayListener);
109cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
110cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        });
111cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
112cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
113e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestScanLocked() {
114e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
115e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
116e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
117e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
118e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestScan();
119e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
120e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
121e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
122e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
123e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
124e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestConnectLocked(final String address) {
125e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
126e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
127e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
128e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
129e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestConnect(address);
130e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
131e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
132e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
133e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
134e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
135e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void requestDisconnectLocked() {
136e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        getHandler().post(new Runnable() {
137e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            @Override
138e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            public void run() {
139e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (mDisplayController != null) {
140e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    mDisplayController.requestDisconnect();
141e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
142e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
143e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        });
144e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
145e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
14689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestRenameLocked(String address, String alias) {
14789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (alias != null) {
14889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            alias = alias.trim();
14989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            if (alias.isEmpty()) {
15089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                alias = null;
15189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            }
15289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
15389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
15489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.renameWifiDisplay(address, alias)) {
15589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
15689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
15789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
15889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
15989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
16089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
16189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void requestForgetLocked(String address) {
16289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.forgetWifiDisplay(address)) {
16389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
16489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
16589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
16689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
16789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
16889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
16989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            requestDisconnectLocked();
17089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
17189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
17289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
173e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatusLocked() {
174e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (mCurrentStatus == null) {
17589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mCurrentStatus = new WifiDisplayStatus(
17689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState, mScanState, mActiveDisplayState,
17789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mActiveDisplay, mAvailableDisplays, mRememberedDisplays);
178e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
179e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        return mCurrentStatus;
180e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
181cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
18289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    private void updateRememberedDisplaysLocked() {
18389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
18489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
18589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
18689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
18789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
188f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown    private void handleConnectLocked(WifiDisplay display,
189f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            Surface surface, int width, int height, int flags) {
190e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        handleDisconnectLocked();
191e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
19289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (mPersistentDataStore.rememberWifiDisplay(display)) {
19389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mPersistentDataStore.saveIfNeeded();
19489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            updateRememberedDisplaysLocked();
19589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            scheduleStatusChangedBroadcastLocked();
19689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
19789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
198f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        int deviceFlags = 0;
199f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
200c5df37c285221d0fb113f55b9e78b35632241d3fJeff Brown            deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT;
201f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        }
202f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
203f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        float refreshRate = 60.0f; // TODO: get this for real
204f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown
20589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        String name = display.getFriendlyDisplayName();
206f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        IBinder displayToken = Surface.createDisplay(name);
207f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
208f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                refreshRate, deviceFlags, surface);
209f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
210cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
211cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
212e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void handleDisconnectLocked() {
213f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        if (mDisplayDevice != null) {
214f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mDisplayDevice.clearSurfaceLocked();
215f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
216f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown            mDisplayDevice = null;
217cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
218cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
219cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
220e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private void scheduleStatusChangedBroadcastLocked() {
22189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        mCurrentStatus = null;
222e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (!mPendingStatusChangeBroadcast) {
223e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mPendingStatusChangeBroadcast = true;
224e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            getHandler().post(mStatusChangeBroadcast);
225e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
226e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
227e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
228e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    private final Runnable mStatusChangeBroadcast = new Runnable() {
229e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
230e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void run() {
231e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            final Intent intent;
232e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
233e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                if (!mPendingStatusChangeBroadcast) {
234e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    return;
235e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
236e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
237e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                mPendingStatusChangeBroadcast = false;
238e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
239e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
240e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
241e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                        getWifiDisplayStatusLocked());
242e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
243e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
244e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            // Send protected broadcast about wifi display status to receivers that
245e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            // have the required permission.
246e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            getContext().sendBroadcast(intent,
247e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    android.Manifest.permission.CONFIGURE_WIFI_DISPLAY);
248e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
249e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    };
250e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
251cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final WifiDisplayController.Listener mWifiDisplayListener =
252cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            new WifiDisplayController.Listener() {
253cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
25489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        public void onFeatureStateChanged(int featureState) {
255e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
25689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                if (mFeatureState != featureState) {
25789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mFeatureState = featureState;
258e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
259e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
260e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
261e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
262e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
263e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
264e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onScanStarted() {
265e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
266180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
267180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
268e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
269e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
270e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
271e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
272e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
27389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        public void onScanFinished(WifiDisplay[] availableDisplays) {
274e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
27589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
27689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        availableDisplays);
27789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
278180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING
27989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                        || !Arrays.equals(mAvailableDisplays, availableDisplays)) {
280180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
28189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    mAvailableDisplays = availableDisplays;
282e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
283e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
284e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
285e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
286e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
287e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
288e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnecting(WifiDisplay display) {
289e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
29089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
29189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
292180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
293180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
294180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
295180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
296180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
297e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
298e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
299e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
300e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
301e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
302e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
303e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        public void onDisplayConnectionFailed() {
304e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            synchronized (getSyncRoot()) {
305180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
306180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
307180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
308180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
309e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
310e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
311e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            }
312e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
313e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
314e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        @Override
315f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown        public void onDisplayConnected(WifiDisplay display, Surface surface,
316f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                int width, int height, int flags) {
317cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
31889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                display = mPersistentDataStore.applyWifiDisplayAlias(display);
319f8f0eddd07d22ab815d97dd32ae6ed52dc31a80cJeff Brown                handleConnectLocked(display, surface, width, height, flags);
320e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
321180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
322180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay == null
323180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || !mActiveDisplay.equals(display)) {
324180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
325180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = display;
326e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
327e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
328cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
329cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
330cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
331cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
332cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void onDisplayDisconnected() {
333cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            // Stop listening.
334cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            synchronized (getSyncRoot()) {
335e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                handleDisconnectLocked();
336e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
337180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
338180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                        || mActiveDisplay != null) {
339180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
340180bbc71810496e280e9993177bfeddb3ad1f558Jeff Brown                    mActiveDisplay = null;
341e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                    scheduleStatusChangedBroadcastLocked();
342e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown                }
343cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
344cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
345cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    };
346cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
347cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    private final class WifiDisplayDevice extends DisplayDevice {
348cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final String mName;
349cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mWidth;
350cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mHeight;
351cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final float mRefreshRate;
352cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private final int mFlags;
353cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
354cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private Surface mSurface;
355cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        private DisplayDeviceInfo mInfo;
356cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
357cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public WifiDisplayDevice(IBinder displayToken, String name,
358cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                int width, int height, float refreshRate, int flags,
359cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                Surface surface) {
360cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            super(WifiDisplayAdapter.this, displayToken);
361cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mName = name;
362cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mWidth = width;
363cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mHeight = height;
364cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mRefreshRate = refreshRate;
365cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mFlags = flags;
366cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = surface;
367cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
368cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
369cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void clearSurfaceLocked() {
370cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mSurface = null;
371cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            sendTraversalRequestLocked();
372cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
373cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
374cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
375cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public void performTraversalInTransactionLocked() {
376cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            setSurfaceInTransactionLocked(mSurface);
377cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
378cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
379cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        @Override
380cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
381cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            if (mInfo == null) {
382cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo = new DisplayDeviceInfo();
383cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.name = mName;
384cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.width = mWidth;
385cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.height = mHeight;
386cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.refreshRate = mRefreshRate;
387cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.flags = mFlags;
388d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown                mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
389cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
390cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            }
391cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return mInfo;
392cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
393cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
394cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
395