Beginnings of bouncer support; add scrims and state tracking

Integrating from prototype app

Change-Id: Ib142cf371c5997f547266d8af7e25129fb4e1343
This commit is contained in:
Adam Powell
2012-10-24 16:26:56 -07:00
parent 9253f56163
commit eee209313d
7 changed files with 156 additions and 34 deletions

View File

@@ -41,6 +41,13 @@
androidprv:layout_maxWidth="480dp"
androidprv:layout_maxHeight="480dp" />
<include layout="@layout/keyguard_multi_user_selector"/>
<View android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_childType="scrim"
android:background="#99000000" />
<com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
android:id="@+id/keyguard_security_container"
android:layout_width="wrap_content"
@@ -61,8 +68,6 @@
</com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
</com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>
<include layout="@layout/keyguard_multi_user_selector"/>
</com.android.internal.policy.impl.keyguard.MultiPaneChallengeLayout>
</com.android.internal.policy.impl.keyguard.KeyguardHostView>

View File

@@ -43,11 +43,16 @@
android:layout_gravity="center"/>
</FrameLayout>
<View android:layout_width="match_parent"
android:layout_height="match_parent"
androidprv:layout_childType="scrim"
android:background="#99000000" />
<com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
android:id="@+id/keyguard_security_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
androidprv:layout_isChallenge="true"
androidprv:layout_childType="challenge"
android:gravity="bottom|center_horizontal"
android:background="@drawable/security_frame">
<com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper

View File

@@ -42,6 +42,13 @@
androidprv:layout_maxWidth="480dp"
androidprv:layout_maxHeight="480dp" />
<include layout="@layout/keyguard_multi_user_selector"/>
<View android:layout_width="match_parent"
android:layout_height="match_parent"
androidprv:layout_childType="scrim"
android:background="#99000000" />
<com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
android:id="@+id/keyguard_security_container"
android:layout_width="wrap_content"
@@ -62,7 +69,5 @@
</com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
</com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>
<include layout="@layout/keyguard_multi_user_selector"/>
</com.android.internal.policy.impl.keyguard.MultiPaneChallengeLayout>
</com.android.internal.policy.impl.keyguard.KeyguardHostView>

View File

@@ -5776,12 +5776,31 @@
<attr name="leftToRight" format="boolean" />
</declare-styleable>
<!-- Some child types have special behavior. -->
<attr name="layout_childType">
<!-- No special behavior. Layout will proceed as normal. -->
<enum name="none" value="0" />
<!-- Widget container.
This will be resized in response to certain events. -->
<enum name="widget" value="1" />
<!-- Security challenge container.
This will be dismissed/shown in response to certain events,
possibly obscuring widget elements. -->
<enum name="challenge" value="2" />
<!-- User switcher.
This will consume space from the total layout area. -->
<enum name="userSwitcher" value="3" />
<!-- Scrim. This will block access to child views that
come before it in the child list in bouncer mode. -->
<enum name="scrim" value="4" />
</attr>
<declare-styleable name="SlidingChallengeLayout">
<attr name="dragHandle" format="reference" />
</declare-styleable>
<declare-styleable name="SlidingChallengeLayout_Layout">
<attr name="layout_isChallenge" format="boolean" />
<attr name="layout_childType" />
</declare-styleable>
<!-- Attributes that can be used with <code>&lt;FragmentBreadCrumbs&gt;</code>
@@ -5800,21 +5819,7 @@
If 0/default, the view will be measured by standard rules
as if this were a FrameLayout. -->
<attr name="layout_centerWithinArea" format="float" />
<!-- Some child types have special behavior. -->
<attr name="layout_childType">
<!-- No special behavior. Layout will proceed as normal. -->
<enum name="none" value="0" />
<!-- Widget container.
This will be resized in response to certain events. -->
<enum name="widget" value="1" />
<!-- Security challenge container.
This will be dismissed/shown in response to certain events,
possibly obscuring widget elements. -->
<enum name="challenge" value="2" />
<!-- User switcher.
This will consume space from the total layout area. -->
<enum name="userSwitcher" value="3" />
</attr>
<attr name="layout_childType" />
<attr name="layout_gravity" />
<attr name="layout_maxWidth" format="dimension" />
<attr name="layout_maxHeight" />

View File

@@ -45,4 +45,16 @@ public interface ChallengeLayout {
* Show the bouncer challenge. This may block access to other child views.
*/
void showBouncer();
/**
* Hide the bouncer challenge if it is currently showing.
* This may restore previously blocked access to other child views.
*/
void hideBouncer();
/**
* Returns true if the challenge is currently in bouncer mode,
* potentially blocking access to other child views.
*/
boolean isBouncing();
}

View File

