• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.phone;
18 
19 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
20 
21 import android.animation.Animator;
22 import android.animation.AnimatorListenerAdapter;
23 import android.annotation.Nullable;
24 import android.view.View;
25 import android.view.WindowInsetsController.Appearance;
26 import android.view.WindowInsetsController.Behavior;
27 import android.view.WindowManager;
28 import android.view.animation.AccelerateInterpolator;
29 
30 import com.android.internal.annotations.VisibleForTesting;
31 import com.android.internal.statusbar.NotificationVisibility;
32 import com.android.internal.view.AppearanceRegion;
33 import com.android.systemui.dagger.SysUISingleton;
34 import com.android.systemui.statusbar.CommandQueue;
35 import com.android.systemui.statusbar.notification.NotificationEntryListener;
36 import com.android.systemui.statusbar.notification.NotificationEntryManager;
37 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
38 
39 import javax.inject.Inject;
40 
41 /**
42  * Apps can request a low profile mode {@link View.SYSTEM_UI_FLAG_LOW_PROFILE}
43  * where status bar and navigation icons dim. In this mode, a notification dot appears
44  * where the notification icons would appear if they would be shown outside of this mode.
45  *
46  * This controller shows and hides the notification dot in the status bar to indicate
47  * whether there are notifications when the device is in {@link View.SYSTEM_UI_FLAG_LOW_PROFILE}.
48  */
49 @SysUISingleton
50 public class LightsOutNotifController {
51     private final CommandQueue mCommandQueue;
52     private final NotificationEntryManager mEntryManager;
53     private final WindowManager mWindowManager;
54 
55     /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */
56     @VisibleForTesting @Appearance int mAppearance;
57 
58     private int mDisplayId;
59     private View mLightsOutNotifView;
60 
61     @Inject
LightsOutNotifController(WindowManager windowManager, NotificationEntryManager entryManager, CommandQueue commandQueue)62     LightsOutNotifController(WindowManager windowManager,
63             NotificationEntryManager entryManager,
64             CommandQueue commandQueue) {
65         mWindowManager = windowManager;
66         mEntryManager = entryManager;
67         mCommandQueue = commandQueue;
68     }
69 
70     /**
71      * Sets the notification dot view after it is created in the StatusBar.
72      * This is the view this controller will show and hide depending on whether:
73      * 1. there are active notifications
74      * 2. an app has requested {@link View.SYSTEM_UI_FLAG_LOW_PROFILE}
75      */
setLightsOutNotifView(View lightsOutNotifView)76     void setLightsOutNotifView(View lightsOutNotifView) {
77         destroy();
78         mLightsOutNotifView = lightsOutNotifView;
79 
80         if (mLightsOutNotifView != null) {
81             mLightsOutNotifView.setVisibility(View.GONE);
82             mLightsOutNotifView.setAlpha(0f);
83             init();
84         }
85     }
86 
destroy()87     private void destroy() {
88         mEntryManager.removeNotificationEntryListener(mEntryListener);
89         mCommandQueue.removeCallback(mCallback);
90     }
91 
init()92     private void init() {
93         mDisplayId = mWindowManager.getDefaultDisplay().getDisplayId();
94         mEntryManager.addNotificationEntryListener(mEntryListener);
95         mCommandQueue.addCallback(mCallback);
96 
97         updateLightsOutView();
98     }
99 
hasActiveNotifications()100     private boolean hasActiveNotifications() {
101         return mEntryManager.hasActiveNotifications();
102     }
103 
104     @VisibleForTesting
updateLightsOutView()105     void updateLightsOutView() {
106         if (mLightsOutNotifView == null) {
107             return;
108         }
109 
110         final boolean showDot = shouldShowDot();
111         if (showDot != isShowingDot()) {
112             if (showDot) {
113                 mLightsOutNotifView.setAlpha(0f);
114                 mLightsOutNotifView.setVisibility(View.VISIBLE);
115             }
116 
117             mLightsOutNotifView.animate()
118                     .alpha(showDot ? 1 : 0)
119                     .setDuration(showDot ? 750 : 250)
120                     .setInterpolator(new AccelerateInterpolator(2.0f))
121                     .setListener(new AnimatorListenerAdapter() {
122                         @Override
123                         public void onAnimationEnd(Animator a) {
124                             mLightsOutNotifView.setAlpha(showDot ? 1 : 0);
125                             mLightsOutNotifView.setVisibility(showDot ? View.VISIBLE : View.GONE);
126                         }
127                     })
128                     .start();
129         }
130     }
131 
132     @VisibleForTesting
isShowingDot()133     boolean isShowingDot() {
134         return mLightsOutNotifView.getVisibility() == View.VISIBLE
135                 && mLightsOutNotifView.getAlpha() == 1.0f;
136     }
137 
138     @VisibleForTesting
shouldShowDot()139     boolean shouldShowDot() {
140         return hasActiveNotifications() && areLightsOut();
141     }
142 
143     @VisibleForTesting
areLightsOut()144     boolean areLightsOut() {
145         return 0 != (mAppearance & APPEARANCE_LOW_PROFILE_BARS);
146     }
147 
148     private final CommandQueue.Callbacks mCallback = new CommandQueue.Callbacks() {
149         @Override
150         public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
151                 AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
152                 @Behavior int behavior, boolean isFullscreen) {
153             if (displayId != mDisplayId) {
154                 return;
155             }
156             mAppearance = appearance;
157             updateLightsOutView();
158         }
159     };
160 
161     private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
162         // Cares about notifications post-filtering
163         @Override
164         public void onNotificationAdded(NotificationEntry entry) {
165             updateLightsOutView();
166         }
167 
168         @Override
169         public void onPostEntryUpdated(NotificationEntry entry) {
170             updateLightsOutView();
171         }
172 
173         @Override
174         public void onEntryRemoved(@Nullable NotificationEntry entry,
175                 NotificationVisibility visibility, boolean removedByUser, int reason) {
176             updateLightsOutView();
177         }
178     };
179 }
180