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