1 /* 2 * Copyright (C) 2014 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.systemui.statusbar.phone; 18 19 import android.content.Context; 20 import android.view.Choreographer; 21 import android.view.KeyEvent; 22 import android.view.LayoutInflater; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.view.accessibility.AccessibilityEvent; 26 27 import com.android.internal.widget.LockPatternUtils; 28 import com.android.keyguard.KeyguardViewBase; 29 import com.android.keyguard.R; 30 import com.android.keyguard.ViewMediatorCallback; 31 import com.android.systemui.keyguard.KeyguardViewMediator; 32 33 import static com.android.keyguard.KeyguardHostView.OnDismissAction; 34 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode; 35 36 /** 37 * A class which manages the bouncer on the lockscreen. 38 */ 39 public class KeyguardBouncer { 40 41 private Context mContext; 42 private ViewMediatorCallback mCallback; 43 private LockPatternUtils mLockPatternUtils; 44 private ViewGroup mContainer; 45 private StatusBarWindowManager mWindowManager; 46 private KeyguardViewBase mKeyguardView; 47 private ViewGroup mRoot; 48 private boolean mShowingSoon; 49 private Choreographer mChoreographer = Choreographer.getInstance(); 50 51 public KeyguardBouncer(Context context, ViewMediatorCallback callback, 52 LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager, 53 ViewGroup container) { 54 mContext = context; 55 mCallback = callback; 56 mLockPatternUtils = lockPatternUtils; 57 mContainer = container; 58 mWindowManager = windowManager; 59 } 60 61 public void show(boolean resetSecuritySelection) { 62 ensureView(); 63 if (resetSecuritySelection) { 64 // showPrimarySecurityScreen() updates the current security method. This is needed in 65 // case we are already showing and the current security method changed. 66 mKeyguardView.showPrimarySecurityScreen(); 67 } 68 if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) { 69 return; 70 } 71 72 // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole 73 // Keyguard. If we need to authenticate, show the bouncer. 74 if (!mKeyguardView.dismiss()) { 75 mShowingSoon = true; 76 77 // Split up the work over multiple frames. 78 mChoreographer.postCallbackDelayed(Choreographer.CALLBACK_ANIMATION, mShowRunnable, 79 null, 16); 80 } 81 } 82 83 private final Runnable mShowRunnable = new Runnable() { 84 @Override 85 public void run() { 86 mRoot.setVisibility(View.VISIBLE); 87 mKeyguardView.onResume(); 88 mKeyguardView.startAppearAnimation(); 89 mShowingSoon = false; 90 mKeyguardView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 91 } 92 }; 93 94 private void cancelShowRunnable() { 95 mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mShowRunnable, null); 96 mShowingSoon = false; 97 } 98 99 public void showWithDismissAction(OnDismissAction r) { 100 ensureView(); 101 mKeyguardView.setOnDismissAction(r); 102 show(false /* resetSecuritySelection */); 103 } 104 105 public void hide(boolean destroyView) { 106 cancelShowRunnable(); 107 if (mKeyguardView != null) { 108 mKeyguardView.setOnDismissAction(null); 109 mKeyguardView.cleanUp(); 110 } 111 if (destroyView) { 112 removeView(); 113 } else if (mRoot != null) { 114 mRoot.setVisibility(View.INVISIBLE); 115 } 116 } 117 118 /** 119 * See {@link StatusBarKeyguardViewManager#startPreHideAnimation}. 120 */ 121 public void startPreHideAnimation(Runnable runnable) { 122 if (mKeyguardView != null) { 123 mKeyguardView.startDisappearAnimation(runnable); 124 } else if (runnable != null) { 125 runnable.run(); 126 } 127 } 128 129 /** 130 * Reset the state of the view. 131 */ 132 public void reset() { 133 cancelShowRunnable(); 134 inflateView(); 135 } 136 137 public void onScreenTurnedOff() { 138 if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) { 139 mKeyguardView.onPause(); 140 } 141 } 142 143 public long getUserActivityTimeout() { 144 if (mKeyguardView != null) { 145 long timeout = mKeyguardView.getUserActivityTimeout(); 146 if (timeout >= 0) { 147 return timeout; 148 } 149 } 150 return KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS; 151 } 152 153 public boolean isShowing() { 154 return mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE); 155 } 156 157 public void prepare() { 158 boolean wasInitialized = mRoot != null; 159 ensureView(); 160 if (wasInitialized) { 161 mKeyguardView.showPrimarySecurityScreen(); 162 } 163 } 164 165 private void ensureView() { 166 if (mRoot == null) { 167 inflateView(); 168 } 169 } 170 171 private void inflateView() { 172 removeView(); 173 mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null); 174 mKeyguardView = (KeyguardViewBase) mRoot.findViewById(R.id.keyguard_host_view); 175 mKeyguardView.setLockPatternUtils(mLockPatternUtils); 176 mKeyguardView.setViewMediatorCallback(mCallback); 177 mContainer.addView(mRoot, mContainer.getChildCount()); 178 mRoot.setVisibility(View.INVISIBLE); 179 mRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME); 180 } 181 182 private void removeView() { 183 if (mRoot != null && mRoot.getParent() == mContainer) { 184 mContainer.removeView(mRoot); 185 mRoot = null; 186 } 187 } 188 189 public boolean onBackPressed() { 190 return mKeyguardView != null && mKeyguardView.handleBackKey(); 191 } 192 193 /** 194 * @return True if and only if the security method should be shown before showing the 195 * notifications on Keyguard, like SIM PIN/PUK. 196 */ 197 public boolean needsFullscreenBouncer() { 198 if (mKeyguardView != null) { 199 SecurityMode mode = mKeyguardView.getSecurityMode(); 200 return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk; 201 } 202 return false; 203 } 204 205 /** 206 * Like {@link #needsFullscreenBouncer}, but uses the currently visible security method, which 207 * makes this method much faster. 208 */ 209 public boolean isFullscreenBouncer() { 210 if (mKeyguardView != null) { 211 SecurityMode mode = mKeyguardView.getCurrentSecurityMode(); 212 return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk; 213 } 214 return false; 215 } 216 217 /** 218 * WARNING: This method might cause Binder calls. 219 */ 220 public boolean isSecure() { 221 return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None; 222 } 223 224 public boolean onMenuPressed() { 225 ensureView(); 226 if (mKeyguardView.handleMenuKey()) { 227 228 // We need to show it in case it is secure. If not, it will get dismissed in any case. 229 mRoot.setVisibility(View.VISIBLE); 230 mKeyguardView.requestFocus(); 231 mKeyguardView.onResume(); 232 return true; 233 } else { 234 return false; 235 } 236 } 237 238 public boolean interceptMediaKey(KeyEvent event) { 239 ensureView(); 240 return mKeyguardView.interceptMediaKey(event); 241 } 242 } 243