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;
20bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.hardware.display.DisplayManager.DisplayListener;
21c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.MediaProjection;
22c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wrightimport android.media.projection.IMediaProjection;
23a506a6ec94863a35acca9feb165db76ddac3892cJeff Brownimport android.os.Binder;
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
19548d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner    /**
19648d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * Gets information about a logical display without applying any compatibility metrics.
19748d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     *
19848d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * @param displayId The logical display id.
19948d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * @param IBinder the activity token for this display.
20048d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * @return The display object, or null if there is no display with the given id.
20148d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     */
20248d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner    public Display getRealDisplay(int displayId, IBinder token) {
20348d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner        return getCompatibleDisplay(displayId, new DisplayAdjustments(token));
204bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
205bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
206bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public void registerDisplayListener(DisplayListener listener, Handler handler) {
207bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (listener == null) {
208bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            throw new IllegalArgumentException("listener must not be null");
209bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
210bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
211bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
212bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            int index = findDisplayListenerLocked(listener);
213bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (index < 0) {
214bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
215bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                registerCallbackIfNeededLocked();
216bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
217bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
218bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
219bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
220bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public void unregisterDisplayListener(DisplayListener listener) {
221bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (listener == null) {
222bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            throw new IllegalArgumentException("listener must not be null");
223bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
224bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
225bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
226bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            int index = findDisplayListenerLocked(listener);
227bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (index >= 0) {
228bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                DisplayListenerDelegate d = mDisplayListeners.get(index);
229bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                d.clearEvents();
230bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.remove(index);
231bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
232bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
233bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
234bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
235bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private int findDisplayListenerLocked(DisplayListener listener) {
236bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        final int numListeners = mDisplayListeners.size();
237bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        for (int i = 0; i < numListeners; i++) {
238bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (mDisplayListeners.get(i).mListener == listener) {
239bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                return i;
240bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
241bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
242bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        return -1;
243bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
244bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
245bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private void registerCallbackIfNeededLocked() {
246bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (mCallback == null) {
247bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            mCallback = new DisplayManagerCallback();
248bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            try {
249bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDm.registerCallback(mCallback);
250bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            } catch (RemoteException ex) {
251bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                Log.e(TAG, "Failed to register callback with display manager service.", ex);
252bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mCallback = null;
253bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
254bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
255bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
256bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
257bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private void handleDisplayEvent(int displayId, int event) {
258bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
2594ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            if (USE_CACHE) {
2604ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mDisplayInfoCache.remove(displayId);
261bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
2624ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
2634ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayIdCache = null;
2644ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
265bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
266bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
267bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            final int numListeners = mDisplayListeners.size();
268bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            for (int i = 0; i < numListeners; i++) {
269bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
270bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
271bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
272bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
273bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
274ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void startWifiDisplayScan() {
275ce468a35b388ca46578934706b38dbae94941643Jeff Brown        synchronized (mLock) {
276ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (mWifiDisplayScanNestCount++ == 0) {
277ce468a35b388ca46578934706b38dbae94941643Jeff Brown                registerCallbackIfNeededLocked();
278ce468a35b388ca46578934706b38dbae94941643Jeff Brown                try {
279ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mDm.startWifiDisplayScan();
280ce468a35b388ca46578934706b38dbae94941643Jeff Brown                } catch (RemoteException ex) {
281ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Log.e(TAG, "Failed to scan for Wifi displays.", ex);
282ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
283ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
284ce468a35b388ca46578934706b38dbae94941643Jeff Brown        }
285ce468a35b388ca46578934706b38dbae94941643Jeff Brown    }
286ce468a35b388ca46578934706b38dbae94941643Jeff Brown
287ce468a35b388ca46578934706b38dbae94941643Jeff Brown    public void stopWifiDisplayScan() {
288ce468a35b388ca46578934706b38dbae94941643Jeff Brown        synchronized (mLock) {
289ce468a35b388ca46578934706b38dbae94941643Jeff Brown            if (--mWifiDisplayScanNestCount == 0) {
290ce468a35b388ca46578934706b38dbae94941643Jeff Brown                try {
291ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    mDm.stopWifiDisplayScan();
292ce468a35b388ca46578934706b38dbae94941643Jeff Brown                } catch (RemoteException ex) {
293ce468a35b388ca46578934706b38dbae94941643Jeff Brown                    Log.e(TAG, "Failed to scan for Wifi displays.", ex);
294ce468a35b388ca46578934706b38dbae94941643Jeff Brown                }
295ce468a35b388ca46578934706b38dbae94941643Jeff Brown            } else if (mWifiDisplayScanNestCount < 0) {
296ce468a35b388ca46578934706b38dbae94941643Jeff Brown                Log.wtf(TAG, "Wifi display scan nest count became negative: "
297ce468a35b388ca46578934706b38dbae94941643Jeff Brown                        + mWifiDisplayScanNestCount);
298ce468a35b388ca46578934706b38dbae94941643Jeff Brown                mWifiDisplayScanNestCount = 0;
299ce468a35b388ca46578934706b38dbae94941643Jeff Brown            }
300e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
301e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
302e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
303e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void connectWifiDisplay(String deviceAddress) {
304e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (deviceAddress == null) {
305e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
306e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
307e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
308e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
309e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.connectWifiDisplay(deviceAddress);
310e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
311e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
312e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
313e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
314e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
3151f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void pauseWifiDisplay() {
3161f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        try {
3171f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mDm.pauseWifiDisplay();
3181f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        } catch (RemoteException ex) {
3191f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            Log.e(TAG, "Failed to pause Wifi display.", ex);
3201f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
3211f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
3221f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
3231f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    public void resumeWifiDisplay() {
3241f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        try {
3251f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            mDm.resumeWifiDisplay();
3261f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        } catch (RemoteException ex) {
3271f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            Log.e(TAG, "Failed to resume Wifi display.", ex);
3281f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        }
3291f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
3301f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
331e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void disconnectWifiDisplay() {
332e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
333e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.disconnectWifiDisplay();
334e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
335e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to disconnect from Wifi display.", ex);
336e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
337e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
338e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
33989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void renameWifiDisplay(String deviceAddress, String alias) {
34089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (deviceAddress == null) {
34189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
34289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
34389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
34489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        try {
34589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mDm.renameWifiDisplay(deviceAddress, alias);
34689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (RemoteException ex) {
34789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Log.e(TAG, "Failed to rename Wifi display " + deviceAddress
34889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    + " with alias " + alias + ".", ex);
34989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
35089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
35189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
35289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void forgetWifiDisplay(String deviceAddress) {
35389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (deviceAddress == null) {
35489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
35589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
35689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
35789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        try {
35889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mDm.forgetWifiDisplay(deviceAddress);
35989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (RemoteException ex) {
36089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Log.e(TAG, "Failed to forget Wifi display.", ex);
36189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
36289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
36389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
364e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatus() {
365e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
366e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            return mDm.getWifiDisplayStatus();
367e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
368e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to get Wifi display status.", ex);
369e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            return new WifiDisplayStatus();
370e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
371e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
372e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
373c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
374c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            String name, int width, int height, int densityDpi, Surface surface, int flags,
37575ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright            VirtualDisplay.Callback callback, Handler handler) {
376a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (TextUtils.isEmpty(name)) {
377a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            throw new IllegalArgumentException("name must be non-null and non-empty");
378a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
379a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (width <= 0 || height <= 0 || densityDpi <= 0) {
380a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            throw new IllegalArgumentException("width, height, and densityDpi must be "
381a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown                    + "greater than 0");
382a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
383a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown
38475ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
385c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
386a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        int displayId;
387a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        try {
388c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken,
389c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    context.getPackageName(), name, width, height, densityDpi, surface, flags);
390a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        } catch (RemoteException ex) {
3917d00affce6e25b22fd8fc135933b3bf6b547a0dcJeff Brown            Log.e(TAG, "Could not create virtual display: " + name, ex);
392a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            return null;
393a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
394a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (displayId < 0) {
3957d00affce6e25b22fd8fc135933b3bf6b547a0dcJeff Brown            Log.e(TAG, "Could not create virtual display: " + name);
396a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            return null;
397a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
398a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        Display display = getRealDisplay(displayId);
399a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (display == null) {
400a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            Log.wtf(TAG, "Could not obtain display info for newly created "
4017d00affce6e25b22fd8fc135933b3bf6b547a0dcJeff Brown                    + "virtual display: " + name);
402a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            try {
403c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                mDm.releaseVirtualDisplay(callbackWrapper);
404a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            } catch (RemoteException ex) {
405a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            }
406a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            return null;
407a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
408c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        return new VirtualDisplay(this, display, callbackWrapper, surface);
40992207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown    }
41092207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown
41175ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
41292207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown        try {
41392207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown            mDm.setVirtualDisplaySurface(token, surface);
41492207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown        } catch (RemoteException ex) {
41592207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown            Log.w(TAG, "Failed to set virtual display surface.", ex);
41692207df753c27b094e9e0ca80d41bc0d54dc6bd5Jeff Brown        }
417a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown    }
418a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown
41975ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    public void resizeVirtualDisplay(IVirtualDisplayCallback token,
42001e840ff9441e005153d799e71d65b38bcb21902Michael Wright            int width, int height, int densityDpi) {
42101e840ff9441e005153d799e71d65b38bcb21902Michael Wright        try {
42201e840ff9441e005153d799e71d65b38bcb21902Michael Wright            mDm.resizeVirtualDisplay(token, width, height, densityDpi);
42301e840ff9441e005153d799e71d65b38bcb21902Michael Wright        } catch (RemoteException ex) {
42401e840ff9441e005153d799e71d65b38bcb21902Michael Wright            Log.w(TAG, "Failed to resize virtual display.", ex);
42501e840ff9441e005153d799e71d65b38bcb21902Michael Wright        }
42601e840ff9441e005153d799e71d65b38bcb21902Michael Wright    }
42701e840ff9441e005153d799e71d65b38bcb21902Michael Wright
42875ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    public void releaseVirtualDisplay(IVirtualDisplayCallback token) {
429a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        try {
430a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            mDm.releaseVirtualDisplay(token);
431a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        } catch (RemoteException ex) {
432a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            Log.w(TAG, "Failed to release virtual display.", ex);
433a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
434a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown    }
435a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown
436bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
437bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        @Override
438bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void onDisplayEvent(int displayId, int event) {
439bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (DEBUG) {
440bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
441bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
442bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            handleDisplayEvent(displayId, event);
443bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
444bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
445bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
446bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final class DisplayListenerDelegate extends Handler {
447bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public final DisplayListener mListener;
448bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
449bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
450bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
451bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            mListener = listener;
452bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
453bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
454bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void sendDisplayEvent(int displayId, int event) {
455bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Message msg = obtainMessage(event, displayId, 0);
456bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            sendMessage(msg);
457bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
458bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
459bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void clearEvents() {
460bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            removeCallbacksAndMessages(null);
461bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
462bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
463bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        @Override
464bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void handleMessage(Message msg) {
465bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            switch (msg.what) {
466bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_ADDED:
467bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayAdded(msg.arg1);
468bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
469bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_CHANGED:
470bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayChanged(msg.arg1);
471bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
472bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_REMOVED:
473bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayRemoved(msg.arg1);
474bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
475bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
476bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
477bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
478c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
47975ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
48075ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        private VirtualDisplayCallbackDelegate mDelegate;
481c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
48275ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) {
48375ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright            if (callback != null) {
48475ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                mDelegate = new VirtualDisplayCallbackDelegate(callback, handler);
4853d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            }
486c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
487c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
488c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
48975ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public void onPaused() {
4903d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            if (mDelegate != null) {
49175ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED);
4923d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            }
493c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
494c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
495c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
49675ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public void onResumed() {
4973d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            if (mDelegate != null) {
49875ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED);
4993d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            }
500c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
501c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
502c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override // Binder call
50375ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public void onStopped() {
5043d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            if (mDelegate != null) {
50575ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED);
5063d0c57a1d3b8eb6bb54045c02c2e93a9313d3cf7Craig Mautner            }
507c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
508c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
509c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
51075ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright    private final static class VirtualDisplayCallbackDelegate extends Handler {
511c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public static final int MSG_DISPLAY_PAUSED = 0;
512c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public static final int MSG_DISPLAY_RESUMED = 1;
513c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public static final int MSG_DISPLAY_STOPPED = 2;
514c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
51575ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        private final VirtualDisplay.Callback mCallback;
516c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
51775ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright        public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback,
518c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                Handler handler) {
519c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
52075ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright            mCallback = callback;
521c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
522c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright
523c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        @Override
524c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        public void handleMessage(Message msg) {
525c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            switch (msg.what) {
526c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                case MSG_DISPLAY_PAUSED:
52775ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                    mCallback.onPaused();
528c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    break;
529c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                case MSG_DISPLAY_RESUMED:
53075ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                    mCallback.onResumed();
531c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    break;
532c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                case MSG_DISPLAY_STOPPED:
53375ee9fcde4d9e1be3883eba6c8d193db4375b052Michael Wright                    mCallback.onStopped();
534c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright                    break;
535c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright            }
536c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright        }
537c39d47a8e7c74bd539104b0efab898ef6fc43ddfMichael Wright    }
538bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown}
539