| /* |
| * 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.PointF; |
| 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; |
| |
| /** |
| * A flag mask to indicates that the application supports xlarge screens. |
| * The flag is set to true if |
| * 1) Application declares it supports xlarge screens in manifest file using <supports-screens> or |
| * 2) The screen size is not xlarge |
| * {@see compatibilityFlag} |
| */ |
| private static final int XLARGE_SCREENS = 32; |
| |
| /** |
| * A flag mask to tell if the application supports xlarge screens. This differs |
| * from XLARGE_SCREENS in that the application that does not support xlarge |
| * screens will be marked as supporting them if the current screen is not |
| * xlarge. |
| */ |
| private static final int CONFIGURED_XLARGE_SCREENS = 64; |
| |
| /** |
| * 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_SUPPORTS_XLARGE_SCREENS) != 0) { |
| mCompatibilityFlags |= XLARGE_SCREENS | CONFIGURED_XLARGE_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_SUPPORTS_XLARGE_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; |
| } |
| } |
| |
| /** |
| * Sets large screen bit in the compatibility flag. |
| */ |
| public void setXLargeScreens(boolean expandable) { |
| if (expandable) { |
| mCompatibilityFlags |= CompatibilityInfo.XLARGE_SCREENS; |
| } else { |
| mCompatibilityFlags &= ~CompatibilityInfo.XLARGE_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 application is configured to be expandable. |
| */ |
| public boolean isConfiguredXLargeScreens() { |
| return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_XLARGE_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) { |
| if (applicationScale == 1.5f) { |
| /* When we scale for compatibility, we can put our stretched |
| bitmaps and ninepatches on exacty 1/2 pixel boundaries, |
| which can give us inconsistent drawing due to imperfect |
| float precision in the graphics engine's inverse matrix. |
| |
| As a work-around, we translate by a tiny amount to avoid |
| landing on exact pixel centers and boundaries, giving us |
| the slop we need to draw consistently. |
| |
| This constant is meant to resolve to 1/255 after it is |
| scaled by 1.5 (applicationScale). Note, this is just a guess |
| as to what is small enough not to create its own artifacts, |
| and big enough to avoid the precision problems. Feel free |
| to experiment with smaller values as you choose. |
| */ |
| final float tinyOffset = 2.0f / (3 * 255); |
| canvas.translate(tinyOffset, tinyOffset); |
| } |
| 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 a Point in screen coordinates into the app window's coordinates. |
| */ |
| public void translatePointInScreenToAppWindow(PointF point) { |
| final float scale = applicationInvertedScale; |
| if (scale != 1.0f) { |
| point.x *= scale; |
| point.y *= scale; |
| } |
| } |
| |
| /** |
| * 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); |
| } |
| } |
| } |