DisplayManagerGlobal.java revision e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9
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;
21bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.Handler;
22bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.IBinder;
23bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.Looper;
24bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.Message;
25bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.RemoteException;
26bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.os.ServiceManager;
27bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.util.Log;
28bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.util.SparseArray;
29bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.view.CompatibilityInfoHolder;
30bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.view.Display;
31bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.view.DisplayInfo;
32bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
33bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport java.util.ArrayList;
34bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
35bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown/**
36bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * Manager communication with the display manager service on behalf of
37bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * an application process.  You're probably looking for {@link DisplayManager}.
38bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown *
39bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * @hide
40bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown */
41bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownpublic final class DisplayManagerGlobal {
42bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final String TAG = "DisplayManager";
43bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final boolean DEBUG = false;
44bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
454ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // True if display info and display ids should be cached.
464ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    //
474ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // FIXME: The cache is currently disabled because it's unclear whether we have the
484ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // necessary guarantees that the caches will always be flushed before clients
494ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // attempt to observe their new state.  For example, depending on the order
504ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // in which the binder transactions take place, we might have a problem where
514ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // an application could start processing a configuration change due to a display
524ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    // orientation change before the display info cache has actually been invalidated.
534ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    private static final boolean USE_CACHE = false;
544ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
55bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static final int EVENT_DISPLAY_ADDED = 1;
56bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static final int EVENT_DISPLAY_CHANGED = 2;
57bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static final int EVENT_DISPLAY_REMOVED = 3;
58bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
59bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static DisplayManagerGlobal sInstance;
60bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
61bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final Object mLock = new Object();
62bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
63bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final IDisplayManager mDm;
64bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
65bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private DisplayManagerCallback mCallback;
66bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
67bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            new ArrayList<DisplayListenerDelegate>();
68bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
69bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
70bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private int[] mDisplayIdCache;
71bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
72bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private DisplayManagerGlobal(IDisplayManager dm) {
73bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        mDm = dm;
74bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
75bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
76bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
77bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets an instance of the display manager global singleton.
78bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
79bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return The display manager instance, may be null early in system startup
80bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * before the display manager has been fully initialized.
81bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
82bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public static DisplayManagerGlobal getInstance() {
83bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (DisplayManagerGlobal.class) {
84bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (sInstance == null) {
85bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
86bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                if (b != null) {
87bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
88bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
89bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
90bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return sInstance;
91bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
92bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
93bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
94bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
95bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Get information about a particular logical display.
96bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
97bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param displayId The logical display id.
98bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return Information about the specified display, or null if it does not exist.
99bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * This object belongs to an internal cache and should be treated as if it were immutable.
100bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
101bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public DisplayInfo getDisplayInfo(int displayId) {
102bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        try {
103bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            synchronized (mLock) {
1044ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                DisplayInfo info;
1054ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1064ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    info = mDisplayInfoCache.get(displayId);
1074ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    if (info != null) {
1084ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                        return info;
1094ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    }
110bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
111bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
112bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                info = mDm.getDisplayInfo(displayId);
113bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                if (info == null) {
114bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    return null;
115bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
1164ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
1174ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1184ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayInfoCache.put(displayId, info);
1194ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
1204ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                registerCallbackIfNeededLocked();
1214ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
122bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                if (DEBUG) {
123bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
124bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
125bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                return info;
126bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
127bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        } catch (RemoteException ex) {
128bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Log.e(TAG, "Could not get display information from display manager.", ex);
129bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return null;
130bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
131bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
132bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
133bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
134bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets all currently valid logical display ids.
135bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
136bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return An array containing all display ids.
137bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
138bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public int[] getDisplayIds() {
139bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        try {
140bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            synchronized (mLock) {
1414ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1424ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    if (mDisplayIdCache != null) {
1434ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                        return mDisplayIdCache;
1444ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    }
1454ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
1464ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
1474ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                int[] displayIds = mDm.getDisplayIds();
1484ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (USE_CACHE) {
1494ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayIdCache = displayIds;
150bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                }
1514ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                registerCallbackIfNeededLocked();
1524ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                return displayIds;
153bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
154bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        } catch (RemoteException ex) {
155bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Log.e(TAG, "Could not get display ids from display manager.", ex);
156bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return new int[] { Display.DEFAULT_DISPLAY };
157bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
158bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
159bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
160bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
161bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets information about a logical display.
162bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
163bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * The display metrics may be adjusted to provide compatibility
164bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * for legacy applications.
165bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
166bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param displayId The logical display id.
167bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param cih The compatibility info, or null if none is required.
168bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return The display object, or null if there is no display with the given id.
169bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
170bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public Display getCompatibleDisplay(int displayId, CompatibilityInfoHolder cih) {
171bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        DisplayInfo displayInfo = getDisplayInfo(displayId);
172bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (displayInfo == null) {
173bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            return null;
174bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
175bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        return new Display(this, displayId, displayInfo, cih);
176bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
177bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
178bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    /**
179bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * Gets information about a logical display without applying any compatibility metrics.
180bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     *
181bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @param displayId The logical display id.
182bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     * @return The display object, or null if there is no display with the given id.
183bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown     */
184bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public Display getRealDisplay(int displayId) {
185bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        return getCompatibleDisplay(displayId, null);
186bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
187bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
188bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public void registerDisplayListener(DisplayListener listener, Handler handler) {
189bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (listener == null) {
190bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            throw new IllegalArgumentException("listener must not be null");
191bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
192bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
193bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
194bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            int index = findDisplayListenerLocked(listener);
195bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (index < 0) {
196bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
197bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                registerCallbackIfNeededLocked();
198bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
199bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
200bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
201bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
202bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    public void unregisterDisplayListener(DisplayListener listener) {
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                DisplayListenerDelegate d = mDisplayListeners.get(index);
211bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                d.clearEvents();
212bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.remove(index);
213bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
214bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
215bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
216bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
217bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private int findDisplayListenerLocked(DisplayListener listener) {
218bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        final int numListeners = mDisplayListeners.size();
219bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        for (int i = 0; i < numListeners; i++) {
220bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (mDisplayListeners.get(i).mListener == listener) {
221bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                return i;
222bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
223bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
224bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        return -1;
225bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
226bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
227bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private void registerCallbackIfNeededLocked() {
228bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        if (mCallback == null) {
229bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            mCallback = new DisplayManagerCallback();
230bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            try {
231bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDm.registerCallback(mCallback);
232bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            } catch (RemoteException ex) {
233bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                Log.e(TAG, "Failed to register callback with display manager service.", ex);
234bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mCallback = null;
235bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
236bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
237bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
238bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
239bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private void handleDisplayEvent(int displayId, int event) {
240bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        synchronized (mLock) {
2414ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            if (USE_CACHE) {
2424ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mDisplayInfoCache.remove(displayId);
243bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
2444ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
2454ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDisplayIdCache = null;
2464ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
247bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
248bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
249bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            final int numListeners = mDisplayListeners.size();
250bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            for (int i = 0; i < numListeners; i++) {
251bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
252bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
253bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
254bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
255bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
256e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void scanWifiDisplays() {
257e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
258e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.scanWifiDisplays();
259e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
260e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to scan for Wifi displays.", ex);
261e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
262e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
263e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
264e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void connectWifiDisplay(String deviceAddress) {
265e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        if (deviceAddress == null) {
266e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            throw new IllegalArgumentException("deviceAddress must not be null");
267e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
268e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
269e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
270e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.connectWifiDisplay(deviceAddress);
271e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
272e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
273e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
274e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
275e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
276e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public void disconnectWifiDisplay() {
277e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
278e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            mDm.disconnectWifiDisplay();
279e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
280e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to disconnect from Wifi display.", ex);
281e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
282e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
283e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
284e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    public WifiDisplayStatus getWifiDisplayStatus() {
285e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        try {
286e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            return mDm.getWifiDisplayStatus();
287e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        } catch (RemoteException ex) {
288e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            Log.e(TAG, "Failed to get Wifi display status.", ex);
289e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown            return new WifiDisplayStatus();
290e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown        }
291e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown    }
292e08ae388d63c4db8f9d9a7ecd634f9a51f6e91b9Jeff Brown
293bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
294bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        @Override
295bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void onDisplayEvent(int displayId, int event) {
296bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            if (DEBUG) {
297bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
298bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
299bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            handleDisplayEvent(displayId, event);
300bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
301bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
302bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
303bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final class DisplayListenerDelegate extends Handler {
304bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public final DisplayListener mListener;
305bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
306bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
307bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
308bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            mListener = listener;
309bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
310bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
311bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void sendDisplayEvent(int displayId, int event) {
312bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            Message msg = obtainMessage(event, displayId, 0);
313bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            sendMessage(msg);
314bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
315bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
316bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void clearEvents() {
317bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            removeCallbacksAndMessages(null);
318bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
319bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
320bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        @Override
321bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        public void handleMessage(Message msg) {
322bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            switch (msg.what) {
323bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_ADDED:
324bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayAdded(msg.arg1);
325bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
326bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_CHANGED:
327bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayChanged(msg.arg1);
328bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
329bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                case EVENT_DISPLAY_REMOVED:
330bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    mListener.onDisplayRemoved(msg.arg1);
331bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                    break;
332bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
333bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        }
334bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
335bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown}
336