diff options
11 files changed, 298 insertions, 35 deletions
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml index 544447149eb8..a3c81054537d 100644 --- a/core/res/res/layout-port/keyguard_host_view.xml +++ b/core/res/res/layout-port/keyguard_host_view.xml @@ -36,7 +36,8 @@ <FrameLayout android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + androidprv:layout_childType="widgets"> <include layout="@layout/keyguard_widget_pager" android:id="@+id/app_widget_container" android:layout_width="match_parent" @@ -51,12 +52,11 @@ <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer android:id="@+id/keyguard_security_container" - android:layout_width="@dimen/keyguard_security_width" + android:layout_width="wrap_content" android:layout_height="@dimen/keyguard_security_height" androidprv:layout_childType="challenge" - android:layout_marginLeft="@dimen/kg_edge_swipe_region_size" - android:layout_marginRight="@dimen/kg_edge_swipe_region_size" android:background="@drawable/kg_bouncer_bg_white" + android:padding="0dp" android:gravity="bottom|center_horizontal"> <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper android:id="@+id/view_flipper" @@ -64,9 +64,7 @@ android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false" - android:paddingLeft="@dimen/keyguard_security_view_margin" android:paddingTop="@dimen/keyguard_security_view_margin" - android:paddingRight="@dimen/keyguard_security_view_margin" android:gravity="center"> </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper> </com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index d186c4a85f66..627099c2fd20 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5798,6 +5798,8 @@ <!-- Scrim. This will block access to child views that come before it in the child list in bouncer mode. --> <enum name="scrim" value="4" /> + <!-- The home for widgets. All widgets will be descendents of this. --> + <enum name="widgets" value="5" /> </attr> <declare-styleable name="SlidingChallengeLayout"> diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml index d1df2a4ca318..053fc851ca31 100644 --- a/core/res/res/values/integers.xml +++ b/core/res/res/values/integers.xml @@ -18,7 +18,7 @@ --> <resources> <integer name="kg_carousel_angle">75</integer> - <integer name="kg_security_flip_duration">75</integer> - <integer name="kg_security_fade_duration">75</integer> + <integer name="kg_security_flip_duration">100</integer> + <integer name="kg_security_fade_duration">100</integer> <integer name="kg_glowpad_rotation_offset">0</integer> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 159eec181275..4a4f1c402572 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2276,14 +2276,12 @@ <string name="keyguard_accessibility_add_widget">Add widget.</string> <!-- Accessibility description of the empty sidget slot (place holder for a new widget). [CHAR_LIMIT=none] --> <string name="keyguard_accessibility_widget_empty_slot">Empty</string> - <!-- Accessibility description of the unlock area. [CHAR_LIMIT=none] --> - <string name="keyguard_accessibility_unlock_area">Unlock area.</string> <!-- Accessibility description of the event of expanding an unlock area. [CHAR_LIMIT=none] --> <string name="keyguard_accessibility_unlock_area_expanded">Unlock area expanded.</string> <!-- Accessibility description of the event of collapsing an unlock area. [CHAR_LIMIT=none] --> <string name="keyguard_accessibility_unlock_area_collapsed">Unlock area collapsed.</string> <!-- Accessibility description of a lock screen widget. [CHAR_LIMIT=none] --> - <string name="keyguard_accessibility_widget">%1$s widget.</string> + <string name="keyguard_accessibility_widget"><xliff:g id="widget_index">%1$s</xliff:g> widget.</string> <!-- Accessibility description of the lock screen user selector widget. [CHAR_LIMIT=none] --> <string name="keyguard_accessibility_user_selector">User selector</string> <!-- Accessibility description of the lock screen status widget. [CHAR_LIMIT=none] --> @@ -2292,6 +2290,28 @@ <string name="keyguard_accessibility_camera">Camera</string> <!-- Accessibility description of the lock media control widget. [CHAR_LIMIT=none] --> <string name="keygaurd_accessibility_media_controls">Media controls</string> + <!-- Accessibility description of widget reordering start. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_widget_reorder_start">Widget reordering started.</string> + <!-- Accessibility description of widget reordering end. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_widget_reorder_end">Widget reordering ended.</string> + <!-- Accessibility description of the a widget deletion event. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_widget_deleted">Widget <xliff:g id="widget_index">%1$s</xliff:g> deleted.</string> + <!-- Accessibility description of the button to expand the lock area. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_expand_lock_area">Expand unlock area.</string> + <!-- Accessibility description of the slide unlock. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_slide_unlock">Slide unlock.</string> + <!-- Accessibility description of the pattern unlock. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_pattern_unlock">Pattern unlock.</string> + <!-- Accessibility description of the face unlock. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_face_unlock">Face unlock.</string> + <!-- Accessibility description of the pin lock. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_pin_unlock">Pin unlock.</string> + <!-- Accessibility description of the password lock. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_password_unlock">Password unlock.</string> + <!-- Accessibility description of the unlock pattern area. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_pattern_area">Pattern area.</string> + <!-- Accessibility description of the unlock slide area. [CHAR_LIMIT=none] --> + <string name="keyguard_accessibility_slide_area">Slide area.</string> <!-- Password keyboard strings. Used by LockScreen and Settings --><skip /> <!-- Label for "switch to symbols" key. Must be short to fit on key! --> diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java index e929fb1cff7b..96cd7ac72758 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -670,13 +670,10 @@ public class KeyguardHostView extends KeyguardViewBase { // Find and show this child. final int childCount = mSecurityViewContainer.getChildCount(); - // Do flip animation to the next screen - if (false) { - mSecurityViewContainer.setInAnimation( - AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_in)); - mSecurityViewContainer.setOutAnimation( - AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_out)); - } + mSecurityViewContainer.setInAnimation( + AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_in)); + mSecurityViewContainer.setOutAnimation( + AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_out)); final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); for (int i = 0; i < childCount; i++) { if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) { diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java index ca78cf95a7eb..5e331e1aafbf 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java @@ -16,6 +16,9 @@ package com.android.internal.policy.impl.keyguard; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; import android.content.ContentResolver; import android.content.Context; import android.os.Handler; @@ -39,11 +42,15 @@ class KeyguardMessageArea extends TextView { static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery; static final int SECURITY_MESSAGE_DURATION = 5000; - static final String SEPARATOR = " "; + protected static final int FADE_DURATION = 750; + static final String SEPARATOR = " "; // are we showing battery information? boolean mShowingBatteryInfo = false; + // is the bouncer up? + boolean mShowingBouncer = false; + // last known plugged in state boolean mPluggedIn = false; @@ -68,7 +75,11 @@ class KeyguardMessageArea extends TextView { public void run() { mMessage = null; mShowingMessage = false; - update(); + if (mShowingBouncer) { + hideMessage(FADE_DURATION, true); + } else { + update(); + } } }; @@ -103,6 +114,18 @@ class KeyguardMessageArea extends TextView { } @Override + public void showBouncer(int duration) { + mMessageArea.hideMessage(duration, false); + mMessageArea.mShowingBouncer = true; + } + + @Override + public void hideBouncer(int duration) { + mMessageArea.showMessage(duration); + mMessageArea.mShowingBouncer = false; + } + + @Override public void setTimeout(int timeoutMs) { mMessageArea.mTimeout = timeoutMs; } @@ -139,6 +162,7 @@ class KeyguardMessageArea extends TextView { } public void securityMessageChanged() { + setAlpha(1f); mShowingMessage = true; update(); mHandler.removeCallbacks(mClearMessageRunnable); @@ -212,4 +236,23 @@ class KeyguardMessageArea extends TextView { return string; } + private void hideMessage(int duration, boolean thenUpdate) { + Animator anim = ObjectAnimator.ofFloat(this, "alpha", 0f); + anim.setDuration(duration); + if (thenUpdate) { + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + update(); + } + }); + } + anim.start(); + } + + private void showMessage(int duration) { + Animator anim = ObjectAnimator.ofFloat(this, "alpha", 1f); + anim.setDuration(duration); + anim.start(); + } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java index f6a90c5941bc..04ab0a2b7f41 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java @@ -1,11 +1,20 @@ package com.android.internal.policy.impl.keyguard; +import android.animation.Animator; +import android.animation.ObjectAnimator; import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.FrameLayout; +import com.android.internal.R; + public class KeyguardSecurityContainer extends FrameLayout { + private float mBackgroundAlpha; + private Drawable mBackgroundDrawable; + public KeyguardSecurityContainer(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -16,5 +25,44 @@ public class KeyguardSecurityContainer extends FrameLayout { public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + mBackgroundDrawable = context.getResources().getDrawable(R.drawable.kg_bouncer_bg_white); + } + + public void setBackgroundAlpha(float alpha) { + if (Float.compare(mBackgroundAlpha, alpha) != 0) { + mBackgroundAlpha = alpha; + invalidate(); + } + } + + public float getBackgroundAlpha() { + return mBackgroundAlpha; + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (mBackgroundAlpha > 0.0f && mBackgroundDrawable != null) { + Drawable bg = mBackgroundDrawable; + bg.setAlpha((int) (mBackgroundAlpha * 255)); + bg.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + bg.draw(canvas); + } + super.dispatchDraw(canvas); + } + + public void showBouncer(int duration) { + SecurityMessageDisplay message = new KeyguardMessageArea.Helper(this); + message.showBouncer(duration); + Animator anim = ObjectAnimator.ofFloat(this, "BackgroundAlpha", 1f); + anim.setDuration(duration); + anim.start(); + } + + public void hideBouncer(int duration) { + SecurityMessageDisplay message = new KeyguardMessageArea.Helper(this); + message.hideBouncer(duration); + Animator anim = ObjectAnimator.ofFloat(this, "BackgroundAlpha", 0f); + anim.setDuration(duration); + anim.start(); } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java index b4bd6e9e7a6c..7100f1c3a690 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java @@ -327,6 +327,14 @@ class KeyguardStatusViewManager implements SecurityMessageDisplay { } @Override + public void showBouncer(int duration) { + } + + @Override + public void hideBouncer(int duration) { + } + + @Override public void setTimeout(int timeout_ms) { } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java index a207f5d1048d..b38eb284d8b5 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java @@ -16,6 +16,10 @@ package com.android.internal.policy.impl.keyguard; +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; @@ -35,8 +39,9 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo public static final int HORIZONTAL = LinearLayout.HORIZONTAL; public static final int VERTICAL = LinearLayout.VERTICAL; + protected static final int ANIMATE_BOUNCE_DURATION = 750; - private View mChallengeView; + private KeyguardSecurityContainer mChallengeView; private View mUserSwitcherView; private View mScrimView; private OnBouncerStateChangedListener mBouncerListener; @@ -87,7 +92,19 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo if (mIsBouncing) return; mIsBouncing = true; if (mScrimView != null) { - mScrimView.setVisibility(GONE); + if (mChallengeView != null) { + mChallengeView.showBouncer(ANIMATE_BOUNCE_DURATION); + } + + Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f); + anim.setDuration(ANIMATE_BOUNCE_DURATION); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mScrimView.setVisibility(VISIBLE); + } + }); + anim.start(); } if (mBouncerListener != null) { mBouncerListener.onBouncerStateChanged(true); @@ -99,7 +116,19 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo if (!mIsBouncing) return; mIsBouncing = false; if (mScrimView != null) { - mScrimView.setVisibility(GONE); + if (mChallengeView != null) { + mChallengeView.hideBouncer(ANIMATE_BOUNCE_DURATION); + } + + Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f); + anim.setDuration(ANIMATE_BOUNCE_DURATION); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mScrimView.setVisibility(INVISIBLE); + } + }); + anim.start(); } if (mBouncerListener != null) { mBouncerListener.onBouncerStateChanged(false); @@ -131,7 +160,8 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo mScrimView.setOnClickListener(null); } mScrimView = scrim; - mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE); + mScrimView.setAlpha(mIsBouncing ? 1.0f : 0.0f); + mScrimView.setVisibility(mIsBouncing ? VISIBLE : INVISIBLE); mScrimView.setFocusable(true); mScrimView.setOnClickListener(mScrimClickListener); } @@ -165,7 +195,11 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo throw new IllegalStateException( "There may only be one child of type challenge"); } - mChallengeView = child; + if (!(child instanceof KeyguardSecurityContainer)) { + throw new IllegalArgumentException( + "Challenge must be a KeyguardSecurityContainer"); + } + mChallengeView = (KeyguardSecurityContainer) child; } else if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) { if (mUserSwitcherView != null) { throw new IllegalStateException( diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java b/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java index ec6472faeea7..7760279d2398 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java @@ -24,4 +24,8 @@ public interface SecurityMessageDisplay { public void setMessage(int resId, boolean important, Object... formatArgs); public void setTimeout(int timeout_ms); + + public void showBouncer(int animationDuration); + + public void hideBouncer(int animationDuration); } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java index 74b05dde38a3..7cf995c4f3f2 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java @@ -16,11 +16,14 @@ package com.android.internal.policy.impl.keyguard; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.FloatProperty; @@ -61,10 +64,12 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout private Drawable mHandleDrawable; private Drawable mFrameDrawable; private Drawable mDragIconDrawable; + private boolean mEdgeCaptured; // Initialized during measurement from child layoutparams private View mChallengeView; private View mScrimView; + private View mWidgetsView; // Range: 0 (fully hidden) to 1 (fully visible) private float mChallengeOffset = 1.f; @@ -110,9 +115,14 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout float mHandleAlpha; float mFrameAlpha; + float mFrameAnimationTarget = Float.MIN_VALUE; private ObjectAnimator mHandleAnimation; private ObjectAnimator mFrameAnimation; + private final Rect mTempRect = new Rect(); + + private boolean mHasGlowpad; + static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA = new FloatProperty<SlidingChallengeLayout>("handleAlpha") { @Override @@ -293,21 +303,43 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout mHandleAnimation.start(); } - void animateFrame(boolean visible, boolean full) { + void animateFrame(final boolean visible, final boolean full) { if (mFrameDrawable == null) return; - if (mFrameAnimation != null) { + final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f; + if (mFrameAnimation != null && targetAlpha != mFrameAnimationTarget) { mFrameAnimation.cancel(); - mFrameAnimation = null; + mFrameAnimationTarget = Float.MIN_VALUE; } - final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f; - if (targetAlpha == mFrameAlpha) { + if (targetAlpha == mFrameAlpha || targetAlpha == mFrameAnimationTarget) { return; } + mFrameAnimationTarget = targetAlpha; mFrameAnimation = ObjectAnimator.ofFloat(this, FRAME_ALPHA, targetAlpha); mFrameAnimation.setInterpolator(sHandleFadeInterpolator); mFrameAnimation.setDuration(HANDLE_ANIMATE_DURATION); + mFrameAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mFrameAnimationTarget = Float.MIN_VALUE; + + if (!visible && full && mChallengeView != null) { + // Mess with padding/margin to remove insets on the bouncer frame. + mChallengeView.setPadding(0, 0, 0, 0); + LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams(); + lp.leftMargin = lp.rightMargin = getChallengeMargin(true); + mChallengeView.setLayoutParams(lp); + } + mFrameAnimation = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + mFrameAnimationTarget = Float.MIN_VALUE; + mFrameAnimation = null; + } + }); mFrameAnimation.start(); } @@ -370,7 +402,9 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout mScrollState = state; animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing); - animateFrame(false , false); + if (!mIsBouncing) { + animateFrame(false, false); + } if (mScrollListener != null) { mScrollListener.onScrollStateChanged(state); } @@ -380,6 +414,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout void completeChallengeScroll() { setChallengeShowing(mChallengeOffset != 0); setScrollState(SCROLL_STATE_IDLE); + mChallengeView.setLayerType(LAYER_TYPE_NONE, null); } void setScrimView(View scrim) { @@ -461,7 +496,22 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout if (mScrimView != null) { mScrimView.setVisibility(VISIBLE); } + + // Mess with padding/margin to inset the bouncer frame. + // We have more space available to us otherwise. + if (mChallengeView != null) { + if (mFrameDrawable == null || !mFrameDrawable.getPadding(mTempRect)) { + mTempRect.set(0, 0, 0, 0); + } + mChallengeView.setPadding(mTempRect.left, mTempRect.top, mTempRect.right, + mTempRect.bottom); + final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams(); + lp.leftMargin = lp.rightMargin = getChallengeMargin(false); + mChallengeView.setLayoutParams(lp); + } + animateFrame(true, true); + if (mBouncerListener != null) { mBouncerListener.onBouncerStateChanged(true); } @@ -470,17 +520,21 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout @Override public void hideBouncer() { if (!mIsBouncing) return; - setChallengeShowing(false); + showChallenge(false); mIsBouncing = false; if (mScrimView != null) { mScrimView.setVisibility(GONE); } - animateFrame(false, false); + animateFrame(false, true); if (mBouncerListener != null) { mBouncerListener.onBouncerStateChanged(false); } } + private int getChallengeMargin(boolean expanded) { + return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop; + } + @Override public void requestDisallowInterceptTouchEvent(boolean allowIntercept) { // We'll intercept whoever we feel like! ...as long as it isn't a challenge view. @@ -495,8 +549,6 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout } mVelocityTracker.addMovement(ev); - //Log.v(TAG, "onIntercept: " + ev); - final int action = ev.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: @@ -525,6 +577,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout mGestureStartY = y; mGestureStartChallengeBottom = getChallengeBottom(); mDragging = true; + mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); } else if (isInChallengeView(x, y)) { mBlockDrag = true; } @@ -601,6 +654,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout mActivePointerId = ev.getPointerId(i); mGestureStartChallengeBottom = getChallengeBottom(); mDragging = true; + mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); break; } } @@ -631,6 +685,52 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout } /** + * The lifecycle of touch events is subtle and it's very easy to do something + * that will cause bugs that will be nasty to track when overriding this method. + * Normally one should always override onInterceptTouchEvent instead. + * + * To put it another way, don't try this at home. + */ + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + final int action = ev.getActionMasked(); + boolean handled = false; + if (action == MotionEvent.ACTION_DOWN) { + // Defensive programming: if we didn't get the UP or CANCEL, reset anyway. + mEdgeCaptured = false; + } + if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) { + // Normally we would need to do a lot of extra stuff here. + // We can only get away with this because we haven't padded in + // the widget pager or otherwise transformed it during layout. + // We also don't support things like splitting MotionEvents. + + // We set handled to captured even if dispatch is returning false here so that + // we don't send a different view a busted or incomplete event stream. + handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev); + } + + if (!handled && !mEdgeCaptured) { + handled = super.dispatchTouchEvent(ev); + } + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + mEdgeCaptured = false; + } + + return handled; + } + + private boolean isEdgeSwipeBeginEvent(MotionEvent ev) { + if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) { + return false; + } + + final float x = ev.getX(); + return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop; + } + + /** * We only want to add additional vertical space to the drag handle when the panel is fully * closed. */ @@ -699,8 +799,16 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout } // We're going to play silly games with the frame's background drawable later. mFrameDrawable = mChallengeView.getBackground(); + + if (!mHasLayout) { + // Set up the margin correctly based on our content for the first run. + mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null; + lp.leftMargin = lp.rightMargin = getChallengeMargin(true); + } } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) { setScrimView(child); + } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) { + mWidgetsView = child; } if (child.getVisibility() == GONE) continue; @@ -980,6 +1088,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout public static final int CHILD_TYPE_NONE = 0; public static final int CHILD_TYPE_CHALLENGE = 2; public static final int CHILD_TYPE_SCRIM = 4; + public static final int CHILD_TYPE_WIDGETS = 5; public LayoutParams() { this(MATCH_PARENT, WRAP_CONTENT); |