Android 设置默认Launcher(Home)简介:
如果定制Android系统,想让我们自己的Launcher(Home)成为默系统认Launcher,不希望用户安装了第三Launcher来替换我们的Launcher,并且不希望系统启动后弹出选择Launcher的界面,我们可以通过修改Framework层来实现,实现之后用户安装的第三方Launcher,系统仅当成一个普通应用来对待。
1、定义自己的Filter:
在frameworks/base/core/java/android/content/Intent.java 中添加一个自己的Filter:
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_HOME_FIRST = “android.intent.category.HOME_FIRST”;
2、通过自己的Filter进行过滤处理:
在frameworks/base/core/java/android/content/pm/PackageParser.java 中做过滤:
Android 安装一个APK的时候首先会解析APK,这里要做很多事情,其中一个事情就是解析Manifest.xml文件,并将所有APK的Manifest封装到各种对象中并保存在内存当中解析Manifest的类是非常重要的,PackageParser.java类注意用于解析Manifest.xml文件,在寻找Launcher的时候是根据AndroidManifest.xml中Launcher的filter(在Manifest中定义的<category android:name="android.intent.category.HOME" />)来过滤。然后根据filter出来的HOME来启动,如果只有一个HOME,则启动这个HOME,如果用户自己装了Launcher,那就会弹出来一个列表供用户选择。
private boolean parseIntent(Resources res,
XmlPullParser parser, AttributeSet attrs, int flags,
IntentInfo outInfo, String[] outError, boolean isActivity)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestIntentFilter);
int priority = sa.getInt(
com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
outInfo.setPriority(priority);
TypedValue v = sa.peekValue(
com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
outInfo.nonLocalizedLabel = v.coerceToString();
}
outInfo.icon = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
outInfo.logo = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
sa.recycle();
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String nodeName = parser.getName();
if (nodeName.equals("action")) {
String value = attrs.getAttributeValue(
ANDROID_RESOURCES, "name");
if (value == null || value == "") {
outError[0] = "No value supplied for <android:name>";
return false;
}
XmlUtils.skipCurrentTag(parser);
outInfo.addAction(value);
} else if (nodeName.equals("category")) {
String value = attrs.getAttributeValue(
ANDROID_RESOURCES, "name");
if (value == null || value == "") {
outError[0] = "No value supplied for <android:name>";
return false;
}
XmlUtils.skipCurrentTag(parser);
// 在此进行过滤处理,处理开始,当解析到我们自己的定义的Intent.CATEGORY_HOME_FIRST时才将value设置为Intent.CATEGORY_HOME
if (value.equals(Intent.CATEGORY_HOME)) {
value = "nothing";
}else if (value.equals(Intent.CATEGORY_HOME_FIRST)) {
value = Intent.CATEGORY_HOME;
}
outInfo.addCategory(value);
// 在此进行过滤处理,处理结束
} else if (nodeName.equals("data")) {
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestData);
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
if (str != null) {
try {
outInfo.addDataType(str);
} catch (IntentFilter.MalformedMimeTypeException e) {
outError[0] = e.toString();
sa.recycle();
return false;
}
}
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
if (str != null) {
outInfo.addDataScheme(str);
}
String host = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestData_host, 0);
String port = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestData_port, 0);
if (host != null) {
outInfo.addDataAuthority(host, port);
}
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestData_path, 0);
if (str != null) {
outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
}
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
if (str != null) {
outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
}
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
if (str != null) {
outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
}
sa.recycle();
XmlUtils.skipCurrentTag(parser);
} else if (!RIGID_PARSER) {
Slog.w(TAG, "Unknown element under <intent-filter>: "
+ parser.getName() + " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
} else {
outError[0] = "Bad element under <intent-filter>: " + parser.getName();
return false;
}
}
outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
if (DEBUG_PARSER) {
final StringBuilder cats = new StringBuilder("Intent d=");
cats.append(outInfo.hasDefault);
cats.append(", cat=");
final Iterator<String> it = outInfo.categoriesIterator();
if (it != null) {
while (it.hasNext()) {
cats.append(' ');
cats.append(it.next());
}
}
Slog.d(TAG, cats.toString());
}
return true;
}
3、在Launcher AndroidManifest.xml中使用定义的Filter
在自己Launcher AndroidManifest.xml 中使用我们刚才自己定义的Filter,当系统解析到此Filter时就会把我们自己的Launcher作为系统默认的Launcher进行处理。
<category android:name="android.intent.category.HOME_FIRST" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<!--在此添加我们定于的Filter-->
<category android:name="android.intent.category.HOME_FIRST" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>