Android - How to receive shortcut create result

3.5k views Asked by At

Looking at the code sample here - I find the following comment puzzling:

// ... We assume here that the
// app has implemented a method called createShortcutResultIntent() that
// returns a broadcast intent.

what does it mean the app has implemented ... where is this implementation done?

is it a broadcast receiver? registered to which intent filter?

is this an abstract method? of which class?

and then I see this code sample - which handles a completely different flow (I think) and I'm lost again

2

There are 2 answers

4
Alex Tern On BEST ANSWER

You can obtain feedback via catching the broadcast event which you setup while use requestPinShortcut function. At first you need a usual broadcast receiver (in the code below it has name ShortcutReceiver). You can even use existing broadcast receiver and simple add new action which it should catch.
Lets the action will be "general.intent.action.SHORTCUT_ADDED" and it will be stored in ShortcutReceiver.kInstalledAction constant. In this case in the manifest you should have:

<receiver android:name=".ShortcutReceiver" >
  <intent-filter>
    <action android:name="general.intent.action.SHORTCUT_ADDED"/>
  </intent-filter>
</receiver>

After this you can use following code in the activity for create a pinned shortcut (in other places change this on object of Context class):

ShortcutManager manager = this.getSystemService(ShortcutManager.class);
Intent targetIntent = new Intent(ShortcutReceiver.kInstalledAction);
targetIntent.setPackage(this.getPackageName());
PendingIntent intent = PendingIntent.getBroadcast(this, 0, targetIntent, 0);
manager.requestPinShortcut(info, intent.getIntentSender());

In this code info is correct object of ShortcutInfo class.
You can handle the event while catch the broadcast:

public class ShortcutReceiver extends BroadcastReceiver {
  public static final String kInstalledAction = "general.intent.action.SHORTCUT_ADDED";

  @Override
  public void onReceive(Context context, Intent intent) {
    
    if (kInstalledAction.equals(intent.getAction())) {
      // Handle the event after the shortcut has been added 
      Toast.makeText(context, "The shortcut has been added", Toast.LENGTH_LONG).show();
    }
  
  }

}

Please take into account that from my experience the broadcast event happens after the shortcut has been added but sometimes there can be some delays (at about some minutes). But may be there is some dependency on the launcher.

Update
As described in other answers on Android 8 catching of implicit intent via broadcast in general doesn't work. So I simple changed the intent to explicit via set package name of the current app. So only our broadcast receiver can catch the intent.

0
Kirill Karmazin On

First things first. Implicit intents on Android 8.0 Oreo:

Because Android 8.0 (API level 26) introduces new limitations for broadcast receivers, you should remove any broadcast receivers that are registered for implicit broadcast intents. Leaving them in place does not break your app at build-time or runtime, but they have no effect when your app runs on Android 8.0. Explicit broadcast intents—those that only your app can respond to—continue to work the same on Android 8.0. There are exceptions to this new restriction. For a list of implicit broadcasts that still work in apps targeting Android 8.0, see Implicit Broadcast Exceptions. https://developer.android.com/about/versions/oreo/android-8.0-changes

Note: there are some exceptions: https://developer.android.com/guide/components/broadcast-exceptions (very few)

Instead, we will use the so-called context-registered receiver, it will last as long as our app lives, or until we unregister it.

Also, ShortcutManager requires API 25 that's why we will use it's compat version in order not to duplicate the code for old and new versions. (ShortcutManagerCompat was added in version 26.1.0)

Code to create a pinned shortcut on the Home screen:

public static void addShortcut(Context context, String id) {
    if(context == null || note == null)
        return;

    //there may be various Home screen apps, better check it
    if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)){

        Intent shortcutIntent = new Intent(context, MainActivity.class);
        shortcutIntent.setAction(Constants.ACTION_SHORTCUT); // !!! intent's action must be set on oreo


        ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, note.get_id().toString())
                .setIntent(shortcutIntent)
                .setShortLabel("MyShortcut") //recommend max 10 chars
                .setLongLabel("Long shortcut name")//recommend max 25 chars
                .setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut))
                .build();


        //callback if user allowed to place the shortcut
        Intent pinnedShortcutCallbackIntent = new Intent(ACTION_SHORTCUT_ADDED_CALLBACK);

        PendingIntent successCallback = PendingIntent.getBroadcast(context, REQ_CODE_SHORTCUT_ADDED_CALLBACK,
                pinnedShortcutCallbackIntent,  0);


        ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, successCallback.getIntentSender());
    }

And here is the code to receive the broadcast in your Activity, for example. Note that this "callback" will be called only if your app is running, receiver is registered and the user allowed the shortcut:

private ShortcutAddedReceiver shortcutAddedReceiver;



private void registerShortcutAddedReceiver(){
    if(shortcutAddedReceiver == null){
        shortcutAddedReceiver = new ShortcutAddedReceiver();
    }
    IntentFilter shortcutAddedFilter = new IntentFilter(ShortcutHelper.ACTION_SHORTCUT_ADDED_CALLBACK);
    registerReceiver(shortcutAddedReceiver, shortcutAddedFilter);
}


private void unregisterShortcutAddedReceiver(){
    if(shortcutAddedReceiver != null){
        unregisterReceiver(shortcutAddedReceiver);
        shortcutAddedReceiver = null;
    }
}


@Override
public void onStart() {
    super.onStart();
    registerShortcutAddedReceiver();
}

@Override
public void onStop() {
    super.onStop();
   unregisterShortcutAddedReceiver();
}


private class ShortcutAddedReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        Snackbar.make(view, "Shortcut added", Snackbar.LENGTH_LONG).show();
    }
}

Hope this helps!