blob: 50faf57a096f73595298053e55f0479ef8958fa6 [file] [log] [blame]
/*
* 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.content.res;
import android.content.pm.ApplicationInfo;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
/**
* CompatibilityInfo class keeps the information about compatibility mode that the application is
* running under.
*
* {@hide}
*/
public class CompatibilityInfo {
private static final boolean DBG = false;
private static final String TAG = "CompatibilityInfo";
/** default compatibility info object for compatible applications */
public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo() {
@Override
public void setExpandable(boolean expandable) {
throw new UnsupportedOperationException("trying to change default compatibility info");
}
};
/**
* The default width of the screen in portrait mode.
*/
public static final int DEFAULT_PORTRAIT_WIDTH = 320;
/**
* The default height of the screen in portrait mode.
*/
public static final int DEFAULT_PORTRAIT_HEIGHT = 480;
/**
* A compatibility flags
*/
private int mCompatibilityFlags;
/**
* A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f)
* {@see compatibilityFlag}
*/
private static final int SCALING_REQUIRED = 1;
/**
* A flag mask to indicates that the application can expand over the original size.
* The flag is set to true if
* 1) Application declares its expandable in manifest file using <supports-screens> or
* 2) Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set
* {@see compatibilityFlag}
*/
private static final int EXPANDABLE = 2;
/**
* A flag mask to tell if the application is configured to be expandable. This differs
* from EXPANDABLE in that the application that is not expandable will be
* marked as expandable if Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set.
*/
private static final int CONFIGURED_EXPANDABLE = 4;
/**
* A flag mask to indicates that the application supports large screens.
* The flag is set to true if
* 1) Application declares it supports large screens in manifest file using <supports-screens> or
* 2) The screen size is not large
* {@see compatibilityFlag}
*/
private static final int LARGE_SCREENS = 8;
/**
* A flag mask to tell if the application supports large screens. This differs
* from LARGE_SCREENS in that the application that does not support large
* screens will be marked as supporting them if the current screen is not
* large.
*/
private static final int CONFIGURED_LARGE_SCREENS = 16;
private static final int SCALING_EXPANDABLE_MASK = SCALING_REQUIRED | EXPANDABLE | LARGE_SCREENS;
/**
* The effective screen density we have selected for this application.
*/
public final int applicationDensity;
/**
* Application's scale.
*/
public final float applicationScale;
/**
* Application's inverted scale.
*/
public final float applicationInvertedScale;
/**
* The flags from ApplicationInfo.
*/
public final int appFlags;
public CompatibilityInfo(ApplicationInfo appInfo) {
appFlags = appInfo.flags;
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
mCompatibilityFlags |= LARGE_SCREENS | CONFIGURED_LARGE_SCREENS;
}
if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
mCompatibilityFlags |= EXPANDABLE | CONFIGURED_EXPANDABLE;
}
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
applicationDensity = DisplayMetrics.DENSITY_DEVICE;
applicationScale = 1.0f;
applicationInvertedScale = 1.0f;
} else {
applicationDensity = DisplayMetrics.DENSITY_DEFAULT;
applicationScale = DisplayMetrics.DENSITY_DEVICE
/ (float) DisplayMetrics.DENSITY_DEFAULT;
applicationInvertedScale = 1.0f / applicationScale;
mCompatibilityFlags |= SCALING_REQUIRED;
}
}
private CompatibilityInfo(int appFlags, int compFlags,
int dens, float scale, float invertedScale) {
this.appFlags = appFlags;
mCompatibilityFlags = compFlags;
applicationDensity = dens;
applicationScale = scale;
applicationInvertedScale = invertedScale;
}
private CompatibilityInfo() {
this(ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
| ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
| ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
| ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS,
EXPANDABLE | CONFIGURED_EXPANDABLE,
DisplayMetrics.DENSITY_DEVICE,
1.0f,
1.0f);
}
/**
* Returns the copy of this instance.
*/
public CompatibilityInfo copy() {
CompatibilityInfo info = new CompatibilityInfo(appFlags, mCompatibilityFlags,
applicationDensity, applicationScale, applicationInvertedScale);
return info;
}
/**
* Sets expandable bit in the compatibility flag.
*/
public void setExpandable(boolean expandable) {
if (expandable) {
mCompatibilityFlags |= CompatibilityInfo.EXPANDABLE;
} else {
mCompatibilityFlags &= ~CompatibilityInfo.EXPANDABLE;
}
}
/**
* Sets large screen bit in the compatibility flag.
*/
public void setLargeScreens(boolean expandable) {
if (expandable) {
mCompatibilityFlags |= CompatibilityInfo.LARGE_SCREENS;
} else {
mCompatibilityFlags &= ~CompatibilityInfo.LARGE_SCREENS;
}
}
/**
* @return true if the application is configured to be expandable.
*/
public boolean isConfiguredExpandable() {
return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0;
}
/**
* @return true if the application is configured to be expandable.
*/
public boolean isConfiguredLargeScreens() {
return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_LARGE_SCREENS) != 0;
}
/**
* @return true if the scaling is required
*/
public boolean isScalingRequired() {
return (mCompatibilityFlags & SCALING_REQUIRED) != 0;
}
public boolean supportsScreen() {
return (mCompatibilityFlags & (EXPANDABLE|LARGE_SCREENS))
== (EXPANDABLE|LARGE_SCREENS);
}
@Override
public String toString() {
return "CompatibilityInfo{scale=" + applicationScale +
", supports screen=" + supportsScreen() + "}";
}
/**
* Returns the translator which translates the coordinates in compatibility mode.
* @param params the window's parameter
*/
public Translator getTranslator() {
return isScalingRequired() ? new Translator() : null;
}
/**
* A helper object to translate the screen and window coordinates back and forth.
* @hide
*/
public class Translator {
final public float applicationScale;
final public float applicationInvertedScale;
private Rect mContentInsetsBuffer = null;
private Rect mVisibleInsetsBuffer = null;
Translator(float applicationScale, float applicationInvertedScale) {
this.applicationScale = applicationScale;
this.applicationInvertedScale = applicationInvertedScale;
}
Translator() {
this(CompatibilityInfo.this.applicationScale,
CompatibilityInfo.this.applicationInvertedScale);
}
/**
* Translate the screen rect to the application frame.
*/
public void translateRectInScreenToAppWinFrame(Rect rect) {
rect.scale(applicationInvertedScale);
}
/**
* Translate the region in window to screen.
*/
public void translateRegionInWindowToScreen(Region transparentRegion) {
transparentRegion.scale(applicationScale);
}
/**
* Apply translation to the canvas that is necessary to draw the content.
*/
public void translateCanvas(Canvas canvas) {
canvas.scale(applicationScale, applicationScale);
}
/**
* Translate the motion event captured on screen to the application's window.
*/
public void translateEventInScreenToAppWindow(MotionEvent event) {
event.scale(applicationInvertedScale);
}
/**
* Translate the window's layout parameter, from application's view to
* Screen's view.
*/
public void translateWindowLayout(WindowManager.LayoutParams params) {
params.scale(applicationScale);
}
/**
* Translate a Rect in application's window to screen.
*/
public void translateRectInAppWindowToScreen(Rect rect) {
rect.scale(applicationScale);
}
/**
* Translate a Rect in screen coordinates into the app window's coordinates.
*/
public void translateRectInScreenToAppWindow(Rect rect) {
rect.scale(applicationInvertedScale);
}
/**
* Translate the location of the sub window.
* @param params
*/
public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
params.scale(applicationScale);
}
/**
* Translate the content insets in application window to Screen. This uses
* the internal buffer for content insets to avoid extra object allocation.
*/
public Rect getTranslatedContentInsets(Rect contentInsets) {
if (mContentInsetsBuffer == null) mContentInsetsBuffer = new Rect();
mContentInsetsBuffer.set(contentInsets);
translateRectInAppWindowToScreen(mContentInsetsBuffer);
return mContentInsetsBuffer;
}
/**
* Translate the visible insets in application window to Screen. This uses
* the internal buffer for content insets to avoid extra object allocation.
*/
public Rect getTranslatedVisbileInsets(Rect visibleInsets) {
if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect();
mVisibleInsetsBuffer.set(visibleInsets);
translateRectInAppWindowToScreen(mVisibleInsetsBuffer);
return mVisibleInsetsBuffer;
}
}
/**
* Returns the frame Rect for applications runs under compatibility mode.
*
* @param dm the display metrics used to compute the frame size.
* @param orientation the orientation of the screen.
* @param outRect the output parameter which will contain the result.
*/
public static void updateCompatibleScreenFrame(DisplayMetrics dm, int orientation,
Rect outRect) {
int width = dm.widthPixels;
int portraitHeight = (int) (DEFAULT_PORTRAIT_HEIGHT * dm.density + 0.5f);
int portraitWidth = (int) (DEFAULT_PORTRAIT_WIDTH * dm.density + 0.5f);
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
int xOffset = (width - portraitHeight) / 2 ;
outRect.set(xOffset, 0, xOffset + portraitHeight, portraitWidth);
} else {
int xOffset = (width - portraitWidth) / 2 ;
outRect.set(xOffset, 0, xOffset + portraitWidth, portraitHeight);
}
}
}