Android start static app shortcut

1.1k Views Asked by At

Past few days I have been trying to figure out how to start app shortcuts added in Android API 25 and I have been somewhat successful. Starting some shortcuts like Google Play Music's work without problem I'm guessing because these shortcuts are starting activities with action.MAIN and category.LAUNCHER or exported, but other activities throw "java.lang.SecurityException: Permission Denial: starting Intent" which seems reasonable as well. This seems dooable since apps like Pixel Launcher, Sesame Shortcuts etc. can do this, there must be some special intent flag or something. I even tried catching shortcut intent inside my app and replicating it but no success

Here is example of how I do this for Google Chrome's "New Tab" shortcut:

val componentName = ComponentName("com.android.chrome", "org.chromium.chrome.browser.LauncherShortcutActivity")
val intent = Intent(action)
intent.component = componentName
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_TASK_ON_HOME)
startActivity(intent)

I got these values from activityInfo metaData which can be fetched with PackageManager

1

There are 1 best solutions below

1
On BEST ANSWER

Here's the code to list all available shortcuts and then launch whatever the first shortcut is (just as an example):

val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps

val shortcutQuery = LauncherApps.ShortcutQuery()
// Set these flags to match your use case, for static shortcuts only,
// use FLAG_MATCH_MANIFEST on its own.
shortcutQuery.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC
        or LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST
        or LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED)
shortcutQuery.setPackage(packageName)

val shortcuts = try {
    launcherApps.getShortcuts(shortcutQuery, Process.myUserHandle())
} catch (e: SecurityException) {
    // This exception will be thrown if your app is not the default launcher
    Collections.emptyList<ShortcutInfo>()
}

// Lists all shortcuts from the query
shortcuts.forEach {
    Log.d(TAG, "Shortcut found ${it.`package`}, ${it.id}")
}

// Starts the first shortcut, as an example (this of course is not safe like this, 
// it will crash if the list is empty, etc).
val shortcut = shortcuts[0]
launcherApps.startShortcut(shortcut.`package`, shortcut.id, null, null, Process.myUserHandle())

This code assumes that you have a variable named context of type Context and a variable named packageName of type String from somewhere.


Credits: This is all based on Quan Vu's work on this topic, his article here and the corresponding repository here.