1bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown/*
2bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * Copyright (C) 2012 The Android Open Source Project
3bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown *
4bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * you may not use this file except in compliance with the License.
6bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * You may obtain a copy of the License at
7bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown *
8bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown *
10bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * Unless required by applicable law or agreed to in writing, software
11bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * See the License for the specific language governing permissions and
14bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * limitations under the License.
15bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown */
16bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
17bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownpackage android.hardware.display;
18bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
19bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.content.Context;
207c72668f19d404b01412abc67937b1b5c660df71Wale Ogunwaleimport android.content.res.Configuration;
21bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.hardware.display.DisplayManager.DisplayListener;
22c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.MediaProjection;
23c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.IMediaProjection;
24bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.Handler;
25bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.IBinder;
26bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.Looper;
27bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.Message;
28bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.RemoteException;
29bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.ServiceManager;
30a506a6ec94863a35acca9feb165db76ddac3892cJeff Brownimport android.text.TextUtils;
31bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.util.Log;
32bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.util.SparseArray;
3348d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautnerimport android.view.DisplayAdjustments;
34bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.view.Display;
35bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.view.DisplayInfo;
36a506a6ec94863a35acca9feb165db76ddac3892cJeff Brownimport android.view.Surface;
37bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
38bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport java.util.ArrayList;
39bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
40bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown/**
41bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * Manager communication with the display manager service on behalf of
42bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * an application process.  You're probably looking for {@link DisplayManager}.
43bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown *
44bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * @hide
45bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown */
46bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownpublic final class DisplayManagerGlobal {
47bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final String TAG = "DisplayManager";
48bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final boolean DEBUG = false;
49bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
504ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // True if display info and display ids should be cached.
514ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    //
524ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // FIXME: The cache is currently disabled because it's unclear whether we have the
534ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // necessary guarantees that the caches will always be flushed before clients
544ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // attempt to observe their new state.  For example, depending on the order
554ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // in which the binder transactions take place, we might have a problem where
564ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // an application could start processing a configuration change due to a display
574ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // orientation change before the display info cache has actually been invalidated.
584ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    private static final boolean USE_CACHE = false;
594ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
60bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static final int EVENT_DISPLAY_ADDED = 1;
61bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static final int EVENT_DISPLAY_CHANGED = 2;
62bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static final int EVENT_DISPLAY_REMOVED = 3;
63bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
64bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static DisplayManagerGlobal sInstance;
65bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
66bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final Object mLock = new Object();
67bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
68bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final IDisplayManager mDm;
69bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
70bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private DisplayManagerCallback mCallback;
71bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
72bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            new ArrayList<DisplayListenerDelegate>();
73bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
74bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
75bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private int[] mDisplayIdCache;
76bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
77ce468a35b388ca46578934706b38dbae94941643Jeff Brown    private int mWifiDisplayScanNestCount;
78ce468a35b388ca46578934706b38dbae94941643Jeff Brown
79bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private DisplayManagerGlobal(IDisplayManager dm) {
80bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        mDm = dm;
81bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
82bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
83bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
84bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets an instance of the display manager global singleton.
85bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
86bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return The display manager instance, may be null early in system startup
87bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * before the display manager has been fully initialized.
88bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
89bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static DisplayManagerGlobal getInstance() {
90bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (DisplayManagerGlobal.class) {
91bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (sInstance == null) {
92bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
93bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                if (b != null) {
94bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
95bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
96bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
97bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return sInstance;
98bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
99bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
100bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
101bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
102bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Get information about a particular logical display.
103bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
104bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param displayId The logical display id.
105bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return Information about the specified display, or null if it does not exist.
106bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * This object belongs to an internal cache and should be treated as if it were immutable.
107bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
108bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public DisplayInfo getDisplayInfo(int displayId) {
109bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        try {
110bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            synchronized (mLock) {
1114ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                DisplayInfo info;
1124ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1134ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    info = mDisplayInfoCache.get(displayId);
1144ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    if (info != null) {
1154ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                        return info;
1164ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    }
117bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
118bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
119bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                info = mDm.getDisplayInfo(displayId);
120bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                if (info == null) {
121bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    return null;
122bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
1234ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
1244ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1254ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayInfoCache.put(displayId, info);
1264ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
1274ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                registerCallbackIfNeededLocked();
1284ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
129bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                if (DEBUG) {
130bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
131bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
132bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                return info;
133bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
134bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        } catch (RemoteException ex) {
135bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Log.e(TAG, "Could not get display information from display manager.", ex);
136bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return null;
137bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
138bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
139bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
140bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
141bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets all currently valid logical display ids.
142bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
143bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return An array containing all display ids.
144bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
145bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public int[] getDisplayIds() {
146bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        try {
147bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            synchronized (mLock) {
1484ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1494ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    if (mDisplayIdCache != null) {
1504ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                        return mDisplayIdCache;
1514ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    }
1524ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
1534ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
1544ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                int[] displayIds = mDm.getDisplayIds();
1554ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1564ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayIdCache = displayIds;
157bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
1584ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                registerCallbackIfNeededLocked();
1594ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                return displayIds;
160bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
161bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        } catch (RemoteException ex) {
162bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Log.e(TAG, "Could not get display ids from display manager.", ex);
163bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return new int[] { Display.DEFAULT_DISPLAY };
164bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
165bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
166bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
167bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
168bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets information about a logical display.
169bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
170bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * The display metrics may be adjusted to provide compatibility
17148d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * for legacy applications or limited screen areas.
172bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
173bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param displayId The logical display id.
17448d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * @param daj The compatibility info and activityToken.
175bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return The display object, or null if there is no display with the given id.
176bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
17748d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner    public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) {
178bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        DisplayInfo displayInfo = getDisplayInfo(displayId);
179bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (displayInfo == null) {
180bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return null;
181bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
18248d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner        return new Display(this, displayId, displayInfo, daj);
183bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
184bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
185bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
186bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets information about a logical display without applying any compatibility metrics.
187bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
188bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param displayId The logical display id.
189bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return The display object, or null if there is no display with the given id.
190bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
191bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public Display getRealDisplay(int displayId) {
19248d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner        return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
19348d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner    }
19448d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner
195bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public void registerDisplayListener(DisplayListener listener, Handler handler) {
196bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (listener == null) {
197bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            throw new IllegalArgumentException("listener must not be null");
198bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
199bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
200bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
201bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            int index = findDisplayListenerLocked(listener);
202bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (index < 0) {
203bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
204bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                registerCallbackIfNeededLocked();
205bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
206bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
207bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
208bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
209bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public void unregisterDisplayListener(DisplayListener listener) {
210bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (listener == null) {
211bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            throw new IllegalArgumentException("listener must not be null");
212bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
213bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
214bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
215bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            int index = findDisplayListenerLocked(listener);
216bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (index >= 0) {
217bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                DisplayListenerDelegate d = mDisplayListeners.get(index);
218bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                d.clearEvents();
219bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.remove(index);
220bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
221bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
222bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
223bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
224bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private int findDisplayListenerLocked(DisplayListener listener) {
225bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        final int numListeners = mDisplayListeners.size();
226bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        for (int i = 0; i < numListeners; i++) {
227bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (mDisplayListeners.get(i).mListener == listener) {
228bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                return i;
229bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
230bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
231bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        return -1;
232bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
233bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
234bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private void registerCallbackIfNeededLocked() {
235bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (mCallback == null) {
236bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            mCallback = new DisplayManagerCallback();
237bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            try {
238bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDm.registerCallback(mCallback);
239bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            } catch (RemoteException ex) {
240bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                Log.e(TAG, "Failed to register callback with display manager service.", ex);
241bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mCallback = null;
242bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
243bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
244bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
245bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
246bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private void handleDisplayEvent(int displayId, int event) {
247bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
2484ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            if (USE_CACHE) {
2494ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mDisplayInfoCache.remove(displayId);
250bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
2514ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
2524ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayIdCache = null;
2534ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
254bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
255bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
256bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            final int numListeners = mDisplayListeners.size();
257bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            for (int i = 0; i < numListeners; i++) {
258bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
259bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
260bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
261bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
262bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
263ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void startWifiDisplayScan() {
264ce468a35b388ca46578934706b38dbae94941643Jeff Brown        synchronized (mLock) {
265ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (mWifiDisplayScanNestCount++ == 0) {
266ce468a35b388ca46578934706b38dbae94941643Jeff Brown                registerCallbackIfNeededLocked();
267ce468a35b388ca46578934706b38dbae94941643Jeff Brown                try {
268ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mDm.startWifiDisplayScan();
269ce468a35b388ca46578934706b38dbae94941643Jeff Brown                } catch (RemoteException ex) {
270ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Log.e(TAG, "Failed to scan for Wifi displays.", ex);
271ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
272ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
273ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
274ce468a35b388ca46578934706b38dbae94941643Jeff Brown    }
275ce468a35b388ca46578934706b38dbae94941643Jeff Brown
276ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void stopWifiDisplayScan() {
277ce468a35b388ca46578934706b38dbae94941643Jeff Brown        synchronized (mLock) {
278ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (--mWifiDisplayScanNestCount == 0) {
279ce468a35b388ca46578934706b38dbae94941643Jeff Brown                try {
280ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mDm.stopWifiDisplayScan();
281ce468a35b388ca46578934706b38dbae94941643Jeff Brown                } catch (RemoteException ex) {
282ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Log.e(TAG, "Failed to scan for Wifi displays.", ex);
283ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
284ce468a35b388ca46578934706b38dbae94941643Jeff Brown            } else if (mWifiDisplayScanNestCount < 0) {
285ce468a35b388ca46578934706b38dbae94941643Jeff Brown                Log.wtf(TAG, "Wifi display scan nest count became negative: "
286ce468a35b388ca46578934706b38dbae94941643Jeff Brown                        + mWifiDisplayScanNestCount);
287ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mWifiDisplayScanNestCount = 0;
288ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
289e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
290e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
291e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
292e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void connectWifiDisplay(String deviceAddress) {
293e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (deviceAddress == null) {
294e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
295e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
296e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
297e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
298e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.connectWifiDisplay(deviceAddress);
299e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
300e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
301e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
302e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
303e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
3041f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void pauseWifiDisplay() {
3051f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        try {
3061f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mDm.pauseWifiDisplay();
3071f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        } catch (RemoteException ex) {
3081f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            Log.e(TAG, "Failed to pause Wifi display.", ex);
3091f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
3101f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
3111f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
3121f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void resumeWifiDisplay() {
3131f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        try {
3141f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mDm.resumeWifiDisplay();
3151f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        } catch (RemoteException ex) {
3161f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            Log.e(TAG, "Failed to resume Wifi display.", ex);
3171f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
3181f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
3191f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
320e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void disconnectWifiDisplay() {
321e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
322e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.disconnectWifiDisplay();
323e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
324e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to disconnect from Wifi display.", ex);
325e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
326e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
327e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
32889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void renameWifiDisplay(String deviceAddress, String alias) {
32989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (deviceAddress == null) {
33089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
33189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
33289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
33389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        try {
33489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mDm.renameWifiDisplay(deviceAddress, alias);
33589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (RemoteException ex) {
33689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Log.e(TAG, "Failed to rename Wifi display " + deviceAddress
33789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    + " with alias " + alias + ".", ex);
33889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
33989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
34089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
34189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void forgetWifiDisplay(String deviceAddress) {
34289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (deviceAddress == null) {
34389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
34489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
34589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
34689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        try {
34789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mDm.forgetWifiDisplay(deviceAddress);
34889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (RemoteException ex) {
34989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Log.e(TAG, "Failed to forget Wifi display.", ex);
35089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
35189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
35289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
353e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatus() {
354e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
355e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            return mDm.getWifiDisplayStatus();
356e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
357e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to get Wifi display status.", ex);
358e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            return new WifiDisplayStatus();
359e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
360e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
361e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
36258e829f71d2c525309e5bb5a1c02dc64397df221Michael Wright    public void requestColorTransform(int displayId, int colorTransformId) {
36358e829f71d2c525309e5bb5a1c02dc64397df221Michael Wright        try {
36458e829f71d2c525309e5bb5a1c02dc64397df221Michael Wright            mDm.requestColorTransform(displayId, colorTransformId);
36558e829f71d2c525309e5bb5a1c02dc64397df221Michael Wright        } catch (RemoteException ex) {
36658e829f71d2c525309e5bb5a1c02dc64397df221Michael Wright            Log.e(TAG, "Failed to request color transform.", ex);
36758e829f71d2c525309e5bb5a1c02dc64397df221Michael Wright        }
36858e829f71d2c525309e5bb5a1c02dc64397df221Michael Wright    }
36958e829f71d2c525309e5bb5a1c02dc64397df221Michael Wright
370c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
371c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            String name, int width, int height, int densityDpi, Surface surface, int flags,
37275ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright            VirtualDisplay.Callback callback, Handler handler) {
373a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (TextUtils.isEmpty(name)) {
374a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            throw new IllegalArgumentException("name must be non-null and non-empty");
375a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
376a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (width <= 0 || height <= 0 || densityDpi <= 0) {
377a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            throw new IllegalArgumentException("width, height, and densityDpi must be "
378a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown                    + "greater than 0");
379a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
380a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown
38175ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
382c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
383a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        int displayId;
384a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        try {
385c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken,
386c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    context.getPackageName(), name, width, height, densityDpi, surface, flags);
387a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        } catch (RemoteException ex) {
3887d00affce6e25b22fd8fc135933b3bf6b547a0dcJeff Brown            Log.e(TAG, "Could not create virtual display: " + name, ex);
389a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            return null;
390a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
391a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (displayId < 0) {
3927d00affce6e25b22fd8fc135933b3bf6b547a0dcJeff Brown            Log.e(TAG, "Could not create virtual display: " + name);
393a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            return null;
394a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
395a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        Display display = getRealDisplay(displayId);
396a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (display == null) {
397a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            Log.wtf(TAG, "Could not obtain display info for newly created "
3987d00affce6e25b22fd8fc135933b3bf6b547a0dcJeff Brown                    + "virtual display: " + name);
399a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            try {
400c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                mDm.releaseVirtualDisplay(callbackWrapper);
401a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            } catch (RemoteException ex) {
402a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            }
403a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            return null;
404a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
405c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        return new VirtualDisplay(this, display, callbackWrapper, surface);
40692207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown    }
40792207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown
40875ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
40992207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown        try {
41092207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown            mDm.setVirtualDisplaySurface(token, surface);
41192207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown        } catch (RemoteException ex) {
41292207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown            Log.w(TAG, "Failed to set virtual display surface.", ex);
41392207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown        }
414a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown    }
415a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown
41675ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    public void resizeVirtualDisplay(IVirtualDisplayCallback token,
41701e840ff9441e005153d799e71d65b38bcb21902Michael Wright            int width, int height, int densityDpi) {
41801e840ff9441e005153d799e71d65b38bcb21902Michael Wright        try {
41901e840ff9441e005153d799e71d65b38bcb21902Michael Wright            mDm.resizeVirtualDisplay(token, width, height, densityDpi);
42001e840ff9441e005153d799e71d65b38bcb21902Michael Wright        } catch (RemoteException ex) {
42101e840ff9441e005153d799e71d65b38bcb21902Michael Wright            Log.w(TAG, "Failed to resize virtual display.", ex);
42201e840ff9441e005153d799e71d65b38bcb21902Michael Wright        }
42301e840ff9441e005153d799e71d65b38bcb21902Michael Wright    }
42401e840ff9441e005153d799e71d65b38bcb21902Michael Wright
42575ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    public void releaseVirtualDisplay(IVirtualDisplayCallback token) {
426a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        try {
427a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            mDm.releaseVirtualDisplay(token);
428a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        } catch (RemoteException ex) {
429a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            Log.w(TAG, "Failed to release virtual display.", ex);
430a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
431a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown    }
432a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown
433bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
434bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        @Override
435bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void onDisplayEvent(int displayId, int event) {
436bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (DEBUG) {
437bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
438bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
439bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            handleDisplayEvent(displayId, event);
440bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
441bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
442bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
443bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final class DisplayListenerDelegate extends Handler {
444bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public final DisplayListener mListener;
445bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
446bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
447bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
448bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            mListener = listener;
449bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
450bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
451bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void sendDisplayEvent(int displayId, int event) {
452bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Message msg = obtainMessage(event, displayId, 0);
453bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            sendMessage(msg);
454bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
455bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
456bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void clearEvents() {
457bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            removeCallbacksAndMessages(null);
458bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
459bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
460bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        @Override
461bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void handleMessage(Message msg) {
462bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            switch (msg.what) {
463bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_ADDED:
464bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayAdded(msg.arg1);
465bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
466bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_CHANGED:
467bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayChanged(msg.arg1);
468bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
469bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_REMOVED:
470bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayRemoved(msg.arg1);
471bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
472bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
473bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
474bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
475c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
47675ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
47775ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        private VirtualDisplayCallbackDelegate mDelegate;
478c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
47975ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) {
48075ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright            if (callback != null) {
48175ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                mDelegate = new VirtualDisplayCallbackDelegate(callback, handler);
4823d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            }
483c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
484c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
485c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
48675ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public void onPaused() {
4873d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            if (mDelegate != null) {
48875ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED);
4893d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            }
490c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
491c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
492c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
49375ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public void onResumed() {
4943d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            if (mDelegate != null) {
49575ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED);
4963d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            }
497c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
498c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
499c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
50075ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public void onStopped() {
5013d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            if (mDelegate != null) {
50275ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED);
5033d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            }
504c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
505c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
506c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
50775ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    private final static class VirtualDisplayCallbackDelegate extends Handler {
508c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public static final int MSG_DISPLAY_PAUSED = 0;
509c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public static final int MSG_DISPLAY_RESUMED = 1;
510c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public static final int MSG_DISPLAY_STOPPED = 2;
511c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
51275ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        private final VirtualDisplay.Callback mCallback;
513c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
51475ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback,
515c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                Handler handler) {
516c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
51775ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright            mCallback = callback;
518c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
519c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
520c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override
521c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public void handleMessage(Message msg) {
522c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            switch (msg.what) {
523c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                case MSG_DISPLAY_PAUSED:
52475ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                    mCallback.onPaused();
525c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    break;
526c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                case MSG_DISPLAY_RESUMED:
52775ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                    mCallback.onResumed();
528c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    break;
529c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                case MSG_DISPLAY_STOPPED:
53075ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                    mCallback.onStopped();
531c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    break;
532c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
533c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
534c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
535bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown}
536