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