/*
* Copyright (C) 2006 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.view;
import android.content.res.CompatibilityInfo;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Slog;
public class Display {
static final String TAG = "Display";
static final boolean DEBUG_COMPAT = false;
/**
* Specify the default Display
*/
public static final int DEFAULT_DISPLAY = 0;
/**
* Use {@link android.view.WindowManager#getDefaultDisplay()
* WindowManager.getDefaultDisplay()} to create a Display object.
* Display gives you access to some information about a particular display
* connected to the device.
*/
Display(int display, CompatibilityInfoHolder compatInfo) {
// initalize the statics when this class is first instansiated. This is
// done here instead of in the static block because Zygote
synchronized (sStaticInit) {
if (!sInitialized) {
nativeClassInit();
sInitialized = true;
}
}
mCompatibilityInfo = compatInfo != null ? compatInfo : new CompatibilityInfoHolder();
mDisplay = display;
init(display);
}
/** @hide */
public static void setCompatibilityInfo(CompatibilityInfo compatInfo) {
if (compatInfo != null && (compatInfo.isScalingRequired()
|| !compatInfo.supportsScreen())) {
sCompatibilityInfo = compatInfo;
} else {
sCompatibilityInfo = null;
}
}
/**
* Returns the index of this display. This is currently undefined; do
* not use.
*/
public int getDisplayId() {
return mDisplay;
}
/**
* Returns the number of displays connected to the device. This is
* currently undefined; do not use.
*/
native static int getDisplayCount();
/**
* Returns the raw size of the display, in pixels. Note that this
* should not generally be used for computing layouts, since
* a device will typically have screen decoration (such as a status bar)
* along the edges of the display that reduce the amount of application
* space available from the raw size returned here. This value is
* adjusted for you based on the current rotation of the display.
*/
public void getSize(Point outSize) {
getSizeInternal(outSize, true);
}
/**
* Returns the raw size of the display, in pixels. Note that this
* should not generally be used for computing layouts, since
* a device will typically have screen decoration (such as a status bar)
* along the edges of the display that reduce the amount of application
* space available from the raw size returned here. This value is
* adjusted for you based on the current rotation of the display.
*/
private void getSizeInternal(Point outSize, boolean doCompat) {
try {
IWindowManager wm = getWindowManager();
if (wm != null) {
wm.getDisplaySize(outSize);
CompatibilityInfo ci;
if (doCompat && (ci=mCompatibilityInfo.getIfNeeded()) != null) {
synchronized (mTmpMetrics) {
mTmpMetrics.unscaledWidthPixels = outSize.x;
mTmpMetrics.unscaledHeightPixels = outSize.y;
mTmpMetrics.density = mDensity;
ci.applyToDisplayMetrics(mTmpMetrics);
outSize.x = mTmpMetrics.widthPixels;
outSize.y = mTmpMetrics.heightPixels;
}
}
} else {
// This is just for boot-strapping, initializing the
// system process before the window manager is up.
outSize.y = getRealHeight();
}
if (DEBUG_COMPAT && doCompat) Slog.v(TAG, "Returning display size: " + outSize);
} catch (RemoteException e) {
Slog.w("Display", "Unable to get display size", e);
}
}
/**
* This is just easier for some parts of the framework.
*/
public void getRectSize(Rect outSize) {
synchronized (mTmpPoint) {
getSizeInternal(mTmpPoint, true);
outSize.set(0, 0, mTmpPoint.x, mTmpPoint.y);
}
}
/**
* Return the maximum screen size dimension that will happen. This is
* mostly for wallpapers.
* @hide
*/
public int getMaximumSizeDimension() {
try {
IWindowManager wm = getWindowManager();
return wm.getMaximumSizeDimension();
} catch (RemoteException e) {
Slog.w("Display", "Unable to get display maximum size dimension", e);
return 0;
}
}
/**
* @deprecated Use {@link #getSize(Point)} instead.
*/
@Deprecated
public int getWidth() {
synchronized (mTmpPoint) {
long now = SystemClock.uptimeMillis();
if (now > (mLastGetTime+20)) {
getSizeInternal(mTmpPoint, true);
mLastGetTime = now;
}
return mTmpPoint.x;
}
}
/**
* @deprecated Use {@link #getSize(Point)} instead.
*/
@Deprecated
public int getHeight() {
synchronized (mTmpPoint) {
long now = SystemClock.uptimeMillis();
if (now > (mLastGetTime+20)) {
getSizeInternal(mTmpPoint, true);
mLastGetTime = now;
}
return mTmpPoint.y;
}
}
/** @hide Returns the actual screen size, not including any decor. */
native public int getRealWidth();
/** @hide Returns the actual screen size, not including any decor. */
native public int getRealHeight();
/** @hide special for when we are faking the screen size. */
native public int getRawWidth();
/** @hide special for when we are faking the screen size. */
native public int getRawHeight();
/**
* Returns the rotation of the screen from its "natural" orientation.
* The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
* (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
* {@link Surface#ROTATION_180 Surface.ROTATION_180}, or
* {@link Surface#ROTATION_270 Surface.ROTATION_270}. For
* example, if a device has a naturally tall screen, and the user has
* turned it on its side to go into a landscape orientation, the value
* returned here may be either {@link Surface#ROTATION_90 Surface.ROTATION_90}
* or {@link Surface#ROTATION_270 Surface.ROTATION_270} depending on
* the direction it was turned. The angle is the rotation of the drawn
* graphics on the screen, which is the opposite direction of the physical
* rotation of the device. For example, if the device is rotated 90
* degrees counter-clockwise, to compensate rendering will be rotated by
* 90 degrees clockwise and thus the returned value here will be
* {@link Surface#ROTATION_90 Surface.ROTATION_90}.
*/
public int getRotation() {
return getOrientation();
}
/**
* @deprecated use {@link #getRotation}
* @return orientation of this display.
*/
@Deprecated native public int getOrientation();
/**
* Return the native pixel format of the display. The returned value
* may be one of the constants int {@link android.graphics.PixelFormat}.
*/
public int getPixelFormat() {
return mPixelFormat;
}
/**
* Return the refresh rate of this display in frames per second.
*/
public float getRefreshRate() {
return mRefreshRate;
}
/**
* Initialize a DisplayMetrics object from this display's data.
*
* @param outMetrics
*/
public void getMetrics(DisplayMetrics outMetrics) {
synchronized (mTmpPoint) {
getSizeInternal(mTmpPoint, false);
outMetrics.widthPixels = mTmpPoint.x;
outMetrics.heightPixels = mTmpPoint.y;
}
getNonSizeMetrics(outMetrics);
CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
if (ci != null) {
ci.applyToDisplayMetrics(outMetrics);
}
if (DEBUG_COMPAT) Slog.v(TAG, "Returning DisplayMetrics: " + outMetrics.widthPixels
+ "x" + outMetrics.heightPixels + " " + outMetrics.density);
}
/**
* Initialize a DisplayMetrics object from this display's data.
*
* @param outMetrics
* @hide
*/
public void getRealMetrics(DisplayMetrics outMetrics) {
outMetrics.widthPixels = getRealWidth();
outMetrics.heightPixels = getRealHeight();
getNonSizeMetrics(outMetrics);
}
private void getNonSizeMetrics(DisplayMetrics outMetrics) {
outMetrics.density = mDensity;
outMetrics.densityDpi = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f);
outMetrics.scaledDensity= outMetrics.density;
outMetrics.xdpi = mDpiX;
outMetrics.ydpi = mDpiY;
outMetrics.unscaledWidthPixels = outMetrics.widthPixels;
outMetrics.unscaledHeightPixels = outMetrics.heightPixels;
}
static IWindowManager getWindowManager() {
synchronized (sStaticInit) {
if (sWindowManager == null) {
sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
}
return sWindowManager;
}
}
/*
* We use a class initializer to allow the native code to cache some
* field offsets.
*/
native private static void nativeClassInit();
private native void init(int display);
private final CompatibilityInfoHolder mCompatibilityInfo;
private final int mDisplay;
// Following fields are initialized from native code
private int mPixelFormat;
private float mRefreshRate;
private float mDensity;
private float mDpiX;
private float mDpiY;
private final Point mTmpPoint = new Point();
private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
private float mLastGetTime;
private static final Object sStaticInit = new Object();
private static boolean sInitialized = false;
private static IWindowManager sWindowManager;
private static volatile CompatibilityInfo sCompatibilityInfo;
/**
* Returns a display object which uses the metric's width/height instead.
* @hide
*/
public static Display createCompatibleDisplay(int displayId, CompatibilityInfoHolder compat) {
return new Display(displayId, compat);
}
}