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