Merge change 5091 into donut

* changes:
  * new screen resolution support impl.   * use full window for activities, and shift & clip the content   * refactored the compatibility code, and introdcued Translator class to handle cooridnate translations.   * removed a workaround to handle an activity with configChagne=rotation in old implementation.   * I'll fix background issue on rotation in next CL.
This commit is contained in:
Android (Google) Code Review
2009-06-24 17:53:57 -07:00
10 changed files with 537 additions and 227 deletions

View File

@@ -17,8 +17,15 @@
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
@@ -27,6 +34,9 @@ import android.view.Gravity;
* {@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();
@@ -40,37 +50,76 @@ public class CompatibilityInfo {
*/
public static final int DEFAULT_PORTRAIT_HEIGHT = 480;
/**
* The x-shift mode that controls the position of the content or the window under
* compatibility mode.
* {@see getTranslator}
* {@see Translator#mShiftMode}
*/
private static final int X_SHIFT_NONE = 0;
private static final int X_SHIFT_CONTENT = 1;
private static final int X_SHIFT_AND_CLIP_CONTENT = 2;
private static final int X_SHIFT_WINDOW = 3;
/**
* A compatibility flags
*/
private int compatibilityFlags;
/**
* 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 <expandable /> or
* 2) The screen size is same as (320 x 480) * density.
* {@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 it runs in (320x 480) * density screen size.
*/
private static final int CONFIGURED_EXPANDABLE = 4;
private static final int SCALING_EXPANDABLE_MASK = SCALING_REQUIRED | EXPANDABLE;
/**
* Application's scale.
*/
public final float mApplicationScale;
public final float applicationScale;
/**
* Application's inverted scale.
*/
public final float mApplicationInvertedScale;
/**
* A boolean flag 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 <expandable /> or
* 2) The screen size is same as (320 x 480) * density.
*/
public boolean mExpandable;
public final float applicationInvertedScale;
/**
* A expandable flag in the configuration.
* Window size in Compatibility Mode, in real pixels. This is updated by
* {@link DisplayMetrics#updateMetrics}.
*/
public final boolean mConfiguredExpandable;
private int mWidth;
private int mHeight;
/**
* A boolean flag to tell if the application needs scaling (when mApplicationScale != 1.0f)
* The x offset to center the window content. In X_SHIFT_WINDOW mode, the offset is added
* to the window's layout. In X_SHIFT_CONTENT/X_SHIFT_AND_CLIP_CONTENT mode, the offset
* is used to translate the Canvas.
*/
public final boolean mScalingRequired;
private int mXOffset;
public CompatibilityInfo(ApplicationInfo appInfo) {
mExpandable = mConfiguredExpandable =
(appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0;
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
compatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE;
}
float packageDensityScale = -1.0f;
if (appInfo.supportsDensities != null) {
@@ -93,23 +142,323 @@ public class CompatibilityInfo {
}
}
if (packageDensityScale > 0.0f) {
mApplicationScale = packageDensityScale;
applicationScale = packageDensityScale;
} else {
mApplicationScale = DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY;
applicationScale =
DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY;
}
applicationInvertedScale = 1.0f / applicationScale;
if (applicationScale != 1.0f) {
compatibilityFlags |= SCALING_REQUIRED;
}
mApplicationInvertedScale = 1.0f / mApplicationScale;
mScalingRequired = mApplicationScale != 1.0f;
}
private CompatibilityInfo() {
mApplicationScale = mApplicationInvertedScale = 1.0f;
mExpandable = mConfiguredExpandable = true;
mScalingRequired = false;
applicationScale = applicationInvertedScale = 1.0f;
compatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE;
}
/**
* Sets the application's visible rect in compatibility mode.
* @param xOffset the application's x offset that is added to center the content.
* @param widthPixels the application's width in real pixels on the screen.
* @param heightPixels the application's height in real pixels on the screen.
*/
public void setVisibleRect(int xOffset, int widthPixels, int heightPixels) {
this.mXOffset = xOffset;
mWidth = widthPixels;
mHeight = heightPixels;
}
/**
* Sets expandable bit in the compatibility flag.
*/
public void setExpandable(boolean expandable) {
if (expandable) {
compatibilityFlags |= CompatibilityInfo.EXPANDABLE;
} else {
compatibilityFlags &= ~CompatibilityInfo.EXPANDABLE;
}
}
/**
* @return true if the application is configured to be expandable.
*/
public boolean isConfiguredExpandable() {
return (compatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0;
}
/**
* @return true if the scaling is required
*/
public boolean isScalingRequired() {
return (compatibilityFlags & SCALING_REQUIRED) != 0;
}
@Override
public String toString() {
return "CompatibilityInfo{scale=" + mApplicationScale +
", expandable=" + mExpandable + "}";
return "CompatibilityInfo{scale=" + applicationScale +
", compatibility flag=" + compatibilityFlags + "}";
}
}
/**
* Returns the translator which can translate the coordinates of the window.
* There are five different types of Translator.
*
* 1) {@link CompatibilityInfo#X_SHIFT_AND_CLIP_CONTENT}
* Shift and clip the content of the window at drawing time. Used for activities'
* main window (with no gravity).
* 2) {@link CompatibilityInfo#X_SHIFT_CONTENT}
* Shift the content of the window at drawing time. Used for windows that is created by
* an application and expected to be aligned with the application window.
* 3) {@link CompatibilityInfo#X_SHIFT_WINDOW}
* Create the window with adjusted x- coordinates. This is typically used
* in popup window, where it has to be placed relative to main window.
* 4) {@link CompatibilityInfo#X_SHIFT_NONE}
* No adjustment required, such as dialog.
* 5) Same as X_SHIFT_WINDOW, but no scaling. This is used by {@link SurfaceView}, which
* does not require scaling, but its window's location has to be adjusted.
*
* @param params the window's parameter
*/
public Translator getTranslator(WindowManager.LayoutParams params) {
if ( (compatibilityFlags & CompatibilityInfo.SCALING_EXPANDABLE_MASK)
== CompatibilityInfo.EXPANDABLE) {
if (DBG) Log.d(TAG, "no translation required");
return null;
}
if ((compatibilityFlags & CompatibilityInfo.EXPANDABLE) == 0) {
if ((params.flags & WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING) != 0) {
if (DBG) Log.d(TAG, "translation for surface view selected");
return new Translator(X_SHIFT_WINDOW, false, 1.0f, 1.0f);
} else {
int shiftMode;
if (params.gravity == Gravity.NO_GRAVITY) {
// For Regular Application window
shiftMode = X_SHIFT_AND_CLIP_CONTENT;
if (DBG) Log.d(TAG, "shift and clip translator");
} else if (params.width == WindowManager.LayoutParams.FILL_PARENT) {
// For Regular Application window
shiftMode = X_SHIFT_CONTENT;
if (DBG) Log.d(TAG, "shift content translator");
} else if ((params.gravity & Gravity.LEFT) != 0 && params.x > 0) {
shiftMode = X_SHIFT_WINDOW;
if (DBG) Log.d(TAG, "shift window translator");
} else {
shiftMode = X_SHIFT_NONE;
if (DBG) Log.d(TAG, "no content/window translator");
}
return new Translator(shiftMode);
}
} else if (isScalingRequired()) {
return new Translator();
} else {
return null;
}
}
/**
* A helper object to translate the screen and window coordinates back and forth.
* @hide
*/
public class Translator {
final private int mShiftMode;
final public boolean scalingRequired;
final public float applicationScale;
final public float applicationInvertedScale;
private Rect mContentInsetsBuffer = null;
private Rect mVisibleInsets = null;
Translator(int shiftMode, boolean scalingRequired, float applicationScale,
float applicationInvertedScale) {
mShiftMode = shiftMode;
this.scalingRequired = scalingRequired;
this.applicationScale = applicationScale;
this.applicationInvertedScale = applicationInvertedScale;
}
Translator(int shiftMode) {
this(shiftMode,
isScalingRequired(),
CompatibilityInfo.this.applicationScale,
CompatibilityInfo.this.applicationInvertedScale);
}
Translator() {
this(X_SHIFT_NONE);
}
/**
* Translate the screen rect to the application frame.
*/
public void translateRectInScreenToAppWinFrame(Rect rect) {
if (rect.isEmpty()) return; // skip if the window size is empty.
switch (mShiftMode) {
case X_SHIFT_AND_CLIP_CONTENT:
rect.intersect(0, 0, mWidth, mHeight);
break;
case X_SHIFT_CONTENT:
rect.intersect(0, 0, mWidth + mXOffset, mHeight);
break;
case X_SHIFT_WINDOW:
case X_SHIFT_NONE:
break;
}
if (scalingRequired) {
rect.scale(applicationInvertedScale);
}
}
/**
* Translate the region in window to screen.
*/
public void translateRegionInWindowToScreen(Region transparentRegion) {
switch (mShiftMode) {
case X_SHIFT_AND_CLIP_CONTENT:
case X_SHIFT_CONTENT:
transparentRegion.scale(applicationScale);
transparentRegion.translate(mXOffset, 0);
break;
case X_SHIFT_WINDOW:
case X_SHIFT_NONE:
transparentRegion.scale(applicationScale);
}
}
/**
* Apply translation to the canvas that is necessary to draw the content.
*/
public void translateCanvas(Canvas canvas) {
if (mShiftMode == X_SHIFT_CONTENT ||
mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
// TODO: clear outside when rotation is changed.
// Translate x-offset only when the content is shifted.
canvas.translate(mXOffset, 0);
}
if (scalingRequired) {
canvas.scale(applicationScale, applicationScale);
}
}
/**
* Translate the motion event captured on screen to the application's window.
*/
public void translateEventInScreenToAppWindow(MotionEvent event) {
if (mShiftMode == X_SHIFT_CONTENT ||
mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
event.translate(-mXOffset, 0);
}
if (scalingRequired) {
event.scale(applicationInvertedScale);
}
}
/**
* Translate the window's layout parameter, from application's view to
* Screen's view.
*/
public void translateWindowLayout(WindowManager.LayoutParams params) {
switch (mShiftMode) {
case X_SHIFT_NONE:
case X_SHIFT_AND_CLIP_CONTENT:
case X_SHIFT_CONTENT:
params.scale(applicationScale);
break;
case X_SHIFT_WINDOW:
params.scale(applicationScale);
params.x += mXOffset;
break;
}
}
/**
* Translate a Rect in application's window to screen.
*/
public void translateRectInAppWindowToScreen(Rect rect) {
// TODO Auto-generated method stub
if (scalingRequired) {
rect.scale(applicationScale);
}
switch(mShiftMode) {
case X_SHIFT_NONE:
case X_SHIFT_WINDOW:
break;
case X_SHIFT_CONTENT:
case X_SHIFT_AND_CLIP_CONTENT:
rect.offset(mXOffset, 0);
break;
}
}
/**
* Translate a Rect in screen coordinates into the app window's coordinates.
*/
public void translateRectInScreenToAppWindow(Rect rect) {
switch (mShiftMode) {
case X_SHIFT_NONE:
case X_SHIFT_WINDOW:
break;
case X_SHIFT_CONTENT: {
rect.intersects(mXOffset, 0, rect.right, rect.bottom);
int dx = Math.min(mXOffset, rect.left);
rect.offset(-dx, 0);
break;
}
case X_SHIFT_AND_CLIP_CONTENT: {
rect.intersects(mXOffset, 0, mWidth + mXOffset, mHeight);
int dx = Math.min(mXOffset, rect.left);
rect.offset(-dx, 0);
break;
}
}
if (scalingRequired) {
rect.scale(applicationInvertedScale);
}
}
/**
* Translate the location of the sub window.
* @param params
*/
public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
if (scalingRequired) {
params.scale(applicationScale);
}
switch (mShiftMode) {
// the window location on these mode does not require adjustmenet.
case X_SHIFT_NONE:
case X_SHIFT_WINDOW:
break;
case X_SHIFT_CONTENT:
case X_SHIFT_AND_CLIP_CONTENT:
params.x += mXOffset;
break;
}
}
/**
* 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 (mVisibleInsets == null) mVisibleInsets = new Rect();
mVisibleInsets.set(visibleInsets);
translateRectInAppWindowToScreen(mVisibleInsets);
return mVisibleInsets;
}
}
}

View File

@@ -158,10 +158,10 @@ public class Resources {
}
updateConfiguration(config, metrics);
assets.ensureStringBlocks();
if (!mCompatibilityInfo.mScalingRequired) {
mPreloadedDrawables = sPreloadedDrawables;
} else {
if (mCompatibilityInfo.isScalingRequired()) {
mPreloadedDrawables = emptySparseArray();
} else {
mPreloadedDrawables = sPreloadedDrawables;
}
}

View File

@@ -106,16 +106,8 @@ public class DisplayMetrics {
* {@hide}
*/
public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation) {
if (compatibilityInfo.mScalingRequired) {
float invertedRatio = compatibilityInfo.mApplicationInvertedScale;
density *= invertedRatio;
scaledDensity *= invertedRatio;
xdpi *= invertedRatio;
ydpi *= invertedRatio;
widthPixels *= invertedRatio;
heightPixels *= invertedRatio;
}
if (!compatibilityInfo.mConfiguredExpandable) {
int xOffset = 0;
if (!compatibilityInfo.isConfiguredExpandable()) {
// Note: this assume that configuration is updated before calling
// updateMetrics method.
int defaultWidth;
@@ -141,11 +133,13 @@ public class DisplayMetrics {
if (defaultWidth == widthPixels && defaultHeight == heightPixels) {
// the screen size is same as expected size. make it expandable
compatibilityInfo.mExpandable = true;
compatibilityInfo.setExpandable(true);
} else {
compatibilityInfo.mExpandable = false;
compatibilityInfo.setExpandable(false);
// adjust the size only when the device's screen is bigger.
if (defaultWidth < widthPixels) {
// content/window's x offset in original pixels
xOffset = ((widthPixels - defaultWidth) / 2);
widthPixels = defaultWidth;
}
if (defaultHeight < heightPixels) {
@@ -153,8 +147,19 @@ public class DisplayMetrics {
}
}
}
compatibilityInfo.setVisibleRect(xOffset, widthPixels, heightPixels);
if (compatibilityInfo.isScalingRequired()) {
float invertedRatio = compatibilityInfo.applicationInvertedScale;
density *= invertedRatio;
scaledDensity *= invertedRatio;
xdpi *= invertedRatio;
ydpi *= invertedRatio;
widthPixels *= invertedRatio;
heightPixels *= invertedRatio;
}
}
@Override
public String toString() {
return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
", height=" + heightPixels + ", scaledDensity=" + scaledDensity +

View File

@@ -212,28 +212,47 @@ public final class MotionEvent implements Parcelable {
}
/**
* Scales down the cood of this event by the given scale.
* Scales down the coordination of this event by the given scale.
*
* @hide
*/
public void scale(float scale) {
if (scale != 1.0f) {
mX *= scale;
mY *= scale;
mRawX *= scale;
mRawY *= scale;
mSize *= scale;
mXPrecision *= scale;
mYPrecision *= scale;
if (mHistory != null) {
float[] history = mHistory;
int length = history.length;
for (int i = 0; i < length; i += 4) {
history[i] *= scale; // X
// history[i + 2] == pressure
history[i + 1] *= scale; // Y
history[i + 3] *= scale; // Size, TODO: square this?
}
mX *= scale;
mY *= scale;
mRawX *= scale;
mRawY *= scale;
mSize *= scale;
mXPrecision *= scale;
mYPrecision *= scale;
if (mHistory != null) {
float[] history = mHistory;
int length = history.length;
for (int i = 0; i < length; i += 4) {
history[i] *= scale; // X
history[i + 1] *= scale; // Y
// no need to scale pressure ([i+2])
history[i + 3] *= scale; // Size, TODO: square this?
}
}
}
/**
* Translate the coordination of the event by given x and y.
*
* @hide
*/
public void translate(float dx, float dy) {
mX += dx;
mY += dy;
mRawX += dx;
mRawY += dx;
if (mHistory != null) {
float[] history = mHistory;
int length = history.length;
for (int i = 0; i < length; i += 4) {
history[i] += dx; // X
history[i + 1] += dy; // Y
// no need to translate pressure (i+2) and size (i+3)
}
}
}

View File

@@ -18,6 +18,7 @@ package android.view;
import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.content.res.CompatibilityInfo.Translator;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
@@ -138,24 +139,21 @@ public class SurfaceView extends View {
int mFormat = -1;
int mType = -1;
final Rect mSurfaceFrame = new Rect();
private final CompatibilityInfo mCompatibilityInfo;
private Translator mTranslator;
public SurfaceView(Context context) {
super(context);
setWillNotDraw(true);
mCompatibilityInfo = context.getResources().getCompatibilityInfo();
}
public SurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(true);
mCompatibilityInfo = context.getResources().getCompatibilityInfo();
}
public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setWillNotDraw(true);
mCompatibilityInfo = context.getResources().getCompatibilityInfo();
}
/**
@@ -258,9 +256,9 @@ public class SurfaceView extends View {
public boolean dispatchTouchEvent(MotionEvent event) {
// SurfaceView uses pre-scaled size unless fixed size is requested. This hook
// scales the event back to the pre-scaled coordinates for such surface.
if (mRequestedWidth < 0 && mCompatibilityInfo.mScalingRequired) {
if (mRequestedWidth < 0 && mTranslator != null) {
MotionEvent scaledBack = MotionEvent.obtain(event);
scaledBack.scale(mCompatibilityInfo.mApplicationScale);
scaledBack.scale(mTranslator.applicationScale);
try {
return super.dispatchTouchEvent(scaledBack);
} finally {
@@ -297,15 +295,18 @@ public class SurfaceView extends View {
if (!mHaveFrame) {
return;
}
float appScale = mCompatibilityInfo.mApplicationScale;
mTranslator = ((ViewRoot)getRootView().getParent()).mTranslator;
float appScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
int myWidth = mRequestedWidth;
if (myWidth <= 0) myWidth = getWidth();
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
// Use original size for surface unless fixed size is requested.
if (mRequestedWidth <= 0 && mCompatibilityInfo.mScalingRequired) {
// Use original size if the app specified the size of the view,
// and let the flinger to scale up.
if (mRequestedWidth <= 0 && mTranslator != null && mTranslator.scalingRequired) {
myWidth *= appScale;
myHeight *= appScale;
}
@@ -325,7 +326,7 @@ public class SurfaceView extends View {
+ " visible=" + visibleChanged
+ " left=" + (mLeft != mLocation[0])
+ " top=" + (mTop != mLocation[1]));
try {
final boolean visible = mVisible = mRequestedVisible;
mLeft = mLocation[0];
@@ -335,16 +336,23 @@ public class SurfaceView extends View {
mFormat = mRequestedFormat;
mType = mRequestedType;
// Scaling window's layout here because mLayout is not used elsewhere.
mLayout.x = (int) (mLeft * appScale);
mLayout.y = (int) (mTop * appScale);
mLayout.width = (int) (getWidth() * appScale);
mLayout.height = (int) (getHeight() * appScale);
// Scaling/Translate window's layout here because mLayout is not used elsewhere.
// Places the window relative
mLayout.x = mLeft;
mLayout.y = mTop;
mLayout.width = getWidth();
mLayout.height = getHeight();
if (mTranslator != null) {
mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
}
mLayout.format = mRequestedFormat;
mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_SCALED
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING
;
mLayout.memoryType = mRequestedType;
@@ -371,13 +379,6 @@ public class SurfaceView extends View {
visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
mVisibleInsets, mSurface);
if (mCompatibilityInfo.mScalingRequired) {
float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
mContentInsets.scale(invertedScale);
mVisibleInsets.scale(invertedScale);
mWinFrame.scale(invertedScale);
}
if (localLOGV) Log.i(TAG, "New surface: " + mSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
mSurfaceFrame.left = 0;
@@ -446,24 +447,14 @@ public class SurfaceView extends View {
private static class MyWindow extends IWindow.Stub {
private final WeakReference<SurfaceView> mSurfaceView;
private final CompatibilityInfo mCompatibilityInfo;
public MyWindow(SurfaceView surfaceView) {
mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
mCompatibilityInfo = surfaceView.getContext().getResources().getCompatibilityInfo();
}
public void resized(int w, int h, Rect coveredInsets,
Rect visibleInsets, boolean reportDraw) {
SurfaceView surfaceView = mSurfaceView.get();
if (mCompatibilityInfo.mScalingRequired) {
float scale = mCompatibilityInfo.mApplicationInvertedScale;
w *= scale;
h *= scale;
coveredInsets.scale(scale);
visibleInsets.scale(scale);
}
if (surfaceView != null) {
if (localLOGV) Log.v(
"SurfaceView", surfaceView + " got resized: w=" +
@@ -626,9 +617,6 @@ public class SurfaceView extends View {
Canvas c = null;
if (!mDrawingStopped && mWindow != null) {
Rect frame = dirty != null ? dirty : mSurfaceFrame;
if (mCompatibilityInfo.mScalingRequired) {
frame.scale(mCompatibilityInfo.mApplicationScale);
}
try {
c = mSurface.lockCanvas(frame);
} catch (Exception e) {

View File

@@ -6543,7 +6543,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
boolean changed = false;
if (DBG) {
System.out.println(this + " View.setFrame(" + left + "," + top + ","
Log.d("View", this + " View.setFrame(" + left + "," + top + ","
+ right + "," + bottom + ")");
}

View File

@@ -128,13 +128,12 @@ public final class ViewRoot extends Handler implements ViewParent,
Rect mDirty; // will be a graphics.Region soon
boolean mIsAnimating;
private CompatibilityInfo mCompatibilityInfo;
CompatibilityInfo.Translator mTranslator;
final View.AttachInfo mAttachInfo;
final Rect mTempRect; // used in the transaction to not thrash the heap.
final Rect mVisRect; // used to retrieve visible rect of focused view.
final Point mVisPoint; // used to retrieve global offset of focused view.
boolean mTraversalScheduled;
boolean mWillDrawSoon;
@@ -218,7 +217,6 @@ public final class ViewRoot extends Handler implements ViewParent,
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mVisPoint = new Point();
mWinFrame = new Rect();
mWindow = new W(this, context);
mInputMethodCallback = new InputMethodCallback(this);
@@ -387,20 +385,25 @@ public final class ViewRoot extends Handler implements ViewParent,
if (mView == null) {
mView = view;
mWindowAttributes.copyFrom(attrs);
mCompatibilityInfo = mView.getContext().getResources().getCompatibilityInfo();
CompatibilityInfo compatibilityInfo =
mView.getContext().getResources().getCompatibilityInfo();
mTranslator = compatibilityInfo.getTranslator(attrs);
boolean restore = false;
if (mCompatibilityInfo.mScalingRequired || !mCompatibilityInfo.mExpandable) {
if (attrs != null && mTranslator != null) {
restore = true;
mWindowAttributes.backup();
}
if (!mCompatibilityInfo.mExpandable) {
adjustWindowAttributesForCompatibleMode(mWindowAttributes);
attrs.backup();
mTranslator.translateWindowLayout(attrs);
}
if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mCompatibilityInfo.mScalingRequired;
mAttachInfo.mApplicationScale = mCompatibilityInfo.mApplicationScale;
mAttachInfo.mScalingRequired =
mTranslator == null ? false : mTranslator.scalingRequired;
mAttachInfo.mApplicationScale =
mTranslator == null ? 1.0f : mTranslator.applicationScale;
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
@@ -421,15 +424,14 @@ public final class ViewRoot extends Handler implements ViewParent,
mAttachInfo.mRootView = null;
unscheduleTraversals();
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
if (restore) {
mWindowAttributes.restore();
}
if (mCompatibilityInfo.mScalingRequired) {
mAttachInfo.mContentInsets.scale(
mCompatibilityInfo.mApplicationInvertedScale);
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
}
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
@@ -541,14 +543,14 @@ public final class ViewRoot extends Handler implements ViewParent,
public void invalidateChild(View child, Rect dirty) {
checkThread();
if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
if (mCurScrollY != 0 || mCompatibilityInfo.mScalingRequired) {
if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
if (mCurScrollY != 0 || mTranslator != null) {
mTempRect.set(dirty);
if (mCurScrollY != 0) {
mTempRect.offset(0, -mCurScrollY);
}
if (mCompatibilityInfo.mScalingRequired) {
mTempRect.scale(mCompatibilityInfo.mApplicationScale);
if (mTranslator != null) {
mTranslator.translateRectInAppWindowToScreen(mTempRect);
}
dirty = mTempRect;
}
@@ -567,7 +569,7 @@ public final class ViewRoot extends Handler implements ViewParent,
return null;
}
public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
if (child != mView) {
throw new RuntimeException("child is not mine, honest!");
}
@@ -628,14 +630,14 @@ public final class ViewRoot extends Handler implements ViewParent,
boolean viewVisibilityChanged = mViewVisibility != viewVisibility
|| mNewSurfaceNeeded;
float appScale = mCompatibilityInfo.mApplicationScale;
float appScale = mAttachInfo.mApplicationScale;
WindowManager.LayoutParams params = null;
if (mWindowAttributesChanged) {
mWindowAttributesChanged = false;
params = lp;
}
Rect frame = mWinFrame;
if (mFirst) {
fullRedrawNeeded = true;
mLayoutRequested = true;
@@ -660,11 +662,11 @@ public final class ViewRoot extends Handler implements ViewParent,
//Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
} else {
desiredWindowWidth = mWinFrame.width();
desiredWindowHeight = mWinFrame.height();
desiredWindowWidth = frame.width();
desiredWindowHeight = frame.height();
if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
if (DEBUG_ORIENTATION) Log.v("ViewRoot",
"View " + host + " resized to: " + mWinFrame);
"View " + host + " resized to: " + frame);
fullRedrawNeeded = true;
mLayoutRequested = true;
windowResizesToFitContent = true;
@@ -810,7 +812,6 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
final Rect frame = mWinFrame;
boolean initialized = false;
boolean contentInsetsChanged = false;
boolean visibleInsetsChanged;
@@ -883,7 +884,7 @@ public final class ViewRoot extends Handler implements ViewParent,
} catch (RemoteException e) {
}
if (DEBUG_ORIENTATION) Log.v(
"ViewRoot", "Relayout returned: frame=" + mWinFrame + ", surface=" + mSurface);
"ViewRoot", "Relayout returned: frame=" + frame + ", surface=" + mSurface);
attachInfo.mWindowLeft = frame.left;
attachInfo.mWindowTop = frame.top;
@@ -958,7 +959,6 @@ public final class ViewRoot extends Handler implements ViewParent,
if (Config.DEBUG && ViewDebug.profileLayout) {
startTime = SystemClock.elapsedRealtime();
}
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
@@ -985,7 +985,10 @@ public final class ViewRoot extends Handler implements ViewParent,
mTmpLocation[1] + host.mBottom - host.mTop);
host.gatherTransparentRegion(mTransparentRegion);
mTransparentRegion.scale(appScale);
if (mTranslator != null) {
mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
}
if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
mPreviousTransparentRegion.set(mTransparentRegion);
// reconfigure window manager
@@ -1016,15 +1019,17 @@ public final class ViewRoot extends Handler implements ViewParent,
= givenContent.bottom = givenVisible.left = givenVisible.top
= givenVisible.right = givenVisible.bottom = 0;
attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
if (mCompatibilityInfo.mScalingRequired) {
insets.contentInsets.scale(appScale);
insets.visibleInsets.scale(appScale);
Rect contentInsets = insets.contentInsets;
Rect visibleInsets = insets.visibleInsets;
if (mTranslator != null) {
contentInsets = mTranslator.getTranslatedContentInsets(contentInsets);
visibleInsets = mTranslator.getTranslatedVisbileInsets(visibleInsets);
}
if (insetsPending || !mLastGivenInsets.equals(insets)) {
mLastGivenInsets.set(insets);
try {
sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
insets.contentInsets, insets.visibleInsets);
contentInsets, visibleInsets);
} catch (RemoteException e) {
}
}
@@ -1167,8 +1172,8 @@ public final class ViewRoot extends Handler implements ViewParent,
mCurScrollY = yoff;
fullRedrawNeeded = true;
}
float appScale = mCompatibilityInfo.mApplicationScale;
boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
float appScale = mAttachInfo.mApplicationScale;
boolean scalingRequired = mAttachInfo.mScalingRequired;
Rect dirty = mDirty;
if (mUseGL) {
@@ -1187,8 +1192,8 @@ public final class ViewRoot extends Handler implements ViewParent,
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try {
canvas.translate(0, -yoff);
if (scalingRequired) {
canvas.scale(appScale, appScale);
if (mTranslator != null) {
mTranslator.translateCanvas(canvas);
}
mView.draw(canvas);
if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
@@ -1239,7 +1244,6 @@ public final class ViewRoot extends Handler implements ViewParent,
int top = dirty.top;
int right = dirty.right;
int bottom = dirty.bottom;
canvas = surface.lockCanvas(dirty);
if (left != dirty.left || top != dirty.top || right != dirty.right ||
@@ -1295,8 +1299,8 @@ public final class ViewRoot extends Handler implements ViewParent,
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try {
canvas.translate(0, -yoff);
if (scalingRequired) {
canvas.scale(appScale, appScale);
if (mTranslator != null) {
mTranslator.translateCanvas(canvas);
}
mView.draw(canvas);
} finally {
@@ -1599,10 +1603,9 @@ public final class ViewRoot extends Handler implements ViewParent,
} else {
didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
}
if (event != null && mCompatibilityInfo.mScalingRequired) {
event.scale(mCompatibilityInfo.mApplicationInvertedScale);
if (event != null && mTranslator != null) {
mTranslator.translateEventInScreenToAppWindow(event);
}
try {
boolean handled;
if (mView != null && mAdded && event != null) {
@@ -1688,6 +1691,7 @@ public final class ViewRoot extends Handler implements ViewParent,
case RESIZED:
Rect coveredInsets = ((Rect[])msg.obj)[0];
Rect visibleInsets = ((Rect[])msg.obj)[1];
if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
&& mPendingContentInsets.equals(coveredInsets)
&& mPendingVisibleInsets.equals(visibleInsets)) {
@@ -1722,7 +1726,7 @@ public final class ViewRoot extends Handler implements ViewParent,
if (mGlWanted && !mUseGL) {
initializeGL();
if (mGlCanvas != null) {
float appScale = mCompatibilityInfo.mApplicationScale;
float appScale = mAttachInfo.mApplicationScale;
mGlCanvas.setViewport(
(int) (mWidth * appScale), (int) (mHeight * appScale));
}
@@ -2356,18 +2360,16 @@ public final class ViewRoot extends Handler implements ViewParent,
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
float appScale = mAttachInfo.mApplicationScale;
boolean restore = false;
float appScale = mCompatibilityInfo.mApplicationScale;
boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
if (params != null && !mCompatibilityInfo.mExpandable) {
if (params != null && mTranslator != null) {
restore = true;
params.backup();
adjustWindowAttributesForCompatibleMode(params);
mTranslator.translateWindowLayout(params);
}
if (params != null && scalingRequired) {
if (!restore) params.backup();
restore = true;
params.scale(appScale);
if (params != null) {
if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
}
int relayoutResult = sWindowSession.relayout(
mWindow, params,
@@ -2378,43 +2380,15 @@ public final class ViewRoot extends Handler implements ViewParent,
if (restore) {
params.restore();
}
if (scalingRequired) {
float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
mPendingContentInsets.scale(invertedScale);
mPendingVisibleInsets.scale(invertedScale);
mWinFrame.scale(invertedScale);
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
}
return relayoutResult;
}
/**
* Adjust the window's layout parameter for compatibility mode. It replaces FILL_PARENT
* with the default window size, and centers if the window wanted to fill
* horizontally.
*
* @param attrs the window's layout params to adjust
*/
private void adjustWindowAttributesForCompatibleMode(WindowManager.LayoutParams attrs) {
// fix app windows only
if (attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
DisplayMetrics metrics = mView.getContext().getResources().getDisplayMetrics();
// TODO: improve gravity logic
if (attrs.width == ViewGroup.LayoutParams.FILL_PARENT) {
attrs.width = metrics.widthPixels;
attrs.gravity |= Gravity.CENTER_HORIZONTAL;
mWindowAttributesChanged = attrs == mWindowAttributes;
}
if (attrs.height == ViewGroup.LayoutParams.FILL_PARENT) {
attrs.height = metrics.heightPixels;
attrs.gravity |= Gravity.TOP;
mWindowAttributesChanged = attrs == mWindowAttributes;
}
if (DEBUG_LAYOUT) {
Log.d(TAG, "Adjusted Attributes for compatibility : " + attrs);
}
}
}
/**
* {@inheritDoc}
*/
@@ -2518,16 +2492,14 @@ public final class ViewRoot extends Handler implements ViewParent,
+ " visibleInsets=" + visibleInsets.toShortString()
+ " reportDraw=" + reportDraw);
Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
if (mCompatibilityInfo.mScalingRequired) {
float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
coveredInsets.scale(invertedScale);
visibleInsets.scale(invertedScale);
msg.arg1 = (int) (w * invertedScale);
msg.arg2 = (int) (h * invertedScale);
} else {
msg.arg1 = w;
msg.arg2 = h;
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(coveredInsets);
mTranslator.translateRectInScreenToAppWindow(visibleInsets);
w *= mTranslator.applicationInvertedScale;
h *= mTranslator.applicationInvertedScale;
}
msg.arg1 = w;
msg.arg2 = h;
msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
sendMessage(msg);
}

View File

@@ -483,6 +483,12 @@ public interface WindowManager extends ViewManager {
* {@hide} */
public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
/** Window flag: special flag to let a window ignore the compatibility scaling.
* This is used by SurfaceView to create a window that does not scale the content.
*
* {@hide} */
public static final int FLAG_NO_COMPATIBILITY_SCALING = 0x00100000;
/** Window flag: a special option intended for system dialogs. When
* this flag is set, the window will demand focus unconditionally when
* it is created.
@@ -978,8 +984,9 @@ public interface WindowManager extends ViewManager {
/**
* Scale the layout params' coordinates and size.
* @hide
*/
void scale(float scale) {
public void scale(float scale) {
x *= scale;
y *= scale;
if (width > 0) {
@@ -997,14 +1004,13 @@ public interface WindowManager extends ViewManager {
void backup() {
int[] backup = mCompatibilityParamsBackup;
if (backup == null) {
// we backup 5 elements, x, y, width, height and gravity.
backup = mCompatibilityParamsBackup = new int[5];
// we backup 4 elements, x, y, width, height
backup = mCompatibilityParamsBackup = new int[4];
}
backup[0] = x;
backup[1] = y;
backup[2] = width;
backup[3] = height;
backup[4] = gravity;
}
/**
@@ -1018,7 +1024,6 @@ public interface WindowManager extends ViewManager {
y = backup[1];
width = backup[2];
height = backup[3];
gravity = backup[4];
}
}

View File

@@ -990,7 +990,7 @@ public class PopupWindow {
int bottomEdge = displayFrame.bottom;
if (ignoreBottomDecorations) {
bottomEdge = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight();
bottomEdge = anchor.getContext().getResources().getDisplayMetrics().heightPixels;
}
final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;

View File

@@ -968,35 +968,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
if (a != null && mSettings.isEnabledLP(a.info, flags)) {
ActivityInfo ainfo = PackageParser.generateActivityInfo(a, flags);
if (ainfo != null) {
ApplicationInfo appInfo = getApplicationInfo(component.getPackageName(),
PackageManager.GET_SUPPORTS_DENSITIES);
if (appInfo != null &&
(appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) == 0) {
// Check if the screen size is same as what the application expect.
CompatibilityInfo info = new CompatibilityInfo(appInfo);
DisplayMetrics metrics = new DisplayMetrics();
metrics.setTo(mMetrics);
int orientation = mMetrics.widthPixels > mMetrics.heightPixels ?
Configuration.ORIENTATION_LANDSCAPE :
Configuration.ORIENTATION_PORTRAIT;
metrics.updateMetrics(info, orientation);
if (!info.mExpandable) {
// Don't allow an app that cannot expand to handle rotation.
ainfo.configChanges &= ~ ActivityInfo.CONFIG_ORIENTATION;
} else {
appInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
}
if (DEBUG_SETTINGS) {
Log.d(TAG, "component=" + component +
", expandable:" +
((appInfo.flags &
ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0));
}
}
}
return ainfo;
return PackageParser.generateActivityInfo(a, flags);
}
if (mResolveComponentName.equals(component)) {
return mResolveActivity;