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.view.WindowManager; 31 import android.widget.FrameLayout; 32 import android.widget.ViewFlipper; 33 34 import com.android.internal.widget.LockPatternUtils; 35 36 import java.lang.Override; 37 38 /** 39 * Subclass of the current view flipper that allows us to overload dispatchTouchEvent() so 40 * we can emulate {@link WindowManager.LayoutParams#FLAG_SLIPPERY} within a view hierarchy. 41 * 42 */ 43 public class KeyguardSecurityViewFlipper extends ViewFlipper implements KeyguardSecurityView { 44 private static final String TAG = "KeyguardSecurityViewFlipper"; 45 private static final boolean DEBUG = KeyguardConstants.DEBUG; 46 47 private Rect mTempRect = new Rect(); 48 KeyguardSecurityViewFlipper(Context context)49 public KeyguardSecurityViewFlipper(Context context) { 50 this(context, null); 51 } 52 KeyguardSecurityViewFlipper(Context context, AttributeSet attr)53 public KeyguardSecurityViewFlipper(Context context, AttributeSet attr) { 54 super(context, attr); 55 } 56 57 @Override onTouchEvent(MotionEvent ev)58 public boolean onTouchEvent(MotionEvent ev) { 59 boolean result = super.onTouchEvent(ev); 60 mTempRect.set(0, 0, 0, 0); 61 for (int i = 0; i < getChildCount(); i++) { 62 View child = getChildAt(i); 63 if (child.getVisibility() == View.VISIBLE) { 64 offsetRectIntoDescendantCoords(child, mTempRect); 65 ev.offsetLocation(mTempRect.left, mTempRect.top); 66 result = child.dispatchTouchEvent(ev) || result; 67 ev.offsetLocation(-mTempRect.left, -mTempRect.top); 68 } 69 } 70 return result; 71 } 72 getSecurityView()73 KeyguardSecurityView getSecurityView() { 74 View child = getChildAt(getDisplayedChild()); 75 if (child instanceof KeyguardSecurityView) { 76 return (KeyguardSecurityView) child; 77 } 78 return null; 79 } 80 81 @Override setKeyguardCallback(KeyguardSecurityCallback callback)82 public void setKeyguardCallback(KeyguardSecurityCallback callback) { 83 KeyguardSecurityView ksv = getSecurityView(); 84 if (ksv != null) { 85 ksv.setKeyguardCallback(callback); 86 } 87 } 88 89 @Override setLockPatternUtils(LockPatternUtils utils)90 public void setLockPatternUtils(LockPatternUtils utils) { 91 KeyguardSecurityView ksv = getSecurityView(); 92 if (ksv != null) { 93 ksv.setLockPatternUtils(utils); 94 } 95 } 96 97 @Override reset()98 public void reset() { 99 KeyguardSecurityView ksv = getSecurityView(); 100 if (ksv != null) { 101 ksv.reset(); 102 } 103 } 104 105 @Override onPause()106 public void onPause() { 107 KeyguardSecurityView ksv = getSecurityView(); 108 if (ksv != null) { 109 ksv.onPause(); 110 } 111 } 112 113 @Override onResume(int reason)114 public void onResume(int reason) { 115 KeyguardSecurityView ksv = getSecurityView(); 116 if (ksv != null) { 117 ksv.onResume(reason); 118 } 119 } 120 121 @Override needsInput()122 public boolean needsInput() { 123 KeyguardSecurityView ksv = getSecurityView(); 124 return (ksv != null) ? ksv.needsInput() : false; 125 } 126 127 @Override getCallback()128 public KeyguardSecurityCallback getCallback() { 129 KeyguardSecurityView ksv = getSecurityView(); 130 return (ksv != null) ? ksv.getCallback() : null; 131 } 132 133 @Override showPromptReason(int reason)134 public void showPromptReason(int reason) { 135 KeyguardSecurityView ksv = getSecurityView(); 136 if (ksv != null) { 137 ksv.showPromptReason(reason); 138 } 139 } 140 141 @Override showMessage(String message, int color)142 public void showMessage(String message, int color) { 143 KeyguardSecurityView ksv = getSecurityView(); 144 if (ksv != null) { 145 ksv.showMessage(message, color); 146 } 147 } 148 149 @Override showUsabilityHint()150 public void showUsabilityHint() { 151 KeyguardSecurityView ksv = getSecurityView(); 152 if (ksv != null) { 153 ksv.showUsabilityHint(); 154 } 155 } 156 157 @Override startAppearAnimation()158 public void startAppearAnimation() { 159 KeyguardSecurityView ksv = getSecurityView(); 160 if (ksv != null) { 161 ksv.startAppearAnimation(); 162 } 163 } 164 165 @Override startDisappearAnimation(Runnable finishRunnable)166 public boolean startDisappearAnimation(Runnable finishRunnable) { 167 KeyguardSecurityView ksv = getSecurityView(); 168 if (ksv != null) { 169 return ksv.startDisappearAnimation(finishRunnable); 170 } else { 171 return false; 172 } 173 } 174 175 @Override checkLayoutParams(ViewGroup.LayoutParams p)176 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 177 return p instanceof LayoutParams; 178 } 179 180 @Override generateLayoutParams(ViewGroup.LayoutParams p)181 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 182 return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : new LayoutParams(p); 183 } 184 185 @Override generateLayoutParams(AttributeSet attrs)186 public LayoutParams generateLayoutParams(AttributeSet attrs) { 187 return new LayoutParams(getContext(), attrs); 188 } 189 190 @Override onMeasure(int widthSpec, int heightSpec)191 protected void onMeasure(int widthSpec, int heightSpec) { 192 final int widthMode = MeasureSpec.getMode(widthSpec); 193 final int heightMode = MeasureSpec.getMode(heightSpec); 194 if (DEBUG && widthMode != MeasureSpec.AT_MOST) { 195 Log.w(TAG, "onMeasure: widthSpec " + MeasureSpec.toString(widthSpec) + 196 " should be AT_MOST"); 197 } 198 if (DEBUG && heightMode != MeasureSpec.AT_MOST) { 199 Log.w(TAG, "onMeasure: heightSpec " + MeasureSpec.toString(heightSpec) + 200 " should be AT_MOST"); 201 } 202 203 final int widthSize = MeasureSpec.getSize(widthSpec); 204 final int heightSize = MeasureSpec.getSize(heightSpec); 205 int maxWidth = widthSize; 206 int maxHeight = heightSize; 207 final int count = getChildCount(); 208 for (int i = 0; i < count; i++) { 209 final View child = getChildAt(i); 210 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 211 212 if (lp.maxWidth > 0 && lp.maxWidth < maxWidth) { 213 maxWidth = lp.maxWidth; 214 } 215 if (lp.maxHeight > 0 && lp.maxHeight < maxHeight) { 216 maxHeight = lp.maxHeight; 217 } 218 } 219 220 final int wPadding = getPaddingLeft() + getPaddingRight(); 221 final int hPadding = getPaddingTop() + getPaddingBottom(); 222 maxWidth = Math.max(0, maxWidth - wPadding); 223 maxHeight = Math.max(0, maxHeight - hPadding); 224 225 int width = widthMode == MeasureSpec.EXACTLY ? widthSize : 0; 226 int height = heightMode == MeasureSpec.EXACTLY ? heightSize : 0; 227 for (int i = 0; i < count; i++) { 228 final View child = getChildAt(i); 229 final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 230 231 final int childWidthSpec = makeChildMeasureSpec(maxWidth, lp.width); 232 final int childHeightSpec = makeChildMeasureSpec(maxHeight, lp.height); 233 234 child.measure(childWidthSpec, childHeightSpec); 235 236 width = Math.max(width, Math.min(child.getMeasuredWidth(), widthSize - wPadding)); 237 height = Math.max(height, Math.min(child.getMeasuredHeight(), heightSize - hPadding)); 238 } 239 setMeasuredDimension(width + wPadding, height + hPadding); 240 } 241 makeChildMeasureSpec(int maxSize, int childDimen)242 private int makeChildMeasureSpec(int maxSize, int childDimen) { 243 final int mode; 244 final int size; 245 switch (childDimen) { 246 case LayoutParams.WRAP_CONTENT: 247 mode = MeasureSpec.AT_MOST; 248 size = maxSize; 249 break; 250 case LayoutParams.MATCH_PARENT: 251 mode = MeasureSpec.EXACTLY; 252 size = maxSize; 253 break; 254 default: 255 mode = MeasureSpec.EXACTLY; 256 size = Math.min(maxSize, childDimen); 257 break; 258 } 259 return MeasureSpec.makeMeasureSpec(size, mode); 260 } 261 262 public static class LayoutParams extends FrameLayout.LayoutParams { 263 @ViewDebug.ExportedProperty(category = "layout") 264 public int maxWidth; 265 266 @ViewDebug.ExportedProperty(category = "layout") 267 public int maxHeight; 268 LayoutParams(ViewGroup.LayoutParams other)269 public LayoutParams(ViewGroup.LayoutParams other) { 270 super(other); 271 } 272 LayoutParams(LayoutParams other)273 public LayoutParams(LayoutParams other) { 274 super(other); 275 276 maxWidth = other.maxWidth; 277 maxHeight = other.maxHeight; 278 } 279 LayoutParams(Context c, AttributeSet attrs)280 public LayoutParams(Context c, AttributeSet attrs) { 281 super(c, attrs); 282 283 final TypedArray a = c.obtainStyledAttributes(attrs, 284 R.styleable.KeyguardSecurityViewFlipper_Layout, 0, 0); 285 maxWidth = a.getDimensionPixelSize( 286 R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxWidth, 0); 287 maxHeight = a.getDimensionPixelSize( 288 R.styleable.KeyguardSecurityViewFlipper_Layout_layout_maxHeight, 0); 289 a.recycle(); 290 } 291 292 /** @hide */ 293 @Override encodeProperties(@onNull ViewHierarchyEncoder encoder)294 protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) { 295 super.encodeProperties(encoder); 296 297 encoder.addProperty("layout:maxWidth", maxWidth); 298 encoder.addProperty("layout:maxHeight", maxHeight); 299 } 300 } 301 } 302