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 android.annotation.SuppressLint;
20 import android.annotation.SystemApi;
21 import android.annotation.TestApi;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.os.Binder;
25 
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Objects;
29 import java.util.concurrent.Executor;
30 
31 /**
32  * A listener that will be invoked when the visibility of the home screen changes.
33  * Register this callback via {@link ActivityManager#addHomeVisibilityListener}
34  * @hide
35  */
36 // This is a single-method listener that needs a bunch of supporting code, so it can't be an
37 // interface
38 @SuppressLint("ListenerInterface")
39 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
40 @TestApi
41 public abstract class HomeVisibilityListener {
42     private Context mContext;
43     private ActivityManager mActivityManager;
44     private Executor mExecutor;
45     /** @hide */
46     android.app.IProcessObserver.Stub mObserver;
47     /** @hide */
48     boolean mIsHomeActivityVisible;
49 
50     /** @hide */
init(Context context, Executor executor, ActivityManager activityManager)51     void init(Context context, Executor executor, ActivityManager activityManager) {
52         mContext = context;
53         mActivityManager = activityManager;
54         mIsHomeActivityVisible = isHomeActivityVisible();
55         mExecutor = executor;
56     }
57 
58     /**
59      * Called when the visibility of the home screen changes.
60      *
61      * @param isHomeActivityVisible Whether the home screen activity is now visible.
62      */
onHomeVisibilityChanged(boolean isHomeActivityVisible)63     public abstract void onHomeVisibilityChanged(boolean isHomeActivityVisible);
64 
HomeVisibilityListener()65     public HomeVisibilityListener() {
66         mObserver = new android.app.IProcessObserver.Stub() {
67             @Override
68             public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
69                 refreshHomeVisibility();
70             }
71 
72             @Override
73             public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) {
74             }
75 
76             @Override
77             public void onProcessDied(int pid, int uid) {
78                 refreshHomeVisibility();
79             }
80 
81             private void refreshHomeVisibility() {
82                 boolean isHomeActivityVisible = isHomeActivityVisible();
83                 if (mIsHomeActivityVisible != isHomeActivityVisible) {
84                     mIsHomeActivityVisible = isHomeActivityVisible;
85                     Binder.withCleanCallingIdentity(() ->
86                             mExecutor.execute(() ->
87                                     onHomeVisibilityChanged(mIsHomeActivityVisible)));
88                 }
89             }
90         };
91     }
92 
isHomeActivityVisible()93     private boolean isHomeActivityVisible() {
94         List<ActivityManager.RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
95         if (tasks == null || tasks.isEmpty()) {
96             return false;
97         }
98 
99         String top = tasks.get(0).topActivity.getPackageName();
100         if (top == null) {
101             return false;
102         }
103 
104         // We can assume that the screen is idle if the home application is in the foreground.
105         ComponentName defaultHomeComponent = mContext.getPackageManager()
106                 .getHomeActivities(new ArrayList<>());
107         if (defaultHomeComponent == null) return false;
108 
109         String defaultHomePackage = defaultHomeComponent.getPackageName();
110         return Objects.equals(top, defaultHomePackage);
111     }
112 }
113