Launcher3 桌面布局一般加载default_workspace_xx.xml 。需要自定义自己的Launcher 布局会以静态overlay的形式来替换原始的default_workspace_xx.xml。这种方式局限是需要有源码的情况下去修改。
Launcher 提供了接口,可以预置一个apk, 来实现自定义。
Launcher#loadDefaultFavoritesIfNecessary 用来获取默认的布局文件。其中get方法是获取所需要信息
synchronized public void loadDefaultFavoritesIfNecessary() { ... 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(), mOpenHelper.mAppWidgetHost, mOpenHelper, partnerRes, workspaceResId); } } }
...
}
其中的关键方法findSystemApk , 判断系统apk中是否有action 为"com.android.launcher3.action.PARTNER_CUSTOMIZATION" 的应用, 如果有,则获取packagename 和resources
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; }
static Pair<String, Resources> findSystemApk(String action, PackageManager pm) { final Intent intent = new Intent(action); for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) { if (info.activityInfo != null && (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { final String packageName = info.activityInfo.packageName; try { final Resources res = pm.getResourcesForApplication(packageName); return Pair.create(packageName, res); } catch (NameNotFoundException e) { Log.w(TAG, "Failed to find resources for " + packageName); } } } return null; }
然后用hasDefaultLayout 去判断是否有这个partner_default_layout.xml ,若有,则以此文件作为默认layout
public boolean hasDefaultLayout() { int defaultLayout = getResources().getIdentifier(Partner.RES_DEFAULT_LAYOUT, "xml", getPackageName()); return defaultLayout != 0; }以上是launcher 中获取默认桌面layout 的过程。
下面自定义一个apk,去自定义这个文件(可以参考GMS包里面的应用GmsSampleLayout,按照里面的方法写)。
创建个apk,AndroidManifast.xml中配置:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.custom.workspace.layout">
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="23" />
<application android:label="@string/app_label">
<receiver android:name=".PartnerCustomizationReceiver">
<intent-filter>
<action android:name="com.android.launcher3.action.PARTNER_CUSTOMIZATION" />
</intent-filter>
</receiver>
</application>
</manifest>
在PartnerCustomizationReceiver.java 中创建广播接收,不做处理
public class PartnerCustomizationReceiver extends BroadcastReceiver {
public PartnerCustomizationReceiver() {
}
public void onReceive(Context context, Intent intent) {
}
}
然后在资源里添加自定义的layout布局,名字为partner_default_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<favorites>
<favorite
packageName="com.android.settings"
className="com.android.settings.wifi.WifiSettings"
screen="3"
x="0"
y="3" />
<favorite
packageName="com.android.gallery3d"
className="com.android.gallery3d.app.GalleryActivity"
screen="3"
x="1"
y="3" />
<favorite
packageName="com.android.settings"
className="com.android.settings.Settings"
screen="3"
x="2"
y="3" />
<favorite
packageName="com.android.music"
className="com.android.music.MusicBrowserActivity"
screen="3"
x="3"
y="3" />
<!-- Far-right screen [4] -->
<!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
<!-- Contacts,Dialer, [All Apps], Messaging, Browser -->
<resolve
container="-101"
screen="0"
x="0"
y="0" >
<favorite uri="\#Intent;action=android.intent.action.DIAL;end" />
<favorite uri="tel:123" />
<favorite uri="\#Intent;action=android.intent.action.CALL_BUTTON;end" />
<favorite
packageName="com.android.dialer"
className="com.android.dialer.DialtactsActivity" />
</resolve>
</favorites>
注意:
1.因为Launcher 的默认布局中有命名空间来规范属性,在这里需要把命名空间去除,并去除每个标签属性前面的launcher关键字;
2.<favorite uri="\#Intent;action=android.intent.action.DIAL;end" /> 这个标签的#前面需要加个反斜杠
android.mk
# WorkSpaceStyle
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := WorkSpaceStyle
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
#LOCAL_OVERRIDES_PACKAGES := BullheadLayout
LOCAL_SRC_FILES := $(call all-java-files-under, src)
include $(BUILD_PACKAGE)
编译后install到手机上,在adb shell pm clear com.android.launcher3.
现在可以查看自定义的桌面了。
后面再更新一篇 在自己写的app上实现主题变更。