Android 12系统源码_页面管理(四)获取系统当前最上层可见Activity的信息

本文介绍了如何通过Android12的ActivityTaskManagerAPI获取系统最上层Activity的信息,包括根任务、TaskInfo属性,并展示了如何实时监听Activity栈的变化。
摘要由CSDN通过智能技术生成

前言

很多应用开发人员,在日常开发过程中,经常会遇到一些需求,例如需要知道当前最上层的Activity是哪个,并结合这个Activity的名称来完成一些特定场景的需求。最简单的方法,是在创建Activity的时候将该Actvity存储到一个集合中,而当Activity销毁的时候,再将该Activity从集合中移除,这种方案虽然能够获取自己应用当前最上层的Activity是那个,但却无法获取除了自己应用以外的其他场景。犹豫谷歌为系统开发提供了特定的API,作为系统开发人员,我们完全可以通过这些API实时获取当前最上层的Activity信息,并将这些信息同步给系统应用。本篇文章我们将会结合Android12的系统源码,来探讨一下如何通过系统内部API实时获取当前系统最上层的Activity的信息,以及如何实时监听当前系统Activity栈信息的变化。

一、获取最上层的根任务信息

1、根任务是指包含一个或多个 Activity 的任务,并且没有父任务,根任务通常是由用户启动的应用程序或系统应用程序的主要任务。
在 Android 12 中,我们可以通过以下代码获取最上层的根任务信息。

IActivityManager ams = ActivityManager.getService(); //获取ActivityManagerService服务对象
List<ActivityTaskManager.RootTaskInfo> runningTasks = mAm.getAllRootTaskInfos();;//调用getAllRootTaskInfos方法

首先调用ActivityManager的getService方法获取ActivityManagerService服务对象,然后调用该服务对象的getAllRootTaskInfos方法,该方法会返回一个指定数量包含所有根任务信息的列表,每个根任务都有其任务 ID、根 Activity 的信息以及与之关联的其他活动堆栈。

2、来看下和RootTaskInfo类相关的代码。

base/core/java/android/app/ActivityTaskManager .java

public class ActivityTaskManager {
    public static class RootTaskInfo extends TaskInfo implements Parcelable {
        // TODO(b/148895075): Move some of the fields to TaskInfo.
        public Rect bounds = new Rect();
        public int[] childTaskIds;
        public String[] childTaskNames;
        public Rect[] childTaskBounds;
        public int[] childTaskUserIds;
        public boolean visible;
        // Index of the stack in the display's stack list, can be used for comparison of stack order
        public int position;
	}
}

3、RootTaskInfo 继承自TaskInfo,继续来看下该类有哪些关键属性。

base/core/java/android/app/TaskInfo.java

public class TaskInfo {
    private static final String TAG = "TaskInfo";

    /**
     * 当前任务对应的用户id    
     * The id of the user the task was running as if this is a leaf task. The id of the current
     * running user of the system otherwise.
     * @hide
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public int userId;

    /**
     * 任务id
     * The identifier for this task.
     */
    public int taskId;

    /**
     * 此任务中是否有正在运行的Activity
     * Whether or not this task has any running activities.
     */
    public boolean isRunning;

    /**
     * 启动当前任务的Intent
     * The base intent of the task (generally the intent that launched the task). This intent can
     * be used to relaunch the task (if it is no longer running) or brought to the front if it is.
     */
    @NonNull
    public Intent baseIntent;

    /**
     * The component of the first activity in the task, can be considered the "application" of this
     * task.
     */
    @Nullable
    public ComponentName baseActivity;

    /**
     * 当前任务对应的Activity栈中的最上层正在显示的activity
     * The component of the top activity in the task, currently showing to the user.
     */
    @Nullable
    public ComponentName topActivity;

    /**
     * The component of the target activity if this task was started from an activity alias.
     * Otherwise, this is null.
     */
    @Nullable
    public ComponentName origActivity;

    /**
     * The component of the activity that started this task (may be the component of the activity
     * alias).
     * @hide
     */
    @Nullable
    public ComponentName realActivity;

    /**
     * The number of activities in this task (including running).
     */
    public int numActivities;

    /**
     * The last time this task was active since boot (including time spent in sleep).
     * @hide
     */
    @UnsupportedAppUsage
    public long lastActiveTime;

    /**
     * 当前任务对应的屏幕设备id
     * The id of the display this task is associated with.
     * @hide
     */
    public int displayId;

    /**
     * The feature id of {@link com.android.server.wm.TaskDisplayArea} this task is associated with.
     * @hide
     */
    public int displayAreaFeatureId = FEATURE_UNDEFINED;

    /**
     * The recent activity values for the highest activity in the stack to have set the values.
     * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.
     */
    @Nullable
    public ActivityManager.TaskDescription taskDescription;

    /**
     * The locusId of the task.
     * @hide
     */
    @Nullable
    public LocusId mTopActivityLocusId;

    /**
     * 当前任务是否支持分屏
     * True if the task can go in the split-screen primary stack.
     * @hide
     */
    @UnsupportedAppUsage
    public boolean supportsSplitScreenMultiWindow;

    /**
     * 当前任务是否支持多窗口
     * Whether this task supports multi windowing modes based on the device settings and the
     * root activity resizability and configuration.
     * @hide
     */
    public boolean supportsMultiWindow;

    /**
     * The resize mode of the task. See {@link ActivityInfo#resizeMode}.
     * @hide
     */
    @UnsupportedAppUsage
    public int resizeMode;

    /**
     * The current configuration of the task.
     * @hide
     */
    @NonNull
    @UnsupportedAppUsage
    public final Configuration configuration = new Configuration();

