Android 7.0 SystemUI(3)--RecentsActivity

本文深入探讨Android 7.0中的RecentsActivity,主要涉及getRecentTasks获取近期任务、getTaskThumbnail获取任务缩略图以及removeTask移除任务的流程。在系统启动时,RecentTasks对象从xml文件加载任务信息,而在activity启动和恢复时更新。任务缩略图在activity暂停后截取并保存,便于后续获取。此外,还介绍了如何通过TaskRecord移除任务的相关操作。
摘要由CSDN通过智能技术生成

RecentsActivity 是最近任务管理界面,通过该activity用户可以对启动的应用进行简单的管理。其配置信息如下

frameworks/base/packages/SystemUI/AndroidManifest.xml

        <activity android:name=".recents.RecentsActivity"
                  android:label="@string/accessibility_desc_recent_apps"
                  android:exported="false"
                  android:launchMode="singleInstance"
                  android:excludeFromRecents="true"
                  android:stateNotNeeded="true"
                  android:resumeWhilePausing="true"
                  android:screenOrientation="behind"
                  android:resizeableActivity="true"
                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
                  android:theme="@style/RecentsTheme.Wallpaper">
            <intent-filter>
                <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
            </intent-filter>
        </activity>
可以看到其launchMode为"singleInstance"。 RecentsActivity 启动的入口在
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java

    private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            awakenDreams();
            toggleRecentApps();
        }
    };
关于 RecentsActivity ,这里主要讨论3个方面,task的获取、应用缩略图的获取、task移除。

getRecentTasks

在ams中,有一个mRecentTasks对象,该对象保存了近期启动的task任务信息,RecentsActivity实际上是要获取mRecentTasks对象

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 

  /**
     * List of intents that were used to start the most recent tasks.
     */
    final RecentTasks mRecentTasks;


在上面的入口中,toggleRecentApps()最终会调用到

frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java

    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,
            boolean includeFrontMostExcludedTask, ArraySet<Integer> quietProfileIds) {
        ...
        int minNumTasksToQuery = 10;
        int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
        int flags = ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
                ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK |
                ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS |
                ActivityManager.RECENT_IGNORE_UNAVAILABLE |
                ActivityManager.RECENT_INCLUDE_PROFILES;
        if (includeFrontMostExcludedTask) {
            flags |= ActivityManager.RECENT_WITH_EXCLUDED;
        }
        List<ActivityManager.RecentTaskInfo> tasks = null;
        try {
            tasks = mAm.getRecentTasksForUser(numTasksToQuery, flags, userId);
        } catch (Exception e) {
            Log.e(TAG, "Failed to get recent tasks", e);
        }

        ...
        return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
    }
这里设置了flag,不去获取HOME_STACK_ID、DOCKED_STACK_ID、PINNED_STACK_ID上的task,根据机器内存大小设置了最大的查询数

frameworks/base/core/java/android/app/ActivityManager.java 
static public int getMaxRecentTasksStatic() {
        if (gMaxRecentTasks < 0) {
            return gMaxRecentTasks = isLowRamDeviceStatic() ? 36 : 48;
        }
        return gMaxRecentTasks;
    }
然后调用ActivityManager的getRecentTasksForUser方法

frameworks/base/core/java/android/app/ActivityManager.java 
public List<RecentTaskInfo> getRecentTasksForUser(int maxNum, int flags, int userId)
            throws SecurityException {
        try {
            return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
                    flags, userId).getList();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
通过binder通信最终会进入到ams

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 
   public ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
            int userId) {
        final int callingUid = Binder.getCallingUid();
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                false, ALLOW_FULL_ONLY, "getRecentTasks", null);

        final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0;
        final boolean withExcluded = (flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0;
        synchronized (this) {
            final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
                    callingUid);
            final boolean detailed = checkCallingPermission(
                    android.Manifest.permission.GET_DETAILED_TASKS)
                    == PackageManager.PERMISSION_GRANTED;

            if (!isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {
                Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
                return ParceledListSlice.emptyList();
            }
            mRecentTasks.loadUserRecentsLocked(userId);

            final int recentsCount = mRecentTasks.size();
            ArrayList<ActivityManager.RecentTaskInfo> res =
                    new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount);

            final Set<Integer> includedUsers;
            if (includeProfiles) {
                includedUsers = mUserController.getProfileIds(userId);
            } else {
                includedUsers = new HashSet<>();
            }
            includedUsers.add(Integer.valueOf(userId));

            for (int i = 0; i < recentsCount && maxNum > 0; i++) {
                TaskRecord tr = mRecentTasks.get(i);
                // Only add calling user or related users recent tasks
                if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
                    continue;
                }

                if (tr.realActivitySuspended) {
                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
                    continue;
                }

                // Return the entry if desired by the caller.  We always return
                // the first entry, because callers always expect this to be the
                // foreground app.  We may filter others if the caller has
                // not supplied RECENT_WITH_EXCLUDED and there is some reason
                // we should exclude the entry.

                if (i == 0
                        || withExcluded
                        || (tr.intent == null)
                        || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                                == 0)) {
                    if (!allowed) {
                        // If the caller doesn't have the GET_TASKS permission, then only
                        // allow them to see a small subset of tasks -- their own and home.
                        if (!tr.isHomeTask() && tr.effectiveUid != callingUid) {
                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
                            continue;
                        }
                    }
                    if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {
                        if (tr.stack != null && tr.stack.isHomeStack()) {
                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                    "Skipping, home stack task: " + tr);
                            continue;
                        }
                    }
                    if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {
                        final ActivityStack stack = tr.stack;
                        if (stack != null && stack.isDockedStack() && stack.topTask() == tr) {
                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                    "Skipping, top task in docked stack: " + tr);
                            continue;
                        }
                    }
                    if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {
                        if (tr.stack != null && tr.stack.isPinnedStack()) {
                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                    "Skipping, pinned stack task: " + tr);
                            continue;
                        }
                    }
                    if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
                        // Don't include auto remove tasks that are finished or finishing.
                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                "Skipping, auto-remove without activity: " + tr);
                        continue;
                    }
                    if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0
                            && !tr.isAvailabl
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值