1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.keyguard; 18 19 import android.annotation.NonNull; 20 import android.content.Context; 21 import android.content.res.TypedArray; 22 import android.graphics.Rect; 23 import android.util.AttributeSet; 24 import android.util.Log; 25 import android.view.MotionEvent; 26 import android.view.View; 27 import android.view.ViewDebug; 28 import android.view.ViewGroup; 29 import android.view.ViewHierarchyEncoder; 30 import android.widget.FrameLayout; 31 import android.widget.ViewFlipper; 32 33 import com.android.systemui.R; 34 35 /** 36 * Subclass of the current view flipper that allows us to overload dispatchTouchEvent() so 37 * we can emulate {@link android.view.WindowManager.LayoutParams#FLAG_SLIPPERY} within a view 38 * hierarchy. 39 */ 40 public class KeyguardSecurityViewFlipper extends ViewFlipper { 41 private static final String TAG = "KeyguardSecurityViewFlipper"; 42 private static final boolean DEBUG = KeyguardConstants.DEBUG; 43 44 private Rect mTempRect = new Rect(); 45 KeyguardSecurityViewFlipper(Context context)46 public KeyguardSecurityViewFlipper(Context context) { 47 this(context, null); 48 } 49 KeyguardSecurityViewFlipper(Context context, AttributeSet attr)50 public KeyguardSecurityViewFlipper(Context context, AttributeSet attr) { 51 super(context, attr); 52 } 53 54 @Override onTouchEvent(MotionEvent ev)55 public boolean onTouchEvent(MotionEvent ev) { 56 boolean result = super.onTouchEvent(ev); 57 mTempRect.set(0, 0, 0, 0); 58 for (int i = 0; i < getChildCount(); i++) { 59 View child = getChildAt(i); 60 if (child.getVisibility() == View.VISIBLE) { 61 offsetRectIntoDescendantCoords(child, mTempRect); 62 ev.offsetLocation(mTempRect.left, mTempRect.top); 63 result = child.dispatchTouchEvent(ev) || result; 64 ev.offsetLocation(-mTempRect.left, -mTempRect.top); 65 } 66 } 67 return result; 68 } 69 getSecurityView()70 KeyguardInputView getSecurityView() { 71 View child = getChildAt(getDisplayedChild()); 72 if (child instanceof KeyguardInputView) { 73 return (KeyguardInputView) child; 74 } 75 return null; 76 } 77 getTitle()78 public CharSequence getTitle() { 79 KeyguardInputView ksv = getSecurityView(); 80 if (ksv != null) { 81 return ksv.getTitle(); 82 } 83 return ""; 84 } 85 86 /** 87 * Translate the entire view, and optionally inform the wrapped view of the progress 88 * so it can animate with the parent. 89 */ animateForIme(int translationY, float interpolatedFraction, boolean appearingAnim)90 public void animateForIme(int translationY, float interpolatedFraction, boolean appearingAnim) { 91 super.setTranslationY(translationY); 92 KeyguardInputView v = getSecurityView(); 93 if (v != null) v.animateForIme(interpolatedFraction, appearingAnim); 94 } 95 96 @Override checkLayoutParams(ViewGroup.LayoutParams p)97 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 98 return p instanceof LayoutParams; 99 } 100 101 @Override generateLayoutParams(ViewGroup.LayoutParams p)102 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 103 return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : new LayoutParams(p); 104 } 105 106 @Override generateLayoutParams(AttributeSet attrs)107 public LayoutParams generateLayoutParams(AttributeSet attrs) { 108 return new LayoutParams(getContext(), attrs); 109 } 110 111 @Override onMeasure(int widthSpec, int heightSpec)112 protected void onMeasure(int widthSpec, int heightSpec) { 113 final int widthMode = MeasureSpec.getMode(widthSpec); 114 final int heightMode = MeasureSpec.getMode(heightSpec); 115 if (DEBUG && widthMode != MeasureSpec.AT_MOST) { 116 Log.w(TAG, "onMeasure: widthSpec " + MeasureSpec.toString(widthSpec) + 117 " should be AT_MOST"); 118 } 119 if (DEBUG && heightMode != MeasureSpec.AT_MOST) { 120 Log.w(TAG, "onMeasure: heightSpec " + MeasureSpec.toString(heightSpec) + 121 " should be AT_MOST"); 122 } 123 124 final int widthSize = MeasureSpec.getSize(widthSpec); 125 final int heightSize = MeasureSpec.getSize(heightSpec); 126 int maxWidth = widthSize; 127 int maxHeight = heightSize; 128 final int count = getChildCount(); 129 for (int i = 0; i < count; i++) { 130 final View child = getChildAt(i); 131 if (child.getVisibility() != View.VISIBLE) continue; 132 133 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 134 135 if (lp.maxWidth > 0 && lp.maxWidth < maxWidth) { 136 maxWidth = lp.maxWidth; 137 } 138 if (lp.maxHeight > 0 && lp.maxHeight < maxHeight) { 139 maxHeight = lp.maxHeight; 140 } 141 } 142 143 final int wPadding = getPaddingLeft() + getPaddingRight(); 144 final int hPadding = getPaddingTop() + getPaddingBottom(); 145 maxWidth = Math.max(0, maxWidth - wPadding); 146 maxHeight = Math.max(0, maxHeight - hPadding); 147 148 int width = widthMode == MeasureSpec.EXACTLY ? widthSize : 0; 149 int height = heightMode == MeasureSpec.EXACTLY ? heightSize : 0; 150 for (int i = 0; i < count; i++) { 151 final View child = getChildAt(i); 152 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 153 154 final int childWidthSpec = makeChildMeasureSpec(maxWidth, lp.width); 155 final int childHeightSpec = makeChildMeasureSpec(maxHeight, lp.height); 156 157 child.measure(childWidthSpec, childHeightSpec); 158 159 width = Math.max(width, Math.min(child.getMeasuredWidth(), widthSize - wPadding)); 160 height = Math.max(height, Math.min(child.getMeasuredHeight(), heightSize - hPadding)); 161 } 162 setMeasuredDimension(width + wPadding, height + hPadding); 163 } 164 makeChildMeasureSpec(int maxSize, int childDimen)165 private int makeChildMeasureSpec(int maxSize, int childDimen) { 166 final int mode; 167 final int size; 168 switch (childDimen) { 169 case LayoutParams.WRAP_CONTENT: 170 mode = MeasureSpec.AT_MOST; 171 size = maxSize; 172 break; 173 case LayoutParams.MATCH_PARENT: 174 mode = MeasureSpec.EXACTLY; 175 size = maxSize; 176 break; 177 default: 178 mode = MeasureSpec.EXACTLY; 179 size = Math.min(maxSize, childDimen); 180 break; 181 } 182 return MeasureSpec.makeMeasureSpec(size, mode); 183 } 184 185 public static class LayoutParams extends FrameLayout.LayoutParams { 186 @ViewDebug.ExportedProperty(category = "layout") 187 public int maxWidth; 188 189 @ViewDebug.ExportedProperty(category = "layout") 190 public int maxHeight; 191 LayoutParams(ViewGroup.LayoutParams other)192 public LayoutParams(ViewGroup.LayoutParams other) { 193 super(other); 194 } 195 LayoutParams(LayoutParams other)196 public LayoutParams(LayoutParams other) { 197 super(other); 198 199 maxWidth = other.maxWidth; 200 maxHeight = other.maxHeight; 201 } 202 LayoutParams(Context c, AttributeSet attrs)203 public LayoutParams(Context c, AttributeSet attrs) { 204 super(c, attrs); 205 206 final TypedArray a = c.obtainStyledAttributes(attrs, 207 R.styleable.KeyguardSecurityViewFlipper_Layout, 0, 0); 208 maxWidth = a.getDimensionPixelSize( 209 R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxWidth, 0); 210 maxHeight = a.getDimensionPixelSize( 211 R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxHeight, 0); 212 a.recycle(); 213 } 214 215 /** @hide */ 216 @Override encodeProperties(@onNull ViewHierarchyEncoder encoder)217 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) { 218 super.encodeProperties(encoder); 219 220 encoder.addProperty("layout:maxWidth", maxWidth); 221 encoder.addProperty("layout:maxHeight", maxHeight); 222 } 223 } 224 } 225