How to create Static, Dynamic & Pinned App Shortcuts in Android App

Shortcuts deliver specific types of content to your users by helping them quickly access parts of your app.

  • Android 7.1 introduced a new feature called App Shortcuts.

  • When you long press your app icon, it shows shortcuts to specific actions which can be launched, on supported launchers.

They are of three types: Static, Dynamic & Pinned.


Static: These are shortcuts that are defined statically in a resource file; These cannot be changed unless you modify the file and re-deploy the app

Dynamic: These are shortcuts that are published at runtime; These can be updated without the need to re-deploy the app

Pinned: shortcuts are used for specific, user-driven actions. For example, a user might want to pin a specific website to the launcher. 

Notes:
enabled: As the name states, whether the shortcut is enabled or not. If you decide to disable your static shortcut you could either set this to false or simply remove it from the <shortcuts> set. You might want to use this feature re to control which shortcut is disabled by build flavor.

icon: The icon shown on the left-hand side of the shortcut.

shortcutDisabledMessage: this is the string shown to a user if they try to launch a disabled shortcut pinned to their home screen.

shortcutLongLabel: This is a longer variant of the shortcut text, shown when the launcher has enough space.

shortcutShortLabel: This is a concise description of the shortcut. This field is mandatory. This is probably the shortcut text that most users will see on their home screen.

intent: here you define your intent (or more intents) that your shortcut will open upon being tapped

res/ xml-v25 /shortcut.xml
In this new resource file, add a <shortcuts> root element, which contains a list of <shortcut> elements. Each <shortcut> element contains information about a static shortcut, including its icon, its description labels, and the intents that it launches within the app:
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">

    <!--static shortcut 1-->
    <shortcut
        android:shortcutId="compose"
        android:enabled="true"
        android:icon="@drawable/chat"
        android:shortcutShortLabel="@string/shortcutShortLabel"
        android:shortcutLongLabel="@string/shortcutLongLabel"
        android:shortcutDisabledMessage="@string/shortcutDisabledMessage">
        <intent
            android:action="com.boltuix.appshortcut.action.VIEW_PROGRESSBAR"
            android:targetClass="com.boltuix.appshortcut.MainActivity"
            android:data="jetpack://view_detail_page"
            android:targetPackage="com.boltuix.appshortcut" />
    </shortcut>

    <!--static shortcut 2-->
    <shortcut
        android:enabled="true"
        android:icon="@drawable/question"
        android:shortcutId="animationViewer"
        android:shortcutShortLabel="@string/shortcutShortLabel2"
        android:shortcutLongLabel="@string/shortcutLongLabel2"
        android:shortcutDisabledMessage="@string/shortcutDisabledMessage2"

        >
        <intent
            android:action="com.boltuix.appshortcut.MainActivity.VIEWER"
            android:targetClass="com.boltuix.appshortcut.MainActivity"
            android:targetPackage="com.boltuix.appshortcut"/>
    </shortcut>
</shortcuts>





AndroidManifest.xml
Add an <meta-data> element to this activity that references the resource file where the app's shortcuts are defined:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.myapplication">
  <application ... >
    <activity android:name="Main">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
      
      <meta-data android:name="android.app.shortcuts"
                 android:resource="@xml/shortcuts" /> 
    </activity>
  </application>
</manifest>
to create a dynamic shortcut in CODE.
 try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
                Log.d("shortcut01", "init shortcut call")
                var shortcutManager: ShortcutManager? = null
                shortcutManager = requireContext().getSystemService(ShortcutManager::class.java)


                val intent = Intent(context, MainActivity::class.java)
                intent.action = Intent.ACTION_VIEW
                intent.data = Uri.parse("jetpack://view_detail_page")
                intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
                // fragment
                val shortcut1 = ShortcutInfo.Builder(requireContext(), "dShortcut1")
                    .setIntent(intent)
                    .setRank(1)
                    .setLongLabel("My Dynamic Fragment")
                    .setShortLabel("Dynamic Fragment")
                    .setDisabledMessage("Dynamic Fragment disabled")
                    .setIcon(Icon.createWithResource(requireContext(), R.drawable.question))
                    .build()


                val intent2 = Intent(context, MainActivity::class.java)
                intent2.action = Intent.ACTION_VIEW
                intent2.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
                //intent
                val shortcut2 = ShortcutInfo.Builder(requireContext(), "dShortcut2")
                    .setIntent(intent2)
                    .setRank(2)
                    .setLongLabel("My Dynamic Activity")
                    .setShortLabel("Dynamic Activity")
                    .setDisabledMessage("Dynamic Activity disabled")
                    .setIcon(Icon.createWithResource(requireContext(), R.drawable.chat))
                    .build()

                shortcutManager!!.dynamicShortcuts = listOf(shortcut1,shortcut2)

            } else {
                Log.d("shortcut01", "no support")
            }
        } catch (g1: Exception) {
            Log.d("shortcut01", "" + g1.message)
        }


Update Shortcut Text at Runtime
  try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
                val shortcutManager: ShortcutManager =
                    context.getSystemService(ShortcutManager::class.java)
                val thirdShortcut = ShortcutInfo.Builder(context, "dShortcut2")
                    .setShortLabel("dynamic s changed")
                    .setLongLabel("dynamic l changed")
                    .build()
                shortcutManager.updateShortcuts(listOf(thirdShortcut))
            } else {
                Log.d("shortcut01", "no support")
            }
        } catch (g1: Exception) {
            Log.d("shortcut01", "" + g1.message)
        }


Update Shortcut Order at Runtime
 val thirdShortcut = ShortcutInfo.Builder(this@MainActivity, "shortcut_dynamic")
                .setRank(2)
                .build()

 val fourthShortcut = ShortcutInfo.Builder(this@MainActivity, "shortcut_web")
                .setRank(2)
                .build()
shortcutManager!!.updateShortcuts(listOf(thirdShortcut, fourthShortcut))

To remove shortcuts
  • Remove a set of dynamic shortcuts using removeDynamicShortcuts(), or remove all dynamic shortcuts using removeAllDynamicShortcuts().
shortcutManager!!.removeAllDynamicShortcuts()
...

Create pinned shortcuts
  • On Android 8.0 (API level 26) and higher, you can create pinned shortcuts. 
  • Unlike static and dynamic shortcuts, pinned shortcuts appear in supported launchers as separate icons. Figure 1 shows the distinction between these two types of shortcuts.

val shortcutManager = getSystemService(ShortcutManager::class.java)

if (shortcutManager!!.isRequestPinShortcutSupported) {
    // Assumes there's already a shortcut with the ID "my-shortcut".
    // The shortcut must be enabled.
    val pinShortcutInfo = ShortcutInfo.Builder(context, "my-shortcut").build()

    // Create the PendingIntent object only if your app needs to be notified
    // that the user allowed the shortcut to be pinned. Note that, if the
    // pinning operation fails, your app isn't notified. We assume here that the
    // app has implemented a method called createShortcutResultIntent() that
    // returns a broadcast intent.
    val pinnedShortcutCallbackIntent = shortcutManager.createShortcutResultIntent(pinShortcutInfo)

    // Configure the intent so that your app's broadcast receiver gets
    // the callback successfully.For details, see PendingIntent.getBroadcast().
    val successCallback = PendingIntent.getBroadcast(context, /* request code */ 0,
            pinnedShortcutCallbackIntent, /* flags */ 0)

    shortcutManager.requestPinShortcut(pinShortcutInfo,
            successCallback.intentSender)
}



GET source code on Github:

 


Comments