diff options
30 files changed, 419 insertions, 237 deletions
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 521e68606c67..85972c3ff6fa 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -309,13 +309,15 @@ public class Editor { } private void setErrorIcon(Drawable icon) { - final Drawables dr = mTextView.mDrawables; - if (dr != null) { - mTextView.setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon, - dr.mDrawableBottom); - } else { - mTextView.setCompoundDrawables(null, null, icon, null); + Drawables dr = mTextView.mDrawables; + if (dr == null) { + mTextView.mDrawables = dr = new Drawables(); } + dr.setErrorDrawable(icon, mTextView); + + mTextView.resetResolvedDrawables(); + mTextView.invalidate(); + mTextView.requestLayout(); } private void hideError() { @@ -329,7 +331,7 @@ public class Editor { } /** - * Returns the Y offset to make the pointy top of the error point + * Returns the X offset to make the pointy top of the error point * at the middle of the error icon. */ private int getErrorX() { @@ -340,8 +342,23 @@ public class Editor { final float scale = mTextView.getResources().getDisplayMetrics().density; final Drawables dr = mTextView.mDrawables; - return mTextView.getWidth() - mErrorPopup.getWidth() - mTextView.getPaddingRight() - - (dr != null ? dr.mDrawableSizeRight : 0) / 2 + (int) (25 * scale + 0.5f); + + final int layoutDirection = mTextView.getLayoutDirection(); + int errorX; + int offset; + switch (layoutDirection) { + default: + case View.LAYOUT_DIRECTION_LTR: + offset = - (dr != null ? dr.mDrawableSizeRight : 0) / 2 + (int) (25 * scale + 0.5f); + errorX = mTextView.getWidth() - mErrorPopup.getWidth() - + mTextView.getPaddingRight() + offset; + break; + case View.LAYOUT_DIRECTION_RTL: + offset = (dr != null ? dr.mDrawableSizeLeft : 0) / 2 - (int) (25 * scale + 0.5f); + errorX = mTextView.getPaddingLeft() + offset; + break; + } + return errorX; } /** @@ -358,16 +375,27 @@ public class Editor { mTextView.getCompoundPaddingBottom() - compoundPaddingTop; final Drawables dr = mTextView.mDrawables; - int icontop = compoundPaddingTop + - (vspace - (dr != null ? dr.mDrawableHeightRight : 0)) / 2; + + final int layoutDirection = mTextView.getLayoutDirection(); + int height; + switch (layoutDirection) { + default: + case View.LAYOUT_DIRECTION_LTR: + height = (dr != null ? dr.mDrawableHeightRight : 0); + break; + case View.LAYOUT_DIRECTION_RTL: + height = (dr != null ? dr.mDrawableHeightLeft : 0); + break; + } + + int icontop = compoundPaddingTop + (vspace - height) / 2; /* * The "2" is the distance between the point and the top edge * of the background. */ final float scale = mTextView.getResources().getDisplayMetrics().density; - return icontop + (dr != null ? dr.mDrawableHeightRight : 0) - mTextView.getHeight() - - (int) (2 * scale + 0.5f); + return icontop + height - mTextView.getHeight() - (int) (2 * scale + 0.5f); } void createInputContentTypeIfNeeded() { @@ -3726,7 +3754,7 @@ public class Editor { super(v, width, height); mView = v; // Make sure the TextView has a background set as it will be used the first time it is - // shown and positionned. Initialized with below background, which should have + // shown and positioned. Initialized with below background, which should have // dimensions identical to the above version for this to work (and is more likely). mPopupInlineErrorBackgroundId = getResourceId(mPopupInlineErrorBackgroundId, com.android.internal.R.styleable.Theme_errorMessageBackground); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 267b22aa34fe..0a16a663f086 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -284,15 +284,144 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private TextUtils.TruncateAt mEllipsize; static class Drawables { + final static int DRAWABLE_NONE = -1; + final static int DRAWABLE_RIGHT = 0; + final static int DRAWABLE_LEFT = 1; + final Rect mCompoundRect = new Rect(); + Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight, - mDrawableStart, mDrawableEnd; + mDrawableStart, mDrawableEnd, mDrawableError, mDrawableTemp; + int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight, - mDrawableSizeStart, mDrawableSizeEnd; + mDrawableSizeStart, mDrawableSizeEnd, mDrawableSizeError, mDrawableSizeTemp; + int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight, - mDrawableHeightStart, mDrawableHeightEnd; + mDrawableHeightStart, mDrawableHeightEnd, mDrawableHeightError, mDrawableHeightTemp; + int mDrawablePadding; + + int mDrawableSaved = DRAWABLE_NONE; + + public void resolveWithLayoutDirection(int layoutDirection) { + switch(layoutDirection) { + case LAYOUT_DIRECTION_RTL: + if (mDrawableStart != null) { + mDrawableRight = mDrawableStart; + + mDrawableSizeRight = mDrawableSizeStart; + mDrawableHeightRight = mDrawableHeightStart; + } + if (mDrawableEnd != null) { + mDrawableLeft = mDrawableEnd; + + mDrawableSizeLeft = mDrawableSizeEnd; + mDrawableHeightLeft = mDrawableHeightEnd; + } + break; + + case LAYOUT_DIRECTION_LTR: + default: + if (mDrawableStart != null) { + mDrawableLeft = mDrawableStart; + + mDrawableSizeLeft = mDrawableSizeStart; + mDrawableHeightLeft = mDrawableHeightStart; + } + if (mDrawableEnd != null) { + mDrawableRight = mDrawableEnd; + + mDrawableSizeRight = mDrawableSizeEnd; + mDrawableHeightRight = mDrawableHeightEnd; + } + break; + } + applyErrorDrawableIfNeeded(layoutDirection); + updateDrawablesLayoutDirection(layoutDirection); + } + + private void updateDrawablesLayoutDirection(int layoutDirection) { + if (mDrawableLeft != null) { + mDrawableLeft.setLayoutDirection(layoutDirection); + } + if (mDrawableRight != null) { + mDrawableRight.setLayoutDirection(layoutDirection); + } + if (mDrawableTop != null) { + mDrawableTop.setLayoutDirection(layoutDirection); + } + if (mDrawableBottom != null) { + mDrawableBottom.setLayoutDirection(layoutDirection); + } + } + + public void setErrorDrawable(Drawable dr, TextView tv) { + if (mDrawableError != dr && mDrawableError != null) { + mDrawableError.setCallback(null); + } + mDrawableError = dr; + + final Rect compoundRect = mCompoundRect; + int[] state = tv.getDrawableState(); + + if (mDrawableError != null) { + mDrawableError.setState(state); + mDrawableError.copyBounds(compoundRect); + mDrawableError.setCallback(tv); + mDrawableSizeError = compoundRect.width(); + mDrawableHeightError = compoundRect.height(); + } else { + mDrawableSizeError = mDrawableHeightError = 0; + } + } + + private void applyErrorDrawableIfNeeded(int layoutDirection) { + // first restore the initial state if needed + switch (mDrawableSaved) { + case DRAWABLE_LEFT: + mDrawableLeft = mDrawableTemp; + mDrawableSizeLeft = mDrawableSizeTemp; + mDrawableHeightLeft = mDrawableHeightTemp; + break; + case DRAWABLE_RIGHT: + mDrawableRight = mDrawableTemp; + mDrawableSizeRight = mDrawableSizeTemp; + mDrawableHeightRight = mDrawableHeightTemp; + break; + case DRAWABLE_NONE: + default: + } + // then, if needed, assign the Error drawable to the correct location + if (mDrawableError != null) { + switch(layoutDirection) { + case LAYOUT_DIRECTION_RTL: + mDrawableSaved = DRAWABLE_LEFT; + + mDrawableTemp = mDrawableLeft; + mDrawableSizeTemp = mDrawableSizeLeft; + mDrawableHeightTemp = mDrawableHeightLeft; + + mDrawableLeft = mDrawableError; + mDrawableSizeLeft = mDrawableSizeError; + mDrawableHeightLeft = mDrawableHeightError; + break; + case LAYOUT_DIRECTION_LTR: + default: + mDrawableSaved = DRAWABLE_RIGHT; + + mDrawableTemp = mDrawableRight; + mDrawableSizeTemp = mDrawableSizeRight; + mDrawableHeightTemp = mDrawableHeightRight; + + mDrawableRight = mDrawableError; + mDrawableSizeRight = mDrawableSizeError; + mDrawableHeightRight = mDrawableHeightError; + break; + } + } + } } + Drawables mDrawables; private CharWrapper mCharWrapper; @@ -8263,63 +8392,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return; } mLastLayoutDirection = layoutDirection; - // No drawable to resolve - if (mDrawables == null) { - return; - } - // No relative drawable to resolve - if (mDrawables.mDrawableStart == null && mDrawables.mDrawableEnd == null) { - return; - } - - Drawables dr = mDrawables; - switch(layoutDirection) { - case LAYOUT_DIRECTION_RTL: - if (dr.mDrawableStart != null) { - dr.mDrawableRight = dr.mDrawableStart; - - dr.mDrawableSizeRight = dr.mDrawableSizeStart; - dr.mDrawableHeightRight = dr.mDrawableHeightStart; - } - if (dr.mDrawableEnd != null) { - dr.mDrawableLeft = dr.mDrawableEnd; - dr.mDrawableSizeLeft = dr.mDrawableSizeEnd; - dr.mDrawableHeightLeft = dr.mDrawableHeightEnd; - } - break; - - case LAYOUT_DIRECTION_LTR: - default: - if (dr.mDrawableStart != null) { - dr.mDrawableLeft = dr.mDrawableStart; - - dr.mDrawableSizeLeft = dr.mDrawableSizeStart; - dr.mDrawableHeightLeft = dr.mDrawableHeightStart; - } - if (dr.mDrawableEnd != null) { - dr.mDrawableRight = dr.mDrawableEnd; - - dr.mDrawableSizeRight = dr.mDrawableSizeEnd; - dr.mDrawableHeightRight = dr.mDrawableHeightEnd; - } - break; - } - updateDrawablesLayoutDirection(dr, layoutDirection); - } - - private void updateDrawablesLayoutDirection(Drawables dr, int layoutDirection) { - if (dr.mDrawableLeft != null) { - dr.mDrawableLeft.setLayoutDirection(layoutDirection); - } - if (dr.mDrawableRight != null) { - dr.mDrawableRight.setLayoutDirection(layoutDirection); - } - if (dr.mDrawableTop != null) { - dr.mDrawableTop.setLayoutDirection(layoutDirection); - } - if (dr.mDrawableBottom != null) { - dr.mDrawableBottom.setLayoutDirection(layoutDirection); + // Resolve drawables + if (mDrawables != null) { + mDrawables.resolveWithLayoutDirection(layoutDirection); } } @@ -8327,6 +8403,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @hide */ protected void resetResolvedDrawables() { + super.resetResolvedDrawables(); mLastLayoutDirection = -1; } diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png Binary files differnew file mode 100644 index 000000000000..8b43f4ee333c --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error.9.png diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png Binary files differnew file mode 100644 index 000000000000..20e9002008bb --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above.9.png diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..b5f397c46411 --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_dark.9.png diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..a04d6954d785 --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_above_holo_light.9.png diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..8567b1f3a837 --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_dark.9.png diff --git a/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..7d1754ce0ef7 --- /dev/null +++ b/core/res/res/drawable-ldrtl-hdpi/popup_inline_error_holo_light.9.png diff --git a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png Binary files differnew file mode 100644 index 000000000000..d2efb6241bc7 --- /dev/null +++ b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error.9.png diff --git a/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png Binary files differnew file mode 100644 index 000000000000..04d200dcb4c9 --- /dev/null +++ b/core/res/res/drawable-ldrtl-ldpi/popup_inline_error_above.9.png diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png Binary files differnew file mode 100644 index 000000000000..27e8d4fe420d --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error.9.png diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png Binary files differnew file mode 100644 index 000000000000..4ae2b91d1fbf --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above.9.png diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..8cc3b693f082 --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_dark.9.png diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..7a84200d72dd --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_above_holo_light.9.png diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..8fc2e2ed9759 --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_dark.9.png diff --git a/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..687a691ad698 --- /dev/null +++ b/core/res/res/drawable-ldrtl-mdpi/popup_inline_error_holo_light.9.png diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png Binary files differnew file mode 100644 index 000000000000..db91a5660466 --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error.9.png diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png Binary files differnew file mode 100644 index 000000000000..90820b5fa9a0 --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above.9.png diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..598997518833 --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_dark.9.png diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..3b3f87d3af10 --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_above_holo_light.9.png diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..75baba28be9e --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_dark.9.png diff --git a/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..6c0203da995e --- /dev/null +++ b/core/res/res/drawable-ldrtl-xhdpi/popup_inline_error_holo_light.9.png diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 22f699ff0b8f..56abed4d416e 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -5088,18 +5088,23 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // top of the stack for the media button event receivers : simply using the top of the // stack would make the entry disappear from the RemoteControlDisplay in conditions such as // notifications playing during music playback. - // crawl the AudioFocus stack until an entry is found with the following characteristics: + // Crawl the AudioFocus stack from the top until an entry is found with the following + // characteristics: // - focus gain on STREAM_MUSIC stream // - non-transient focus gain on a stream other than music FocusStackEntry af = null; - Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); - while(stackIterator.hasNext()) { - FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); - if ((fse.mStreamType == AudioManager.STREAM_MUSIC) - || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) { - af = fse; - break; + try { + for (int index = mFocusStack.size()-1; index >= 0; index--) { + FocusStackEntry fse = mFocusStack.elementAt(index); + if ((fse.mStreamType == AudioManager.STREAM_MUSIC) + || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) { + af = fse; + break; + } } + } catch (ArrayIndexOutOfBoundsException e) { + Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e); + af = null; } if (af == null) { clearRemoteControlDisplay_syncAfRcs(); @@ -5120,6 +5125,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { clearRemoteControlDisplay_syncAfRcs(); return; } + // refresh conditions were verified: update the remote controls // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java index dbd999913637..762711d1b745 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java @@ -18,10 +18,9 @@ package com.android.internal.policy.impl.keyguard; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; -import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Point; +import android.graphics.Rect; import android.os.Handler; import android.os.SystemClock; import android.util.Log; @@ -53,17 +52,20 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli private final Handler mHandler = new Handler(); private final KeyguardActivityLauncher mActivityLauncher; private final Callbacks mCallbacks; + private final CameraWidgetInfo mWidgetInfo; private final WindowManager mWindowManager; private final Point mRenderedSize = new Point(); - private final int[] mScreenLocation = new int[2]; + private final int[] mTmpLoc = new int[2]; + private final Rect mTmpRect = new Rect(); - private View mWidgetView; private long mLaunchCameraStart; private boolean mActive; private boolean mTransitioning; - private boolean mRecovering; private boolean mDown; + private FixedSizeFrameLayout mPreview; + private View mFullscreenPreview; + private final Runnable mTransitionToCameraRunnable = new Runnable() { @Override public void run() { @@ -81,19 +83,16 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable); }}; - private final Runnable mRecoverRunnable = new Runnable() { + private final Runnable mPostTransitionToCameraEndAction = new Runnable() { @Override public void run() { - recover(); + mHandler.post(mTransitionToCameraEndAction); }}; - private final Runnable mRecoverEndAction = new Runnable() { + private final Runnable mRecoverRunnable = new Runnable() { @Override public void run() { - if (!mRecovering) - return; - mCallbacks.onCameraLaunchedUnsuccessfully(); - reset(); + recover(); }}; private final Runnable mRenderRunnable = new Runnable() { @@ -119,13 +118,43 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli }; }; + private static final class FixedSizeFrameLayout extends FrameLayout { + int width; + int height; + + FixedSizeFrameLayout(Context context) { + super(context); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + measureChildren( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + setMeasuredDimension(width, height); + } + } + private CameraWidgetFrame(Context context, Callbacks callbacks, - KeyguardActivityLauncher activityLauncher) { + KeyguardActivityLauncher activityLauncher, + CameraWidgetInfo widgetInfo, View previewWidget) { super(context); mCallbacks = callbacks; mActivityLauncher = activityLauncher; + mWidgetInfo = widgetInfo; mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); KeyguardUpdateMonitor.getInstance(context).registerCallback(mCallback); + + mPreview = new FixedSizeFrameLayout(context); + mPreview.addView(previewWidget); + addView(mPreview); + + View clickBlocker = new View(context); + clickBlocker.setBackgroundColor(Color.TRANSPARENT); + clickBlocker.setOnClickListener(this); + addView(clickBlocker); + + setContentDescription(context.getString(R.string.keyguard_accessibility_camera)); if (DEBUG) Log.d(TAG, "new CameraWidgetFrame instance " + instanceId()); } @@ -137,24 +166,17 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli CameraWidgetInfo widgetInfo = launcher.getCameraWidgetInfo(); if (widgetInfo == null) return null; - View widgetView = widgetInfo.layoutId > 0 ? - inflateWidgetView(context, widgetInfo) : - inflateGenericWidgetView(context); - if (widgetView == null) + View previewWidget = getPreviewWidget(context, widgetInfo); + if (previewWidget == null) return null; - ImageView preview = new ImageView(context); - preview.setLayoutParams(new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT)); - preview.setScaleType(ScaleType.FIT_CENTER); - preview.setContentDescription(preview.getContext().getString( - R.string.keyguard_accessibility_camera)); - CameraWidgetFrame cameraWidgetFrame = new CameraWidgetFrame(context, callbacks, launcher); - cameraWidgetFrame.addView(preview); - cameraWidgetFrame.mWidgetView = widgetView; - preview.setOnClickListener(cameraWidgetFrame); - return cameraWidgetFrame; + return new CameraWidgetFrame(context, callbacks, launcher, widgetInfo, previewWidget); + } + + private static View getPreviewWidget(Context context, CameraWidgetInfo widgetInfo) { + return widgetInfo.layoutId > 0 ? + inflateWidgetView(context, widgetInfo) : + inflateGenericWidgetView(context); } private static View inflateWidgetView(Context context, CameraWidgetInfo widgetInfo) { @@ -188,119 +210,99 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli return iv; } - public void render() { - final Throwable[] thrown = new Throwable[1]; - final Bitmap[] offscreen = new Bitmap[1]; - try { - final int width = getRootView().getWidth(); - final int height = getRootView().getHeight(); - if (mRenderedSize.x == width && mRenderedSize.y == height) { - if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s", - width, height)); - return; - } - if (width == 0 || height == 0) { - return; - } - final long start = SystemClock.uptimeMillis(); - offscreen[0] = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - final Canvas c = new Canvas(offscreen[0]); - mWidgetView.measure( - MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); - mWidgetView.layout(0, 0, width, height); - mWidgetView.draw(c); - - final long end = SystemClock.uptimeMillis(); - if (DEBUG) Log.d(TAG, String.format( - "Rendered camera widget in %sms size=%sx%s instance=%s at %s", - end - start, - width, height, - instanceId(), - end)); - mRenderedSize.set(width, height); - } catch (Throwable t) { - thrown[0] = t; + private void render() { + final View root = getRootView(); + final int width = root.getWidth(); + final int height = root.getHeight(); + if (mRenderedSize.x == width && mRenderedSize.y == height) { + if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s", width, height)); + return; + } + if (width == 0 || height == 0) { + return; } - mHandler.post(new Runnable() { - @Override - public void run() { - if (thrown[0] == null) { - try { - ((ImageView) getChildAt(0)).setImageBitmap(offscreen[0]); - } catch (Throwable t) { - thrown[0] = t; - } - } - if (thrown[0] == null) - return; - - Log.w(TAG, "Error rendering camera widget", thrown[0]); - try { - removeAllViews(); - final View genericView = inflateGenericWidgetView(mContext); - addView(genericView); - } catch (Throwable t) { - Log.w(TAG, "Error inflating generic camera widget", t); - } - }}); - } - - private void transitionToCamera() { - if (mTransitioning || mDown) return; + mPreview.width = width; + mPreview.height = height; + mPreview.requestLayout(); - mTransitioning = true; + final int thisWidth = getWidth() - getPaddingLeft() - getPaddingRight(); + final int thisHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - final View child = getChildAt(0); - final View root = getRootView(); + final float pvScaleX = (float) thisWidth / width; + final float pvScaleY = (float) thisHeight / height; + final float pvScale = Math.min(pvScaleX, pvScaleY); - final int startWidth = child.getWidth(); - final int startHeight = child.getHeight(); + final int pvWidth = (int) (pvScale * width); + final int pvHeight = (int) (pvScale * height); - final int finishWidth = root.getWidth(); - final int finishHeight = root.getHeight(); + final float pvTransX = pvWidth < thisWidth ? (thisWidth - pvWidth) / 2 : 0; + final float pvTransY = pvHeight < thisHeight ? (thisHeight - pvHeight) / 2 : 0; - final float scaleX = (float) finishWidth / startWidth; - final float scaleY = (float) finishHeight / startHeight; - final float scale = Math.round( Math.max(scaleX, scaleY) * 100) / 100f; + mPreview.setPivotX(0); + mPreview.setPivotY(0); + mPreview.setScaleX(pvScale); + mPreview.setScaleY(pvScale); + mPreview.setTranslationX(pvTransX); + mPreview.setTranslationY(pvTransY); - final int[] loc = new int[2]; - root.getLocationInWindow(loc); - final int finishCenter = loc[1] + finishHeight / 2; + mRenderedSize.set(width, height); + if (DEBUG) Log.d(TAG, String.format("Rendered camera widget size=%sx%s instance=%s", + width, height, instanceId())); + } - child.getLocationInWindow(loc); - final int startCenter = loc[1] + startHeight / 2; + private void transitionToCamera() { + if (mTransitioning || mDown) return; - if (DEBUG) Log.d(TAG, String.format("Transitioning to camera. " + - "(start=%sx%s, finish=%sx%s, scale=%s,%s, startCenter=%s, finishCenter=%s)", - startWidth, startHeight, - finishWidth, finishHeight, - scaleX, scaleY, - startCenter, finishCenter)); + mTransitioning = true; enableWindowExitAnimation(false); - animate() - .scaleX(scale) - .scaleY(scale) - .translationY(finishCenter - startCenter) - .setDuration(WIDGET_ANIMATION_DURATION) - .withEndAction(mTransitionToCameraEndAction) - .start(); - mCallbacks.onLaunchingCamera(); - } + mPreview.getLocationInWindow(mTmpLoc); + final float pvHeight = mPreview.getHeight() * mPreview.getScaleY(); + final float pvCenter = mTmpLoc[1] + pvHeight / 2f; - private void recover() { - if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis()); - mRecovering = true; - animate() + final ViewGroup root = (ViewGroup) getRootView(); + if (mFullscreenPreview == null) { + mFullscreenPreview = getPreviewWidget(mContext, mWidgetInfo); + mFullscreenPreview.setClickable(false); + root.addView(mFullscreenPreview); + } + + root.getWindowVisibleDisplayFrame(mTmpRect); + final float fsHeight = mTmpRect.height(); + final float fsCenter = mTmpRect.top + fsHeight / 2; + + final float fsScaleY = pvHeight / fsHeight; + final float fsTransY = pvCenter - fsCenter; + final float fsScaleX = mPreview.getScaleX(); + + mPreview.setVisibility(View.GONE); + mFullscreenPreview.setVisibility(View.VISIBLE); + mFullscreenPreview.setTranslationY(fsTransY); + mFullscreenPreview.setScaleX(fsScaleX); + mFullscreenPreview.setScaleY(fsScaleY); + mFullscreenPreview + .animate() .scaleX(1) .scaleY(1) + .translationX(0) .translationY(0) .setDuration(WIDGET_ANIMATION_DURATION) - .withEndAction(mRecoverEndAction) + .withEndAction(mPostTransitionToCameraEndAction) .start(); + mCallbacks.onLaunchingCamera(); + } + + private void recover() { + if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis()); + mCallbacks.onCameraLaunchedUnsuccessfully(); + reset(); + } + + @Override + public void setOnLongClickListener(OnLongClickListener l) { + // ignore } @Override @@ -340,8 +342,8 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli return true; } - getLocationOnScreen(mScreenLocation); - int rawBottom = mScreenLocation[1] + getHeight(); + getLocationOnScreen(mTmpLoc); + int rawBottom = mTmpLoc[1] + getHeight(); if (event.getRawY() > rawBottom) { if (DEBUG) Log.d(TAG, "onUserInteraction eaten: below widget"); return true; @@ -388,14 +390,14 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli if (DEBUG) Log.d(TAG, "reset at " + SystemClock.uptimeMillis()); mLaunchCameraStart = 0; mTransitioning = false; - mRecovering = false; mDown = false; cancelTransitionToCamera(); mHandler.removeCallbacks(mRecoverRunnable); - animate().cancel(); - setScaleX(1); - setScaleY(1); - setTranslationY(0); + mPreview.setVisibility(View.VISIBLE); + if (mFullscreenPreview != null) { + mFullscreenPreview.animate().cancel(); + mFullscreenPreview.setVisibility(View.GONE); + } enableWindowExitAnimation(true); } @@ -403,11 +405,18 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s", w, h, oldw, oldh, SystemClock.uptimeMillis())); - final Handler worker = getWorkerHandler(); - (worker != null ? worker : mHandler).post(mRenderRunnable); + mHandler.post(mRenderRunnable); super.onSizeChanged(w, h, oldw, oldh); } + @Override + public void onBouncerShowing(boolean showing) { + if (showing) { + mTransitioning = false; + mHandler.post(mRecoverRunnable); + } + } + private void enableWindowExitAnimation(boolean isEnabled) { View root = getRootView(); ViewGroup.LayoutParams lp = root.getLayoutParams(); @@ -427,15 +436,14 @@ public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnCli if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged " + showing + " at " + SystemClock.uptimeMillis()); if (mTransitioning && !showing) { - mTransitioning = false; - mRecovering = false; - mHandler.removeCallbacks(mRecoverRunnable); - if (mLaunchCameraStart > 0) { - long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart; - if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime)); - mLaunchCameraStart = 0; - onCameraLaunched(); - } + mTransitioning = false; + mHandler.removeCallbacks(mRecoverRunnable); + if (mLaunchCameraStart > 0) { + long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart; + if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime)); + mLaunchCameraStart = 0; + onCameraLaunched(); + } } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java index 3c792064a392..53b149c447a4 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java @@ -512,6 +512,10 @@ public class KeyguardWidgetFrame extends FrameLayout { return false; } + public void onBouncerShowing(boolean showing) { + // hook for subclasses + } + public void setWorkerHandler(Handler workerHandler) { mWorkerHandler = workerHandler; } @@ -519,4 +523,5 @@ public class KeyguardWidgetFrame extends FrameLayout { public Handler getWorkerHandler() { return mWorkerHandler; } + } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java index 85b5472ab081..f62af8e483df 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java @@ -775,6 +775,9 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f)); mZoomInOutAnim.start(); } + if (currentPage instanceof KeyguardWidgetFrame) { + ((KeyguardWidgetFrame)currentPage).onBouncerShowing(false); + } } // Zoom out after the bouncer is initiated @@ -800,6 +803,9 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f)); mZoomInOutAnim.start(); } + if (currentPage instanceof KeyguardWidgetFrame) { + ((KeyguardWidgetFrame)currentPage).onBouncerShowing(true); + } } boolean isAddPage(int pageIndex) { diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index da6f1fab6d3b..c33fc71ed4db 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -386,6 +386,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private Locale mLastSystemLocale; private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor(); private final IPackageManager mIPackageManager; + private boolean mInputBoundToKeyguard; class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler) { @@ -877,10 +878,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final boolean hardKeyShown = haveHardKeyboard && conf.hardKeyboardHidden != Configuration.HARDKEYBOARDHIDDEN_YES; - final boolean isScreenLocked = mKeyguardManager != null - && mKeyguardManager.isKeyguardLocked() - && mKeyguardManager.isKeyguardSecure(); - mImeWindowVis = (!isScreenLocked && (mInputShown || hardKeyShown)) ? + final boolean isScreenLocked = + mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); + final boolean isScreenSecurelyLocked = + isScreenLocked && mKeyguardManager.isKeyguardSecure(); + final boolean inputShown = mInputShown && (!isScreenLocked || mInputBoundToKeyguard); + mImeWindowVis = (!isScreenSecurelyLocked && (inputShown || hardKeyShown)) ? (InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE) : 0; updateImeWindowStatusLocked(); } @@ -1124,6 +1127,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return mNoBinding; } + if (mCurClient == null) { + mInputBoundToKeyguard = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); + if (DEBUG) { + Slog.v(TAG, "New bind. keyguard = " + mInputBoundToKeyguard); + } + } + if (mCurClient != cs) { // If the client is changing, we need to switch over to the new // one. diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index fa84f486ac59..e2be577b489f 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -1128,13 +1128,13 @@ public class NotificationManagerService extends INotificationManager.Stub final boolean hasCustomVibrate = notification.vibrate != null; // new in 4.2: if there was supposed to be a sound and we're in vibrate mode, - // and no other vibration is specified, we apply the default vibration anyway + // and no other vibration is specified, we fall back to vibration final boolean convertSoundToVibration = !hasCustomVibrate && hasValidSound && (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); - // The DEFAULT_VIBRATE flag trumps any custom vibration. + // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. final boolean useDefaultVibrate = (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; @@ -1147,8 +1147,8 @@ public class NotificationManagerService extends INotificationManager.Stub // does not have the VIBRATE permission. long identity = Binder.clearCallingIdentity(); try { - mVibrator.vibrate(convertSoundToVibration ? mFallbackVibrationPattern - : mDefaultVibrationPattern, + mVibrator.vibrate(useDefaultVibrate ? mDefaultVibrationPattern + : mFallbackVibrationPattern, ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1); } finally { Binder.restoreCallingIdentity(identity); diff --git a/tests/MemoryUsage/Android.mk b/tests/MemoryUsage/Android.mk index e7bfb4f45c6f..0ab793b0e0c4 100644 --- a/tests/MemoryUsage/Android.mk +++ b/tests/MemoryUsage/Android.mk @@ -8,7 +8,8 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := MemoryUsage -LOCAL_SDK_VERSION := 7 +LOCAL_CERTIFICATE := platform +LOCAL_JAVA_LIBRARIES := android.test.runner include $(BUILD_PACKAGE) diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java index 5e27ba791e36..b550957de63a 100644 --- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java +++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java @@ -18,14 +18,17 @@ package com.android.tests.memoryusage; import android.app.ActivityManager; import android.app.ActivityManager.ProcessErrorStateInfo; import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.ActivityManagerNative; +import android.app.IActivityManager; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.os.Debug.MemoryInfo; +import android.os.RemoteException; +import android.os.UserHandle; import android.test.InstrumentationTestCase; import android.util.Log; @@ -48,8 +51,9 @@ public class MemoryUsageTest extends InstrumentationTestCase { private static final int SLEEP_TIME = 1000; private static final int THRESHOLD = 1024; - private static final int MAX_ITERATIONS = 10; - private static final int MIN_ITERATIONS = 4; + private static final int MAX_ITERATIONS = 20; + private static final int MIN_ITERATIONS = 6; + private static final int JOIN_TIMEOUT = 10000; private static final String TAG = "MemoryUsageInstrumentation"; private static final String KEY_APPS = "apps"; @@ -58,10 +62,13 @@ public class MemoryUsageTest extends InstrumentationTestCase { private Map<String, String> mNameToProcess; private Map<String, String> mNameToResultKey; + private IActivityManager mAm; + public void testMemory() { MemoryUsageInstrumentation instrumentation = - (MemoryUsageInstrumentation) getInstrumentation(); + (MemoryUsageInstrumentation) getInstrumentation(); Bundle args = instrumentation.getBundle(); + mAm = ActivityManagerNative.getDefault(); createMappings(); parseArgs(args); @@ -136,7 +143,16 @@ public class MemoryUsageTest extends InstrumentationTestCase { String process = mNameToProcess.get(appName); Intent startIntent = mNameToIntent.get(appName); - getInstrumentation().getContext().startActivity(startIntent); + + AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent); + Thread t = new Thread(runnable); + t.start(); + try { + t.join(JOIN_TIMEOUT); + } catch (InterruptedException e) { + // ignore + } + return process; } @@ -234,7 +250,7 @@ public class MemoryUsageTest extends InstrumentationTestCase { } int[] pids = { - proc.pid }; + proc.pid }; MemoryInfo meminfo = am.getProcessMemoryInfo(pids)[0]; return meminfo.getTotalPss(); @@ -242,4 +258,29 @@ public class MemoryUsageTest extends InstrumentationTestCase { } return -1; } + + private class AppLaunchRunnable implements Runnable { + private Intent mLaunchIntent; + + public AppLaunchRunnable(Intent intent) { + mLaunchIntent = intent; + } + + public void run() { + try { + String mimeType = mLaunchIntent.getType(); + if (mimeType == null && mLaunchIntent.getData() != null + && "content".equals(mLaunchIntent.getData().getScheme())) { + mimeType = mAm.getProviderMimeType(mLaunchIntent.getData(), + UserHandle.USER_CURRENT); + } + + mAm.startActivityAndWait(null, mLaunchIntent, mimeType, + null, null, 0, mLaunchIntent.getFlags(), null, null, null, + UserHandle.USER_CURRENT_OR_SELF); + } catch (RemoteException e) { + Log.w(TAG, "Error launching app", e); + } + } + } } |