我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android 9.0 Launcher Workspace 加载

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android 9.0 Launcher Workspace 加载

在这里插入图片描述
 加载Workspace入口在/packages/apps/Launcher3/class="lazy" data-src/com/android/launcher3/model/LoaderTask.java,想了解Launcher app的启动流程,可以先看看这篇文章,https://www.jianshu.com/p/0b273112cd7e

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

progrss.png
代码入口:
/packages/apps/Launcher3/class="lazy" data-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/class="lazy" data-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/class="lazy" data-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(),

在这里插入图片描述


 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);
    }
    
    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;
    }
	...
	  
    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/class="lazy" data-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/class="lazy" data-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;
    }

如图:
在这里插入图片描述

总结:

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


作者:Albert0211


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android 9.0 Launcher Workspace 加载

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android 9.0 Launcher Workspace 加载

加载Workspace入口在/packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java,想了解Launcher app的启动流程,可以先看看这篇文章,ht
2022-06-06

Android 9.0 Vold 挂载流程分析

在Android 系统中所有的热插拔设备都是通过Vold 进程挂载的。通过kernel–>vold–>StorageManagerService这样的架构去逐级上报热插拔事件。 一、Vold 入口 --> /system/vold/main
2022-06-06

Android车载Launcher开发(1) - 显示Widget

1.Launcher简介 Launcher是安卓系统中的桌面启动器,安卓系统的桌面UI统称为Launcher。Launcher是安卓系统中的主要程序组件之一,安卓系统中如果没有Launcher就无法启动安卓桌面。作为车机开机后用户接触到的第
2023-08-20

Android实现向Launcher添加快捷方式的方法

本文实例讲述了Android实现向Launcher添加快捷方式的方法。分享给大家供大家参考。具体如下: 当我们在应用程序Launcher的桌面空白处长按触摸时,会出现一个对话框,提示选择要添加的桌面组件,如下图所示选择快捷方式后,会弹出一个
2022-06-06

Android数据转移中怎么用Launcher导出数据库给另一台机器加载

本篇内容主要讲解“Android数据转移中怎么用Launcher导出数据库给另一台机器加载”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android数据转移中怎么用Launcher导出数据库给
2023-06-25

Android Glide图片加载(加载监听、加载动画)

本文实例为大家分享了Android Glide图片加载的具体代码,供大家参考,具体内容如下 1.普通用法Glide.with(context) .load(url) .into(view); with中可以放context、activity
2022-06-06

Android的Launcher启动器中添加快捷方式及小部件实例

前言: 最近一直在看Launcher模块,经过差不多两个月学习,终于摸透了Launcher的一些主要功能实现,目前继续还处于 摸索状态。未看Launcher时,于我而言,只能膜拜,以为所有功能都是它实现的 ;入门后,才发现,Launcher
2022-06-06

Android动态加载布局

ListView我们一直都在用,只不过当Adapter中的内容比较多的时候我们有时候没办法去设置一些组件,举个例子:可以看到京东的故事里面的这样一个布局,这个布局可以说是我目前见到的内容比较多的了,它的每一项都包含头像、姓名、分类、内容、图
2022-06-06

Unity3d Android无法加载a

前几天做了AssentBundle的例子,遇到了问题,在论坛上问了三天都没人解答,最后在一个朋友的帮助下解决了。下面介绍AssentBundle。AssetBundles让你通过WWW类流式加载额外的资源并在运行时实例化它们。AssetBu
2023-01-31

android WebView加载html5介绍

Android设备多分辨率的问题 Android浏览器默认预览模式浏览 会缩小页面 WebView中则会以原始大小显示 Android浏览器和WebView默认为mdpi。hdpi相当于mdpi的1.5倍 ldpi相当于0.75倍 三种解决
2022-06-06

Android如何实现加载圈

这篇文章主要介绍“Android如何实现加载圈”,在日常操作中,相信很多人在Android如何实现加载圈问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android如何实现加载圈”的疑惑有所帮助!接下来,请跟
2023-07-02

Android ViewPager动态加载问题

今天做项目时,纠结了很久,动态添加view,刚开始按照其他的adapter处理,但是不会刷新view,来回翻几页,还会view覆盖,最后手动调用adapter的destroyItem和instantiateItem方法,还是不行,最后重写n
2022-06-06

Android 中怎么加载GIF图

这篇文章给大家介绍Android 中怎么加载GIF图,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。具体的实现代码如下: Glide.with( this ).asGif().load( R.drawable.yiba_
2023-05-30

Android ViewPager加载图片效果

目前项目中需要用到ViewPager加载图片,现在在此记录一下。 首先先看布局文件:activity_main.xml
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录