OSDN Git Service

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