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.app.ActivityManager; 20 import android.app.ActivityManagerNative; 21 import android.app.admin.DevicePolicyManager; 22 import android.content.BroadcastReceiver; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.ServiceConnection; 28 import android.content.pm.ActivityInfo; 29 import android.content.pm.PackageManager; 30 import android.content.pm.ResolveInfo; 31 import android.content.res.Configuration; 32 import android.hardware.fingerprint.FingerprintManager; 33 import android.os.AsyncTask; 34 import android.os.Bundle; 35 import android.os.IBinder; 36 import android.os.Message; 37 import android.os.Messenger; 38 import android.os.RemoteException; 39 import android.os.UserHandle; 40 import android.provider.MediaStore; 41 import android.service.media.CameraPrewarmService; 42 import android.telecom.TelecomManager; 43 import android.util.AttributeSet; 44 import android.util.Log; 45 import android.util.TypedValue; 46 import android.view.View; 47 import android.view.ViewGroup; 48 import android.view.accessibility.AccessibilityNodeInfo; 49 import android.view.animation.AnimationUtils; 50 import android.view.animation.Interpolator; 51 import android.widget.FrameLayout; 52 import android.widget.TextView; 53 54 import com.android.internal.widget.LockPatternUtils; 55 import com.android.keyguard.KeyguardUpdateMonitor; 56 import com.android.keyguard.KeyguardUpdateMonitorCallback; 57 import com.android.systemui.EventLogConstants; 58 import com.android.systemui.EventLogTags; 59 import com.android.systemui.R; 60 import com.android.systemui.assist.AssistManager; 61 import com.android.systemui.statusbar.CommandQueue; 62 import com.android.systemui.statusbar.KeyguardAffordanceView; 63 import com.android.systemui.statusbar.KeyguardIndicationController; 64 import com.android.systemui.statusbar.policy.AccessibilityController; 65 import com.android.systemui.statusbar.policy.FlashlightController; 66 import com.android.systemui.statusbar.policy.PreviewInflater; 67 68 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; 69 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 70 71 /** 72 * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status 73 * text. 74 */ 75 public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener, 76 UnlockMethodCache.OnUnlockMethodChangedListener, 77 AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener { 78 79 final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView"; 80 81 private static final Intent SECURE_CAMERA_INTENT = 82 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE) 83 .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 84 private static final Intent INSECURE_CAMERA_INTENT = 85 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); 86 private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL); 87 private static final int DOZE_ANIMATION_STAGGER_DELAY = 48; 88 private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250; 89 private static final long TRANSIENT_FP_ERROR_TIMEOUT = 1300; 90 91 private KeyguardAffordanceView mCameraImageView; 92 private KeyguardAffordanceView mLeftAffordanceView; 93 private LockIcon mLockIcon; 94 private TextView mIndicationText; 95 private ViewGroup mPreviewContainer; 96 97 private View mLeftPreview; 98 private View mCameraPreview; 99 100 private ActivityStarter mActivityStarter; 101 private UnlockMethodCache mUnlockMethodCache; 102 private LockPatternUtils mLockPatternUtils; 103 private FlashlightController mFlashlightController; 104 private PreviewInflater mPreviewInflater; 105 private KeyguardIndicationController mIndicationController; 106 private AccessibilityController mAccessibilityController; 107 private PhoneStatusBar mPhoneStatusBar; 108 109 private final Interpolator mLinearOutSlowInInterpolator; 110 private boolean mUserSetupComplete; 111 private boolean mPrewarmBound; 112 private Messenger mPrewarmMessenger; 113 private final ServiceConnection mPrewarmConnection = new ServiceConnection() { 114 115 @Override 116 public void onServiceConnected(ComponentName name, IBinder service) { 117 mPrewarmMessenger = new Messenger(service); 118 } 119 120 @Override 121 public void onServiceDisconnected(ComponentName name) { 122 mPrewarmMessenger = null; 123 } 124 }; 125 126 private boolean mLeftIsVoiceAssist; 127 private AssistManager mAssistManager; 128 KeyguardBottomAreaView(Context context)129 public KeyguardBottomAreaView(Context context) { 130 this(context, null); 131 } 132 KeyguardBottomAreaView(Context context, AttributeSet attrs)133 public KeyguardBottomAreaView(Context context, AttributeSet attrs) { 134 this(context, attrs, 0); 135 } 136 KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr)137 public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) { 138 this(context, attrs, defStyleAttr, 0); 139 } 140 KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)141 public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr, 142 int defStyleRes) { 143 super(context, attrs, defStyleAttr, defStyleRes); 144 mLinearOutSlowInInterpolator = 145 AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); 146 } 147 148 private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() { 149 @Override 150 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 151 super.onInitializeAccessibilityNodeInfo(host, info); 152 String label = null; 153 if (host == mLockIcon) { 154 label = getResources().getString(R.string.unlock_label); 155 } else if (host == mCameraImageView) { 156 label = getResources().getString(R.string.camera_label); 157 } else if (host == mLeftAffordanceView) { 158 if (mLeftIsVoiceAssist) { 159 label = getResources().getString(R.string.voice_assist_label); 160 } else { 161 label = getResources().getString(R.string.phone_label); 162 } 163 } 164 info.addAction(new AccessibilityAction(ACTION_CLICK, label)); 165 } 166 167 @Override 168 public boolean performAccessibilityAction(View host, int action, Bundle args) { 169 if (action == ACTION_CLICK) { 170 if (host == mLockIcon) { 171 mPhoneStatusBar.animateCollapsePanels( 172 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); 173 return true; 174 } else if (host == mCameraImageView) { 175 launchCamera(); 176 return true; 177 } else if (host == mLeftAffordanceView) { 178 launchLeftAffordance(); 179 return true; 180 } 181 } 182 return super.performAccessibilityAction(host, action, args); 183 } 184 }; 185 186 @Override onFinishInflate()187 protected void onFinishInflate() { 188 super.onFinishInflate(); 189 mLockPatternUtils = new LockPatternUtils(mContext); 190 mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container); 191 mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button); 192 mLeftAffordanceView = (KeyguardAffordanceView) findViewById(R.id.left_button); 193 mLockIcon = (LockIcon) findViewById(R.id.lock_icon); 194 mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text); 195 watchForCameraPolicyChanges(); 196 updateCameraVisibility(); 197 mUnlockMethodCache = UnlockMethodCache.getInstance(getContext()); 198 mUnlockMethodCache.addListener(this); 199 mLockIcon.update(); 200 setClipChildren(false); 201 setClipToPadding(false); 202 mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext)); 203 inflateCameraPreview(); 204 mLockIcon.setOnClickListener(this); 205 mLockIcon.setOnLongClickListener(this); 206 mCameraImageView.setOnClickListener(this); 207 mLeftAffordanceView.setOnClickListener(this); 208 initAccessibility(); 209 } 210 initAccessibility()211 private void initAccessibility() { 212 mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate); 213 mLeftAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate); 214 mCameraImageView.setAccessibilityDelegate(mAccessibilityDelegate); 215 } 216 217 @Override onConfigurationChanged(Configuration newConfig)218 protected void onConfigurationChanged(Configuration newConfig) { 219 super.onConfigurationChanged(newConfig); 220 int indicationBottomMargin = getResources().getDimensionPixelSize( 221 R.dimen.keyguard_indication_margin_bottom); 222 MarginLayoutParams mlp = (MarginLayoutParams) mIndicationText.getLayoutParams(); 223 if (mlp.bottomMargin != indicationBottomMargin) { 224 mlp.bottomMargin = indicationBottomMargin; 225 mIndicationText.setLayoutParams(mlp); 226 } 227 228 // Respect font size setting. 229 mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX, 230 getResources().getDimensionPixelSize( 231 com.android.internal.R.dimen.text_size_small_material)); 232 } 233 setActivityStarter(ActivityStarter activityStarter)234 public void setActivityStarter(ActivityStarter activityStarter) { 235 mActivityStarter = activityStarter; 236 } 237 setFlashlightController(FlashlightController flashlightController)238 public void setFlashlightController(FlashlightController flashlightController) { 239 mFlashlightController = flashlightController; 240 } 241 setAccessibilityController(AccessibilityController accessibilityController)242 public void setAccessibilityController(AccessibilityController accessibilityController) { 243 mAccessibilityController = accessibilityController; 244 mLockIcon.setAccessibilityController(accessibilityController); 245 accessibilityController.addStateChangedCallback(this); 246 } 247 setPhoneStatusBar(PhoneStatusBar phoneStatusBar)248 public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) { 249 mPhoneStatusBar = phoneStatusBar; 250 updateCameraVisibility(); // in case onFinishInflate() was called too early 251 } 252 setUserSetupComplete(boolean userSetupComplete)253 public void setUserSetupComplete(boolean userSetupComplete) { 254 mUserSetupComplete = userSetupComplete; 255 updateCameraVisibility(); 256 updateLeftAffordanceIcon(); 257 } 258 getCameraIntent()259 private Intent getCameraIntent() { 260 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); 261 boolean canSkipBouncer = updateMonitor.getUserCanSkipBouncer( 262 KeyguardUpdateMonitor.getCurrentUser()); 263 boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()); 264 return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT; 265 } 266 updateCameraVisibility()267 private void updateCameraVisibility() { 268 if (mCameraImageView == null) { 269 // Things are not set up yet; reply hazy, ask again later 270 return; 271 } 272 ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(), 273 PackageManager.MATCH_DEFAULT_ONLY, 274 KeyguardUpdateMonitor.getCurrentUser()); 275 boolean visible = !isCameraDisabledByDpm() && resolved != null 276 && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance) 277 && mUserSetupComplete; 278 mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE); 279 } 280 updateLeftAffordanceIcon()281 private void updateLeftAffordanceIcon() { 282 mLeftIsVoiceAssist = canLaunchVoiceAssist(); 283 int drawableId; 284 int contentDescription; 285 boolean visible = mUserSetupComplete; 286 if (mLeftIsVoiceAssist) { 287 drawableId = R.drawable.ic_mic_26dp; 288 contentDescription = R.string.accessibility_voice_assist_button; 289 } else { 290 visible &= isPhoneVisible(); 291 drawableId = R.drawable.ic_phone_24dp; 292 contentDescription = R.string.accessibility_phone_button; 293 } 294 mLeftAffordanceView.setVisibility(visible ? View.VISIBLE : View.GONE); 295 mLeftAffordanceView.setImageDrawable(mContext.getDrawable(drawableId)); 296 mLeftAffordanceView.setContentDescription(mContext.getString(contentDescription)); 297 } 298 isLeftVoiceAssist()299 public boolean isLeftVoiceAssist() { 300 return mLeftIsVoiceAssist; 301 } 302 isPhoneVisible()303 private boolean isPhoneVisible() { 304 PackageManager pm = mContext.getPackageManager(); 305 return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) 306 && pm.resolveActivity(PHONE_INTENT, 0) != null; 307 } 308 isCameraDisabledByDpm()309 private boolean isCameraDisabledByDpm() { 310 final DevicePolicyManager dpm = 311 (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE); 312 if (dpm != null && mPhoneStatusBar != null) { 313 try { 314 final int userId = ActivityManagerNative.getDefault().getCurrentUser().id; 315 final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId); 316 final boolean disabledBecauseKeyguardSecure = 317 (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0 318 && mPhoneStatusBar.isKeyguardSecure(); 319 return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure; 320 } catch (RemoteException e) { 321 Log.e(TAG, "Can't get userId", e); 322 } 323 } 324 return false; 325 } 326 watchForCameraPolicyChanges()327 private void watchForCameraPolicyChanges() { 328 final IntentFilter filter = new IntentFilter(); 329 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 330 getContext().registerReceiverAsUser(mDevicePolicyReceiver, 331 UserHandle.ALL, filter, null, null); 332 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback); 333 } 334 335 @Override onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled)336 public void onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled) { 337 mCameraImageView.setClickable(touchExplorationEnabled); 338 mLeftAffordanceView.setClickable(touchExplorationEnabled); 339 mCameraImageView.setFocusable(accessibilityEnabled); 340 mLeftAffordanceView.setFocusable(accessibilityEnabled); 341 mLockIcon.update(); 342 } 343 344 @Override onClick(View v)345 public void onClick(View v) { 346 if (v == mCameraImageView) { 347 launchCamera(); 348 } else if (v == mLeftAffordanceView) { 349 launchLeftAffordance(); 350 } if (v == mLockIcon) { 351 if (!mAccessibilityController.isAccessibilityEnabled()) { 352 handleTrustCircleClick(); 353 } else { 354 mPhoneStatusBar.animateCollapsePanels( 355 CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); 356 } 357 } 358 } 359 360 @Override onLongClick(View v)361 public boolean onLongClick(View v) { 362 handleTrustCircleClick(); 363 return true; 364 } 365 handleTrustCircleClick()366 private void handleTrustCircleClick() { 367 EventLogTags.writeSysuiLockscreenGesture( 368 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK, 0 /* lengthDp - N/A */, 369 0 /* velocityDp - N/A */); 370 mIndicationController.showTransientIndication( 371 R.string.keyguard_indication_trust_disabled); 372 mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser()); 373 } 374 bindCameraPrewarmService()375 public void bindCameraPrewarmService() { 376 Intent intent = getCameraIntent(); 377 ActivityInfo targetInfo = PreviewInflater.getTargetActivityInfo(mContext, intent, 378 KeyguardUpdateMonitor.getCurrentUser()); 379 if (targetInfo != null && targetInfo.metaData != null) { 380 String clazz = targetInfo.metaData.getString( 381 MediaStore.META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE); 382 if (clazz != null) { 383 Intent serviceIntent = new Intent(); 384 serviceIntent.setClassName(targetInfo.packageName, clazz); 385 serviceIntent.setAction(CameraPrewarmService.ACTION_PREWARM); 386 try { 387 if (getContext().bindServiceAsUser(serviceIntent, mPrewarmConnection, 388 Context.BIND_AUTO_CREATE, new UserHandle(UserHandle.USER_CURRENT))) { 389 mPrewarmBound = true; 390 } 391 } catch (SecurityException e) { 392 Log.w(TAG, "Unable to bind to prewarm service package=" + targetInfo.packageName 393 + " class=" + clazz, e); 394 } 395 } 396 } 397 } 398 unbindCameraPrewarmService(boolean launched)399 public void unbindCameraPrewarmService(boolean launched) { 400 if (mPrewarmBound) { 401 if (mPrewarmMessenger != null && launched) { 402 try { 403 mPrewarmMessenger.send(Message.obtain(null /* handler */, 404 CameraPrewarmService.MSG_CAMERA_FIRED)); 405 } catch (RemoteException e) { 406 Log.w(TAG, "Error sending camera fired message", e); 407 } 408 } 409 mContext.unbindService(mPrewarmConnection); 410 mPrewarmBound = false; 411 } 412 } 413 launchCamera()414 public void launchCamera() { 415 final Intent intent = getCameraIntent(); 416 boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity( 417 mContext, intent, KeyguardUpdateMonitor.getCurrentUser()); 418 if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) { 419 AsyncTask.execute(new Runnable() { 420 @Override 421 public void run() { 422 int result = ActivityManager.START_CANCELED; 423 try { 424 result = ActivityManagerNative.getDefault().startActivityAsUser( 425 null, getContext().getBasePackageName(), 426 intent, 427 intent.resolveTypeIfNeeded(getContext().getContentResolver()), 428 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, 429 UserHandle.CURRENT.getIdentifier()); 430 } catch (RemoteException e) { 431 Log.w(TAG, "Unable to start camera activity", e); 432 } 433 mActivityStarter.preventNextAnimation(); 434 final boolean launched = isSuccessfulLaunch(result); 435 post(new Runnable() { 436 @Override 437 public void run() { 438 unbindCameraPrewarmService(launched); 439 } 440 }); 441 } 442 }); 443 } else { 444 445 // We need to delay starting the activity because ResolverActivity finishes itself if 446 // launched behind lockscreen. 447 mActivityStarter.startActivity(intent, false /* dismissShade */, 448 new ActivityStarter.Callback() { 449 @Override 450 public void onActivityStarted(int resultCode) { 451 unbindCameraPrewarmService(isSuccessfulLaunch(resultCode)); 452 } 453 }); 454 } 455 } 456 isSuccessfulLaunch(int result)457 private static boolean isSuccessfulLaunch(int result) { 458 return result == ActivityManager.START_SUCCESS 459 || result == ActivityManager.START_DELIVERED_TO_TOP 460 || result == ActivityManager.START_TASK_TO_FRONT; 461 } 462 launchLeftAffordance()463 public void launchLeftAffordance() { 464 if (mLeftIsVoiceAssist) { 465 launchVoiceAssist(); 466 } else { 467 launchPhone(); 468 } 469 } 470 launchVoiceAssist()471 private void launchVoiceAssist() { 472 Runnable runnable = new Runnable() { 473 @Override 474 public void run() { 475 mAssistManager.launchVoiceAssistFromKeyguard(); 476 mActivityStarter.preventNextAnimation(); 477 } 478 }; 479 if (mPhoneStatusBar.isKeyguardCurrentlySecure()) { 480 AsyncTask.execute(runnable); 481 } else { 482 mPhoneStatusBar.executeRunnableDismissingKeyguard(runnable, null /* cancelAction */, 483 false /* dismissShade */, false /* afterKeyguardGone */); 484 } 485 } 486 canLaunchVoiceAssist()487 private boolean canLaunchVoiceAssist() { 488 return mAssistManager.canVoiceAssistBeLaunchedFromKeyguard(); 489 } 490 launchPhone()491 private void launchPhone() { 492 final TelecomManager tm = TelecomManager.from(mContext); 493 if (tm.isInCall()) { 494 AsyncTask.execute(new Runnable() { 495 @Override 496 public void run() { 497 tm.showInCallScreen(false /* showDialpad */); 498 } 499 }); 500 } else { 501 mActivityStarter.startActivity(PHONE_INTENT, false /* dismissShade */); 502 } 503 } 504 505 506 @Override onVisibilityChanged(View changedView, int visibility)507 protected void onVisibilityChanged(View changedView, int visibility) { 508 super.onVisibilityChanged(changedView, visibility); 509 if (changedView == this && visibility == VISIBLE) { 510 mLockIcon.update(); 511 updateCameraVisibility(); 512 } 513 } 514 getLeftView()515 public KeyguardAffordanceView getLeftView() { 516 return mLeftAffordanceView; 517 } 518 getRightView()519 public KeyguardAffordanceView getRightView() { 520 return mCameraImageView; 521 } 522 getLeftPreview()523 public View getLeftPreview() { 524 return mLeftPreview; 525 } 526 getRightPreview()527 public View getRightPreview() { 528 return mCameraPreview; 529 } 530 getLockIcon()531 public KeyguardAffordanceView getLockIcon() { 532 return mLockIcon; 533 } 534 getIndicationView()535 public View getIndicationView() { 536 return mIndicationText; 537 } 538 539 @Override hasOverlappingRendering()540 public boolean hasOverlappingRendering() { 541 return false; 542 } 543 544 @Override onUnlockMethodStateChanged()545 public void onUnlockMethodStateChanged() { 546 mLockIcon.update(); 547 updateCameraVisibility(); 548 } 549 inflateCameraPreview()550 private void inflateCameraPreview() { 551 mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent()); 552 if (mCameraPreview != null) { 553 mPreviewContainer.addView(mCameraPreview); 554 mCameraPreview.setVisibility(View.INVISIBLE); 555 } 556 } 557 updateLeftPreview()558 private void updateLeftPreview() { 559 View previewBefore = mLeftPreview; 560 if (previewBefore != null) { 561 mPreviewContainer.removeView(previewBefore); 562 } 563 if (mLeftIsVoiceAssist) { 564 mLeftPreview = mPreviewInflater.inflatePreviewFromService( 565 mAssistManager.getVoiceInteractorComponentName()); 566 } else { 567 mLeftPreview = mPreviewInflater.inflatePreview(PHONE_INTENT); 568 } 569 if (mLeftPreview != null) { 570 mPreviewContainer.addView(mLeftPreview); 571 mLeftPreview.setVisibility(View.INVISIBLE); 572 } 573 } 574 startFinishDozeAnimation()575 public void startFinishDozeAnimation() { 576 long delay = 0; 577 if (mLeftAffordanceView.getVisibility() == View.VISIBLE) { 578 startFinishDozeAnimationElement(mLeftAffordanceView, delay); 579 delay += DOZE_ANIMATION_STAGGER_DELAY; 580 } 581 startFinishDozeAnimationElement(mLockIcon, delay); 582 delay += DOZE_ANIMATION_STAGGER_DELAY; 583 if (mCameraImageView.getVisibility() == View.VISIBLE) { 584 startFinishDozeAnimationElement(mCameraImageView, delay); 585 } 586 mIndicationText.setAlpha(0f); 587 mIndicationText.animate() 588 .alpha(1f) 589 .setInterpolator(mLinearOutSlowInInterpolator) 590 .setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION); 591 } 592 startFinishDozeAnimationElement(View element, long delay)593 private void startFinishDozeAnimationElement(View element, long delay) { 594 element.setAlpha(0f); 595 element.setTranslationY(element.getHeight() / 2); 596 element.animate() 597 .alpha(1f) 598 .translationY(0f) 599 .setInterpolator(mLinearOutSlowInInterpolator) 600 .setStartDelay(delay) 601 .setDuration(DOZE_ANIMATION_ELEMENT_DURATION); 602 } 603 604 private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() { 605 @Override 606 public void onReceive(Context context, Intent intent) { 607 post(new Runnable() { 608 @Override 609 public void run() { 610 updateCameraVisibility(); 611 } 612 }); 613 } 614 }; 615 616 private final Runnable mTransientFpErrorClearRunnable = new Runnable() { 617 @Override 618 public void run() { 619 mLockIcon.setTransientFpError(false); 620 mIndicationController.hideTransientIndication(); 621 } 622 }; 623 624 private final Runnable mHideTransientIndicationRunnable = new Runnable() { 625 @Override 626 public void run() { 627 mIndicationController.hideTransientIndication(); 628 } 629 }; 630 631 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = 632 new KeyguardUpdateMonitorCallback() { 633 @Override 634 public void onUserSwitchComplete(int userId) { 635 updateCameraVisibility(); 636 } 637 638 @Override 639 public void onStartedWakingUp() { 640 mLockIcon.setDeviceInteractive(true); 641 } 642 643 @Override 644 public void onFinishedGoingToSleep(int why) { 645 mLockIcon.setDeviceInteractive(false); 646 } 647 648 @Override 649 public void onKeyguardVisibilityChanged(boolean showing) { 650 mLockIcon.update(); 651 } 652 653 @Override 654 public void onFingerprintAuthenticated(int userId, boolean wakeAndUnlocking) { 655 } 656 657 @Override 658 public void onFingerprintRunningStateChanged(boolean running) { 659 mLockIcon.update(); 660 } 661 662 @Override 663 public void onFingerprintHelp(int msgId, String helpString) { 664 if (!KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed()) { 665 return; 666 } 667 mLockIcon.setTransientFpError(true); 668 mIndicationController.showTransientIndication(helpString, 669 getResources().getColor(R.color.system_warning_color, null)); 670 removeCallbacks(mTransientFpErrorClearRunnable); 671 postDelayed(mTransientFpErrorClearRunnable, TRANSIENT_FP_ERROR_TIMEOUT); 672 } 673 674 @Override 675 public void onFingerprintError(int msgId, String errString) { 676 if (!KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed() 677 || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { 678 return; 679 } 680 // TODO: Go to bouncer if this is "too many attempts" (lockout) error. 681 mIndicationController.showTransientIndication(errString, 682 getResources().getColor(R.color.system_warning_color, null)); 683 removeCallbacks(mHideTransientIndicationRunnable); 684 postDelayed(mHideTransientIndicationRunnable, 5000); 685 } 686 }; 687 setKeyguardIndicationController( KeyguardIndicationController keyguardIndicationController)688 public void setKeyguardIndicationController( 689 KeyguardIndicationController keyguardIndicationController) { 690 mIndicationController = keyguardIndicationController; 691 } 692 setAssistManager(AssistManager assistManager)693 public void setAssistManager(AssistManager assistManager) { 694 mAssistManager = assistManager; 695 updateLeftAffordance(); 696 } 697 updateLeftAffordance()698 public void updateLeftAffordance() { 699 updateLeftAffordanceIcon(); 700 updateLeftPreview(); 701 } 702 } 703