1 /*
2  * Copyright (C) 2020 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 android.app;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
20 import static android.view.Display.DEFAULT_DISPLAY;
21 
22 import android.annotation.SuppressLint;
23 import android.annotation.SystemApi;
24 import android.annotation.TestApi;
25 import android.content.Context;
26 import android.os.Binder;
27 import android.util.Log;
28 
29 import java.util.List;
30 import java.util.concurrent.Executor;
31 
32 /**
33  * A listener that will be invoked when the visibility of the home screen changes.
34  * Register this callback via {@link ActivityManager#addHomeVisibilityListener}
35  * @hide
36  */
37 // This is a single-method listener that needs a bunch of supporting code, so it can't be an
38 // interface
39 @SuppressLint("ListenerInterface")
40 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
41 @TestApi
42 public abstract class HomeVisibilityListener {
43     private static final String TAG = HomeVisibilityListener.class.getSimpleName();
44     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
45     private ActivityTaskManager mActivityTaskManager;
46     private Executor mExecutor;
47     private int mMaxScanTasksForHomeVisibility;
48     /** @hide */
49     android.app.IProcessObserver.Stub mObserver;
50     /** @hide */
51     boolean mIsHomeActivityVisible;
52 
53     /** @hide */
init(Context context, Executor executor)54     void init(Context context, Executor executor) {
55         mActivityTaskManager = ActivityTaskManager.getInstance();
56         mExecutor = executor;
57         mMaxScanTasksForHomeVisibility = context.getResources().getInteger(
58                 com.android.internal.R.integer.config_maxScanTasksForHomeVisibility);
59         mIsHomeActivityVisible = isHomeActivityVisible();
60     }
61 
62     /**
63      * Called when the visibility of the home screen changes.
64      *
65      * @param isHomeActivityVisible Whether the home screen activity is now visible.
66      */
onHomeVisibilityChanged(boolean isHomeActivityVisible)67     public abstract void onHomeVisibilityChanged(boolean isHomeActivityVisible);
68 
HomeVisibilityListener()69     public HomeVisibilityListener() {
70         mObserver = new android.app.IProcessObserver.Stub() {
71             @Override
72             public void onProcessStarted(int pid, int processUid, int packageUid,
73                     String packageName, String processName) {
74             }
75 
76             @Override
77             public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
78                 refreshHomeVisibility();
79             }
80 
81             @Override
82             public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) {
83             }
84 
85             @Override
86             public void onProcessDied(int pid, int uid) {
87                 refreshHomeVisibility();
88             }
89 
90             private void refreshHomeVisibility() {
91                 boolean isHomeActivityVisible = isHomeActivityVisible();
92                 if (mIsHomeActivityVisible != isHomeActivityVisible) {
93                     mIsHomeActivityVisible = isHomeActivityVisible;
94                     Binder.withCleanCallingIdentity(() ->
95                             mExecutor.execute(() ->
96                                     onHomeVisibilityChanged(mIsHomeActivityVisible)));
97                 }
98             }
99         };
100     }
101 
isHomeActivityVisible()102     private boolean isHomeActivityVisible() {
103         List<ActivityManager.RunningTaskInfo> tasksTopToBottom = mActivityTaskManager.getTasks(
104                 mMaxScanTasksForHomeVisibility, /* filterOnlyVisibleRecents= */ true,
105                 /* keepIntentExtra= */ false, DEFAULT_DISPLAY);
106         if (tasksTopToBottom == null || tasksTopToBottom.isEmpty()) {
107             return false;
108         }
109 
110         for (int i = 0, taskSize = tasksTopToBottom.size(); i < taskSize; ++i) {
111             ActivityManager.RunningTaskInfo task = tasksTopToBottom.get(i);
112             if (DBG) {
113                 Log.d(TAG, "Task#" + i + ": activity=" + task.topActivity
114                         + ", visible=" + task.isVisible()
115                         + ", flg=" + Integer.toHexString(task.baseIntent.getFlags())
116                         + ", type=" + task.getActivityType());
117             }
118             if (task.isVisible() && (task.getActivityType() == ACTIVITY_TYPE_HOME)) {
119                 return true;
120             }
121         }
122         return false;
123     }
124 }
125