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