/*
* 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.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.view.CompatibilityInfoHolder;
import android.view.Display;
import android.view.DisplayInfo;
import java.util.ArrayList;
/**
* Manages the properties, media routing and power state of attached displays.
*
* Get an instance of this class by calling
* {@link android.content.Context#getSystemService(java.lang.String)
* Context.getSystemService()} with the argument
* {@link android.content.Context#DISPLAY_SERVICE}.
*
*/
public final class DisplayManager {
private static final String TAG = "DisplayManager";
private static final boolean DEBUG = false;
private static final int MSG_DISPLAY_ADDED = 1;
private static final int MSG_DISPLAY_REMOVED = 2;
private static final int MSG_DISPLAY_CHANGED = 3;
private static DisplayManager sInstance;
private final IDisplayManager mDm;
// Guarded by mDisplayLock
private final Object mDisplayLock = new Object();
private final ArrayList mDisplayListeners =
new ArrayList();
private DisplayManager(IDisplayManager dm) {
mDm = dm;
}
/**
* Gets an instance of the display manager.
*
* @return The display manager instance, may be null early in system startup
* before the display manager has been fully initialized.
*
* @hide
*/
public static DisplayManager getInstance() {
synchronized (DisplayManager.class) {
if (sInstance == null) {
IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
if (b != null) {
sInstance = new DisplayManager(IDisplayManager.Stub.asInterface(b));
}
}
return sInstance;
}
}
/**
* Get information about a particular logical display.
*
* @param displayId The logical display id.
* @param outInfo A structure to populate with the display info.
* @return True if the logical display exists, false otherwise.
* @hide
*/
public boolean getDisplayInfo(int displayId, DisplayInfo outInfo) {
try {
return mDm.getDisplayInfo(displayId, outInfo);
} catch (RemoteException ex) {
Log.e(TAG, "Could not get display information from display manager.", ex);
return false;
}
}
/**
* 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 applicationContext The application context from which to obtain
* compatible metrics.
* @return The display object.
*/
public Display getDisplay(int displayId, Context applicationContext) {
if (applicationContext == null) {
throw new IllegalArgumentException("applicationContext must not be null");
}
CompatibilityInfoHolder cih = null;
if (displayId == Display.DEFAULT_DISPLAY) {
cih = applicationContext.getCompatibilityInfo();
}
return getCompatibleDisplay(displayId, cih);
}
/**
* 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.
*
* @hide
*/
public Display getCompatibleDisplay(int displayId, CompatibilityInfoHolder cih) {
return new Display(displayId, cih);
}
/**
* Gets information about a logical display without applying any compatibility metrics.
*
* @param displayId The logical display id.
* @return The display object.
*
* @hide
*/
public Display getRealDisplay(int displayId) {
return getCompatibleDisplay(displayId, null);
}
/**
* Registers an display listener to receive notifications about when
* displays are added, removed or changed.
*
* @param listener The listener to register.
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
*
* @see #unregisterDisplayListener
*/
public void registerDisplayListener(DisplayListener listener, Handler handler) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
synchronized (mDisplayLock) {
int index = findDisplayListenerLocked(listener);
if (index < 0) {
mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
}
}
}
/**
* Unregisters an input device listener.
*
* @param listener The listener to unregister.
*
* @see #registerDisplayListener
*/
public void unregisterDisplayListener(DisplayListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
synchronized (mDisplayLock) {
int index = findDisplayListenerLocked(listener);
if (index >= 0) {
DisplayListenerDelegate d = mDisplayListeners.get(index);
d.removeCallbacksAndMessages(null);
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;
}
/**
* Listens for changes in available display devices.
*/
public interface DisplayListener {
/**
* Called whenever a logical display has been added to the system.
* Use {@link DisplayManager#getDisplay} to get more information about the display.
*
* @param displayId The id of the logical display that was added.
*/
void onDisplayAdded(int displayId);
/**
* Called whenever a logical display has been removed from the system.
*
* @param displayId The id of the logical display that was removed.
*/
void onDisplayRemoved(int displayId);
/**
* Called whenever the properties of a logical display have changed.
*
* @param displayId The id of the logical display that changed.
*/
void onDisplayChanged(int displayId);
}
private static final class DisplayListenerDelegate extends Handler {
public final DisplayListener mListener;
public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
super(handler != null ? handler.getLooper() : Looper.myLooper());
mListener = listener;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DISPLAY_ADDED:
mListener.onDisplayAdded(msg.arg1);
break;
case MSG_DISPLAY_REMOVED:
mListener.onDisplayRemoved(msg.arg1);
break;
case MSG_DISPLAY_CHANGED:
mListener.onDisplayChanged(msg.arg1);
break;
}
}
}
}