/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.display; import android.content.Context; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.SparseArray; import android.view.CompatibilityInfoHolder; import android.view.Display; import android.view.DisplayInfo; import java.util.ArrayList; /** * Manager communication with the display manager service on behalf of * an application process. You're probably looking for {@link DisplayManager}. * * @hide */ public final class DisplayManagerGlobal { private static final String TAG = "DisplayManager"; private static final boolean DEBUG = false; public static final int EVENT_DISPLAY_ADDED = 1; public static final int EVENT_DISPLAY_CHANGED = 2; public static final int EVENT_DISPLAY_REMOVED = 3; private static DisplayManagerGlobal sInstance; private final Object mLock = new Object(); private final IDisplayManager mDm; private DisplayManagerCallback mCallback; private final ArrayList mDisplayListeners = new ArrayList(); private final SparseArray mDisplayInfoCache = new SparseArray(); private int[] mDisplayIdCache; private DisplayManagerGlobal(IDisplayManager dm) { mDm = dm; } /** * Gets an instance of the display manager global singleton. * * @return The display manager instance, may be null early in system startup * before the display manager has been fully initialized. */ public static DisplayManagerGlobal getInstance() { synchronized (DisplayManagerGlobal.class) { if (sInstance == null) { IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE); if (b != null) { sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b)); } } return sInstance; } } /** * Get information about a particular logical display. * * @param displayId The logical display id. * @return Information about the specified display, or null if it does not exist. * This object belongs to an internal cache and should be treated as if it were immutable. */ public DisplayInfo getDisplayInfo(int displayId) { try { synchronized (mLock) { DisplayInfo info = mDisplayInfoCache.get(displayId); if (info != null) { return info; } info = mDm.getDisplayInfo(displayId); if (info == null) { return null; } if (DEBUG) { Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info); } mDisplayInfoCache.put(displayId, info); registerCallbackIfNeededLocked(); return info; } } catch (RemoteException ex) { Log.e(TAG, "Could not get display information from display manager.", ex); return null; } } /** * Gets all currently valid logical display ids. * * @return An array containing all display ids. */ public int[] getDisplayIds() { try { synchronized (mLock) { if (mDisplayIdCache == null) { mDisplayIdCache = mDm.getDisplayIds(); registerCallbackIfNeededLocked(); } return mDisplayIdCache; } } catch (RemoteException ex) { Log.e(TAG, "Could not get display ids from display manager.", ex); return new int[] { Display.DEFAULT_DISPLAY }; } } /** * Gets information about a logical display. * * The display metrics may be adjusted to provide compatibility * for legacy applications. * * @param displayId The logical display id. * @param cih The compatibility info, or null if none is required. * @return The display object, or null if there is no display with the given id. */ public Display getCompatibleDisplay(int displayId, CompatibilityInfoHolder cih) { DisplayInfo displayInfo = getDisplayInfo(displayId); if (displayInfo == null) { return null; } return new Display(this, displayId, displayInfo, cih); } /** * Gets information about a logical display without applying any compatibility metrics. * * @param displayId The logical display id. * @return The display object, or null if there is no display with the given id. */ public Display getRealDisplay(int displayId) { return getCompatibleDisplay(displayId, null); } public void registerDisplayListener(DisplayListener listener, Handler handler) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } synchronized (mLock) { int index = findDisplayListenerLocked(listener); if (index < 0) { mDisplayListeners.add(new DisplayListenerDelegate(listener, handler)); registerCallbackIfNeededLocked(); } } } public void unregisterDisplayListener(DisplayListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } synchronized (mLock) { int index = findDisplayListenerLocked(listener); if (index >= 0) { DisplayListenerDelegate d = mDisplayListeners.get(index); d.clearEvents(); mDisplayListeners.remove(index); } } } private int findDisplayListenerLocked(DisplayListener listener) { final int numListeners = mDisplayListeners.size(); for (int i = 0; i < numListeners; i++) { if (mDisplayListeners.get(i).mListener == listener) { return i; } } return -1; } private void registerCallbackIfNeededLocked() { if (mCallback == null) { mCallback = new DisplayManagerCallback(); try { mDm.registerCallback(mCallback); } catch (RemoteException ex) { Log.e(TAG, "Failed to register callback with display manager service.", ex); mCallback = null; } } } private void handleDisplayEvent(int displayId, int event) { synchronized (mLock) { mDisplayInfoCache.remove(displayId); if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) { mDisplayIdCache = null; } final int numListeners = mDisplayListeners.size(); for (int i = 0; i < numListeners; i++) { mDisplayListeners.get(i).sendDisplayEvent(displayId, event); } } } private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub { @Override public void onDisplayEvent(int displayId, int event) { if (DEBUG) { Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event); } handleDisplayEvent(displayId, event); } } private static final class DisplayListenerDelegate extends Handler { public final DisplayListener mListener; public DisplayListenerDelegate(DisplayListener listener, Handler handler) { super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/); mListener = listener; } public void sendDisplayEvent(int displayId, int event) { Message msg = obtainMessage(event, displayId, 0); sendMessage(msg); } public void clearEvents() { removeCallbacksAndMessages(null); } @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_DISPLAY_ADDED: mListener.onDisplayAdded(msg.arg1); break; case EVENT_DISPLAY_CHANGED: mListener.onDisplayChanged(msg.arg1); break; case EVENT_DISPLAY_REMOVED: mListener.onDisplayRemoved(msg.arg1); break; } } } }