KeyguardBottomAreaView.java revision 40aa8811bc817293d7400c14fa60350d2350d29f
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
17package com.android.systemui.statusbar.phone;
18
19import android.app.ActivityManager;
20import android.app.ActivityManagerNative;
21import android.app.admin.DevicePolicyManager;
22import android.content.BroadcastReceiver;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.ServiceConnection;
28import android.content.pm.ActivityInfo;
29import android.content.pm.PackageManager;
30import android.content.pm.ResolveInfo;
31import android.content.res.Configuration;
32import android.os.AsyncTask;
33import android.os.Bundle;
34import android.os.IBinder;
35import android.os.Message;
36import android.os.Messenger;
37import android.os.RemoteException;
38import android.os.UserHandle;
39import android.provider.MediaStore;
40import android.service.media.CameraPrewarmService;
41import android.telecom.TelecomManager;
42import android.util.AttributeSet;
43import android.util.Log;
44import android.util.TypedValue;
45import android.view.View;
46import android.view.ViewGroup;
47import android.view.accessibility.AccessibilityNodeInfo;
48import android.view.animation.AnimationUtils;
49import android.view.animation.Interpolator;
50import android.widget.FrameLayout;
51import android.widget.TextView;
52
53import com.android.internal.widget.LockPatternUtils;
54import com.android.keyguard.KeyguardUpdateMonitor;
55import com.android.keyguard.KeyguardUpdateMonitorCallback;
56import com.android.systemui.EventLogConstants;
57import com.android.systemui.EventLogTags;
58import com.android.systemui.R;
59import com.android.systemui.assist.AssistManager;
60import com.android.systemui.statusbar.CommandQueue;
61import com.android.systemui.statusbar.KeyguardAffordanceView;
62import com.android.systemui.statusbar.KeyguardIndicationController;
63import com.android.systemui.statusbar.policy.AccessibilityController;
64import com.android.systemui.statusbar.policy.FlashlightController;
65import com.android.systemui.statusbar.policy.PreviewInflater;
66
67import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
68import 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 */
74public 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}
688