当前位置: 首页 > news >正文

MTKLauncher_布局页面分析

文章目录

  • 前言
    • 遇到的困难点
    • 针对性解决困难
  • 需求
  • 相关资料
  • Launcher3 源码 目录简单介绍
  • Launcher3 简介及页面布局分析
    • UI整体架构
    • 数据加载
    • 布局加载
      • 布局加载核心思想
      • device_profiles.xml 加载
      • InvariantDeviceProfile
        • initGrid(context, gridName)
        • getPredefinedDeviceProfiles
        • invDistWeightedInterpolate
        • initGrid(Context context, Info displayInfo, DisplayOption displayOption,boolean isSplitDisplay)
      • default_workspace_MxN.xml
        • 查找资源文件 default_workspace_MxN.xml 位置
  • MTK Launcher3 源码位置
  • 需求实现


前言

第一次拿着开发板,想研究一下Launcher3源码,第一次接触Launcher3,一步一步看看Launcher3 定制的话有哪些内容需要掌握的。

遇到的困难点

  • 拿到源码从何看起,从何研究起。
  • 源码无论在线的谷歌源码还是各大半导体厂商提供的Launcher3源码,存在一定的差别。
    需要针对性看,特别是针对自己的开发板上面看尤其重要,不然对不上。
  • 部分代码看不明白,布局和UI如何对上的。
  • 源码到底在哪里,配置文件、布局文件到底是哪一个,对不上,琢磨实验好久。

针对性解决困难

  • 多从广义角度、全局角度来看Launcher3,不要一下子钻进了牛角尖 出不来,毫无收获
  • 多看一看网上在线的第三方博客、别人的总结、比人的分析,从中自己体会,理解
  • 多打印日志,调试;在源码里面搜索关键字、关键文件路径
  • 不管你是开发板或者公司产品,务必先针对一款源码熟悉、了解、分析,尽量不要好多平台源码一起看,源码部分架构不一样的,代码也不一样的。
  • 多啃、多吃啃源码还是有必要的

需求

remind:初识Launcher首页布局是怎么加载的

首页页面是如何加载的,如何配置,如下图界面我想更改一下每个图标的位置,我想自定义这个界面如何实现?

在这里插入图片描述

比如如下看网上别人定制的桌面,蛮好看的,如下图:
在这里插入图片描述

相关资料

Launcher3 相关资料参考
菜鸟成长之路-源码分析专栏
Android Launcher3 简介
Launcher3 高端定制
Launcher3 开发
Launcher3 Android Code Search在线源码查看
Launcher3 xref 在线源码查看
Launcher3 RK 源码查看
Launcher3 解析
Launcher3 AndroidP AS版本
谷歌Launcher3 Android13源码修改
Launcher3 和 Launcher3QuickStep 区别
Android14 不分Launcher3修改
Launcher3 LoaderTask 的数据加载
Android14 浅析Launcher
Android O Launcher3-Workspace加载

Launcher3 源码 目录简单介绍

当拿到Launcher3 源码时候,对源码还是一脸懵逼, 用了这么久的手机,源码不熟悉 也正常,先有个大概了解

allapps 目录:主要存放主菜单界面相关代码。
anim目录:存放动画相关代码,主要是动画基类代码。
compat目录:主要存放解决兼容性相关的代码。
config目录:主要配置Launcher相关功能的宏开关,目前Launcher原生新增的功能宏开关都在这个目录。
dragndrop目录:主要存放拖拽相关操作的代码
graphics目录:主要存放处理图标大小、颜色、自适应等相关的代码
model目录:存放Launcher加载流程相关模块化的代码
notification目录:存放通知相关的代码
pageindicators目录:存放桌面页面指示器相关的代码
popu目录:存放长按图标显示弹出框相关的代码
provider目录:存放Launcher数据库相关的代码
qsb目录:存放搜索功能相关的代码
shortcuts目录:存放桌面所属应用某些功能的快捷图标相关的代码。

Launcher3 简介及页面布局分析

回归到需求,我们需要了解的是布局相关,那还是从整体架构来看看 Launcher3

UI整体架构

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

UI 架构是我们比较熟悉的内容,用了这么多年的手机,手机桌面部分不就是这些内容的嘛,从研发的角度讲我们可以和对应的名称 关联起来。

数据加载

数据加载是Launcher3中一个比较核心的内容,后续需要深入了解,下面给一下加载流程图,后续再继续分析,在看源码过程中提供一个源码查看方向,针对本文就此打住,需要了解 非深入研究部分
在这里插入图片描述

布局加载

本身我们通过Launcher3 找到主Activity,主Activity里面再找对应的layout 布局,launcher.xml,这些和上面的UI架构对应 对应的是模块,非本文核心问题。我们的核心问题是找桌面的那些Icon 文件夹 快捷 搜索栏 UI和布局及数据如何展现的,这些其实是配置或者在源码里面硬编码更改。

