How in the world does Nova manage this? I\'m literally trying to do exactly the same thing: provide users with a button to press to clear and pick their new default launcher
r2DoesInc's solution doesn't work on my 4.2.2 test device.
My solution: Disable then re-enable my app's HomeActivity, it doesn't have to create FakeHome
PackageManager p = getPackageManager();
ComponentName cN = new ComponentName(this, HomeActivity.class);
p.setComponentEnabledSetting(cN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME));
p.setComponentEnabledSetting(cN, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
The code to do this is actually just a very clever work around.
When a component with
<category android:name="android.intent.category.HOME" />
is enabled, generally from an install of a new home application, the default home app gets cleared.
To take advantage of this by creating an empty activity with the home component like this.
<activity
android:name="com.t3hh4xx0r.haxlauncher.FakeHome"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
When you want to set your new default, you enable this component, then call the home intent and then disable your fake home component again.
public static void makePrefered(Context c) {
PackageManager p = c.getPackageManager();
ComponentName cN = new ComponentName(c, FakeHome.class);
p.setComponentEnabledSetting(cN, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Intent selector = new Intent(Intent.ACTION_MAIN);
selector.addCategory(Intent.CATEGORY_HOME);
c.startActivity(selector);
p.setComponentEnabledSetting(cN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
The end result is that the system thinks a new home app was installed, so the default is cleared allowing you to set yours with no special permissions.
Thank you to Kevin from TeslaCoil and NovaLauncher for the information on how this is done!
Taking @Bruce's answer (without using fake home activity) further, you can use PackageManager.setComponentEnabledSetting to first disable the component, then resolveActivity for the home intent (rather than using startActivity), then enable the component, and then startActivity with the intent.
Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
PackageManager pm = getPackageManager();
ResolveInfo rInfo = pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (!rInfo.activityInfo.packageName.equals(getPackageName())) { // your app is not the default HOME
ComponentName cn = <ComponentName object of your home activity>
pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
pm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
startActivity(homeIntent);
}
I use the following code on Android 4.1.2 with a platform-signed kiosk-mode application on an industrial tablet. It uses the deprecated PackageManager.addPreferredActivity()
, but the advantage is that it works without user interaction. It even works after the standard Android launcher has been choosen with the "always" option.
// Requires permission SET_PREFERRED_APPLICATIONS.
public static boolean setPreferredHomeActivity (Context context, String packageName, String className) {
ComponentName oldPreferredActivity = getPreferredHomeActivity(context);
if (oldPreferredActivity != null && packageName.equals(oldPreferredActivity.getPackageName()) && className.equals(oldPreferredActivity.getClassName())) {
return false; }
if (oldPreferredActivity != null) {
context.getPackageManager().clearPackagePreferredActivities(oldPreferredActivity.getPackageName()); }
IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_HOME);
filter.addCategory(Intent.CATEGORY_DEFAULT);
ComponentName[] currentHomeActivities = getActivitiesListByActionAndCategory(context, Intent.ACTION_MAIN, Intent.CATEGORY_HOME);
ComponentName newPreferredActivity = new ComponentName(packageName, className);
context.getPackageManager().addPreferredActivity(filter, IntentFilter.MATCH_CATEGORY_EMPTY, currentHomeActivities, newPreferredActivity);
return true; }
private static ComponentName getPreferredHomeActivity (Context context) {
ArrayList<IntentFilter> filters = new ArrayList<>();
List<ComponentName> componentNames = new ArrayList<>();
context.getPackageManager().getPreferredActivities(filters, componentNames, null);
for (int i = 0; i < filters.size(); i++) {
IntentFilter filter = filters.get(i);
if (filter.hasAction(Intent.ACTION_MAIN) && filter.hasCategory(Intent.CATEGORY_HOME)) {
return componentNames.get(i); }}
return null; }
private static ComponentName[] getActivitiesListByActionAndCategory (Context context, String action, String category) {
Intent queryIntent = new Intent(action);
queryIntent.addCategory(category);
List<ResolveInfo> resInfos = context.getPackageManager().queryIntentActivities(queryIntent, PackageManager.MATCH_DEFAULT_ONLY);
ComponentName[] componentNames = new ComponentName[resInfos.size()];
for (int i = 0; i < resInfos.size(); i++) {
ActivityInfo activityInfo = resInfos.get(i).activityInfo;
componentNames[i] = new ComponentName(activityInfo.packageName, activityInfo.name); }
return componentNames; }