DisplayManager.java revision b47bbc3d80badb94229bc4ce7a2d5006faa9ef15
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.hardware.display;
18
19import android.content.Context;
20import android.os.Handler;
21import android.os.IBinder;
22import android.os.Looper;
23import android.os.Message;
24import android.os.RemoteException;
25import android.os.ServiceManager;
26import android.util.Log;
27import android.view.CompatibilityInfoHolder;
28import android.view.Display;
29import android.view.DisplayInfo;
30
31import java.util.ArrayList;
32
33/**
34 * Manages the properties, media routing and power state of attached displays.
35 * <p>
36 * Get an instance of this class by calling
37 * {@link android.content.Context#getSystemService(java.lang.String)
38 * Context.getSystemService()} with the argument
39 * {@link android.content.Context#DISPLAY_SERVICE}.
40 * </p>
41 */
42public final class DisplayManager {
43    private static final String TAG = "DisplayManager";
44    private static final boolean DEBUG = false;
45
46    private static final int MSG_DISPLAY_ADDED = 1;
47    private static final int MSG_DISPLAY_REMOVED = 2;
48    private static final int MSG_DISPLAY_CHANGED = 3;
49
50    private static DisplayManager sInstance;
51
52    private final IDisplayManager mDm;
53
54    // Guarded by mDisplayLock
55    private final Object mDisplayLock = new Object();
56    private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
57            new ArrayList<DisplayListenerDelegate>();
58
59
60    private DisplayManager(IDisplayManager dm) {
61        mDm = dm;
62    }
63
64    /**
65     * Gets an instance of the display manager.
66     *
67     * @return The display manager instance, may be null early in system startup
68     * before the display manager has been fully initialized.
69     *
70     * @hide
71     */
72    public static DisplayManager getInstance() {
73        synchronized (DisplayManager.class) {
74            if (sInstance == null) {
75                IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
76                if (b != null) {
77                    sInstance = new DisplayManager(IDisplayManager.Stub.asInterface(b));
78                }
79            }
80            return sInstance;
81        }
82    }
83
84    /**
85     * Get information about a particular logical display.
86     *
87     * @param displayId The logical display id.
88     * @param outInfo A structure to populate with the display info.
89     * @return True if the logical display exists, false otherwise.
90     * @hide
91     */
92    public boolean getDisplayInfo(int displayId, DisplayInfo outInfo) {
93        try {
94            return mDm.getDisplayInfo(displayId, outInfo);
95        } catch (RemoteException ex) {
96            Log.e(TAG, "Could not get display information from display manager.", ex);
97            return false;
98        }
99    }
100
101    /**
102     * Gets information about a logical display.
103     *
104     * The display metrics may be adjusted to provide compatibility
105     * for legacy applications.
106     *
107     * @param displayId The logical display id.
108     * @param applicationContext The application context from which to obtain
109     * compatible metrics.
110     * @return The display object.
111     */
112    public Display getDisplay(int displayId, Context applicationContext) {
113        if (applicationContext == null) {
114            throw new IllegalArgumentException("applicationContext must not be null");
115        }
116
117        CompatibilityInfoHolder cih = null;
118        if (displayId == Display.DEFAULT_DISPLAY) {
119            cih = applicationContext.getCompatibilityInfo();
120        }
121        return getCompatibleDisplay(displayId, cih);
122    }
123
124    /**
125     * Gets information about a logical display.
126     *
127     * The display metrics may be adjusted to provide compatibility
128     * for legacy applications.
129     *
130     * @param displayId The logical display id.
131     * @param cih The compatibility info, or null if none is required.
132     * @return The display object.
133     *
134     * @hide
135     */
136    public Display getCompatibleDisplay(int displayId, CompatibilityInfoHolder cih) {
137        return new Display(displayId, cih);
138    }
139
140    /**
141     * Gets information about a logical display without applying any compatibility metrics.
142     *
143     * @param displayId The logical display id.
144     * @return The display object.
145     *
146     * @hide
147     */
148    public Display getRealDisplay(int displayId) {
149        return getCompatibleDisplay(displayId, null);
150    }
151
152    /**
153     * Registers an display listener to receive notifications about when
154     * displays are added, removed or changed.
155     *
156     * @param listener The listener to register.
157     * @param handler The handler on which the listener should be invoked, or null
158     * if the listener should be invoked on the calling thread's looper.
159     *
160     * @see #unregisterDisplayListener
161     */
162    public void registerDisplayListener(DisplayListener listener, Handler handler) {
163        if (listener == null) {
164            throw new IllegalArgumentException("listener must not be null");
165        }
166
167        synchronized (mDisplayLock) {
168            int index = findDisplayListenerLocked(listener);
169            if (index < 0) {
170                mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
171            }
172        }
173    }
174
175    /**
176     * Unregisters an input device listener.
177     *
178     * @param listener The listener to unregister.
179     *
180     * @see #registerDisplayListener
181     */
182    public void unregisterDisplayListener(DisplayListener listener) {
183        if (listener == null) {
184            throw new IllegalArgumentException("listener must not be null");
185        }
186
187        synchronized (mDisplayLock) {
188            int index = findDisplayListenerLocked(listener);
189            if (index >= 0) {
190                DisplayListenerDelegate d = mDisplayListeners.get(index);
191                d.removeCallbacksAndMessages(null);
192                mDisplayListeners.remove(index);
193            }
194        }
195    }
196
197    private int findDisplayListenerLocked(DisplayListener listener) {
198        final int numListeners = mDisplayListeners.size();
199        for (int i = 0; i < numListeners; i++) {
200            if (mDisplayListeners.get(i).mListener == listener) {
201                return i;
202            }
203        }
204        return -1;
205    }
206
207    /**
208     * Listens for changes in available display devices.
209     */
210    public interface DisplayListener {
211        /**
212         * Called whenever a logical display has been added to the system.
213         * Use {@link DisplayManager#getDisplay} to get more information about the display.
214         *
215         * @param displayId The id of the logical display that was added.
216         */
217        void onDisplayAdded(int displayId);
218
219        /**
220         * Called whenever a logical display has been removed from the system.
221         *
222         * @param displayId The id of the logical display that was removed.
223         */
224        void onDisplayRemoved(int displayId);
225
226        /**
227         * Called whenever the properties of a logical display have changed.
228         *
229         * @param displayId The id of the logical display that changed.
230         */
231        void onDisplayChanged(int displayId);
232    }
233
234    private static final class DisplayListenerDelegate extends Handler {
235        public final DisplayListener mListener;
236
237        public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
238            super(handler != null ? handler.getLooper() : Looper.myLooper());
239            mListener = listener;
240        }
241
242        @Override
243        public void handleMessage(Message msg) {
244            switch (msg.what) {
245                case MSG_DISPLAY_ADDED:
246                    mListener.onDisplayAdded(msg.arg1);
247                    break;
248                case MSG_DISPLAY_REMOVED:
249                    mListener.onDisplayRemoved(msg.arg1);
250                    break;
251                case MSG_DISPLAY_CHANGED:
252                    mListener.onDisplayChanged(msg.arg1);
253                    break;
254            }
255        }
256    }
257}
258