博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[深入SystemUI]-了解recents的启动流程(一)
阅读量:7125 次
发布时间:2019-06-28

本文共 12148 字,大约阅读时间需要 40 分钟。

本文流程基于Android 9.0

preloadRecentApps()流程介绍

1. PhoneWindowManager的事件分发

PhoneWindowManager处理点击事件的方法是interceptKeyBeforeDispatching()。相应处理逻辑如下: 点击switch

} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {    //不处于锁屏界面    if (!keyguardOn) {        //ACTION_DOWN并且只点了一次        if (down && repeatCount == 0) {            //预加载recent            preloadRecentApps();        } else if (!down) {            //当不处于ACTION_DOWN时,可能是up或者cancel            toggleRecentApps();        }    }    return -1;}复制代码

2.调用StatusBaraManbagerService的preloadRecentApps

private void preloadRecentApps() {    mPreloadedRecentApps = true;    StatusBarManagerInternal statusbar = getStatusBarManagerInternal();    if (statusbar != null) {        //调用statusbar的preloadRecentApps()        statusbar.preloadRecentApps();    }}复制代码

这里的是statusbar是通过getStatusBarManagerInternal()获取的,getStatusBarManagerInternal()实现如下:

StatusBarManagerInternal getStatusBarManagerInternal() {    synchronized (mServiceAquireLock) {        if (mStatusBarManagerInternal == null) {            mStatusBarManagerInternal =                    LocalServices.getService(StatusBarManagerInternal.class);        }        return mStatusBarManagerInternal;    }}复制代码

那么通过LocalServices.getService()是怎么得到的呢?其实在StatusBarManagerService初始化的时候,就将StatusBarManagerInernal的实现加进了LocalService中。

/** * Construct the service, add the status bar view to the window manager */public StatusBarManagerService(Context context, WindowManagerService windowManager) {    mContext = context;    mWindowManager = windowManager;    LocalServices.addService(StatusBarManagerInternal.class, mInternalService);    LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider);}复制代码

mInternalService的实现如下:

/** * Private API used by NotificationManagerService. */private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {    private boolean mNotificationLightOn;    // 接口其他一些方法的实现    @Override    public void toggleRecentApps() {        if (mBar != null) {            try {                mBar.toggleRecentApps();            } catch (RemoteException ex) {}        }    }    @Override    public void setCurrentUser(int newUserId) {        if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId);        mCurrentUserId = newUserId;    }    @Override    public void preloadRecentApps() {        if (mBar != null) {            try {                mBar.preloadRecentApps();            } catch (RemoteException ex) {}        }    }    @Override    public void cancelPreloadRecentApps() {        if (mBar != null) {            try {                mBar.cancelPreloadRecentApps();            } catch (RemoteException ex) {}        }    }    @Override    public void showRecentApps(boolean triggeredFromAltTab) {        if (mBar != null) {            try {                mBar.showRecentApps(triggeredFromAltTab);            } catch (RemoteException ex) {}        }    }    @Override    public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {        if (mBar != null) {            try {                mBar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey);            } catch (RemoteException ex) {}        }    }    // 接口其他一些方法的实现};复制代码

3.跨进程调用preloadRecentApps的实际实现

可以看出,调用mInternalService实际上是调用mBar:IStatusBar的方法。

mBar对应的对象时什么呢?

// ================================================================================// Callbacks from the status bar service.// ================================================================================@Overridepublic void registerStatusBar(IStatusBar bar, List
iconSlots, List
iconList, int switches[], List
binders, Rect fullscreenStackBounds, Rect dockedStackBounds) { enforceStatusBarService(); Slog.i(TAG, "registerStatusBar bar=" + bar); mBar = bar; // code...}复制代码

registerStatusBar在哪里调用呢?在StatusBarstart()方法中调用到:

@Overridepublic void start() {    //code...    try {        mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,                fullscreenStackBounds, dockedStackBounds);    } catch (RemoteException ex) {        // If the system process isn't there we're doomed anyway.    }    //code...}复制代码

CommandQueue其实是IStatusBar的一个代理类,调用mCommandQueuepreloadRecentApps()方法其实是调用CommandQueue内部接口CallbackspreloadRecentApps(),而实现CommandQueue.Callbacks是在Recents类中实现的,对应的preloadRecentApps()的实际实现也是在Recents中,具体实现如下:

/** * Preloads info for the Recents activity. */@Overridepublic void preloadRecentApps() {    // Ensure the device has been provisioned before allowing the user to interact with    // recents    if (!isUserSetup()) {        return;    }    if (mOverviewProxyService.getProxy() != null) {        // TODO: Proxy to Launcher        return;    }    int currentUser = sSystemServicesProxy.getCurrentUser();    //判断当前用户是否为系统用户    if (sSystemServicesProxy.isSystemUser(currentUser)) {        //mImpl为RecentsImpl,调用的实际上是RecentsImpl的preloadRecents()        mImpl.preloadRecents();    } else {        if (mSystemToUserCallbacks != null) {            IRecentsNonSystemUserCallbacks callbacks =                    mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);            if (callbacks != null) {                try {                    callbacks.preloadRecents();                } catch (RemoteException e) {                    Log.e(TAG, "Callback failed", e);                }            } else {                Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);            }        }    }}复制代码

4.从AMS中获取任务队列,加入到任务栈TaskStack中

RecentsImplpreloadRecents方法:

public void preloadRecents() {    //如果屏幕固定,直接返回,屏幕固定功能是在Android5.1上增加的,当打开此功能时,不允许切换到其他界面    if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) {        return;    }    // Skip preloading recents when keyguard is showing    final StatusBar statusBar = getStatusBar();    if (statusBar != null && statusBar.isKeyguardShowing()) {        return;    }    // Preload only the raw task list into a new load plan (which will be consumed by the    // RecentsActivity) only if there is a task to animate to.  Post this to ensure that we    // don't block the touch feedback on the nav bar button which triggers this.    mHandler.post(() -> {        SystemServicesProxy ssp = Recents.getSystemServices();        // 判断最近任务不可见        if (!ssp.isRecentsActivityVisible(null)) {            ActivityManager.RunningTaskInfo runningTask =                    ActivityManagerWrapper.getInstance().getRunningTask();            //如果获取到的runningTask(运行着的任务)为null时,则直接返回            if (runningTask == null) {                return;            }            RecentsTaskLoader loader = Recents.getTaskLoader();            sInstanceLoadPlan = new RecentsTaskLoadPlan(mContext);            loader.preloadTasks(sInstanceLoadPlan, runningTask.id);            TaskStack stack = sInstanceLoadPlan.getTaskStack();            if (stack.getTaskCount() > 0) {                // Only preload the icon (but not the thumbnail since it may not have been taken                // for the pausing activity)                preloadIcon(runningTask.id);                // At this point, we don't know anything about the stack state.  So only                // calculate the dimensions of the thumbnail that we need for the transition                // into Recents, but do not draw it until we construct the activity options when                // we start Recents                updateHeaderBarLayout(stack, null /* window rect override*/);            }        }    });}复制代码

RecentsTaskLoaderpreloadTasks()方法:

/** Preloads recents tasks using the specified plan to store the output. */public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId) {    preloadTasks(plan, runningTaskId, ActivityManagerWrapper.getInstance().getCurrentUserId());}/** Preloads recents tasks using the specified plan to store the output. */public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,        int currentUserId) {    try {        Trace.beginSection("preloadPlan");        plan.preloadPlan(new PreloadOptions(), this, runningTaskId, currentUserId);    } finally {        Trace.endSection();    }}复制代码

RecentsTaskLoadPlanpreloadPlan()方法,将从AMS中获取的任务队列加入到任务栈TaskStack中:

/** * Preloads the list of recent tasks from the system. After this call, the TaskStack will * have a list of all the recent tasks with their metadata, not including icons or * thumbnails which were not cached and have to be loaded. * * The tasks will be ordered by: * - least-recent to most-recent stack tasks * * Note: Do not lock, since this can be calling back to the loader, which separately also drives * this call (callers should synchronize on the loader before making this call). */public void preloadPlan(PreloadOptions opts, RecentsTaskLoader loader, int runningTaskId,        int currentUserId) {    Resources res = mContext.getResources();    ArrayList
allTasks = new ArrayList<>(); if (mRawTasks == null) { //从ActivityManagerService中获取原始的任务列表 mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks( ActivityManager.getMaxRecentTasksStatic(), currentUserId); // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it Collections.reverse(mRawTasks); } int taskCount = mRawTasks.size(); //通过遍历,将RawTask变为最近任务中可以用于加载显式的Task类型,最终加入到最近任务栈中mStack for (int i = 0; i < taskCount; i++) { ActivityManager.RecentTaskInfo t = mRawTasks.get(i); // Compose the task key final ComponentName sourceComponent = t.origActivity != null // Activity alias if there is one ? t.origActivity // The real activity if there is no alias (or the target if there is one) : t.realActivity; final int windowingMode = t.configuration.windowConfiguration.getWindowingMode(); TaskKey taskKey = new TaskKey(t.persistentId, windowingMode, t.baseIntent, sourceComponent, t.userId, t.lastActiveTime); boolean isFreeformTask = windowingMode == WINDOWING_MODE_FREEFORM; boolean isStackTask = !isFreeformTask; boolean isLaunchTarget = taskKey.id == runningTaskId; ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey); if (info == null) { continue; } // Load the title, icon, and color String title = opts.loadTitles ? loader.getAndUpdateActivityTitle(taskKey, t.taskDescription) : ""; String titleDescription = opts.loadTitles ? loader.getAndUpdateContentDescription(taskKey, t.taskDescription) : ""; Drawable icon = isStackTask ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, false) : null; ThumbnailData thumbnail = loader.getAndUpdateThumbnail(taskKey, false /* loadIfNotCached */, false /* storeInCache */); int activityColor = loader.getActivityPrimaryColor(t.taskDescription); int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription); boolean isSystemApp = (info != null) && ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); // TODO: Refactor to not do this every preload if (mTmpLockedUsers.indexOfKey(t.userId) < 0) { mTmpLockedUsers.put(t.userId, mKeyguardManager.isDeviceLocked(t.userId)); } boolean isLocked = mTmpLockedUsers.get(t.userId); // Add the task to the stack Task task = new Task(taskKey, icon, thumbnail, title, titleDescription, activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp, t.supportsSplitScreenMultiWindow, t.taskDescription, t.resizeMode, t.topActivity, isLocked); allTasks.add(task); } // Initialize the stacks mStack = new TaskStack(); //这里是预先将任务队列加载显式到TaskStackView上 mStack.setTasks(allTasks, false /* notifyStackChanges */);}复制代码

注意:保存任务队列的都是一些临时变量,会伴随着gc回收掉。

参考:

转载地址:http://ovrel.baihongyu.com/

你可能感兴趣的文章
inode 索引节点和软硬链接
查看>>
文本处理工具基础(grep系、sed、awk等)
查看>>
Android常用URI收藏
查看>>
团队用过最好的bug管理软件-delbug管理
查看>>
Swift和OC的区别
查看>>
Java下一个简单的数据库分库帮助类
查看>>
Thread初探
查看>>
磁盘的读写原理
查看>>
配置防盗链、访问控制Directory针对目录、访问控制FilesMatch针对链接
查看>>
Tomcat 仅用ip和端口 不用项目名就能访问项目
查看>>
LNMP平台部署及应用
查看>>
appium python 实例链接
查看>>
redis 关于string数据类型的学习
查看>>
上一个项目的开发中需要实现从word中读取表格数据的功能,在JAVA社区搜索了很多资料,终于找到了两...
查看>>
IP SLA冗余切换
查看>>
关于安全运维中,网络及安全设备基线设置的方法和必要性。
查看>>
nodejs渐入佳境[24]-用户权限-express+mongoDB+authtoken
查看>>
关于GITLAB若干权限问题
查看>>
强大的PDF创建和管理控件ActivePDF Toolkit
查看>>
linux下DNS的配置
查看>>