DisplayManagerGlobal.java revision 48d0d1886731ff19ed3fb47a5997be5df0d1bba8
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;
21a506a6ec94863a35acca9feb165db76ddac3892cJeff Brownimport android.os.Binder;
22bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.Handler;
23bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.IBinder;
24bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.Looper;
25bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.Message;
26bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.RemoteException;
27bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.ServiceManager;
28a506a6ec94863a35acca9feb165db76ddac3892cJeff Brownimport android.text.TextUtils;
29bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.util.Log;
30bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.util.SparseArray;
3148d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautnerimport android.view.DisplayAdjustments;
32bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.view.Display;
33bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.view.DisplayInfo;
34a506a6ec94863a35acca9feb165db76ddac3892cJeff Brownimport android.view.Surface;
35bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
36bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport java.util.ArrayList;
37bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
38bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown/**
39bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * Manager communication with the display manager service on behalf of
40bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * an application process.  You're probably looking for {@link DisplayManager}.
41bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown *
42bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * @hide
43bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown */
44bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownpublic final class DisplayManagerGlobal {
45bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final String TAG = "DisplayManager";
46bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final boolean DEBUG = false;
47bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
484ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // True if display info and display ids should be cached.
494ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    //
504ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // FIXME: The cache is currently disabled because it's unclear whether we have the
514ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // necessary guarantees that the caches will always be flushed before clients
524ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // attempt to observe their new state.  For example, depending on the order
534ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // in which the binder transactions take place, we might have a problem where
544ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // an application could start processing a configuration change due to a display
554ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // orientation change before the display info cache has actually been invalidated.
564ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    private static final boolean USE_CACHE = false;
574ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
58bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static final int EVENT_DISPLAY_ADDED = 1;
59bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static final int EVENT_DISPLAY_CHANGED = 2;
60bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static final int EVENT_DISPLAY_REMOVED = 3;
61bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
62bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static DisplayManagerGlobal sInstance;
63bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
64bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final Object mLock = new Object();
65bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
66bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final IDisplayManager mDm;
67bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
68bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private DisplayManagerCallback mCallback;
69bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
70bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            new ArrayList<DisplayListenerDelegate>();
71bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
72bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
73bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private int[] mDisplayIdCache;
74bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
75bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private DisplayManagerGlobal(IDisplayManager dm) {
76bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        mDm = dm;
77bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
78bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
79bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
80bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets an instance of the display manager global singleton.
81bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
82bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return The display manager instance, may be null early in system startup
83bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * before the display manager has been fully initialized.
84bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
85bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static DisplayManagerGlobal getInstance() {
86bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (DisplayManagerGlobal.class) {
87bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (sInstance == null) {
88bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
89bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                if (b != null) {
90bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
91bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
92bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
93bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return sInstance;
94bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
95bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
96bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
97bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
98bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Get information about a particular logical display.
99bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
100bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param displayId The logical display id.
101bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return Information about the specified display, or null if it does not exist.
102bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * This object belongs to an internal cache and should be treated as if it were immutable.
103bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
104bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public DisplayInfo getDisplayInfo(int displayId) {
105bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        try {
106bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            synchronized (mLock) {
1074ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                DisplayInfo info;
1084ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1094ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    info = mDisplayInfoCache.get(displayId);
1104ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    if (info != null) {
1114ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                        return info;
1124ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    }
113bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
114bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
115bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                info = mDm.getDisplayInfo(displayId);
116bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                if (info == null) {
117bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    return null;
118bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
1194ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
1204ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1214ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayInfoCache.put(displayId, info);
1224ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
1234ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                registerCallbackIfNeededLocked();
1244ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
125bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                if (DEBUG) {
126bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
127bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
128bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                return info;
129bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
130bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        } catch (RemoteException ex) {
131bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Log.e(TAG, "Could not get display information from display manager.", ex);
132bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return null;
133bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
134bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
135bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
136bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
137bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets all currently valid logical display ids.
138bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
139bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return An array containing all display ids.
140bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
141bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public int[] getDisplayIds() {
142bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        try {
143bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            synchronized (mLock) {
1444ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1454ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    if (mDisplayIdCache != null) {
1464ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                        return mDisplayIdCache;
1474ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    }
1484ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
1494ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
1504ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                int[] displayIds = mDm.getDisplayIds();
1514ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1524ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayIdCache = displayIds;
153bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
1544ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                registerCallbackIfNeededLocked();
1554ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                return displayIds;
156bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
157bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        } catch (RemoteException ex) {
158bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Log.e(TAG, "Could not get display ids from display manager.", ex);
159bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return new int[] { Display.DEFAULT_DISPLAY };
160bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
161bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
162bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
163bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
164bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets information about a logical display.
165bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
166bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * The display metrics may be adjusted to provide compatibility
16748d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * for legacy applications or limited screen areas.
168bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
169bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param displayId The logical display id.
17048d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * @param daj The compatibility info and activityToken.
171bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return The display object, or null if there is no display with the given id.
172bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
17348d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner    public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) {
174bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        DisplayInfo displayInfo = getDisplayInfo(displayId);
175bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (displayInfo == null) {
176bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return null;
177bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
17848d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner        return new Display(this, displayId, displayInfo, daj);
179bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
180bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
181bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
182bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets information about a logical display without applying any compatibility metrics.
183bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
184bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param displayId The logical display id.
185bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return The display object, or null if there is no display with the given id.
186bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
187bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public Display getRealDisplay(int displayId) {
18848d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner        return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
18948d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner    }
19048d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner
19148d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner    /**
19248d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * Gets information about a logical display without applying any compatibility metrics.
19348d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     *
19448d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * @param displayId The logical display id.
19548d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * @param IBinder the activity token for this display.
19648d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     * @return The display object, or null if there is no display with the given id.
19748d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner     */
19848d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner    public Display getRealDisplay(int displayId, IBinder token) {
19948d0d1886731ff19ed3fb47a5997be5df0d1bba8Craig Mautner        return getCompatibleDisplay(displayId, new DisplayAdjustments(token));
200bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
201bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
202bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public void registerDisplayListener(DisplayListener listener, Handler handler) {
203bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (listener == null) {
204bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            throw new IllegalArgumentException("listener must not be null");
205bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
206bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
207bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
208bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            int index = findDisplayListenerLocked(listener);
209bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (index < 0) {
210bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
211bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                registerCallbackIfNeededLocked();
212bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
213bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
214bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
215bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
216bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public void unregisterDisplayListener(DisplayListener listener) {
217bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (listener == null) {
218bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            throw new IllegalArgumentException("listener must not be null");
219bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
220bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
221bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
222bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            int index = findDisplayListenerLocked(listener);
223bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (index >= 0) {
224bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                DisplayListenerDelegate d = mDisplayListeners.get(index);
225bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                d.clearEvents();
226bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.remove(index);
227bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
228bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
229bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
230bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
231bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private int findDisplayListenerLocked(DisplayListener listener) {
232bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        final int numListeners = mDisplayListeners.size();
233bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        for (int i = 0; i < numListeners; i++) {
234bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (mDisplayListeners.get(i).mListener == listener) {
235bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                return i;
236bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
237bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
238bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        return -1;
239bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
240bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
241bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private void registerCallbackIfNeededLocked() {
242bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (mCallback == null) {
243bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            mCallback = new DisplayManagerCallback();
244bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            try {
245bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDm.registerCallback(mCallback);
246bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            } catch (RemoteException ex) {
247bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                Log.e(TAG, "Failed to register callback with display manager service.", ex);
248bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mCallback = null;
249bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
250bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
251bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
252bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
253bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private void handleDisplayEvent(int displayId, int event) {
254bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
2554ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            if (USE_CACHE) {
2564ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mDisplayInfoCache.remove(displayId);
257bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
2584ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
2594ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayIdCache = null;
2604ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
261bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
262bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
263bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            final int numListeners = mDisplayListeners.size();
264bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            for (int i = 0; i < numListeners; i++) {
265bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
266bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
267bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
268bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
269bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
270e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void scanWifiDisplays() {
271e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
272e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.scanWifiDisplays();
273e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
274e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to scan for Wifi displays.", ex);
275e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
276e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
277e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
278e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void connectWifiDisplay(String deviceAddress) {
279e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (deviceAddress == null) {
280e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
281e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
282e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
283e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
284e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.connectWifiDisplay(deviceAddress);
285e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
286e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
287e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
288e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
289e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
290e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void disconnectWifiDisplay() {
291e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
292e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.disconnectWifiDisplay();
293e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
294e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to disconnect from Wifi display.", ex);
295e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
296e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
297e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
29889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void renameWifiDisplay(String deviceAddress, String alias) {
29989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (deviceAddress == null) {
30089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
30189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
30289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
30389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        try {
30489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mDm.renameWifiDisplay(deviceAddress, alias);
30589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (RemoteException ex) {
30689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Log.e(TAG, "Failed to rename Wifi display " + deviceAddress
30789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown                    + " with alias " + alias + ".", ex);
30889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
30989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
31089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
31189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    public void forgetWifiDisplay(String deviceAddress) {
31289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        if (deviceAddress == null) {
31389d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
31489d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
31589d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
31689d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        try {
31789d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            mDm.forgetWifiDisplay(deviceAddress);
31889d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        } catch (RemoteException ex) {
31989d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown            Log.e(TAG, "Failed to forget Wifi display.", ex);
32089d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown        }
32189d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown    }
32289d5546d7fd3a3bb19820c42e8b4527013dd6545Jeff Brown
323e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatus() {
324e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
325e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            return mDm.getWifiDisplayStatus();
326e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
327e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to get Wifi display status.", ex);
328e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            return new WifiDisplayStatus();
329e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
330e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
331e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
332a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown    public VirtualDisplay createPrivateVirtualDisplay(Context context, String name,
333a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            int width, int height, int densityDpi, Surface surface) {
334a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (TextUtils.isEmpty(name)) {
335a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            throw new IllegalArgumentException("name must be non-null and non-empty");
336a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
337a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (width <= 0 || height <= 0 || densityDpi <= 0) {
338a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            throw new IllegalArgumentException("width, height, and densityDpi must be "
339a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown                    + "greater than 0");
340a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
341a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (surface == null) {
342a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            throw new IllegalArgumentException("surface must not be null");
343a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
344a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown
345a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        Binder token = new Binder();
346a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        int displayId;
347a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        try {
348a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            displayId = mDm.createPrivateVirtualDisplay(token, context.getPackageName(),
349a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown                    name, width, height, densityDpi, surface);
350a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        } catch (RemoteException ex) {
351a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            Log.e(TAG, "Could not create private virtual display: " + name, ex);
352a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            return null;
353a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
354a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (displayId < 0) {
355a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            Log.e(TAG, "Could not create private virtual display: " + name);
356a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            return null;
357a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
358a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        Display display = getRealDisplay(displayId);
359a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        if (display == null) {
360a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            Log.wtf(TAG, "Could not obtain display info for newly created "
361a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown                    + "private virtual display: " + name);
362a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            try {
363a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown                mDm.releaseVirtualDisplay(token);
364a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            } catch (RemoteException ex) {
365a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            }
366a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            return null;
367a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
368a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        return new VirtualDisplay(this, display, token);
369a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown    }
370a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown
371a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown    public void releaseVirtualDisplay(IBinder token) {
372a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        try {
373a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            mDm.releaseVirtualDisplay(token);
374a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        } catch (RemoteException ex) {
375a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown            Log.w(TAG, "Failed to release virtual display.", ex);
376a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown        }
377a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown    }
378a506a6ec94863a35acca9feb165db76ddac3892cJeff Brown
379bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
380bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        @Override
381bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void onDisplayEvent(int displayId, int event) {
382bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (DEBUG) {
383bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
384bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
385bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            handleDisplayEvent(displayId, event);
386bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
387bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
388bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
389bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final class DisplayListenerDelegate extends Handler {
390bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public final DisplayListener mListener;
391bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
392bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
393bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
394bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            mListener = listener;
395bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
396bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
397bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void sendDisplayEvent(int displayId, int event) {
398bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Message msg = obtainMessage(event, displayId, 0);
399bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            sendMessage(msg);
400bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
401bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
402bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void clearEvents() {
403bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            removeCallbacksAndMessages(null);
404bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
405bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
406bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        @Override
407bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void handleMessage(Message msg) {
408bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            switch (msg.what) {
409bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_ADDED:
410bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayAdded(msg.arg1);
411bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
412bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_CHANGED:
413bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayChanged(msg.arg1);
414bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
415bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_REMOVED:
416bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayRemoved(msg.arg1);
417bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
418bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
419bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
420bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
421bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown}
422