布局加载核心思想

我自己开发过程中,看 device_profiles.xml 时候,一脸懵,不清楚每个字段 比如 grid-option 、display-option、numRows、numColumns、numFolderRows、numFolderColumns、numHotseatIcons、minWidthDps、minHeightDps、iconImageSize、iconTextSize… 到底啥玩意 这么多配置,后来想一想见名知意。 就是显示的属性和配置呀,都是见名知意。

launcher:defaultLayoutId="@xml/default_workspace_5x5"
launcher:defaultLayoutId="@xml/default_workspace_4x4" 
launcher:defaultLayoutId="@xml/default_workspace_3x3"

布局里面好多 grid-option 、display-option,到底用哪一个对应的 default_workspace_MxN

核心思想:

  • 动态选择,更具屏幕大小分辨率动态适配加载选择
  • 更具横竖屏动态选择

device_profiles.xml 加载

我们先给一个简单的流程图
在这里插入图片描述

device_profiles.xml 文件用于定义不同设备配置的布局,该文件是启动器根据设备的特性(如屏幕尺寸、分辨率、密度等)来适配布局和图标大小等元素的重要配置文件。

该文件的主要功能有定义网格布局、设置图标大小、配置热区、定义所有应用列表的布局、屏幕和设备类型特定配置、壁纸和背景设置、提供默认布局等。


<profiles xmlns:launcher="http://schemas.android.com/apk/res-auto" ><grid-optionlauncher:name="3_by_3"launcher:numRows="3"launcher:numColumns="3"launcher:numFolderRows="2"launcher:numFolderColumns="3"launcher:numHotseatIcons="3"launcher:dbFile="launcher_3_by_3.db"launcher:defaultLayoutId="@xml/default_workspace_3x3" ><display-optionlauncher:name="Super Short Stubby"launcher:minWidthDps="255"launcher:minHeightDps="300"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Shorter Stubby"launcher:minWidthDps="255"launcher:minHeightDps="400"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /></grid-option><grid-optionlauncher:name="4_by_4"launcher:numRows="4"launcher:numColumns="4"launcher:numFolderRows="3"launcher:numFolderColumns="4"launcher:numHotseatIcons="4"launcher:dbFile="launcher_4_by_4.db"launcher:defaultLayoutId="@xml/default_workspace_4x4" ><display-optionlauncher:name="Short Stubby"launcher:minWidthDps="275"launcher:minHeightDps="420"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Stubby"launcher:minWidthDps="255"launcher:minHeightDps="450"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Nexus S"launcher:minWidthDps="296"launcher:minHeightDps="491.33"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Nexus 4"launcher:minWidthDps="359"launcher:minHeightDps="567"launcher:iconImageSize="54"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /><display-optionlauncher:name="Nexus 5"launcher:minWidthDps="335"launcher:minHeightDps="567"launcher:iconImageSize="54"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /></grid-option><grid-optionlauncher:name="5_by_5"launcher:numRows="5"launcher:numColumns="5"launcher:numFolderRows="4"launcher:numFolderColumns="4"launcher:numHotseatIcons="5"launcher:dbFile="launcher.db"launcher:defaultLayoutId="@xml/default_workspace_5x5" ><display-optionlauncher:name="Large Phone"launcher:minWidthDps="406"launcher:minHeightDps="694"launcher:iconImageSize="56"launcher:iconTextSize="14.4"launcher:canBeDefault="true" /><display-optionlauncher:name="Large Phone Split Display"launcher:minWidthDps="406"launcher:minHeightDps="694"launcher:iconImageSize="56"launcher:iconTextSize="14.4"launcher:canBeDefault="split_display" /><display-optionlauncher:name="Shorter Stubby"launcher:minWidthDps="255"launcher:minHeightDps="400"launcher:iconImageSize="48"launcher:iconTextSize="13.0"launcher:canBeDefault="true" /></grid-option>

InvariantDeviceProfile

初始化地方

 Launcher.javaInvariantDeviceProfile idp = app.getInvariantDeviceProfile();LauncherAppState.javapublic InvariantDeviceProfile getInvariantDeviceProfile() {return mInvariantDeviceProfile;}LauncherAppState 构造方法mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);InvariantDeviceProfile.java    构造方法@TargetApi(23)private InvariantDeviceProfile(Context context) {String gridName = getCurrentGridName(context);String newGridName = initGrid(context, gridName);
....}
initGrid(context, gridName)

