Android 9.0 Launcher Workspace加载
加载Workspace入口在/packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java,想了解Launcher app的启动流程,可以先看看这篇文章,https://www.jianshu.com/p/0b273112cd7e
1、Workspace加载调用过程,如图
代码入口:
/packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java,
public void run() { synchronized (this) { // Skip fast if we are already stopped. if (mStopped) { return; } } TraceHelper.beginSection(TAG); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { TraceHelper.partitionSection(TAG, "step 1.1: loading workspace"); loadWorkspace(); ... transaction.commit(); } catch (CancellationException e) { // Loader stopped, ignore TraceHelper.partitionSection(TAG, "Cancelled"); } TraceHelper.endSection(TAG); } } ···
接下来是总体调用过程:
private void loadWorkspace() { ... LauncherSettings.Settings.call(contentResolver, LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES); ... } // If there are any empty screens remove them, and update. if (unusedScreens.size() != 0) { mBgDataModel.workspaceScreens.removeAll(unusedScreens); LauncherModel.updateWorkspaceScreenOrder(context, mBgDataModel.workspaceScreens); } }
/packages/apps/Launcher3/src/com/android/launcher3/LauncherSettings.java
public static final class Settings { ... public static final String METHOD_LOAD_DEFAULT_FAVORITES = "load_default_favorites"; ... public static Bundle call(ContentResolver cr, String method) { return cr.call(CONTENT_URI, method, null, null); } ... }
/packages/apps/Launcher3/src/com/android/launcher3/LauncherProvider.java
@Override public Bundle call(String method, final String arg, final Bundle extras) { Log.e(TAG,"method-- "+method); if (Binder.getCallingUid() != Process.myUid()) { return null; } createDbIfNotExists(); switch (method) { ... case LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES: { loadDefaultFavoritesIfNecessary(); return null; } ... } }
2、具体加载流程,是这个方法 loadDefaultFavoritesIfNecessary(),
/**
* Loads the default workspace based on the following priority scheme: * 1) From the app restrictions * 2) From a package provided by play store * 3) From a partner configuration APK, already in the system image * 4) The default configuration for the particular device */
synchronized private void loadDefaultFavoritesIfNecessary() { SharedPreferences sp = Utilities.getPrefs(getContext()); boolean aBoolean = sp.getBoolean(EMPTY_DATABASE_CREATED, false); if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) { AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost(); AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHost); if (loader == null) { loader = AutoInstallsLayout.get(getContext(),widgetHost, mOpenHelper); } if (loader == null) { final Partner partner = Partner.get(getContext().getPackageManager()); if (partner != null && partner.hasDefaultLayout()) { final Resources partnerRes = partner.getResources(); int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT, "xml", partner.getPackageName()); if (workspaceResId != 0) { loader = new DefaultLayoutParser(getContext(), widgetHost, mOpenHelper, partnerRes, workspaceResId); } } } final boolean usingExternallyProvidedLayout = loader != null; if (loader == null) { loader = getDefaultLayoutParser(widgetHost); } mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase()); if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0) && usingExternallyProvidedLayout) { // Unable to load external layout. Cleanup and load the internal layout. mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase()); mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), getDefaultLayoutParser(widgetHost)); } clearFlagEmptyDbCreated(); } }
1) From the app restrictions
private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(AppWidgetHost widgetHost) { Context ctx = getContext(); UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE); Bundle bundle = um.getApplicationRestrictions(ctx.getPackageName()); if (bundle == null) { return null; } String packageName = bundle.getString(RESTRICTION_PACKAGE_NAME); if (packageName != null) { try { Resources targetResources = ctx.getPackageManager() .getResourcesForApplication(packageName); return AutoInstallsLayout.get(ctx, packageName, targetResources, widgetHost, mOpenHelper); } catch (NameNotFoundException e) { Log.e(TAG, "Target package for restricted profile not found", e); return null; } } return null; }
2) From a package provided by play store
static AutoInstallsLayout get(Context context, AppWidgetHost appWidgetHost, LayoutParserCallback callback) { Pair<String, Resources> customizationApkInfo = Utilities.findSystemApk( ACTION_LAUNCHER_CUSTOMIZATION, context.getPackageManager()); if (customizationApkInfo == null) { return null; } return get(context, customizationApkInfo.first, customizationApkInfo.second, appWidgetHost, callback); } /** Marker action used to discover a package which defines launcher customization */ static final String ACTION_LAUNCHER_CUSTOMIZATION = "android.autoinstalls.config.action.PLAY_AUTO_INSTALL";
3) From a partner configuration APK, already in the system image
... if (loader == null) { final Partner partner = Partner.get(getContext().getPackageManager()); if (partner != null && partner.hasDefaultLayout()) { final Resources partnerRes = partner.getResources(); int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT, "xml", partner.getPackageName()); if (workspaceResId != 0) { loader = new DefaultLayoutParser(getContext(), widgetHost, mOpenHelper, partnerRes, workspaceResId); } } } public static synchronized Partner get(PackageManager pm) { if (!sSearched) { Pair<String, Resources> apkInfo = Utilities.findSystemApk(ACTION_PARTNER_CUSTOMIZATION, pm); if (apkInfo != null) { sPartner = new Partner(apkInfo.first, apkInfo.second); } sSearched = true; } return sPartner; } ... /** Marker action used to discover partner */ private static final String ACTION_PARTNER_CUSTOMIZATION = "com.android.launcher3.action.PARTNER_CUSTOMIZATION";
#####4) The default configuration for the particular device
... if (loader == null) { loader = getDefaultLayoutParser(widgetHost); } ... private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost){ InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext()); int defaultLayout = idp.defaultLayoutId; UserManagerCompat um = UserManagerCompat.getInstance(getContext()); if (um.isDemoUser() && idp.demoModeLayoutId != 0) { defaultLayout = idp.demoModeLayoutId; } return new DefaultLayoutParser(getContext(), widgetHost, mOpenHelper, getContext().getResources(), defaultLayout); } public class DefaultLayoutParser extends AutoInstallsLayout { private static final String TAG = "DefaultLayoutParser"; ... public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost, LayoutParserCallback callback, Resources sourceRes, int layoutId) { super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES); } ... }
第一次加载,执行最后一个 loader = getDefaultLayoutParser(widgetHost)。 接下来,便是加载布局文件,解析数据,该文件在/packages/apps/Launcher3/res/xml目录下。具体是解析defaultLayout,对应default_workspace_3x3,default_workspace_4x4,default_workspace_5x6等的某一个文件,这个文件是从在InvariantDeviceProfile中获取的。
3、加载,解析代码
packages/apps/Launcher3/src/com/android/launcher3/LauncherProvider.java:
... mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) ... @Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) { ArrayList<Long> screenIds = new ArrayList<Long>(); // TODO: Use multiple loaders with fall-back and transaction. int count = loader.loadLayout(db, screenIds); Log.e(TAG, "loadFavorites count : "+count); // Add the screens specified by the items above Collections.sort(screenIds); int rank = 0; ContentValues values = new ContentValues(); for (Long id : screenIds) { values.clear(); values.put(LauncherSettings.WorkspaceScreens._ID, id); values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank); if (dbInsertAndCheck(this, db, WorkspaceScreens.TABLE_NAME, null, values) < 0) { throw new RuntimeException("Failed initialize screen table" + "from default layout"); } Log.e(TAG,"loadFavorites id: "+id+",Screenrank: "+rank); rank++; } // Ensure that the max ids are initialized mMaxItemId = initializeMaxItemId(db); mMaxScreenId = initializeMaxScreenId(db); Log.e(TAG,"loadFavorites favorite mMaxItemId: "+mMaxItemId+",workSpaceScreen mMaxScreenId: "+mMaxScreenId); return count; } }
/packages/apps/Launcher3/src/com/android/launcher3/AutoInstallsLayout.java
public int loadLayout(SQLiteDatabase db, ArrayList<Long> screenIds) { mDb = db; try { return parseLayout(mLayoutId, screenIds); } catch (Exception e) { Log.e(TAG, "Error parsing layout: " + e); return -1; } } protected int parseLayout(int layoutId, ArrayList<Long> screenIds) throws XmlPullParserException, IOException { XmlResourceParser parser = mSourceRes.getXml(layoutId); beginDocument(parser, mRootTag); final int depth = parser.getDepth(); int type; ArrayMap<String, TagParser> tagParserMap = getLayoutElementsMap(); int count = 0; while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { if (type != XmlPullParser.START_TAG) { continue; } Log.e(TAG,"parseLayout layoutId-- "+layoutId+",screenIds-- "+screenIds+",count-- "+count); count += parseAndAddNode(parser, tagParserMap, screenIds); } return count; } protected int parseAndAddNode( XmlResourceParser parser, ArrayMap<String, TagParser> tagParserMap, ArrayList<Long> screenIds) throws XmlPullParserException, IOException { if (TAG_INCLUDE.equals(parser.getName())) { final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0); if (resId != 0) { // recursively load some more favorites, why not? return parseLayout(resId, screenIds); } else { return 0; } } mValues.clear(); parseContainerAndScreen(parser, mTemp); final long container = mTemp[0]; final long screenId = mTemp[1]; mValues.put(Favorites.CONTAINER, container); mValues.put(Favorites.SCREEN, screenId); mValues.put(Favorites.CELLX, convertToDistanceFromEnd(getAttributeValue(parser, ATTR_X), mColumnCount)); mValues.put(Favorites.CELLY, convertToDistanceFromEnd(getAttributeValue(parser, ATTR_Y), mRowCount)); TagParser tagParser = tagParserMap.get(parser.getName()); if (tagParser == null) { if (LOGD) Log.d(TAG, "Ignoring unknown element tag: " + parser.getName()); return 0; } long newElementId = tagParser.parseAndAdd(parser); if (newElementId >= 0) { // Keep track of the set of screens which need to be added to the db. if (!screenIds.contains(screenId) && container == Favorites.CONTAINER_DESKTOP) { screenIds.add(screenId); } return 1; } return 0; }
如图:
总结:
1、 第一次启动Launcher,加载器是由getDefaultLayoutParser生成。如果看执行效果,可以删除launcher.db ,重启ActivityManager。
rm /data/data/com.android.launcher3/databases/launcher.db
  adb shell am restart
2、 非初次启动,EMPTY_DATABASE_CREATED=false, 不会初始化loader。
3、定制化需求,可以考虑添加对应的default_workspace.xml文件。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
关于《自动化测试实战宝典:Robot Framework + Python从小工到专家》
受新冠疫情影响,笔者被“困”在湖北老家七十余天,于4月1号(愚人节)这天,终于返回到广州。当前国内疫情基本已趋于平稳,但全球疫情整体势态仍在持续疯涨,累计确诊病例已近80万人。祈祷这场全球性灾难能尽早得到控制,让大家的生活早日恢复正常。同时呼吁,全体读者,在当前的疫情势态下,大家仍然不能放松警惕,时刻做好个人防护工作。 对于忠者的读者,相信都已经知道了,笔者的新书《自动化测试实战宝典:Robot Framework + Python从小工到专家》在3月份上市了。 承蒙各位读者和行业同仁的喜爱,新书上市不久,打破了多项记录,上市两周,持续占据京东新书畅销榜前三名、新书好评度100%,并且上市不到两周时间出版社就已经开始加印数量(二印) 从新书3月10号,官宣上市起:重磅消息 |《自动化测试实战宝典:从小工到专家》隆重上市!,期间陆续收到了大量读者来信,一方面是对本书内容价值的肯定,另一方面赞许从书中知识的学习受益匪浅,收获颇丰。作为本书的作者,看到辛苦13个月的创作成果,能帮助普惠到行业同仁,甚感欣慰。 当然,新书除了收到业界同行大量好评外,也有一些少量来自同行或者读者购书前所存在的疑惑...
- 下一篇
C# 基础知识系列-7 Linq详解
C# 基础知识系列-7 Linq详解 前言在上一篇中简单介绍了Linq的入门级用法,这一篇尝试讲解一些更加深入的使用方法,与前一篇的结构不一样的地方是,这一篇我会先介绍Linq里的支持方法,然后以实际需求为引导,分别以方法链的形式和类SQL的形式写出来。 前置概念介绍Predicate谓词、断言,等价于Func即返回bool的表达式Expression表达式树,这个类很关键,但是在这里会细说,我们会讲它的一个特殊的泛型类型:Expression>这个在某些数据源的查询中十分重要,它代表lambda表达式中一种特殊的表达式,即没有大括号和return关键字的那种。我们先准备两个类: Student/学生类:/// /// 学生/// public class Student{ /// <summary> /// 学号 /// </summary> public int StudentId { get; set; } /// <summary> /// 姓名 /// </summary> public string Name { get...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2整合Redis,开启缓存,提高访问速度
- MySQL8.0.19开启GTID主从同步CentOS8
- Hadoop3单机部署,实现最简伪集群
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16