• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
KeyguardBottomAreaView(Context context)134     public KeyguardBottomAreaView(Context context) {
135         this(context, null);
136     }
137 
KeyguardBottomAreaView(Context context, AttributeSet attrs)138     public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
139         this(context, attrs, 0);
140     }
141 
KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr)142     public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
143         this(context, attrs, defStyleAttr, 0);
144     }
145 
KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)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
onFinishInflate()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 
initAccessibility()214     private void initAccessibility() {
215         mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
216         mLeftAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate);
217         mCameraImageView.setAccessibilityDelegate(mAccessibilityDelegate);
218     }
219 
220     @Override
onConfigurationChanged(Configuration newConfig)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 
setActivityStarter(ActivityStarter activityStarter)255     public void setActivityStarter(ActivityStarter activityStarter) {
256         mActivityStarter = activityStarter;
257     }
258 
setFlashlightController(FlashlightController flashlightController)259     public void setFlashlightController(FlashlightController flashlightController) {
260         mFlashlightController = flashlightController;
261     }
262 
setAccessibilityController(AccessibilityController accessibilityController)263     public void setAccessibilityController(AccessibilityController accessibilityController) {
264         mAccessibilityController = accessibilityController;
265         mLockIcon.setAccessibilityController(accessibilityController);
266         accessibilityController.addStateChangedCallback(this);
267     }
268 
setPhoneStatusBar(PhoneStatusBar phoneStatusBar)269     public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
270         mPhoneStatusBar = phoneStatusBar;
271         updateCameraVisibility(); // in case onFinishInflate() was called too early
272     }
273 
setUserSetupComplete(boolean userSetupComplete)274     public void setUserSetupComplete(boolean userSetupComplete) {
275         mUserSetupComplete = userSetupComplete;
276         updateCameraVisibility();
277         updateLeftAffordanceIcon();
278     }
279 
getCameraIntent()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      */
resolveCameraIntent()291     public ResolveInfo resolveCameraIntent() {
292         return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
293                 PackageManager.MATCH_DEFAULT_ONLY,
294                 KeyguardUpdateMonitor.getCurrentUser());
295     }
296 
updateCameraVisibility()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 
updateLeftAffordanceIcon()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 
isLeftVoiceAssist()327     public boolean isLeftVoiceAssist() {
328         return mLeftIsVoiceAssist;
329     }
330 
isPhoneVisible()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 
isCameraDisabledByDpm()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 
watchForCameraPolicyChanges()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
onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled)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
onClick(View v)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
onLongClick(View v)389     public boolean onLongClick(View v) {
390         handleTrustCircleClick();
391         return true;
392     }
393 
handleTrustCircleClick()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 
bindCameraPrewarmService()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 
unbindCameraPrewarmService(boolean launched)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 
launchCamera(String source)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 
isSuccessfulLaunch(int result)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 
launchLeftAffordance()505     public void launchLeftAffordance() {
506         if (mLeftIsVoiceAssist) {
507             launchVoiceAssist();
508         } else {
509             launchPhone();
510         }
511     }
512 
launchVoiceAssist()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 
canLaunchVoiceAssist()529     private boolean canLaunchVoiceAssist() {
530         return mAssistManager.canVoiceAssistBeLaunchedFromKeyguard();
531     }
532 
launchPhone()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
onVisibilityChanged(View changedView, int visibility)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 
getLeftView()557     public KeyguardAffordanceView getLeftView() {
558         return mLeftAffordanceView;
559     }
560 
getRightView()561     public KeyguardAffordanceView getRightView() {
562         return mCameraImageView;
563     }
564 
getLeftPreview()565     public View getLeftPreview() {
566         return mLeftPreview;
567     }
568 
getRightPreview()569     public View getRightPreview() {
570         return mCameraPreview;
571     }
572 
getLockIcon()573     public LockIcon getLockIcon() {
574         return mLockIcon;
575     }
576 
getIndicationView()577     public View getIndicationView() {
578         return mIndicationText;
579     }
580 
581     @Override
hasOverlappingRendering()582     public boolean hasOverlappingRendering() {
583         return false;
584     }
585 
586     @Override
onUnlockMethodStateChanged()587     public void onUnlockMethodStateChanged() {
588         mLockIcon.update();
589         updateCameraVisibility();
590     }
591 
inflateCameraPreview()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 
updateLeftPreview()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 
startFinishDozeAnimation()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 
startFinishDozeAnimationElement(View element, long delay)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 
setKeyguardIndicationController( KeyguardIndicationController keyguardIndicationController)707     public void setKeyguardIndicationController(
708             KeyguardIndicationController keyguardIndicationController) {
709         mIndicationController = keyguardIndicationController;
710     }
711 
setAssistManager(AssistManager assistManager)712     public void setAssistManager(AssistManager assistManager) {
713         mAssistManager = assistManager;
714         updateLeftAffordance();
715     }
716 
updateLeftAffordance()717     public void updateLeftAffordance() {
718         updateLeftAffordanceIcon();
719         updateLeftPreview();
720     }
721 
onKeyguardShowingChanged()722     public void onKeyguardShowingChanged() {
723         updateLeftAffordance();
724         inflateCameraPreview();
725     }
726 }
727