Android 9.0 Launcher Workspace 加载_第1张图片
 加载Workspace入口在/packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java,想了解Launcher app的启动流程,可以先看看这篇文章,https://www.jianshu.com/p/0b273112cd7e

1、Workspace加载调用过程,如图

Android 9.0 Launcher Workspace 加载_第2张图片
代码入口:
/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(),

Android 9.0 Launcher Workspace 加载_第3张图片
/**
* 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 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 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 screenIds = new ArrayList();            // 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 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 screenIds)            throws XmlPullParserException, IOException {        XmlResourceParser parser = mSourceRes.getXml(layoutId);        beginDocument(parser, mRootTag);        final int depth = parser.getDepth();        int type;        ArrayMap 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 tagParserMap,        ArrayList 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;    }

如图:
Android 9.0 Launcher Workspace 加载_第4张图片

总结:

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文件。

更多相关文章

  1. arcgis for Android 100.2 加载shp
  2. android沉浸式状态栏底部背景用图片代替
  3. Android Studio中的build.gradle文件解析
  4. 浅入浅出Android(015):使用ImageView显示网络图片
  5. Android利用DownloadManager实现文件下载
  6. Android应用开发提高系列(5)――Android动态加载(下)――加载已安装A
  7. Android7.0文件读写(获取拍照结果)笔记
  8. 2010-02-27 传智播客—Android(二)数据存储和访问 之文件

随机推荐

  1. Android常用控件之GridView使用BaseAdapt
  2. 手机APP制作先选Android还是iOS,为什么?
  3. Android 读取系统信息
  4. 为什么Android变得对商业世界至关重要?
  5. Eclipse – 建構 Android 的開發環境
  6. Android意图[结构]和意图过滤器
  7. Android 小项目之--使用【AudioManager】
  8. Android(安卓)MediaPlayer 字幕同步
  9. Android自带示例程序--Snake
  10. Android嵌套滑动和NestedScrollView