1 /*
2  * Copyright (C) 2019 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.notification;
18 
19 import android.content.Context;
20 import android.util.ArraySet;
21 
22 import com.android.internal.annotations.VisibleForTesting;
23 import com.android.systemui.plugins.statusbar.StatusBarStateController;
24 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
25 import com.android.systemui.statusbar.StatusBarState;
26 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
27 import com.android.systemui.statusbar.phone.UnlockMethodCache;
28 import com.android.systemui.statusbar.policy.KeyguardMonitor;
29 
30 import javax.inject.Inject;
31 import javax.inject.Singleton;
32 
33 /**
34  * A controller which dynamically controls the visibility of Notification content
35  */
36 @Singleton
37 public class DynamicPrivacyController implements UnlockMethodCache.OnUnlockMethodChangedListener {
38 
39     private final UnlockMethodCache mUnlockMethodCache;
40     private final NotificationLockscreenUserManager mLockscreenUserManager;
41     private final StatusBarStateController mStateController;
42     private final KeyguardMonitor mKeyguardMonitor;
43     private ArraySet<Listener> mListeners = new ArraySet<>();
44 
45     private boolean mLastDynamicUnlocked;
46     private boolean mCacheInvalid;
47     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
48 
49     @Inject
DynamicPrivacyController(Context context, KeyguardMonitor keyguardMonitor, NotificationLockscreenUserManager notificationLockscreenUserManager, StatusBarStateController stateController)50     DynamicPrivacyController(Context context,
51             KeyguardMonitor keyguardMonitor,
52             NotificationLockscreenUserManager notificationLockscreenUserManager,
53             StatusBarStateController stateController) {
54         this(notificationLockscreenUserManager, keyguardMonitor,
55                 UnlockMethodCache.getInstance(context),
56                 stateController);
57     }
58 
59     @VisibleForTesting
DynamicPrivacyController(NotificationLockscreenUserManager notificationLockscreenUserManager, KeyguardMonitor keyguardMonitor, UnlockMethodCache unlockMethodCache, StatusBarStateController stateController)60     DynamicPrivacyController(NotificationLockscreenUserManager notificationLockscreenUserManager,
61             KeyguardMonitor keyguardMonitor,
62             UnlockMethodCache unlockMethodCache,
63             StatusBarStateController stateController) {
64         mLockscreenUserManager = notificationLockscreenUserManager;
65         mStateController = stateController;
66         mUnlockMethodCache = unlockMethodCache;
67         mKeyguardMonitor = keyguardMonitor;
68         mUnlockMethodCache.addListener(this);
69         mLastDynamicUnlocked = isDynamicallyUnlocked();
70     }
71 
72     @Override
onUnlockMethodStateChanged()73     public void onUnlockMethodStateChanged() {
74         if (isDynamicPrivacyEnabled()) {
75             // We only want to notify our listeners if dynamic privacy is actually active
76             boolean dynamicallyUnlocked = isDynamicallyUnlocked();
77             if (dynamicallyUnlocked != mLastDynamicUnlocked || mCacheInvalid) {
78                 mLastDynamicUnlocked = dynamicallyUnlocked;
79                 for (Listener listener : mListeners) {
80                     listener.onDynamicPrivacyChanged();
81                 }
82             }
83             mCacheInvalid = false;
84         } else {
85             mCacheInvalid = true;
86         }
87     }
88 
isDynamicPrivacyEnabled()89     private boolean isDynamicPrivacyEnabled() {
90         return !mLockscreenUserManager.shouldHideNotifications(
91                 mLockscreenUserManager.getCurrentUserId());
92     }
93 
isDynamicallyUnlocked()94     public boolean isDynamicallyUnlocked() {
95         return (mUnlockMethodCache.canSkipBouncer() || mKeyguardMonitor.isKeyguardGoingAway()
96                 || mKeyguardMonitor.isKeyguardFadingAway())
97                 && isDynamicPrivacyEnabled();
98     }
99 
addListener(Listener listener)100     public void addListener(Listener listener) {
101         mListeners.add(listener);
102     }
103 
104     /**
105      * Is the notification shade currently in a locked down mode where it's fully showing but the
106      * contents aren't revealed yet?
107      */
isInLockedDownShade()108     public boolean isInLockedDownShade() {
109         if (!mStatusBarKeyguardViewManager.isShowing()
110                 || !mUnlockMethodCache.isMethodSecure()) {
111             return false;
112         }
113         int state = mStateController.getState();
114         if (state != StatusBarState.SHADE && state != StatusBarState.SHADE_LOCKED) {
115             return false;
116         }
117         if (!isDynamicPrivacyEnabled() || isDynamicallyUnlocked()) {
118             return false;
119         }
120         return true;
121     }
122 
setStatusBarKeyguardViewManager( StatusBarKeyguardViewManager statusBarKeyguardViewManager)123     public void setStatusBarKeyguardViewManager(
124             StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
125         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
126     }
127 
128     public interface Listener {
onDynamicPrivacyChanged()129         void onDynamicPrivacyChanged();
130     }
131 }