androidandroid-intentandroid-activityandroid-appshortcut

App Shortcut only works once, just resumes the app after that


I have a dynamic app shortcut which looks like this

ShortcutInfo composeShortcut = new ShortcutInfo.Builder(App.getInstance(),
                                                                           getString(R.string.compose_shortcut_id))
                    .setShortLabel(getString(R.string.compose_app_shortcut_short_label))
                    .setLongLabel(getString(R.string.compose_app_shortcut_long_label))
                    .setDisabledMessage(getString(R.string.compose_app_shortcut_disabled_message))
                    .setIcon(Icon.createWithResource(App.getInstance(), R.drawable.compose_icon))
                    .setIntent(new Intent(context, ComposeActivity.class))
                                              .setAction(Intent.ACTION_DEFAULT)
                                              .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP))
                    .build();
            shortcutManager.setDynamicShortcuts(Arrays.asList(composeShortcut));

First time when I click this shortcut, it opens ComposeActivity just fine but not after that, I have to kill the app after which it works again for one time.

Desired flow - Whenever I click the app shortcut, the ComposeActivity should open. If the app is already running then ComposeActivity should open on top of the current activity only if the current activity is not already a ComposeActivity.

Current flow - First time I press the app shortcut, Compose activity opens just fine, but not after that. App is only resumed after that. I have to kill the app and again click the shortcut for it to open the ComposeActivity.

More info - Compose Activity in AndroidManifest is defined like this:

...
<activity 
android:name=".shared.publish.compose.view.activity.ComposeActivity"
android:screenOrientation="portrait"
android:theme="@style/compose_theme"
android:windowSoftInputMode="stateVisible|adjustResize"/>

<activity
    android:name=".shared.activity.SplashScreenActivity"
    android:label="@string/app_name"
    android:screenOrientation="portrait"
    android:theme="@style/splash_screen_theme">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
...

Solution

  • So I finally found the solution. Thanks to some useful information from David Wasser.

    Firstly App shortcut works for Activity with Action MAIN and Category LAUNCHER.

    So in manifest I added the following intent filter to my ComposeActivity

     <Activity android:name=".view.activity.ComposeActivity"
         android:relinquishTaskIdentity="true">
         <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
         </intent-filter> 
     </Activity>
    

    If you look closely I have also set android:relinquishTaskIdentity="true". This makes sure that if I have already open the ComposeActivity from shortcut and then I can again use it and open ComposeActivity.

    Next I updated the Intent used for Shortcut

    new Intent(context, ComposeActivity.class))
    .setAction(Intent.ACTION_MAIN)
    .addCategory(Intent.CATEGORY_LAUNCHER)
    .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
    

    By doing this, ComposeActivity will always open if it already not on top of the activity stack. Also it will open on top of any existing activity.

    But there is one problem. If there is no activity open, then Compose will not have any activity below it. App will close if back button is pressed.

    One thing you can do is

    @Override
    public void onBackPressed() {
        if(isTaskRoot()){
            if (getIntent().hasCategory(Intent.CATEGORY_LAUNCHER) 
                  && Intent.ACTION_MAIN.equals(getIntent().getAction())) {
                //launch any activity
            }
        }
        finish();
    }
    

    With this I could have any activity to open when ComposeActivity is the only activity in the back stack. In my case I launched my HomeActivity.