    /**
     * Used as an opaque identifier for this task.
     * @hide
     */
    @NonNull
    public WindowContainerToken token;

    /**
     * 用于控制画中画模式的参数类
     * The PictureInPictureParams for the Task, if set.
     * @hide
     */
    @Nullable
    public PictureInPictureParams pictureInPictureParams;

    /**
     * The {@link Rect} copied from {@link DisplayCutout#getSafeInsets()} if the cutout is not of
     * (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS),
     * {@code null} otherwise.
     * @hide
     */
    @Nullable
    public Rect displayCutoutInsets;

    /**
     * 当前任务最上层Activity的类型
     * The activity type of the top activity in this task.
     * @hide
     */
    public @WindowConfiguration.ActivityType int topActivityType;

    /**
     * The {@link ActivityInfo} of the top activity in this task.
     * @hide
     */
    @Nullable
    public ActivityInfo topActivityInfo;

    /**
     * Whether the direct top activity is in size compat mode on foreground.
     * @hide
     */
    public boolean topActivityInSizeCompat;

    /**
     * Whether this task is resizable. Unlike {@link #resizeMode} (which is what the top activity
     * supports), this is what the system actually uses for resizability based on other policy and
     * developer options.
     * @hide
     */
    public boolean isResizeable;

    /**
     * Relative position of the task's top left corner in the parent container.
     * @hide
     */
    public Point positionInParent;

    /**
     * The launch cookies associated with activities in this task if any.
     * @see ActivityOptions#setLaunchCookie(IBinder)
     * @hide
     */
    public ArrayList<IBinder> launchCookies = new ArrayList<>();

    /**
     * The identifier of the parent task that is created by organizer, otherwise
     * {@link ActivityTaskManager#INVALID_TASK_ID}.
     * @hide
     */
    public int parentTaskId;

    /**
     * 当前任务是否持有焦点
     * Whether this task is focused.
     * @hide
     */
    public boolean isFocused;

    /**
     * 当前任务是否可见
     * Whether this task is visible.
     * @hide
     */
    public boolean isVisible;

    /**
     * Whether this task is sleeping due to sleeping display.
     * @hide
     */
    public boolean isSleeping;

}

TaskInfo类中也包含了很多对于当前任务至关重要的信息:任务对应的用户id、任务id、任务中是否有运行的Activity、启动任务的Intent、任务对应的Activity栈最上层Activity,对应的屏幕设备id、任务是否支持分屏、任务是否支持多窗口、用于控制画中画模式的参数类、任务是否持有焦点、任务是否可见等。

二、实时监听Activity栈信息变化。

1、我们主要是通过调用ActivityManagerService的相关方法来实时监听Activity对应的任务栈的变化的,具体可以参考以下代码。

public class ActivityTopTaskManager {

    private Context mContext;
    private final SparseArray<TopTaskInfoContainer> mTopTasks = new SparseArray<>();
    private IActivityManager mAm;
    private final Object mLock = new Object();
    
    public void init(Context context) {
        try {
            mContext = context;
		   //获取ActivityManagerService的实例对象
           IActivityManager am = ActivityManager.getService();
           //调用registerTaskStackListener方法,注册监听任务栈变化的回调对象
           am.registerTaskStackListener(new TaskStackListener() {
                @Override
                public void onTaskStackChanged() throws RemoteException {
                	//调用updateTasks
          			updateTasks();
                }
            });;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
	 //获取任务栈信息
    public void updateTasks() {
        try {
            List<ActivityTaskManager.RootTaskInfo> rootTasks = mAm.getAllRootTaskInfos();
            if (rootTasks == null) {
                return;
            }
            int focusedStackId = INVALID_STACK_ID;
            final ActivityTaskManager.RootTaskInfo focusedTaskInfo = mAm.getFocusedRootTaskInfo();
            if (focusedTaskInfo != null) {
                focusedStackId = focusedTaskInfo.taskId;
            }
            SparseArray<TopTaskInfoContainer> topTasks = new SparseArray<>();
            synchronized (mLock) {
                for (ActivityTaskManager.RootTaskInfo info : rootTasks) {
                    int displayId = info.displayId;
                    if (info.childTaskNames.length == 0 || !info.visible) { // empty stack or not shown
                        continue;
                    }
                    TopTaskInfoContainer newTopTaskInfo = new TopTaskInfoContainer(
                            info.topActivity, info.childTaskIds[info.childTaskIds.length - 1],
                            info.displayId, info.position, info);
                    TopTaskInfoContainer currentTopTaskInfo = topTasks.get(displayId);
                    if (currentTopTaskInfo == null || newTopTaskInfo.position > currentTopTaskInfo.position) {
                        topTasks.put(displayId, newTopTaskInfo);
                        Log.i(TAG, "Updating top task to: " + newTopTaskInfo);
                    }
                }
                for (int i = 0; i < topTasks.size(); i++) {
                    TopTaskInfoContainer topTask = topTasks.valueAt(i);
                    int displayId = topTasks.keyAt(i);
                    mTopTasks.put(displayId, topTask);
                }
            }
        } catch (Exception e) {
            Log.d(TAG, "updateTasks: e = " + e);
        }
    }
}
  • 调用ActivityManagerService的registerTaskStackListener方法注册回调对象,实时监听当前任务栈的变化。
  • 继续调用ActivityManagerService的getAllRootTaskInfos方法,获取当前的所有跟任务信息,该方法返回一个类型为RootTaskInfo的集合,关于RootTaskInfo这个类,前面我们已经做过简单介绍了。
  • 最后结合RootTaskInfo的相关属性,可以成功获取到当前系统中每个屏幕设备对应的最上层可见的Activity的包名和组件名称。
  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值