49

I am creating a launcher (kiosk) app that will be downloadable through google. When first installing this application the user has the ability of choosing which launcher (mine or the stock) will be the default. I am trying to bring this up manually if the user does not make my application the default launcher. I want the user to be forced into selecting ALWAYS instead of JUST ONCE when that dialog comes up, otherwise the dialog will continue to appear periodically with a friendly message. This is what I have attempted so far.

I created a method to check for if my application is the default

/**
 * method checks to see if app is currently set as default launcher
 * @return boolean true means currently set as default, otherwise false
 */ 
private boolean isMyAppLauncherDefault() {
    final IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
    filter.addCategory(Intent.CATEGORY_HOME);

    List<IntentFilter> filters = new ArrayList<IntentFilter>();
    filters.add(filter);

    final String myPackageName = getPackageName();
    List<ComponentName> activities = new ArrayList<ComponentName>();
    final PackageManager packageManager = (PackageManager) getPackageManager();

    packageManager.getPreferredActivities(filters, activities, null);

    for (ComponentName activity : activities) {
        if (myPackageName.equals(activity.getPackageName())) {
            return true;
        }
    }
    return false;
}   

Then I make the attempt of launching the chooser

/**
 * method starts an intent that will bring up a prompt for the user
 * to select their default launcher. It comes up each time it is
 * detected that our app is not the default launcher
 */
private void launchAppChooser() {
    Log.d(TAG, "launchAppChooser()");
    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_HOME);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
}

When I do this I am not receiving the choice between my app and the stock launcher. I tried using startActivity(Intent.createChooser(intent, "Please set launcher settings to ALWAYS")); and I get the choices between my app and the stock launcher, however, I don't get the options ALWAYS or JUST ONCE.

I can create a custom dialog for this instead of launching chooser but I need to know how to set the default app launcher programmatically. Thanks in advance!

portfoliobuilder
  • 7,556
  • 14
  • 76
  • 136
  • You shouldn't force the user to do something. Let them decide what they want. What if the user wants to try your app but then wants to switch back immediately. The built in chooser will do just fine. – Longi Jan 16 '15 at 20:01
  • 1
    Actually this is the common behavior of launcher apps. Download any launcher application built for children and it is this way. The reason is actually protecting the user (children). The purpose of this is to further ensure that the child is in a contained and controlled environment. That is why most launcher apps built for kids, e.g. Famigo and others, have this behavior. – portfoliobuilder Jan 16 '15 at 20:13
  • 1
    can our app be chosen without promting to the user, is there a method to give package name for default launcher? – Vikas Pandey Oct 08 '17 at 13:24

5 Answers5

87

This is actually possible with a little workaround:

Create an empty Activity that acts as a launcher called FakeLauncherActivity. Add it to your manifest as a disabled component:

<activity
    android:name="com.path.to.your.FakeLauncherActivity"
    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>

Check whether your desired launcher activity is the default one (with the isMyAppLauncherDefault() from your question).

If not, offer the user to choose the preferred launcher activity like this:

public static void resetPreferredLauncherAndOpenChooser(Context context) {
    PackageManager packageManager = context.getPackageManager();
    ComponentName componentName = new ComponentName(context, com.path.to.your.FakeLauncherActivity.class);
    packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

    Intent selector = new Intent(Intent.ACTION_MAIN);
    selector.addCategory(Intent.CATEGORY_HOME);
    selector.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(selector);

    packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, PackageManager.DONT_KILL_APP);
}

This method temporarily enables FakeLauncherActivity, which leads to a change in the set of available launcher activities, which forces Android to forget its default launcher. You will see something like...

521-735/system_process I/PackageManager﹕ Result set changed, dropping preferred activity for Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 } type null

... in your log.

The method then simply opens a launcher intent where you can see all installed launchers and the buttons "Always" / "Just once". Finally, the method disables FakeLauncherActivity again so that it doesn't display in the list.

You could repeat that as often as you want and only let the user proceed if your desired launcher activity is set as default.

