With over 14 years of iteration under its belt, Google has had a lot of time to make Android a polished mobile operating system. Google continues to address pain points in the Android experience with each new release, but one aspect that many users still complain about is the share menu. In fact, I’ve seen people complain about Android’s share menu when it isn’t even relevant to the conversation.
Fortunately, Google does seem to be aware of these complaints and is taking a big step in addressing them. Google is working on turning Android’s system share sheet into a new modular system component that could launch in Android 14. In this edition of Android Dessert Bites, I’ll be talking about how Google could fix one of the biggest problems with the Android Sharesheet.
How the Android Sharesheet works
One of Android’s best features is its intent system. Intents are how apps share data with one another, such as text, images, documents, links, or files. Apps define which intents they can handle so the system knows which apps can handle certain types of data. For example, an app that can open PDF files can register an intent filter in its Manifest that tells the system it can handle PDFs; when the user then goes to open a PDF file using, say, a file manager app, an intent containing the path to the PDF file is forwarded to the app that handles those files.
If there are multiple apps installed on the device that can handle PDF files (there usually are), the system decides which one to forward the intent to by displaying a disambiguation dialog called the intent resolver. The intent resolver lets the user pick which app should handle the intent, as shown below.
Android generally lets third-party applications become the default handler for a myriad of common app intents, and this is even enforced by the CDD. This intent system is a large part of what makes Android so extensible as a platform. There are, however, certain intents that are reserved for system apps, such as the one for invoking the system file picker/Photo Picker (ACTION_GET_CONTENT). Another intent that’s reserved for the system is ACTION_CHOOSER because it’s handled by the Android Sharesheet.
The Android Sharesheet is a system activity that lets the user pick which app to share data with, much like the Android intent resolver. Unlike the Android intent resolver, though, the Android Sharesheet doesn’t let users set a default handler, so users will always see the disambiguation dialog and always have to pick which app to share data with. The Android Sharesheet is thus better suited for sharing data that doesn’t have a well-defined target.
For example, when a user wants to share an image with a friend, the user can pick the particular social media or messaging app their friend is on from among the apps that tell the system they can handle image content. The Android Sharesheet exists because the user may want to share an image with one friend in a particular app and then share a different image with a second friend in another app. The Android intent resolver isn’t really suited for this kind of data sharing, as the user would need to repeatedly set and unset defaults or decline to set a default each time they want to share.
The Android Sharesheet also has a number of extra features that facilitate sharing data with the right app or contact. Apps can publish “Direct Share” targets that can be shown near the top of the share menu. A Direct Share target can, for example, let the user share content directly with a particular contact. The system can show up to 8 Direct Share targets at a time; Direct Share targets are selected and ranked according to a prediction service that shows targets the user is more likely to use, though the efficacy of this ranking system is frequently criticized online. Fortunately, users can manually pin Direct Share targets as well as regular share targets in the Android Sharesheet. Lastly, the Sharesheet can show text and image previews as well as chips to launch Google’s Nearby Share service or the system image editor.
The share menu is usually launched when a user taps a “share” button placed within an app. The app then invokes the Android Sharesheet by creating and sending an ACTION_CHOOSER intent that wraps an ACTION_SEND intent. The share targets that appear in the share menu are determined by which apps can handle the ACTION_SEND intent and the data’s MIME type. In the above screenshots, for example, only the apps that can handle the ACTION_SEND intent and the ‘image/png’ MIME type appear in the share menu.
The problems with the Android Sharesheet
One of the biggest problems with the Android Sharesheet before Android 10 was its performance. It used to be really slow at populating Direct Share targets. The reason why is that the share menu used to retrieve results reactively on demand, as in, it would pull Direct Share targets every time the share menu was invoked.
This “pull” model was replaced with a “push” model in Android 10 that was significantly faster. The older ChooserTargetService Direct Share APIs were replaced with the new Sharing Shortcuts API that lets apps publish their Direct Share targets in advance. As a result, the system can cache Direct Share targets so that they don’t have to be retrieved every time the share menu is opened.
The slow performance of the share menu prior to Android 10 is part of the reason why many apps eschewed the system Sharesheet in favor of a custom one. Most developers want to give their users a good experience, so many apps launch their own share menus when the user presses the in-app share button. These custom share menus lack some of the capabilities of the system Sharesheet such as the ability to show Direct Share targets and the work profile tab, but they could be significantly faster to launch than the system one. Yet, even after the system share menu’s performance problem has been mostly resolved, many apps continue to deploy their own share menus.
As you can tell, there’s little visual consistency among these custom share menus. Most of them look nothing like the system share menu, let alone each other. That makes it harder to rely on muscle memory to pick the right option, slowing down the process of sharing content. So why do they deploy them? Well, the issue is that the system share menu treats every app the same.
Let’s take Twitter as an example. If I open a tweet and hit the share button, Twitter’s custom share menu prominently shows me options to share the tweet’s URL via a direct message with another user on the platform (with some suggestions on who to DM at the top) or as a separate tweet on my profile. I’m also given the option to save the tweet to my bookmarks, copy the link to the clipboard, or share the link with a handful of apps that Twitter chooses to show.
There’s also a “share via” button that, when tapped, opens the system share menu. Since I’m sharing a URL, the system share menu queries which activities can handle the ACTION_SEND intent with the ‘text/plain’ MIME type. Twitter has two activities that can handle this: the DM activity and the tweet compose activity, and both of these appear in the system share menu as share targets. However, they appear towards the bottom of the system share menu for me, because I have a lot of apps installed on my device and the list is sorted alphabetically. That’s a problem for Twitter as it wants to show users options that would keep them on the platform for longer.
Apps used to be able to game the system by specifying labels for their activities that, when sorted alphabetically, would be placed at the very top of the share menu. Google cracked down on this practice in Android 10, however, so now share targets are always sorted alphabetically by the app’s name. Android 11 then implemented app stacking in the Sharesheet so that share targets from the same app would be stacked into a single target.
Sure, Twitter could use the Sharing Shortcuts API to implement these actions as Direct Share targets, allowing them to appear higher up in the share sheet. However, there’s no guarantee those targets will appear, as the system controls the ranking of Direct Share targets.
A great solution to this problem was brought up by Manuel Vonau in this Android Police article over a year ago. If the system share menu offers a dedicated section near the top for the app that invoked the share menu to place whatever share targets it wants, then many apps won’t need their own custom share menus anymore.
This wouldn’t fully eliminate custom share menus on Android, though. Some apps will continue to implement them as they can’t integrate certain things into the system share menu as share targets, or they want to maintain visual consistency in their share menus across devices.
One way Google could solve this problem is to introduce an embeddable system share menu component that apps could integrate into their own share menus. That way, apps could still provide their own share UI and the familiarity of the system share menu. I don’t know if this approach is one Google is considering, but regardless, there’s one major issue they have to resolve before they can do anything else: system share menus aren’t consistent across devices.
I’ve mentioned “Android Sharesheet” a lot, but I’ve only shown off the system share menu as it appears on a Pixel 6 Pro and Zenfone 9 running Android 13. The system share menu in ASUS’s ZenUI OS doesn’t look that different from the share menu in AOSP/Pixel, but if you look at the share menu on other OEM devices, you’ll notice a lot of differences. For comparison, here are screenshots showing the share menu in ZenUI, OneUI, AOSP/Pixel, OxygenOS, and MIUI.
There’s no provision in the CDD or GMS Requirements that enforces visual cohesion for the system share menu. The only things that are enforced are the inclusion of a prominent Nearby Share entry point in the share menu on devices with GMS, and that the Sharesheet API and API behavior work as expected. Apart from that, OEMs can customize the system share menu UI to their liking and add additional features. If Google wants to make the share menu experience more consistent in Android, they need to start by reigning in system share menu customization by OEMs. Fortunately, there’s evidence they might do just that.
Android 13's hidden "unbundled" system share menu
When Google released the Android 13 QPR1 beta, I noticed a new app called “IntentResolver” was included in the system image (specifically under /system/priv-app). Following the release of Android 13 QPR1’s source code, it became clear what this app was for: an implementation of Android’s “chooser” code (ie. the intent resolver and Sharesheet) that’s unbundled from the framework. This is confirmed by examining the code that Google made public following Android 13 QPR1’s release. Google forked the framework chooser code and all its dependencies to a new repository in AOSP, /packages/modules/IntentResolver.
Because it implements the same code, the new IntentResolver app is capable of handling the ACTION_CHOOSER intent. However, this new app currently does not handle the ACTION_CHOOSER intent on devices running Android 13 QPR1. This is because the component within the app that would handle the ACTION_CHOOSER intent is disabled by default.
The reason it’s disabled is that Google is still experimenting with whether or not they want to unbundle the intent resolver and Sharesheet code from the framework. As a result, the new unbundled “chooser” is hidden behind a flag called CHOOSER_UNBUNDLED. When this flag is enabled, SystemUI will enable the IntentResolver component that can handle the ACTION_CHOOSER intent. Because IntentResolver’s chooser component has a higher priority than its framework counterpart (500 versus 100), IntentResolver will then take over the handling of the ACTION_CHOOSER intent, similar to how the new Photo Picker is able to take over the ACTION_GET_CONTENT intent from the system file picker.
(The framework chooser component having a priority of ‘100’ is actually a rather new development. Its priority was raised to 100 in Android 12 to block third-party apps from replacing the system share menu.)
Here is a video demonstrating the new unbundled share menu on a Pixel 4 running an Android 13 QPR1 build compiled from source. As you can see, there’s no visual difference between the framework share menu and the unbundled share menu. This is to be expected since they share the same code. However, system logs reveal that the component handling the ACTION_CHOOSER intent indeed changes when the CHOOSER_UNBUNDLED flag is enabled.
While I only show the IntentResolver app handling the share menu in this video, it also handles, well, intent resolution as its name implies. It does, after all, contain the ResolverActivity class responsible for Android intent resolution as well as the ChooserActivity class responsible for the Android Sharesheet.
You might be wondering at this point: What’s the point in all this if it looks the same and does the same thing? Well, consider that the /packages/modules path in AOSP is where the source code repositories for each modular system component, ie. Project Mainline modules, reside. This is evidence that Google could turn IntentResolver into a new Project Mainline module in a future release, meaning it could receive updates directly from Google through Play System Updates. Right now, the system share menu can only be updated via a regular OTA update since it’s part of the framework package. Plus, OEMs can heavily customize the framework share menu, but they would be far more limited in what they can do to a Google-signed and provided module, outside of maybe some light theming through the use of Runtime Resource Overlays (RROs).
If Google shifts the Android Sharesheet to a Project Mainline module that they control, the system share menu will be much more consistent across Android devices. Plus, they’ll be able to experiment and make improvements much more quickly. Hopefully, this is the direction that Google is going, because the share menu experience is currently a mess on Android. However, we’ll have to wait and see whether Google continues to include this app in Android 14 builds and especially whether they decide to make this a part of Project Mainline.
Thanks for reading another Android Dessert Bites post! If you want to learn more about what goes on under the hood in the Android platform, check out some of the other posts in my Android Dessert Bites series on the Esper blog.