KeyguardSelectorView.java revision f4d922b2d9c2011bcdc0543b5cdf2dd53ca04b25
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 */ 16package com.android.keyguard; 17 18import android.animation.ObjectAnimator; 19import android.app.SearchManager; 20import android.app.admin.DevicePolicyManager; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.graphics.drawable.Drawable; 25import android.os.Build; 26import android.os.PowerManager; 27import android.os.UserHandle; 28import android.provider.Settings; 29import android.telephony.TelephonyManager; 30import android.util.AttributeSet; 31import android.util.Log; 32import android.util.Slog; 33import android.view.View; 34import android.widget.LinearLayout; 35 36import com.android.internal.telephony.IccCardConstants.State; 37import com.android.internal.widget.LockPatternUtils; 38import com.android.internal.widget.multiwaveview.GlowPadView; 39import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener; 40import com.android.keyguard.KeyguardHostView.OnDismissAction; 41 42public class KeyguardSelectorView extends LinearLayout implements KeyguardSecurityView { 43 private static final boolean DEBUG = KeyguardHostView.DEBUG; 44 private static final String TAG = "SecuritySelectorView"; 45 private static final String ASSIST_ICON_METADATA_NAME = 46 "com.android.systemui.action_assist_icon"; 47 // Flag to enable/disable hotword detection on lock screen. 48 private static final boolean FLAG_HOTWORD = true; 49 50 private KeyguardSecurityCallback mCallback; 51 private GlowPadView mGlowPadView; 52 private ObjectAnimator mAnim; 53 private View mFadeView; 54 private boolean mIsBouncing; 55 private boolean mCameraDisabled; 56 private boolean mSearchDisabled; 57 private LockPatternUtils mLockPatternUtils; 58 private SecurityMessageDisplay mSecurityMessageDisplay; 59 private Drawable mBouncerFrame; 60 private HotwordServiceClient mHotwordClient; 61 62 OnTriggerListener mOnTriggerListener = new OnTriggerListener() { 63 64 public void onTrigger(View v, int target) { 65 final int resId = mGlowPadView.getResourceIdForTarget(target); 66 if (FLAG_HOTWORD) { 67 maybeStopHotwordDetector(); 68 } 69 switch (resId) { 70 case R.drawable.ic_action_assist_generic: 71 Intent assistIntent = 72 ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) 73 .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); 74 if (assistIntent != null) { 75 mActivityLauncher.launchActivity(assistIntent, false, true, null, null); 76 } else { 77 Log.w(TAG, "Failed to get intent for assist activity"); 78 } 79 mCallback.userActivity(0); 80 break; 81 82 case R.drawable.ic_lockscreen_camera: 83 mActivityLauncher.launchCamera(null, null); 84 mCallback.userActivity(0); 85 break; 86 87 case R.drawable.ic_lockscreen_unlock_phantom: 88 case R.drawable.ic_lockscreen_unlock: 89 mCallback.userActivity(0); 90 mCallback.dismiss(false); 91 break; 92 } 93 } 94 95 public void onReleased(View v, int handle) { 96 if (!mIsBouncing) { 97 doTransition(mFadeView, 1.0f); 98 } 99 } 100 101 public void onGrabbed(View v, int handle) { 102 mCallback.userActivity(0); 103 doTransition(mFadeView, 0.0f); 104 } 105 106 public void onGrabbedStateChange(View v, int handle) { 107 108 } 109 110 public void onFinishFinalAnimation() { 111 112 } 113 114 }; 115 116 KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { 117 118 @Override 119 public void onDevicePolicyManagerStateChanged() { 120 updateTargets(); 121 } 122 123 @Override 124 public void onSimStateChanged(State simState) { 125 updateTargets(); 126 } 127 128 @Override 129 public void onPhoneStateChanged(int phoneState) { 130 if (FLAG_HOTWORD) { 131 // We need to stop the hotwording when a phone call comes in 132 // TODO(sansid): This is not really needed if onPause triggers 133 // when we navigate away from the keyguard 134 if (phoneState == TelephonyManager.CALL_STATE_RINGING) { 135 if (DEBUG) Log.d(TAG, "Stopping due to CALL_STATE_RINGING"); 136 maybeStopHotwordDetector(); 137 } 138 } 139 } 140 141 @Override 142 public void onUserSwitching(int userId) { 143 maybeStopHotwordDetector(); 144 } 145 }; 146 147 private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() { 148 149 @Override 150 KeyguardSecurityCallback getCallback() { 151 return mCallback; 152 } 153 154 @Override 155 LockPatternUtils getLockPatternUtils() { 156 return mLockPatternUtils; 157 } 158 159 @Override 160 Context getContext() { 161 return mContext; 162 }}; 163 164 public KeyguardSelectorView(Context context) { 165 this(context, null); 166 } 167 168 public KeyguardSelectorView(Context context, AttributeSet attrs) { 169 super(context, attrs); 170 mLockPatternUtils = new LockPatternUtils(getContext()); 171 } 172 173 @Override 174 protected void onFinishInflate() { 175 super.onFinishInflate(); 176 mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view); 177 mGlowPadView.setOnTriggerListener(mOnTriggerListener); 178 updateTargets(); 179 180 mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); 181 View bouncerFrameView = findViewById(R.id.keyguard_selector_view_frame); 182 mBouncerFrame = bouncerFrameView.getBackground(); 183 if (FLAG_HOTWORD) { 184 mHotwordClient = new HotwordServiceClient(getContext(), mHotwordCallback); 185 } 186 } 187 188 public void setCarrierArea(View carrierArea) { 189 mFadeView = carrierArea; 190 } 191 192 public boolean isTargetPresent(int resId) { 193 return mGlowPadView.getTargetPosition(resId) != -1; 194 } 195 196 @Override 197 public void showUsabilityHint() { 198 mGlowPadView.ping(); 199 } 200 201 private void updateTargets() { 202 int currentUserHandle = mLockPatternUtils.getCurrentUser(); 203 DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager(); 204 int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUserHandle); 205 boolean secureCameraDisabled = mLockPatternUtils.isSecure() 206 && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0; 207 boolean cameraDisabledByAdmin = dpm.getCameraDisabled(null, currentUserHandle) 208 || secureCameraDisabled; 209 final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext()); 210 boolean disabledBySimState = monitor.isSimLocked(); 211 boolean cameraTargetPresent = 212 isTargetPresent(R.drawable.ic_lockscreen_camera); 213 boolean searchTargetPresent = 214 isTargetPresent(R.drawable.ic_action_assist_generic); 215 216 if (cameraDisabledByAdmin) { 217 Log.v(TAG, "Camera disabled by Device Policy"); 218 } else if (disabledBySimState) { 219 Log.v(TAG, "Camera disabled by Sim State"); 220 } 221 boolean currentUserSetup = 0 != Settings.Secure.getIntForUser( 222 mContext.getContentResolver(), 223 Settings.Secure.USER_SETUP_COMPLETE, 224 0 /*default */, 225 currentUserHandle); 226 boolean searchActionAvailable = 227 ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) 228 .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; 229 mCameraDisabled = cameraDisabledByAdmin || disabledBySimState || !cameraTargetPresent 230 || !currentUserSetup; 231 mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent 232 || !currentUserSetup; 233 updateResources(); 234 } 235 236 public void updateResources() { 237 // Update the search icon with drawable from the search .apk 238 if (!mSearchDisabled) { 239 Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) 240 .getAssistIntent(mContext, false, UserHandle.USER_CURRENT); 241 if (intent != null) { 242 // XXX Hack. We need to substitute the icon here but haven't formalized 243 // the public API. The "_google" metadata will be going away, so 244 // DON'T USE IT! 245 ComponentName component = intent.getComponent(); 246 boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component, 247 ASSIST_ICON_METADATA_NAME + "_google", R.drawable.ic_action_assist_generic); 248 249 if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component, 250 ASSIST_ICON_METADATA_NAME, R.drawable.ic_action_assist_generic)) { 251 Slog.w(TAG, "Couldn't grab icon from package " + component); 252 } 253 } 254 } 255 256 mGlowPadView.setEnableTarget(R.drawable.ic_lockscreen_camera, !mCameraDisabled); 257 mGlowPadView.setEnableTarget(R.drawable.ic_action_assist_generic, !mSearchDisabled); 258 } 259 260 void doTransition(View view, float to) { 261 if (mAnim != null) { 262 mAnim.cancel(); 263 } 264 mAnim = ObjectAnimator.ofFloat(view, "alpha", to); 265 mAnim.start(); 266 } 267 268 public void setKeyguardCallback(KeyguardSecurityCallback callback) { 269 mCallback = callback; 270 } 271 272 public void setLockPatternUtils(LockPatternUtils utils) { 273 mLockPatternUtils = utils; 274 } 275 276 @Override 277 public void reset() { 278 mGlowPadView.reset(false); 279 } 280 281 @Override 282 public boolean needsInput() { 283 return false; 284 } 285 286 @Override 287 public void onPause() { 288 KeyguardUpdateMonitor.getInstance(getContext()).removeCallback(mUpdateCallback); 289 } 290 291 @Override 292 public void onResume(int reason) { 293 KeyguardUpdateMonitor.getInstance(getContext()).registerCallback(mUpdateCallback); 294 // TODO: Figure out if there's a better way to do it. 295 // Right now we don't get onPause at all, and onResume gets called 296 // multiple times (even when the screen is turned off with VIEW_REVEALED) 297 if (reason == SCREEN_ON) { 298 if (!KeyguardUpdateMonitor.getInstance(getContext()).isSwitchingUser()) { 299 maybeStartHotwordDetector(); 300 } 301 } else { 302 maybeStopHotwordDetector(); 303 } 304 } 305 306 @Override 307 public KeyguardSecurityCallback getCallback() { 308 return mCallback; 309 } 310 311 @Override 312 public void showBouncer(int duration) { 313 mIsBouncing = true; 314 KeyguardSecurityViewHelper. 315 showBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration); 316 } 317 318 @Override 319 public void hideBouncer(int duration) { 320 mIsBouncing = false; 321 KeyguardSecurityViewHelper. 322 hideBouncer(mSecurityMessageDisplay, mFadeView, mBouncerFrame, duration); 323 } 324 325 /** 326 * Start the hotword detector if: 327 * <li> HOTWORDING_ENABLED is true and 328 * <li> HotwordUnlock is initialized and 329 * <li> TelephonyManager is in CALL_STATE_IDLE 330 * 331 * If this method is called when the screen is off, 332 * it attempts to stop hotwording if it's running. 333 */ 334 private void maybeStartHotwordDetector() { 335 if (FLAG_HOTWORD) { 336 if (DEBUG) Log.d(TAG, "maybeStartHotwordDetector()"); 337 // Don't start it if the screen is off or not showing 338 PowerManager powerManager = (PowerManager) getContext().getSystemService( 339 Context.POWER_SERVICE); 340 if (!powerManager.isScreenOn()) { 341 if (DEBUG) Log.d(TAG, "screen was off, not starting"); 342 return; 343 } 344 345 KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(getContext()); 346 if (monitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE) { 347 if (DEBUG) Log.d(TAG, "Call underway, not starting"); 348 return; 349 } 350 if (!mHotwordClient.start()) { 351 Log.w(TAG, "Failed to start the hotword detector"); 352 } 353 } 354 } 355 356 /** 357 * Stop hotword detector if HOTWORDING_ENABLED is true. 358 */ 359 private void maybeStopHotwordDetector() { 360 if (FLAG_HOTWORD) { 361 if (DEBUG) Log.d(TAG, "maybeStopHotwordDetector()"); 362 mHotwordClient.stop(); 363 } 364 } 365 366 private final HotwordServiceClient.Callback mHotwordCallback = 367 new HotwordServiceClient.Callback() { 368 private static final String TAG = "HotwordServiceClient.Callback"; 369 370 @Override 371 public void onServiceConnected() { 372 if (DEBUG) Log.d(TAG, "onServiceConnected()"); 373 } 374 375 @Override 376 public void onServiceDisconnected() { 377 if (DEBUG) Log.d(TAG, "onServiceDisconnected()"); 378 } 379 380 @Override 381 public void onHotwordDetectionStarted() { 382 if (DEBUG) Log.d(TAG, "onHotwordDetectionStarted()"); 383 // TODO: Change the usage of SecurityMessageDisplay to a better visual indication. 384 mSecurityMessageDisplay.setMessage("\"Ok Google...\"", true); 385 } 386 387 @Override 388 public void onHotwordDetectionStopped() { 389 if (DEBUG) Log.d(TAG, "onHotwordDetectionStopped()"); 390 // TODO: Change the usage of SecurityMessageDisplay to a better visual indication. 391 } 392 393 @Override 394 public void onHotwordDetected(String action) { 395 if (DEBUG) Log.d(TAG, "onHotwordDetected(" + action + ")"); 396 if (action != null) { 397 Intent intent = new Intent(action); 398 mActivityLauncher.launchActivity(intent, true, true, null, null); 399 } 400 mCallback.userActivity(0); 401 } 402 }; 403} 404