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.assist;
18 
19 import android.app.ActivityManager;
20 import android.app.KeyguardManager;
21 import android.content.BroadcastReceiver;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.pm.ResolveInfo;
27 
28 import androidx.annotation.Nullable;
29 
30 import com.android.systemui.BootCompleteCache;
31 import com.android.systemui.Dependency;
32 import com.android.systemui.broadcast.BroadcastDispatcher;
33 import com.android.systemui.plugins.statusbar.StatusBarStateController;
34 import com.android.systemui.shared.system.ActivityManagerWrapper;
35 import com.android.systemui.shared.system.PackageManagerWrapper;
36 import com.android.systemui.shared.system.TaskStackChangeListener;
37 import com.android.systemui.statusbar.StatusBarState;
38 import com.android.systemui.statusbar.phone.StatusBar;
39 
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Optional;
43 
44 import javax.inject.Inject;
45 import javax.inject.Singleton;
46 
47 import dagger.Lazy;
48 
49 /** Class to monitor and report the state of the phone. */
50 @Singleton
51 public final class PhoneStateMonitor {
52 
53     public static final int PHONE_STATE_AOD1 = 1;
54     public static final int PHONE_STATE_AOD2 = 2;
55     public static final int PHONE_STATE_BOUNCER = 3;
56     public static final int PHONE_STATE_UNLOCKED_LOCKSCREEN = 4;
57     public static final int PHONE_STATE_HOME = 5;
58     public static final int PHONE_STATE_OVERVIEW = 6;
59     public static final int PHONE_STATE_ALL_APPS = 7;
60     public static final int PHONE_STATE_APP_DEFAULT = 8;
61     public static final int PHONE_STATE_APP_IMMERSIVE = 9;
62     public static final int PHONE_STATE_APP_FULLSCREEN = 10;
63 
64     private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
65             PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
66             Intent.ACTION_PACKAGE_ADDED,
67             Intent.ACTION_PACKAGE_CHANGED,
68             Intent.ACTION_PACKAGE_REMOVED
69     };
70 
71     private final Context mContext;
72     private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
73     private final StatusBarStateController mStatusBarStateController;
74 
75     private boolean mLauncherShowing;
76     @Nullable private ComponentName mDefaultHome;
77 
78     @Inject
PhoneStateMonitor(Context context, BroadcastDispatcher broadcastDispatcher, Optional<Lazy<StatusBar>> statusBarOptionalLazy, BootCompleteCache bootCompleteCache)79     PhoneStateMonitor(Context context, BroadcastDispatcher broadcastDispatcher,
80             Optional<Lazy<StatusBar>> statusBarOptionalLazy, BootCompleteCache bootCompleteCache) {
81         mContext = context;
82         mStatusBarOptionalLazy = statusBarOptionalLazy;
83         mStatusBarStateController = Dependency.get(StatusBarStateController.class);
84 
85         ActivityManagerWrapper activityManagerWrapper = ActivityManagerWrapper.getInstance();
86         mDefaultHome = getCurrentDefaultHome();
87         bootCompleteCache.addListener(() -> mDefaultHome = getCurrentDefaultHome());
88         IntentFilter intentFilter = new IntentFilter();
89         for (String action : DEFAULT_HOME_CHANGE_ACTIONS) {
90             intentFilter.addAction(action);
91         }
92         broadcastDispatcher.registerReceiver(new BroadcastReceiver() {
93             @Override
94             public void onReceive(Context context, Intent intent) {
95                 mDefaultHome = getCurrentDefaultHome();
96             }
97         }, intentFilter);
98         mLauncherShowing = isLauncherShowing(activityManagerWrapper.getRunningTask());
99         activityManagerWrapper.registerTaskStackListener(new TaskStackChangeListener() {
100             @Override
101             public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
102                 mLauncherShowing = isLauncherShowing(taskInfo);
103             }
104         });
105     }
106 
getPhoneState()107     public int getPhoneState() {
108         int phoneState;
109         if (isShadeFullscreen()) {
110             phoneState = getPhoneLockscreenState();
111         } else if (mLauncherShowing) {
112             phoneState = getPhoneLauncherState();
113         } else {
114             phoneState = getPhoneAppState();
115         }
116         return phoneState;
117     }
118 
119     @Nullable
getCurrentDefaultHome()120     private static ComponentName getCurrentDefaultHome() {
121         List<ResolveInfo> homeActivities = new ArrayList<>();
122         ComponentName defaultHome =
123                 PackageManagerWrapper.getInstance().getHomeActivities(homeActivities);
124         if (defaultHome != null) {
125             return defaultHome;
126         }
127 
128         int topPriority = Integer.MIN_VALUE;
129         ComponentName topComponent = null;
130         for (ResolveInfo resolveInfo : homeActivities) {
131             if (resolveInfo.priority > topPriority) {
132                 topComponent = resolveInfo.activityInfo.getComponentName();
133                 topPriority = resolveInfo.priority;
134             } else if (resolveInfo.priority == topPriority) {
135                 topComponent = null;
136             }
137         }
138         return topComponent;
139     }
140 
getPhoneLockscreenState()141     private int getPhoneLockscreenState() {
142         if (isDozing()) {
143             return PHONE_STATE_AOD1;
144         } else if (isBouncerShowing()) {
145             return PHONE_STATE_BOUNCER;
146         } else if (isKeyguardLocked()) {
147             return PHONE_STATE_AOD2;
148         } else {
149             return PHONE_STATE_UNLOCKED_LOCKSCREEN;
150         }
151     }
152 
getPhoneLauncherState()153     private int getPhoneLauncherState() {
154         if (isLauncherInOverview()) {
155             return PHONE_STATE_OVERVIEW;
156         } else if (isLauncherInAllApps()) {
157             return PHONE_STATE_ALL_APPS;
158         } else {
159             return PHONE_STATE_HOME;
160         }
161     }
162 
getPhoneAppState()163     private int getPhoneAppState() {
164         if (isAppImmersive()) {
165             return PHONE_STATE_APP_IMMERSIVE;
166         } else if (isAppFullscreen()) {
167             return PHONE_STATE_APP_FULLSCREEN;
168         } else {
169             return PHONE_STATE_APP_DEFAULT;
170         }
171     }
172 
isShadeFullscreen()173     private boolean isShadeFullscreen() {
174         int statusBarState = mStatusBarStateController.getState();
175         return statusBarState == StatusBarState.KEYGUARD
176                 || statusBarState == StatusBarState.SHADE_LOCKED;
177     }
178 
isDozing()179     private boolean isDozing() {
180         return mStatusBarStateController.isDozing();
181     }
182 
isLauncherShowing(ActivityManager.RunningTaskInfo runningTaskInfo)183     private boolean isLauncherShowing(ActivityManager.RunningTaskInfo runningTaskInfo) {
184         if (runningTaskInfo == null) {
185             return false;
186         } else {
187             return runningTaskInfo.topActivity.equals(mDefaultHome);
188         }
189     }
190 
isAppImmersive()191     private boolean isAppImmersive() {
192         return mStatusBarOptionalLazy.get().get().inImmersiveMode();
193     }
194 
isAppFullscreen()195     private boolean isAppFullscreen() {
196         return mStatusBarOptionalLazy.get().get().inFullscreenMode();
197     }
198 
isBouncerShowing()199     private boolean isBouncerShowing() {
200         return mStatusBarOptionalLazy.map(
201                 statusBarLazy -> statusBarLazy.get().isBouncerShowing()).orElse(false);
202     }
203 
isKeyguardLocked()204     private boolean isKeyguardLocked() {
205         // TODO: Move binder call off of critical path
206         KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
207         return keyguardManager != null && keyguardManager.isKeyguardLocked();
208     }
209 
isLauncherInOverview()210     private boolean isLauncherInOverview() {
211         // TODO
212         return false;
213     }
214 
isLauncherInAllApps()215     private boolean isLauncherInAllApps() {
216         // TODO
217         return false;
218     }
219 }
220