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.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
21 import static android.view.Display.DEFAULT_DISPLAY;
22 
23 import android.annotation.SuppressLint;
24 import android.annotation.SystemApi;
25 import android.annotation.TestApi;
26 import android.content.Context;
27 import android.os.Binder;
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 ActivityTaskManager mActivityTaskManager;
44     private Executor mExecutor;
45     private int mMaxScanTasksForHomeVisibility;
46     /** @hide */
47     android.app.IProcessObserver.Stub mObserver;
48     /** @hide */
49     boolean mIsHomeActivityVisible;
50 
51     /** @hide */
init(Context context, Executor executor)52     void init(Context context, Executor executor) {
53         mActivityTaskManager = ActivityTaskManager.getInstance();
54         mExecutor = executor;
55         mMaxScanTasksForHomeVisibility = context.getResources().getInteger(
56                 com.android.internal.R.integer.config_maxScanTasksForHomeVisibility);
57         mIsHomeActivityVisible = isHomeActivityVisible();
58     }
59 
60     /**
61      * Called when the visibility of the home screen changes.
62      *
63      * @param isHomeActivityVisible Whether the home screen activity is now visible.
64      */
onHomeVisibilityChanged(boolean isHomeActivityVisible)65     public abstract void onHomeVisibilityChanged(boolean isHomeActivityVisible);
66 
HomeVisibilityListener()67     public HomeVisibilityListener() {
68         mObserver = new android.app.IProcessObserver.Stub() {
69             @Override
70             public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
71                 refreshHomeVisibility();
72             }
73 
74             @Override
75             public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) {
76             }
77 
78             @Override
79             public void onProcessDied(int pid, int uid) {
80                 refreshHomeVisibility();
81             }
82 
83             private void refreshHomeVisibility() {
84                 boolean isHomeActivityVisible = isHomeActivityVisible();
85                 if (mIsHomeActivityVisible != isHomeActivityVisible) {
86                     mIsHomeActivityVisible = isHomeActivityVisible;
87                     Binder.withCleanCallingIdentity(() ->
88                             mExecutor.execute(() ->
89                                     onHomeVisibilityChanged(mIsHomeActivityVisible)));
90                 }
91             }
92         };
93     }
94 
isHomeActivityVisible()95     private boolean isHomeActivityVisible() {
96         List<ActivityManager.RunningTaskInfo> tasksTopToBottom = mActivityTaskManager.getTasks(
97                 mMaxScanTasksForHomeVisibility, /* filterOnlyVisibleRecents= */ true,
98                 /* keepIntentExtra= */ false, DEFAULT_DISPLAY);
99         if (tasksTopToBottom == null || tasksTopToBottom.isEmpty()) {
100             return false;
101         }
102 
103         for (int i = 0, taskSize = tasksTopToBottom.size(); i < taskSize; ++i) {
104             ActivityManager.RunningTaskInfo task = tasksTopToBottom.get(i);
105             if (!task.isVisible()
106                     || (task.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0) {
107                 continue;
108             }
109             return task.getActivityType() == ACTIVITY_TYPE_HOME;
110         }
111         return false;
112     }
113 }
114