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