@@ -32,15 +32,24 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
private static final String TAG = "MultiPaneChallengeLayout";
final int mOrientation;
private boolean mIsBouncing;
public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
public static final int VERTICAL = LinearLayout.VERTICAL;
private View mChallengeView;
private View mUserSwitcherView;
private View mScrimView;
private final Rect mTempRect = new Rect();
private final OnClickListener mScrimClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
hideBouncer();
}
};
public MultiPaneChallengeLayout(Context context) {
this(context, null);
}
@@ -75,7 +84,35 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
@Override
public void showBouncer() {
// TODO Block access to other views
if (mIsBouncing) return;
mIsBouncing = true;
if (mScrimView != null) {
mScrimView.setVisibility(GONE);
}
}
@Override
public void hideBouncer() {
if (!mIsBouncing) return;
mIsBouncing = false;
if (mScrimView != null) {
mScrimView.setVisibility(GONE);
}
}
@Override
public boolean isBouncing() {
return mIsBouncing;
}
void setScrimView(View scrim) {
if (mScrimView != null) {
mScrimView.setOnClickListener(null);
}
mScrimView = scrim;
mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE);
mScrimView.setFocusable(true);
mScrimView.setOnClickListener(mScrimClickListener);
}
@Override
@@ -139,6 +176,9 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
} else if (Gravity.isHorizontal(lp.gravity)) {
widthUsed += child.getMeasuredWidth() * 1.5f;
}
} else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
setScrimView(child);
child.measure(widthSpec, heightSpec);
}
}
@@ -148,6 +188,7 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER ||
lp.childType == LayoutParams.CHILD_TYPE_SCRIM ||
child.getVisibility() == GONE) {
// Don't need to measure GONE children, and the user switcher was already measured.
continue;
@@ -208,6 +249,11 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
// We did the user switcher above if we have one.
if (child == mUserSwitcherView || child.getVisibility() == GONE) continue;
if (child == mScrimView) {
child.layout(0, 0, width, height);
continue;
}
layoutWithGravity(width, height, child, padding, false);
}
}
@@ -333,6 +379,7 @@ public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayo
public static final int CHILD_TYPE_WIDGET = 1;
public static final int CHILD_TYPE_CHALLENGE = 2;
public static final int CHILD_TYPE_USER_SWITCHER = 3;
public static final int CHILD_TYPE_SCRIM = 4;
public int gravity = Gravity.NO_GRAVITY;

View File

@@ -46,10 +46,12 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
// Initialized during measurement from child layoutparams
private View mChallengeView;
private View mScrimView;
// Range: 0 (fully hidden) to 1 (fully visible)
private float mChallengeOffset = 1.f;
private boolean mChallengeShowing = true;
private boolean mIsBouncing = false;
private final Scroller mScroller;
private int mScrollState;
@@ -100,6 +102,13 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
}
};
private final OnClickListener mScrimClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
hideBouncer();
}
};
/**
* Listener interface that reports changes in scroll state of the challenge area.
*/
@@ -232,6 +241,16 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
setScrollState(SCROLL_STATE_IDLE);
}
void setScrimView(View scrim) {
if (mScrimView != null) {
mScrimView.setOnClickListener(null);
}
mScrimView = scrim;
mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE);
mScrimView.setFocusable(true);
mScrimView.setOnClickListener(mScrimClickListener);
}
/**
* Animate the bottom edge of the challenge view to the given position.
*
@@ -293,6 +312,31 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
return mChallengeShowing;
}
@Override
public boolean isBouncing() {
return mIsBouncing;
}
@Override
public void showBouncer() {
if (mIsBouncing) return;
showChallenge(true);
mIsBouncing = true;
if (mScrimView != null) {
mScrimView.setVisibility(GONE);
}
}
@Override
public void hideBouncer() {
if (!mIsBouncing) return;
setChallengeShowing(false);
mIsBouncing = false;
if (mScrimView != null) {
mScrimView.setVisibility(GONE);
}
}
@Override
public void requestDisallowInterceptTouchEvent(boolean allowIntercept) {
// We'll intercept whoever we feel like! ...as long as it isn't a challenge view.
@@ -463,7 +507,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.isChallenge) {
if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
if (mChallengeView != null) {
throw new IllegalStateException(
"There may only be one child with layout_isChallenge=\"true\"");
@@ -472,6 +516,8 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
if (mChallengeView != oldChallengeView) {
mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE);
}
} else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
setScrimView(child);
}
if (child.getVisibility() == GONE) continue;
@@ -497,7 +543,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.isChallenge) {
if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
// Challenge views pin to the bottom, offset by a portion of their height,
// and center horizontally.
final int center = (paddingLeft + width - paddingRight) / 2;
@@ -657,12 +703,6 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
}
}
@Override
public void showBouncer() {
// TODO Block access to other views
showChallenge(true);
}
public void showHandle(boolean show) {
mShowHandle = show;
invalidate();
@@ -691,7 +731,10 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
}
public static class LayoutParams extends MarginLayoutParams {
public boolean isChallenge = false;
public int childType = CHILD_TYPE_NONE;
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 LayoutParams() {
this(MATCH_PARENT, WRAP_CONTENT);
@@ -712,7 +755,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
public LayoutParams(LayoutParams source) {
super(source);
isChallenge = source.isChallenge;
childType = source.childType;
}
public LayoutParams(Context c, AttributeSet attrs) {
@@ -720,8 +763,8 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
final TypedArray a = c.obtainStyledAttributes(attrs,
R.styleable.SlidingChallengeLayout_Layout);
isChallenge = a.getBoolean(R.styleable.SlidingChallengeLayout_Layout_layout_isChallenge,
false);
childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType,
CHILD_TYPE_NONE);
a.recycle();
}
}