How Lollipop’s Share Menu is Organized

Maxxxxxxx
4 min readDec 27, 2014

And some features Android Developers can use to play nice.

Lollipop now puts your most used apps at the top of the Share Menu for faster access… But what classifies as “most used”?

(If you aren’t interested in the technical details,
there is a TL;DR and a Corgi puppy at the end)

The marvelous thing about Android is that it is open source, we can just look at the code. Here is the Comparator (sorting algorithm) for the Share Menu: https://github.com/android/platform_frameworks_base/blob/lollipop-release/core/java/com/android/internal/app/ResolverActivity.java#L1052

The key pieces are shown here:

final long timeDiff = 
getPackageTimeSpent(rhs...) - getPackageTimeSpent(lhs...);
if (timeDiff != 0) {
return timeDiff > 0 ? 1 : -1;
}
... sa and sb are set to the app's names ...return mCollator.compare(sa.toString(), sb.toString());
  1. Options with a higher getPackageTimeSpent() value are ranked higher.
  2. Within those of the same time value, they are sorted alphabetically.

Here is the gist of what getPackageTimeSpent() returns:

...
final UsageStats stats = mStats.get(packageName);
if (stats != null) {
return stats.getTotalTimeInForeground();
}
...

Using the new UsageStatsManager API (added in Lollipop) it queries getTotalTimeInForeground() which is described as follows:

“Get the total time this package[app] spent in the foreground, measured in milliseconds.”

So there you have it. It’s organized by the total amount of time you spend in the app, with it visible on your screen.

But wait! There is another thing that can change the ordering of the menu.

Initial Intents

There is an API that has been around for a long time that developers can use to add choices to the top of the Share Menu when they launch it from their app.

Intent.EXTRA_INITIAL_INTENTS

Some of the ways developers might use this feature are:

  1. To add options to the menu that should only be available when sharing from their app.
  2. To add additional app options that wouldn’t directly match the type of Intent that is being shared.
  3. To provide different data for different apps. For example, share a long piece of text to email apps and a shorter snippet to SMS apps. Also, if a specific app needs additional data, this can be used to avoid sending that data to other apps.

Any apps added as INITIAL_INTENTS will always appear at the top of the list, regardless of the Share Menu’s new sorting. (Here is the source code)

Apps that do the 3rd use case above, typically end up making the entire menu organized alphabetically. This was fine in the past, but now that Lollipop has moved beyond alphabetical sorting, it isn’t ideal.

Thankfully, Lollipop added a new API developers can use instead, so they don’t mess up the Share Menu’s new ordering.

Replacement Extras

Intent.EXTRA_REPLACEMENT_EXTRAS

This lets you supply alternative extras per app. For Lollipop and beyond, this should be used instead of INITIAL_INTENTS when all you want to do is provide different data per app.

Here is an example of how to use it:

// Create the intent with the content you want to share
Intent shareIntent = new Intent(Intent.ACTION_SEND)
.putExtra("extraA", valueA)
.putExtra("extraB", valueB)
.setType(“text/plain”);
// Create a chooser intent with it
Intent chooser = Intent.createChooser(shareIntent, null);
// Make the replacements bundle, add it to the chooser
Bundle replacements = new Bundle();
chooser.putExtra(Intent.EXTRA_REPLACEMENT_EXTRAS, replacements);
// For each app you want to supply alternative extras,
// create a bundle, adding it to the replacements
// with the package name of the app as the key
Bundle twitterExtras = new Bundle();
replacements.putBundle(“com.twitter.android”, twitterExtras);
twitterExtras.putString("extraA", twitterValueA);
twitterExtras.putString("extraC", twitterValueC);
// Show the Share Menu
startActivity(chooser);

In the example above, if the user selects Twitter, then Twitter will receive any extras included in the original shareIntent, plus any additional ones in twitterExtras. It will also replace any in the original intent with the same key name. So Twitter would end up getting:

  • extraA : twitterValueA
  • extraB : valueB
  • extraC : twitterValueC

Apps that don’t have replacement extras specified will get the extras from shareIntent like normal.

This lets you supply app specific data without interfering with the Share Menu order.

Summary TL;DR

As promised, here is a photo of a corgi puppy playing cards that has nothing to do with Intents or Share Menus.

The Share Menu is organized by the time spent in each app. If you leave an app open for a long time it will move up in the list. The number of times you share to an app does not have an effect. If 90% of your shares go to a specific app, but you don’t spend a lot of time with it open, it won’t stay at the top of the list.

Also, app developers can set what options appear at the top of a Share Menu shown to you from their app.

Some apps manipulate this method in order to share different data, depending on the app you select from their Share Menu. Such as sending a shorter snippet to SMS and a longer one to email clients. This has the unintended consequence of changing the order of their menu. Thankfully, Lollipop added a new feature that developers can use to share app-specific data without breaking the ordering of the new Share Menu.

I’m the Android Lead at Pocket. I also created Fliktu to make sharing better on Android. I occasionally write about Android. This post was just a clever ruse to get you to look at a photo of my dog.
Follow me here on Medium or
Twitter.

--

--