Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cdf8b487 authored by Adam Powell's avatar Adam Powell
Browse files

Fix keyguard bugs

Integrate from proto app

Get some layout/alignment right between security views, bouncer,
etc. Expand the space available for the more cramped security views
when not in the bouncer.

Fix bug 7434391 - don't allow widget swiping in bouncer mode. Fix a
few other bouncer-related state tracking problems as well.

Use layers when moving the security view around.

Change-Id: Ied14bab8bb5c3d997c734a3ae657b766c427253f
parent e0ec5d42
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -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>
+2 −0
Original line number Diff line number Diff line
@@ -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">
+119 −10
Original line number Diff line number Diff line
@@ -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);
            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;
                        }
                    }
@@ -630,6 +684,52 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
        return true;
    }

    /**
     * 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);