大家这么想,为啥是Grid? init Grid 是做什么的。 其实桌面中WorkSpack 中的CellLayout, 不就是由网格组成的嘛, 然后给对应的坐标,告诉放到哪一个位置不就可以了嘛。 所以这个名字 Grid 是很有意义的。

   //初始化网格private String initGrid(Context context, String gridName) {......// getPredefinedDeviceProfiles  获取预定义的文件配置列表ArrayList<DisplayOption> allOptions =getPredefinedDeviceProfiles(context, gridName, isSplitDisplay);DisplayOption displayOption =invDistWeightedInterpolate(displayInfo, allOptions, isSplitDisplay);Log.d(TAG," initGrid  gridName:"+displayOption.grid.name);		initGrid(context, displayInfo, displayOption, isSplitDisplay);return displayOption.grid.name;}
getPredefinedDeviceProfiles

getPredefinedDeviceProfiles 获取预定义的文件配置列表

  private static ArrayList<DisplayOption> getPredefinedDeviceProfiles(Context context, String gridName, boolean isSplitDisplay) {ArrayList<DisplayOption> profiles = new ArrayList<>();Log.d(TAG,"getPredefinedDeviceProfiles   huoqu yudingyi device list gridName:"+gridName);try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {final int depth = parser.getDepth();int type;while (((type = parser.next()) != XmlPullParser.END_TAG ||parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {Log.d(TAG,"getPredefinedDeviceProfiles   GridOption.TAG_NAME:"+GridOption.TAG_NAME+"   parser.getName:"+parser.getName());if ((type == XmlPullParser.START_TAG)&& GridOption.TAG_NAME.equals(parser.getName())) {GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser));final int displayDepth = parser.getDepth();while (((type = parser.next()) != XmlPullParser.END_TAG ||parser.getDepth() > displayDepth)&& type != XmlPullParser.END_DOCUMENT) {if ((type == XmlPullParser.START_TAG) && "display-option".equals(parser.getName())) {Log.d(TAG,"getPredefinedDeviceProfiles  display-option  parser.getName:"+parser.getName());profiles.add(new DisplayOption(gridOption, context,Xml.asAttributeSet(parser),isSplitDisplay ? DEFAULT_SPLIT_DISPLAY : DEFAULT_TRUE));}}}}} catch (IOException|XmlPullParserException e) {throw new RuntimeException(e);}ArrayList<DisplayOption> filteredProfiles = new ArrayList<>();if (!TextUtils.isEmpty(gridName)) {for (DisplayOption option : profiles) {if (gridName.equals(option.grid.name)) {filteredProfiles.add(option);}}}Log.d(TAG,"getPredefinedDeviceProfiles  000 profiles:"+profiles.size()+"   filteredProfiles:"+filteredProfiles.size() );if (filteredProfiles.isEmpty()) {// No grid found, use the default optionsfor (DisplayOption option : profiles) {if (option.canBeDefault) {filteredProfiles.add(option);}}}Log.d(TAG,"getPredefinedDeviceProfiles 111 profiles:"+profiles.size()+"   filteredProfiles:"+filteredProfiles.size() );if (filteredProfiles.isEmpty()) {throw new RuntimeException("No display option with canBeDefault=true");}return filteredProfiles;}

这个方法比较核心,关注三点:

  • 加载R.xml.device_profiles 文件,并解析
  • DisplayOption类和device_profiles 里面的display-option
    属性,不就对上了嘛,得到一个displayOption 配置列表
  • 解析device_profiles,将grid-option 节点想的一级属性信息,封装在了DisplayOption,这样实现了
    通过displayOption 能够获取 配置文件中上一层的grid 信息。 比如获取gridname,
    也就是接下来要讲的MxN.xml

在这里插入图片描述

invDistWeightedInterpolate

接着上面的 getPredefinedDeviceProfiles 方法讲,这个方法返回的是List 集合

ArrayList<DisplayOption> getPredefinedDeviceProfiles

那么为什么会返回一个集合? 我们通过 上面分析 device_profiles.xml 配置文件中,grid-option 节点下对应的是多个display-option的。 比如如下日志,可以说明问题:
在这里插入图片描述
在这里插入图片描述

返回了DisplayOption 集合后,如何选择其一适合自己的呢? invDistWeightedInterpolate 就派上用场了

private static DisplayOption invDistWeightedInterpolate(Info displayInfo, ArrayList<DisplayOption> points, boolean isSplitDisplay) {int minWidthPx = Integer.MAX_VALUE;int minHeightPx = Integer.MAX_VALUE;for (WindowBounds bounds : displayInfo.supportedBounds) {boolean isTablet = displayInfo.isTablet(bounds);if (isTablet && isSplitDisplay) {// For split displays, take half width per pageminWidthPx = Math.min(minWidthPx, bounds.availableSize.x / 2);minHeightPx = Math.min(minHeightPx, bounds.availableSize.y);} else if (!isTablet && bounds.isLandscape()) {// We will use transposed layout in this caseminWidthPx = Math.min(minWidthPx, bounds.availableSize.y);minHeightPx = Math.min(minHeightPx, bounds.availableSize.x);} else {minWidthPx = Math.min(minWidthPx, bounds.availableSize.x);minHeightPx = Math.min(minHeightPx, bounds.availableSize.y);}}float width = dpiFromPx(minWidthPx, displayInfo.densityDpi);float height = dpiFromPx(minHeightPx, displayInfo.densityDpi);// Sort the profiles based on the closeness to the device sizeCollections.sort(points, (a, b) ->Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps),dist(width, height, b.minWidthDps, b.minHeightDps)));GridOption closestOption = points.get(0).grid;float weights = 0;DisplayOption p = points.get(0);if (dist(width, height, p.minWidthDps, p.minHeightDps) == 0) {return p;}DisplayOption out = new DisplayOption(closestOption);for (int i = 0; i < points.size() && i < KNEARESTNEIGHBOR; ++i) {p = points.get(i);float w = weight(width, height, p.minWidthDps, p.minHeightDps, WEIGHT_POWER);weights += w;out.add(new DisplayOption().add(p).multiply(w));}return out.multiply(1.0f / weights);}

如则经过一系列的计算,来得到与当前屏幕可用宽高最为合适的各参数大小。具体算法这边就不细究了。

initGrid(Context context, Info displayInfo, DisplayOption displayOption,boolean isSplitDisplay)

得到了gridName,DisplayOption 不就可以获取得到 快捷方式、文件夹、图标等一些列的参数了嘛,且看 源码。

 private void initGrid(Context context, Info displayInfo, DisplayOption displayOption,boolean isSplitDisplay) {Log.d(TAG,"initGrid...");		DisplayMetrics metrics = context.getResources().getDisplayMetrics();GridOption closestProfile = displayOption.grid;numRows = closestProfile.numRows;numColumns = closestProfile.numColumns;dbFile = closestProfile.dbFile;defaultLayoutId = closestProfile.defaultLayoutId;demoModeLayoutId = closestProfile.demoModeLayoutId;numFolderRows = closestProfile.numFolderRows;numFolderColumns = closestProfile.numFolderColumns;isScalable = closestProfile.isScalable;devicePaddingId = closestProfile.devicePaddingId;mExtraAttrs = closestProfile.extraAttrs;iconSize = displayOption.iconSize;landscapeIconSize = displayOption.landscapeIconSize;iconBitmapSize = ResourceUtils.pxFromDp(iconSize, metrics);iconTextSize = displayOption.iconTextSize;landscapeIconTextSize = displayOption.landscapeIconTextSize;fillResIconDpi = getLauncherIconDensity(iconBitmapSize);minCellHeight = displayOption.minCellHeight;minCellWidth = displayOption.minCellWidth;borderSpacing = displayOption.borderSpacing;Log.d(TAG,"initGrid displayOption   iconSize:"+iconSize+"  landscapeIconSize:"+landscapeIconSize+"  iconTextSize:"+iconTextSize+"  landscapeIconTextSize:"+landscapeIconTextSize);Log.d(TAG,"initGrid displayOption   minCellHeight:"+minCellHeight+"  minCellWidth:"+minCellWidth+"   borderSpacing:"+borderSpacing+"   ");numShownHotseatIcons = closestProfile.numHotseatIcons;numDatabaseHotseatIcons = isSplitDisplay? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons;numAllAppsColumns = closestProfile.numAllAppsColumns;numDatabaseAllAppsColumns = isSplitDisplay? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns;Log.d(TAG,"initGrid closestProfile  numRows:"+numRows+"  numColumns:"+numColumns+"   dbFile:"+dbFile+"   defaultLayoutId:"+defaultLayoutId+"   demoModeLayoutId:"+demoModeLayoutId);Log.d(TAG,"initGrid closestProfile  numFolderRows:"+numFolderRows+"   numFolderColumns:"+numFolderColumns+"   isScalable:"+isScalable+"  devicePaddingId:"+devicePaddingId);Log.d(TAG,"initGrid closestProfile  numShownHotseatIcons:"+numShownHotseatIcons+"   numDatabaseHotseatIcons:"+numDatabaseHotseatIcons);if (Utilities.isGridOptionsEnabled(context)) {allAppsIconSize = displayOption.allAppsIconSize;allAppsIconTextSize = displayOption.allAppsIconTextSize;} else {allAppsIconSize = iconSize;allAppsIconTextSize = iconTextSize;}if (devicePaddingId != 0) {devicePaddings = new DevicePaddings(context, devicePaddingId);}// If the partner customization apk contains any grid overrides, apply them// Supported overrides: numRows, numColumns, iconSizeapplyPartnerDeviceProfileOverrides(context, metrics);final List<DeviceProfile> localSupportedProfiles = new ArrayList<>();defaultWallpaperSize = new Point(displayInfo.currentSize);for (WindowBounds bounds : displayInfo.supportedBounds) {localSupportedProfiles.add(new DeviceProfile.Builder(context, this, displayInfo).setUseTwoPanels(isSplitDisplay).setWindowBounds(bounds).build());// Wallpaper size should be the maximum of the all possible sizes Launcher expectsint displayWidth = bounds.bounds.width();int displayHeight = bounds.bounds.height();defaultWallpaperSize.y = Math.max(defaultWallpaperSize.y, displayHeight);// We need to ensure that there is enough extra space in the wallpaper// for the intended parallax effectsfloat parallaxFactor =dpiFromPx(Math.min(displayWidth, displayHeight), displayInfo.densityDpi) < 720? 2: wallpaperTravelToScreenWidthRatio(displayWidth, displayHeight);defaultWallpaperSize.x =Math.max(defaultWallpaperSize.x, Math.round(parallaxFactor * displayWidth));}supportedProfiles = Collections.unmodifiableList(localSupportedProfiles);ComponentName cn = new ComponentName(context.getPackageName(), getClass().getName());defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);}

部分日志如下:

initGrid displayOption   iconSize:55.69532  landscapeIconSize:55.69532  iconTextSize:14.34668  landscapeIconTextSize:14.34668
initGrid displayOption   minCellHeight:0.0  minCellWidth:0.0   borderSpacing:0.0   
initGrid closestProfile  numRows:5  numColumns:5   dbFile:launcher.db   defaultLayoutId:2131951619   demoModeLayoutId:2131951619
initGrid closestProfile  numFolderRows:4   numFolderColumns:4   isScalable:false  devicePaddingId:0
initGrid closestProfile  numShownHotseatIcons:5   numDatabaseHotseatIcons:5
InvariantDeviceProfile  gridName:5_by_5  newGridName:5_by_5

default_workspace_MxN.xml

经过上面的分析,其实已经找到了GridName,如当前 调试是5_by_5。获取后保存一份,下次获取。每次也要获取一份新的,在上面分析中 筛选DisPlayOption 里面

String newGridName = initGrid(context, gridName);private String initGrid(Context context, String gridName) {...DisplayOption displayOption =invDistWeightedInterpolate(displayInfo, allOptions, isSplitDisplay);Log.d(TAG," initGrid  gridName:"+displayOption.grid.name);		initGrid(context, displayInfo, displayOption, isSplitDisplay);return displayOption.grid.name;}解析文件要解析道德其实是 launcher:defaultLayoutId="@xml/default_workspace_5x5" 
defaultLayoutId 属性, 在initGrid 中解析到defaultLayoutId ,然后找到对应的布局
<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"><!-- Hotseat (We use the screen as the position of the item in the hotseat) --><!-- Dialer Messaging [All Apps] Contacts Camera --><favorite container="-101" screen="0" x="0" y="0" packageName="com.google.android.dialer" className="com.google.android.dialer.extensions.GoogleDialtactsActivity"/><favorite container="-101" screen="1" x="1" y="0" packageName="com.google.android.apps.messaging" className="com.google.android.apps.messaging.ui.ConversationListActivity"/><favorite container="-101" screen="2" x="2" y="0" packageName="com.google.android.calendar" className="com.android.calendar.event.LaunchInfoActivity"/><favorite container="-101" screen="3" x="3" y="0" packageName="com.google.android.contacts" className="com.android.contacts.activities.PeopleActivity"/><favorite container="-101" screen="4" x="4" y="0" packageName="com.mediatek.camera" className="com.mediatek.camera.CameraLauncher"/><!-- In Launcher3, workspaces extend infinitely to the right, incrementing from zero --><!-- Google folder --><!-- Google, Chrome, Gmail, Maps, YouTube, (Drive), (Music), (Movies), Hangouts, Photos --><folder title="@string/google_folder_title" screen="0" x="0" y="4"><favorite packageName="com.google.android.googlequicksearchbox" className="com.google.android.googlequicksearchbox.SearchActivity"/><favorite packageName="com.android.chrome" className="com.google.android.apps.chrome.Main"/><favorite packageName="com.google.android.gm" className="com.google.android.gm.ConversationListActivityGmail"/><favorite packageName="com.google.android.apps.maps" className="com.google.android.maps.MapsActivity"/><favorite packageName="com.google.android.youtube" className="com.google.android.youtube.app.honeycomb.Shell$HomeActivity"/><favorite packageName="com.google.android.apps.docs" className="com.google.android.apps.docs.app.NewMainProxyActivity"/><favorite packageName="com.google.android.apps.youtube.music" className="com.google.android.apps.youtube.music.activities.MusicActivity"/><favorite packageName="com.google.android.videos" className="com.google.android.videos.GoogleTvEntryPoint"/><favorite packageName="com.google.android.apps.tachyon" className="com.google.android.apps.tachyon.MainActivity"/><favorite packageName="com.google.android.apps.photos" className="com.google.android.apps.photos.home.HomeActivity"/><favorite packageName="com.google.android.apps.adm" className="com.google.android.apps.adm.activities.MainActivity"/></folder><favorite screen="0" x="2" y="4" packageName="com.google.android.apps.googleassistant" className="com.google.android.apps.googleassistant.AssistantActivity"/><favorite screen="0" x="4" y="4" packageName="com.android.vending" className="com.android.vending.AssetBrowserActivity"/>
</favorites>
查找资源文件 default_workspace_MxN.xml 位置

找到 default_workspace_5x5.xml 在哪里呢? 我用的是mtk 平台,搜索文件名如下:
在这里插入图片描述
你会发现好多个呀,下面给出具体位置:

MTK 平台GMS版本
\vendor\google\overlay\gms_overlay\vendor\google\apps\SearchLauncher\res\xml\default_workspace_5x5.xml

MTK Launcher3 源码位置

我在MTK 平台上面测试验证,GMS 版本下:
Launcher3 源码存在两份,分别位于 package/app/和vendor/mediatek/proprietary/packages/apps/下,当前调试源码位置:

packages\apps\Launcher3

需求实现

上面我们已经找到了 default_workspace_5x5.xml ,首页的配置就在上面 ,我们更改配置即可,具体更改 每个 字段含有,见名知意的。 可以自己实验。
比如,我自己更改如下,实际效果如下

  <favorite screen="0" x="2" y="4" packageName="com.google.android.apps.googleassistant" className="com.google.android.apps.googleassistant.AssistantActivity"/>

在这里插入图片描述

相关文章:

MTKLauncher_布局页面分析

文章目录 前言遇到的困难点针对性解决困难 需求相关资料Launcher3 源码 目录简单介绍Launcher3 简介及页面布局分析UI整体架构数据加载布局加载布局加载核心思想device_profiles.xml 加载InvariantDeviceProfileinitGrid(context, gridName)getPredefinedDeviceProfilesinvDist…...

C#实现隐藏和显示任务栏

实现步骤 为了能够控制Windows任务栏&#xff0c;我们需要利用Windows API提供的功能。具体来说&#xff0c;我们会使用到user32.dll中的两个函数&#xff1a;FindWindow和ShowWindow。这两个函数可以帮助我们找到任务栏窗口&#xff0c;并对其执行显示或隐藏的操作 引入命名空…...

基于springboot+vue实现的公司财务管理系统(源码+L文+ppt)4-102

基于springbootvue实现的公司财务管理系统&#xff08;源码L文ppt&#xff09;4-102 摘要 本系统是基于SpringBoot框架开发的公司财务管理系统,该系统包含固定资产管理、资产申领管理、资产采购管理、员工工资管理等功能。公司财务管理系统是一种帮助公司进行有效资金管理、会…...

rnn/lstm

tip&#xff1a;本人比较小白&#xff0c;看到july大佬的文章受益匪浅&#xff0c;现在其文章基础上加上自己的归纳、理解&#xff0c;以及gpt的答疑&#xff0c;如果有侵权会删。 july大佬文章来源&#xff1a;如何从RNN起步&#xff0c;一步一步通俗理解LSTM_rnn lstm-CSDN博…...

袋鼠云产品功能更新报告12期|让数据资产管理更高效

本期&#xff0c;我们更新和优化了数据资产平台相关功能&#xff0c;为您提供更高效的产品能力。以下为第12期袋鼠云产品功能更新报告&#xff0c;请继续阅读。 一、【元数据】重点更新 &#xff5c;01 元数据管理优化&#xff0c;支持配置表生命周期 之前系统中缺少一个可以…...

MATLAB——入门知识

内容源于b站清风数学建模 目录 1.帮助文档 2.注释 3.特殊字符 4.设置MATLAB数值显示格式 4.1.临时更改 4.2.永久改 5.常用函数 6.易错点 1.帮助文档 doc sum help sum edit sum 2.注释 ctrl R/T 3.特殊字符 4.设置MATLAB数值显示格式 4.1.临时更改 format lon…...

C#从零开始学习(用户界面)(unity Lab4)

这是书本中第四个unity Lab 在这次实验中,将学习如何搭建一个开始界面 分数系统 点击球,会增加分数 public void ClickOnBall(){Score;}在OneBallBehaviour类添加下列方法 void OnMouseDown(){GameController controller Camera.main.GetComponent<GameController>();…...

Axure PR 9 多级下拉清除选择器 设计交互

大家好&#xff0c;我是大明同学。 Axure选择器是一种在交互设计中常用的组件&#xff0c;这期内容&#xff0c;我们来探讨Axure中选择器设计与交互技巧。 OK&#xff0c;这期内容正式开始 下拉列表选择输入框元件 创建选择输入框所需的元件 1.在元件库中拖出一个矩形元件。…...

分布式项目pom配置

1. 父项目打包方式为 pom <packaging>pom</packaging> 2. 父项目版本配置 <properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncod…...

2. Flink快速上手

文章目录 1. 环境准备1.1 系统环境1.2 安装配置Java 8和Scala 2.121.3 使用集成开发环境IntelliJ IDEA1.4 安装插件2. 创建项目2.1 创建工程2.1.1 创建Maven项目2.1.2 设置项目基本信息2.1.3 生成项目基本框架2.2 添加项目依赖2.2.1 添加Flink相关依赖2.2.2 添加slf4j-nop依赖2…...

Java-I/O框架06:常见字符编码、字符流抽象类

视频链接&#xff1a;16.16 字符流抽象类_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Tz4y1X7H7?spm_id_from333.788.videopod.episodes&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5&p16 1.常见字符编码 IOS-8859-1收录了除ASCII外&#xff0c;还包括西欧…...

计算机网络-MSTP的基础概念

前面我们大致了解了MSTP的由来&#xff0c;是为了解决STP/RSTP只有一根生成树导致的VLAN流量负载分担与次优路径问题&#xff0c;了解MSTP采用实例映射VLAN的方式实现多实例生成树&#xff0c;MSTP有很多的理论概念需要知道&#xff0c;其实与其它的知识一样理论复杂配置还好的…...

P1037 [NOIP2002 普及组] 产生数

[NOIP2002 普及组] 产生数 题目描述 给出一个整数 n n n 和 k k k 个变换规则。 规则&#xff1a; 一位数可变换成另一个一位数。规则的右部不能为零。 例如&#xff1a; n 234 , k 2 n234,k2 n234,k2。有以下两个规则&#xff1a; 2 ⟶ 5 2\longrightarrow 5 2⟶5。 …...

【分布式知识】分布式对象存储组件-Minio

文章目录 什么是minio核心特点&#xff1a;使用场景&#xff1a;开发者工具&#xff1a;社区和支持&#xff1a; 核心概念什么是对象存储&#xff1f;MinIO 如何确定对对象的访问权限&#xff1f;我可以在存储桶内按文件夹结构组织对象吗&#xff1f;如何备份和恢复 MinIO 上的…...

跨平台开发支付组件,实现支付宝支付

效果图&#xff1a; custom-payment &#xff1a; 在生成预付订单之后页面中需要弹出一个弹层&#xff0c;弹层中展示的内容为支付方式&#xff08;渠道&#xff09;&#xff0c;由用户选择一种支付方式进行支付。 该弹层组件是以扩展组件 uni-popup 为核心的&#xff0c;关于…...

API 接口:为电商行业高效发展注入强劲动力

一、动力之源&#xff1a;API 接口在电商中的角色剖析 在电商行业的广袤版图中&#xff0c;API 接口宛如一台强劲的发动机&#xff0c;是推动其高效发展的核心动力来源。它不再仅仅是一个技术工具&#xff0c;而是成为了连接电商各个环节的 “神经系统”&#xff0c;使得信息、…...

Golang的跨平台开发

Golang的跨平台开发 一、Golang跨平台开发概述 语言是一种开源的编程语言&#xff0c;由Google开发&#xff0c;广泛应用于云计算和网络编程领域。Golang具有并发性好、性能优异、内存管理自动化等特点&#xff0c;因此备受开发者青睐。其中&#xff0c;Golang的跨平台特性使得…...

txt数据转为pdf格式并使用base64解密输出

使用该方法请注意&#xff1a;因为此方法使用了base64解密&#xff0c;需要保证txt中的数据首先用了base64加密&#xff0c;如果只是普通的二进制数据&#xff0c;该方法并不适用 第一步 <dependency><groupId>org.apache.pdfbox</groupId><artifactId&…...

鸿蒙开发-状态+判断+循环

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;鸿蒙开发篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来鸿蒙开发篇专栏内容:鸿蒙开发-状态判断循环 目录 1.状态1原始类型 2.引用类型 2.判断 3.循环 1.基本使用…...

基于SSM网上招投标管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;招标者管理&#xff0c;专家管理&#xff0c;项目分类管理&#xff0c;招标项目管理&#xff0c;系统管理 前台账号功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0…...

「C/C++」C++ 设计模式 之 单例模式(Singleton)

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…...

WPF的行为(Behavior)

WPF&#xff08;Windows Presentation Foundation&#xff09;是微软.NET框架中用于构建Windows客户端应用程序的UI框架。它提供了一种声明性的方式来定义用户界面&#xff0c;并且支持MVVM&#xff08;Model-View-ViewModel&#xff09;设计模式。 在WPF中&#xff0c;“行为…...

SpringBoot框架:闲一品交易平台的新突破

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;闲一品交易平台当然也不能排除在外。闲一品交易平台是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&…...

关于AI绘画 | Stable Diffusion 技术专栏推荐文章

AI绘画 | Stable Diffusion 技术专栏推荐文章 引言 随着人工智能技术的发展&#xff0c;AI绘画逐渐成为艺术创作的新潮流。在众多的AI绘画工具中&#xff0c;Stable Diffusion因其强大的功能和易用性受到了广泛的关注。本文将详细介绍由“泰山AI”创建的技术专栏“AI绘画 | S…...

Oracle 第13章:事务处理

在数据库管理系统&#xff08;DBMS&#xff09;中&#xff0c;事务处理是一个非常重要的概念&#xff0c;它确保了数据的一致性和可靠性。下面我将解释事务的概念与特性&#xff0c;并讨论如何进行事务管理。 事务的概念与特性 事务是指作为一个工作单元的一组有序的SQL操作。…...

String的长度有限,而我对你的思念却无限延伸

公主请阅 1. 为什么学习string类&#xff1f;2. string类的常用接口2.1 string类对象的常见构造2.1.1 string 2.2 operator[]2.3 迭代器2.4 auto自动推导数据类型2.5 范围for2.6 迭代器第二层2.7 size和length获取字符串的长度2.8 max_size 获取这个字符串能设置的最大长度2.9 …...

二叉树的后序遍历

给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1] 解释&#xff1a; 示例 2&#xff1a; 输入&#xff1a;root [1,2,3,4,5,null,8,null,null,6,7,9] 输出&#xf…...

Nvidia未来的Blackwell Ultra GPU将更名为B300系列

据TrendForce报道&#xff0c;英伟达&#xff08;Nvidia&#xff09;计划将其Blackwell Ultra产品线重新命名为B300系列&#xff0c;以更好地与即将推出的B100和B200产品进行区分。Blackwell Ultra系列将是一个具有更高性能的升级版本。但据报道&#xff0c;这种升级后的内存配…...

BUUCTF靶场Misc练习

在BUUCTF中&#xff0c;你需要留意各种关于涉及 flag{ } 的信息。只要找的到flag&#xff0c;你就算成功。本文记录我刷BUUCTF的Misc类方法和个人感悟。 Misc第一题 签到 题解在题目中&#xff0c;如图所示 flag是 flag{buu_ctf} 第二题 &#xff08;题目如图所示&#xff…...

ChatGPT、Python和OpenCV支持下的空天地遥感数据识别与计算——从0基础到15个案例实战

从无人机监测农田到卫星数据支持气候研究&#xff0c;空天地遥感数据正以前所未有的方式为科研和商业带来深刻变革。然而&#xff0c;对于许多专业人士而言&#xff0c;如何高效地处理、分析和应用遥感数据仍是一个充满挑战的课题。本教程应运而生&#xff0c;致力于为您搭建一…...

网站怎么做移动端/新型网络营销模式

神器简介有时候&#xff0c;你很想关心她&#xff0c;但是你太忙了&#xff0c;以至于她一直抱怨&#xff0c;觉得你不够关心她。你暗自下决心&#xff0c;下次一定要准时发消息给她&#xff0c;哪怕是几句话&#xff0c;可是你又忘记了。你觉得自己很委屈&#xff0c;但是她又…...

wordpress ppt/网站优化要多少钱

Apachephpmysql配置详解 http://tech.163.com/06/0206/11/299AMBLT0009159K.html...

wordpress怎么安装上服务器/百度一下百度一下你知道

笔者使用代码及相关文件下载链接: 【源代码文件】pytorch-grad-cam源代码阅读和调试 源代码链接: jacobgil/pytorch-grad-cam pytorch-grad-cam源代码阅读和调试(上) pytorch-grad-cam源代码阅读和调试(中) pytorch-grad-cam源代码阅读和调试(下) 代码改进自定义一个类Guide…...

网页设计素材电影/广州aso优化公司 有限公司

【实例简介】主题模型(Topic Model)LDA详解及其Matlab代码【实例截图】【核心代码】LDA讲解及matlab程序└── LDA讲解及matlab程序├── LDA实验│ ├── Matlab Topic Modeling Toolbox 1.docx│ └── topictoolbox│ ├── AssociationLDA2.m│ ├── Associ…...

大学生做网站/免费收录软文网站

个人理解&#xff1a; 1、NAS本身不是一种传输协议&#xff0c;只是一个名词而已&#xff0c;就是一个网络储存。 2、NAS系统本身就是一个Linux&#xff0c;也不是什么发行版&#xff0c;就是在Linux下实现了网络储存。 3、NAS系统里面实现了很多通用的网络传输协议&#xff0c…...

类似凡科网的网站/小程序开发收费价目表

缘起 随着互联网企业的不断发展&#xff0c;产品项目中的模块越来越多&#xff0c;用户体验要求也越来越高&#xff0c;想实现小步快跑、快速迭代的目的越来越难&#xff0c;还有应用之间的互相调用等等问题&#xff0c;插件化技术应用而生。如果没有插件化技术&#xff0c;美…...