saschoar
  • 8,150
  • 5
  • 43
  • 46
  • 2
    Wow! After all this time a viable answer! Thank you good sir!! – portfoliobuilder Jun 04 '15 at 01:40
  • 1
    What version of Android have you used this code in? I cannot get it to work in 4.4.2 – tallpaul Jun 08 '15 at 11:20
  • The methods and constants in the code are supported by all Android API levels. I also tested it on an Android 4.4.2 device. At which point does it fail for you? – saschoar Jun 08 '15 at 14:41
  • Sorry for the late reply, I have just tried again with no luck. The dialog does appear the first time, but if the user selects another launcher as default, then reopens this app, the dialog never seems to appear again. – tallpaul Jun 23 '15 at 15:31
  • 1
    Alright, that's why you'd have to check if your launcher is the default one (`isMyAppLauncherDefault()`) every time the user opens or returns to your app. – saschoar Jun 25 '15 at 08:52
  • 7
    I figured out that my answer is just a copy of this: http://stackoverflow.com/a/13239706/1140682 ... so please go ahead and upvote that one please. When I answered here, I didn't know where I've got my solution from, but now I found the source again. – saschoar Oct 08 '15 at 13:03
  • 1
    Could you please provide some more information about what exactly does not work? I successfully tested it on stock Android 6.0. – saschoar Sep 20 '16 at 09:00
  • 1
    yes, it works for provided intent, however I want to reset default browser. So my intent is created for action_view, some https link used as data. And for this 'browser'-intent this code works only below android 6. – orium Sep 20 '16 at 09:43
  • 1
    @tallpaul Hi. I know this question is a year ago, but now I have the same problem testing the above code on Andorid 4.4.2. Have you solved it yet?Thank you in advance! –  Oct 05 '16 at 14:16
  • 1
    I also cannot get the default app. Could you look at the issue at http://stackoverflow.com/questions/40501710/wrong-to-get-all-defaults-app-in-android-l – Jame Nov 09 '16 at 07:49
  • 1
    can our app be chosen without promting to the user, is there a method to give package name for default launcher? – Vikas Pandey Oct 08 '17 at 13:25
  • 1
    is it possible to prioritise order of the app in select dialog? – Vikas Pandey Oct 08 '17 at 13:26
  • 2
    i'm developing launcher app but i'm facing challenging in preserving the default launcher as my launcher app i.e. i set my launcher as default, after reboot my device, device again ask me for set default launcher. Please guide me so that i can fix this issue in my project. Thanks in advance. – Pritesh Vishwakarma Sep 28 '19 at 06:41
8

The isMyAppLauncherDefault() function in the question doesn't always work for some reason. This code might be better for determining what is the default package for the HOME screen.

Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
ResolveInfo resolveInfo = getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
String currentHomePackage = resolveInfo.activityInfo.packageName;
Zohar
  • 1,820
  • 1
  • 18
  • 16
7

I want the user to be forced into selecting ALWAYS instead of JUST ONCE when that dialog comes up

That is not possible, except perhaps on rooted devices, barring some security flaw in Android.

When I do this I am not receiving the choice between my app and the stock launcher

Correct. If a default has already been chosen, this will simply launch the default.

I tried using startActivity(Intent.createChooser(intent, "Please set launcher settings to ALWAYS")); and I get the choices between my app and the stock launcher, however, I don't get the options ALWAYS or JUST ONCE.

Correct. createChooser() forces a choice, but does not allow setting a default.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    What you have described is what I have been experiencing, but this is not what I have noticed from other apps. If you download Famigo app from google play store, you will see what I mean. When Famigo is not default app, a dialog comes up saying that user must set the app as default otherwise certain features cannot be accessed. You have to choose ALWAYS. Once you do that, when you go to device settings it says as default launcher that "chosen to launch app by default for some actions". Inside the Famigo app, you can undo this default setting with one button click. – portfoliobuilder Jan 16 '15 at 20:56
  • 2
    @portfoliobuilder: Then sometime I will work on figuring out how they do it, then report the security flaw to Google and try to get the flaw fixed. – CommonsWare Jan 16 '15 at 20:59
  • 1
    Hi I have rooted device. How can forcefully show my launcher as default launcher[Without any popup's even user press on Home button] How to forcefully press on ALWAYS through programatically – madhu527 Jan 12 '18 at 07:34
4

Android Q (API 29) has RoleManager. Let's say your app is a Launcher.

[AndroidManifest.xml]
<activity
    ... />

    <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>


private val startForResult = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { activityResult ->
    if (activityResult.resultCode == Activity.RESULT_OK) {
        // Perhaps log the result here.
    }
}

private fun showLauncherSelection() {
    val roleManager = requireActivity().getSystemService(Context.ROLE_SERVICE)
            as RoleManager
    if (roleManager.isRoleAvailable(RoleManager.ROLE_HOME) &&
        !roleManager.isRoleHeld(RoleManager.ROLE_HOME)
    ) {
        val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME)
        startForResult.launch(intent)
    }
}

When you call showLauncherSelection(), you should see a dialog similar to the following.

enter image description here

There are other roles, such as ROLE_BROWSER, ROLE_DIALER, ROLE_SMS, and such.

solamour
  • 2,764
  • 22
  • 22
3

If you are implementing Google EMM solution (Dedicated Device):

https://developer.android.com/work/dpc/dedicated-devices/cookbook

// Create an intent filter to specify the Home category.
IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_HOME);
filter.addCategory(Intent.CATEGORY_DEFAULT);

// Set the activity as the preferred option for the device.
ComponentName activity = new ComponentName(context, KioskModeActivity.class);
DevicePolicyManager dpm =
    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.addPersistentPreferredActivity(adminName, filter, activity);
Saba
  • 1,208
  • 14
  • 19
  • 1
    how to get an adminName ? – Pritesh Vishwakarma Sep 28 '19 at 12:06
  • 1
    @PriteshVishwakarma here is the documentation: https://developer.android.com/guide/topics/admin/device-admin – Saba Oct 25 '19 at 11:30
  • And if you want to set another app to be the launcher, construct the ComponentName with strings : `new ComponentName("com.example.myotherapp", "com.example.myotherapp.MainActivity")` . – Bako Jan 08 '21 at 13:38