桥下红药

以无心之心读书

Android8.0 Launcher2 笔记

总分类 评论已关闭

目录:packages/apps/Launcher2

涉及系统服务类(AIDL与系统通信传递数据): LauncherApps、ILauncherApps <-> LauncherAppsService

LauncherAppsService 主要往系统服务里面注册个 IBinder

class LauncherAppsService{
    publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl);
}

IBinder 实现类是 LauncherAppsService.LauncherAppsImpl

1. LauncherApplication 是 Launcher App的入口

//一个很重要的类 private LauncherModel mModel; public void onCreate() { super.onCreate(); //.....根据屏幕的尺寸和密度来控制图标大小 recreateWidgetPreviewDb(); mIconCache = new IconCache(this); //主要操作都在该类 mModel = new LauncherModel(this, mIconCache); LauncherApps launcherApps = (LauncherApps) getSystemService(Context.LAUNCHER_APPS_SERVICE); launcherApps.registerCallback(mModel.getLauncherAppsCallback()); //...注册一大堆广播,接收状态改变 }

LauncherModel 里面除了监听系统回调外,还有桌面图标的数据库操作。

//方法粗略
static void moveItemInDatabase();
static void addItemToDatabase();
static void deleteItemFromDatabase();
static void checkItemInfoLocked();
static void updateItemInDatabase();
static void modifyItemInDatabase();

//清除掉工作线程
public void flushWorkerThread()

//内部类
private class LauncherAppsCallback extends LauncherApps.Callback{}

这里需要关心下 LauncherApps.Callback 有哪些回调?

abstract public void onPackageRemoved(String packageName, UserHandle user);

abstract public void onPackageAdded(String packageName, UserHandle user);

abstract public void onPackageChanged(String packageName, UserHandle user);

abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
                boolean replacing);

abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
                boolean replacing);

public void onPackagesSuspended(String[] packageNames, UserHandle user);

public void onPackagesUnsuspended(String[] packageNames, UserHandle user);

public void onShortcutsChanged(@NonNull String packageName,
                @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user);

2. 主界面 Launcher

桌面App实际就是展示手机已安装App列表、小组件、目录这些。操作一般是拖拽、合并目录、删除等。最后点击 列表item 启动目标App。

Launcher.java的onCreate函数中调用了mModel.startLoader函数 , startLoader函数会post一个Runnable消息 , run方法中会调用 loadAndBindAllApps -> loadAllAppsByBatch -> LauncherApps.getActivityList

重点关注下 getActivityList 获取App列表

    public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
        logErrorForInvalidProfileAccess(user);
        try {
            return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
                    packageName, user), user);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

mService.getLauncherActivities(mContext.getPackageName(),packageName, user) 这段就是获取结果了,mService 是 ILauncherApps 接口,它的实现文章一开始就说了是 LauncherAppsService.LauncherAppsImpl

在获取完App列表之后,就会回调 LauncherModel.Callbacks 相关接口(bindAllApplications)回调结果。

  public interface Callbacks {
        public boolean setLoadOnResume();

        public int getCurrentWorkspaceScreen();

        public void startBinding();

        public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end);

        public void bindFolders(HashMap<Long, FolderInfo> folders);

        public void finishBindingItems();

        public void bindAppWidget(LauncherAppWidgetInfo info);

        public void bindAllApplications(ArrayList<ApplicationInfo> apps);

        public void bindAppsAdded(ArrayList<ApplicationInfo> apps);

        public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);

        public void bindComponentsRemoved(ArrayList<String> packageNames,
                                          ArrayList<ApplicationInfo> appInfos,
                                          boolean matchPackageNamesOnly, UserHandle user);

        public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);

        public boolean isAllAppsVisible();

        public boolean isAllAppsButtonRank(int rank);

        public void bindSearchablesChanged();

        public void onPageBoundSynchronously(int page);
    }

Launcher Activity 通过接口回调 bindAllApplications 获取到数据了,展示控件就不说了大约操作就是判断是 小组件还是 App 还有App是否隐藏状态等等。

3.列表App点击事件

点击事件是在 Launcher completeAddShortcut函数绑定的,实现接口就是 Launcher 。

1.Launcher的onClick函数


public void onClick(View v) { //省略部分代码 Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { // Open shortcut final Intent intent = ((ShortcutInfo) tag).intent; int[] pos = new int[2]; v.getLocationOnScreen(pos); intent.setSourceBounds(new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight())); //调用startActivitySafely启动App的MainActivity boolean success = startActivitySafely(v, intent, tag); //...... } else if (tag instanceof FolderInfo) { //..... } else if (v == mAllAppsButton) { //..... } }

而点击应用图标,最终会调用Launcher.java的startActivitySafely来启动应用。

后面的流程就是 startActivitySafely -> startActivity -> LauncherApps 对象的 startMainActivity方法

上一篇

评论已关闭。