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