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