MultiPaneChallengeLayoutpublic class MultiPaneChallengeLayout extends android.view.ViewGroup implements ChallengeLayout
Fields Summary |
---|
private static final String | TAG | final int | mOrientation | private boolean | mIsBouncing | public static final int | HORIZONTAL | public static final int | VERTICAL | public static final int | ANIMATE_BOUNCE_DURATION | private KeyguardSecurityContainer | mChallengeView | private android.view.View | mUserSwitcherView | private android.view.View | mScrimView | private OnBouncerStateChangedListener | mBouncerListener | private final android.graphics.Rect | mTempRect | private final android.graphics.Rect | mZeroPadding | private final android.graphics.Rect | mInsets | private final android.util.DisplayMetrics | mDisplayMetrics | private final OnClickListener | mScrimClickListener |
Constructors Summary |
---|
public MultiPaneChallengeLayout(android.content.Context context)
this(context, null);
| public MultiPaneChallengeLayout(android.content.Context context, android.util.AttributeSet attrs)
this(context, attrs, 0);
| public MultiPaneChallengeLayout(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.MultiPaneChallengeLayout, defStyleAttr, 0);
mOrientation = a.getInt(R.styleable.MultiPaneChallengeLayout_android_orientation,
HORIZONTAL);
a.recycle();
final Resources res = getResources();
mDisplayMetrics = res.getDisplayMetrics();
setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
Methods Summary |
---|
protected boolean | checkLayoutParams(ViewGroup.LayoutParams p)
return p instanceof LayoutParams;
| protected ViewGroup.LayoutParams | generateDefaultLayoutParams()
return new LayoutParams();
| public ViewGroup.LayoutParams | generateLayoutParams(android.util.AttributeSet attrs)
return new LayoutParams(getContext(), attrs, this);
| protected ViewGroup.LayoutParams | generateLayoutParams(ViewGroup.LayoutParams p)
return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
new LayoutParams(p);
| public int | getBouncerAnimationDuration()
return ANIMATE_BOUNCE_DURATION;
| private int | getVirtualHeight(com.android.keyguard.MultiPaneChallengeLayout$LayoutParams lp, int height, int heightUsed)
int virtualHeight = height;
final View root = getRootView();
if (root != null) {
// This calculation is super dodgy and relies on several assumptions.
// Specifically that the root of the window will be padded in for insets
// and that the window is LAYOUT_IN_SCREEN.
virtualHeight = mDisplayMetrics.heightPixels - root.getPaddingTop() - mInsets.top;
}
if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) {
// Always measure the user switcher as if there were no IME insets
// on the window.
return virtualHeight - heightUsed;
} else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) {
return height;
}
return Math.min(virtualHeight - heightUsed, height);
| public void | hideBouncer()
if (!mIsBouncing) return;
mIsBouncing = false;
if (mScrimView != null) {
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);
}
| public boolean | isBouncing()
return mIsBouncing;
| public boolean | isChallengeOverlapping()
return false;
| public boolean | isChallengeShowing()
return true;
| private void | layoutWithGravity(int width, int height, android.view.View child, android.graphics.Rect padding, boolean adjustPadding)
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int heightUsed = padding.top + padding.bottom - getPaddingTop() - getPaddingBottom();
height = getVirtualHeight(lp, height, heightUsed);
final int gravity = Gravity.getAbsoluteGravity(lp.gravity, getLayoutDirection());
final boolean fixedLayoutSize = lp.centerWithinArea > 0;
final boolean fixedLayoutHorizontal = fixedLayoutSize && mOrientation == HORIZONTAL;
final boolean fixedLayoutVertical = fixedLayoutSize && mOrientation == VERTICAL;
final int adjustedWidth;
final int adjustedHeight;
if (fixedLayoutHorizontal) {
final int paddedWidth = width - padding.left - padding.right;
adjustedWidth = (int) (paddedWidth * lp.centerWithinArea + 0.5f);
adjustedHeight = height;
} else if (fixedLayoutVertical) {
final int paddedHeight = height - getPaddingTop() - getPaddingBottom();
adjustedWidth = width;
adjustedHeight = (int) (paddedHeight * lp.centerWithinArea + 0.5f);
} else {
adjustedWidth = width;
adjustedHeight = height;
}
final boolean isVertical = Gravity.isVertical(gravity);
final boolean isHorizontal = Gravity.isHorizontal(gravity);
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
int left = padding.left;
int top = padding.top;
int right = left + childWidth;
int bottom = top + childHeight;
switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
case Gravity.TOP:
top = fixedLayoutVertical ?
padding.top + (adjustedHeight - childHeight) / 2 : padding.top;
bottom = top + childHeight;
if (adjustPadding && isVertical) {
padding.top = bottom;
padding.bottom += childHeight / 2;
}
break;
case Gravity.BOTTOM:
bottom = fixedLayoutVertical
? padding.top + height - (adjustedHeight - childHeight) / 2
: padding.top + height;
top = bottom - childHeight;
if (adjustPadding && isVertical) {
padding.bottom = height - top;
padding.top += childHeight / 2;
}
break;
case Gravity.CENTER_VERTICAL:
top = padding.top + (height - childHeight) / 2;
bottom = top + childHeight;
break;
}
switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
left = fixedLayoutHorizontal ?
padding.left + (adjustedWidth - childWidth) / 2 : padding.left;
right = left + childWidth;
if (adjustPadding && isHorizontal && !isVertical) {
padding.left = right;
padding.right += childWidth / 2;
}
break;
case Gravity.RIGHT:
right = fixedLayoutHorizontal
? width - padding.right - (adjustedWidth - childWidth) / 2
: width - padding.right;
left = right - childWidth;
if (adjustPadding && isHorizontal && !isVertical) {
padding.right = width - left;
padding.left += childWidth / 2;
}
break;
case Gravity.CENTER_HORIZONTAL:
final int paddedWidth = width - padding.left - padding.right;
left = (paddedWidth - childWidth) / 2;
right = left + childWidth;
break;
}
top += mInsets.top;
bottom += mInsets.top;
child.layout(left, top, right, bottom);
| protected void | onLayout(boolean changed, int l, int t, int r, int b)
final Rect padding = mTempRect;
padding.left = getPaddingLeft();
padding.top = getPaddingTop();
padding.right = getPaddingRight();
padding.bottom = getPaddingBottom();
final int width = r - l;
final int height = b - t;
final int insetHeight = height - mInsets.top - mInsets.bottom;
// Reserve extra space in layout for the user switcher by modifying
// local padding during this layout pass
if (mUserSwitcherView != null && mUserSwitcherView.getVisibility() != GONE) {
layoutWithGravity(width, insetHeight, mUserSwitcherView, padding, true);
}
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
// 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;
} else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) {
layoutWithGravity(width, insetHeight, child, mZeroPadding, false);
continue;
}
layoutWithGravity(width, insetHeight, child, padding, false);
}
| protected void | onMeasure(int widthSpec, int heightSpec)
if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
throw new IllegalArgumentException(
"MultiPaneChallengeLayout must be measured with an exact size");
}
final int width = MeasureSpec.getSize(widthSpec);
final int height = MeasureSpec.getSize(heightSpec);
setMeasuredDimension(width, height);
final int insetHeight = height - mInsets.top - mInsets.bottom;
final int insetHeightSpec = MeasureSpec.makeMeasureSpec(insetHeight, MeasureSpec.EXACTLY);
int widthUsed = 0;
int heightUsed = 0;
// First pass. Find the challenge view and measure the user switcher,
// which consumes space in the layout.
mChallengeView = null;
mUserSwitcherView = null;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
if (mChallengeView != null) {
throw new IllegalStateException(
"There may only be one child of type challenge");
}
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(
"There may only be one child of type userSwitcher");
}
mUserSwitcherView = child;
if (child.getVisibility() == GONE) continue;
int adjustedWidthSpec = widthSpec;
int adjustedHeightSpec = insetHeightSpec;
if (lp.maxWidth >= 0) {
adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
Math.min(lp.maxWidth, width), MeasureSpec.EXACTLY);
}
if (lp.maxHeight >= 0) {
adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
Math.min(lp.maxHeight, insetHeight), MeasureSpec.EXACTLY);
}
// measureChildWithMargins will resolve layout direction for the LayoutParams
measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
// Only subtract out space from one dimension. Favor vertical.
// Offset by 1.5x to add some balance along the other edge.
if (Gravity.isVertical(lp.gravity)) {
heightUsed += child.getMeasuredHeight() * 1.5f;
} 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);
}
}
// Second pass. Measure everything that's left.
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
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;
}
final int virtualHeight = getVirtualHeight(lp, insetHeight, heightUsed);
int adjustedWidthSpec;
int adjustedHeightSpec;
if (lp.centerWithinArea > 0) {
if (mOrientation == HORIZONTAL) {
adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
(int) ((width - widthUsed) * lp.centerWithinArea + 0.5f),
MeasureSpec.EXACTLY);
adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
virtualHeight, MeasureSpec.EXACTLY);
} else {
adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
width - widthUsed, MeasureSpec.EXACTLY);
adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
(int) (virtualHeight * lp.centerWithinArea + 0.5f),
MeasureSpec.EXACTLY);
}
} else {
adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
width - widthUsed, MeasureSpec.EXACTLY);
adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
virtualHeight, MeasureSpec.EXACTLY);
}
if (lp.maxWidth >= 0) {
adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
Math.min(lp.maxWidth, MeasureSpec.getSize(adjustedWidthSpec)),
MeasureSpec.EXACTLY);
}
if (lp.maxHeight >= 0) {
adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
Math.min(lp.maxHeight, MeasureSpec.getSize(adjustedHeightSpec)),
MeasureSpec.EXACTLY);
}
measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
}
| public void | requestChildFocus(android.view.View child, android.view.View focused)
if (mIsBouncing && child != mChallengeView) {
// Clear out of the bouncer if the user tries to move focus outside of
// the security challenge view.
hideBouncer();
}
super.requestChildFocus(child, focused);
| public void | setInsets(android.graphics.Rect insets)
mInsets.set(insets);
| public void | setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener)
mBouncerListener = listener;
| void | setScrimView(android.view.View scrim)
if (mScrimView != null) {
mScrimView.setOnClickListener(null);
}
mScrimView = scrim;
if (mScrimView != null) {
mScrimView.setAlpha(mIsBouncing ? 1.0f : 0.0f);
mScrimView.setVisibility(mIsBouncing ? VISIBLE : INVISIBLE);
mScrimView.setFocusable(true);
mScrimView.setOnClickListener(mScrimClickListener);
}
| public void | showBouncer()
if (mIsBouncing) return;
mIsBouncing = true;
if (mScrimView != null) {
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);
}
| public void | showChallenge(boolean b)
|
|