Office Hours — Today, March 4

Tuesday, March 2

Mar 4
8:20 AM
Mark M.
has entered the room
Mark M.
turned on guest access
8:40 AM
Tad F.
has entered the room
Tad F.
Hi Mark!
Mark M.
hello, Tad!
how can I help you today?
957458041@qq.com
has entered the room
Tad F.
I have a "mystery" I hope you can help me solve, which is about why implicit intents aren't resolving correctly on some devices.
Mark M.
(BTW, hello 957458041@qq.com -- I will be with you shortly!)
Tad F.
As you may remember, my app allows people to create "playlists" of photos and videos (and annotate them with voice-over, visual effects, etc.)
When the user wants to add to the playlist, they tap on a FAB for adding
This causes an intent to be created, which I pass along to the Android APIs to open up relevant apps to satisfy the intent based on media type
All this has been working well for over a year
Recently, I decided I wanted to augment the choice of what the user can choose - I went from creating an implicit intent to resolve to a camera, video and file chooser...
to also wanting to include the ability for the user to indicate they want to choose from my app's library, or create what I call a "section header"
This all worked great also -here is an example:
8:45 AM
Tad F.
Mark M.
I assume that bottom sheet is yours?
Tad F.
The "Camera", "Camcorder" and "Files" have been there all along. The "Section Heading" and "Library" are new
No - that bottom sheet is automatically popped up by Android, based on my intents
Example:
View paste
    public static Intent createFilePictureVideoChooserIntent(boolean allowChoosingMultipleFiles, boolean allowVideo, boolean allowLibrary, boolean allowSectionHeader) {
        Context context = InTouch.getInstance().getApplicationContext();
        Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);

        // Set up for choosing files
        Intent contentSelectionIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
        contentSelectionIntent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
        contentSelectionIntent.addFlags(URI_PERMISSIONS_FLAGS);
        contentSelectionIntent.setType("*/*");
        if ( allowVideo ) {
            contentSelectionIntent.putExtra(Intent.EXTRA_MIME_TYPES, getSupportedMediaMimeTypes());
        } else {
            contentSelectionIntent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {getImageMimeType().toLowerCase() + "/*"});
        }
Mark M.
that's interesting -- I have never seen one formatted that way
Tad F.
The above all works great on all devices
My problem started when I wanted to have Android add icons in that chooser window for my two other choices - "My Library" and "Section Header"
Here is what I did:
I added these to the manifest:
View paste
        <activity
            android:name=".ui.LibraryChooserStub"
            android:exported="false">
            <intent-filter
                android:icon="@drawable/ic_library"
                android:label="@string/nav_title_library">
                <action android:name="SIT_Library" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
Then in that same method I do this:
(that builds the chooser intent)
View paste (8 more lines)
        boolean addedLibrary = false;
        Realm libraryRealm = null;
        try {
            libraryRealm = InTouchDataMgr.get().getRealm();
            if (allowLibrary && InTouchDataMgr.get().getMediaCount(libraryRealm) > 0) {
                // Add Intent for the library
                intentArrayList.add(new Intent(LIBRARY_ACTION));
                addedLibrary = true;
            }
        } catch (Exception ignore ) {
        } finally  {
            InTouchDataMgr.get().closeRealmSafely(libraryRealm);
        }
        if ( allowSectionHeader ) {
            // Add Intent to create a new Section Header
...
So after all this - I have intents loaded that should drive Android to match them to the stubs I declare in my manifest
And all those activities do is return back their same action:
View paste
public class LibraryChooserStub extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setResult(RESULT_OK, new Intent(LIBRARY_ACTION));
        finish();
    }
}
So in the class that is handling the result of the chooser, I can test for that and take the appropriate action
8:50 AM
Tad F.
Basically, I wanted the same user experience whether it was to choose a file, take a photo, take a video, or choose from the app library or insert a "section header" into the playlist.,
And all this works great on most, but not all, devices.
Pixel 4 for example - that exact same code results in this:
My latter two icons/choices are not shown at all???
Why on some and not others, particularly why not on the newest hardware?
Mark M.
as an experiment have you tried marking them as exported?
Tad F.
It's like the implicit intent resolution isn't working
I have not
Was just about to
Mark M.
when I saw that manifest entry, that jumped out at my
er, at me
personally, I have not tried messing with the sharesheet anywhere near to this extent
Tad F.
ok I can try that real quick if you want to move on to 957...@qq.com?
Mark M.
that sounds good -- I will be back with you in a bit
957458041@qq.com: your turn! do you have a question?
8:55 AM
Mark M.
957458041@qq.com if you have a question, go ahead!
Tad F.
Mark - I'm not sure whether that caused a separate issue or not. I tried it on a Pixel 3 emulator, and this is what I get (those two icons are NOT the ones specified in the manifest, they are the app icon!):
Mark M.
Tad: not sure what happened with your screenshot there, but the share sheet is nearly unreadable
Tad F.
Right
Mark M.
you mentioned the icon being your app icon -- is the caption under it your app title?
Tad F.
That's exactly the way it looks onscreen!
Mark M.
OK, that's very strange, though I rarely test on emulators
Tad F.
Yes the caption under that is the app title
It's like it is using some weird font
Mark M.
the icons seem blurry, so I assumed there was some rendering issue
9:00 AM
957458041@qq.com
has left the room
Mark M.
anyway, AFAIK, the share sheet is not designed for what you're trying to do
it's designed for starting generally-available activities, not private ones (non-exported)
in principle, your approach (with the activities being exported) should work, though you run a slight risk of other apps starting those activities
Tad F.
Interesting that it works on many devices though as private...
If other apps start those activities they are gonna be unimpressed, as all they do is return a string :)
Mark M.
today, that might be what they do -- you would have to bear in mind about this effect, though, in future work
you don't want a security problem because of your desire to use the system share sheet
Tad F.
My other option from a UI perspective I suppose is to have the "Create Section Header" and "Choose from App Library" be menu options instead of share sheet options.
I just thought it would be a better user experience to do it all from the same spot.
Since they all have to do with populating the playlist
Mark M.
a third option would be to render your own bottom sheet rather than using the system share sheet, though that gets icky on Android 11+
Tad F.
Maybe a better option would be for the FAB to actually open up into a different set of choices.
Mark M.
you could use the floating action menu pattern
Tad F.
Give me a sec I'll show you what I mean and get your opinion
9:05 AM
Mark M.
have tapping the FAB open a fly-out set of options, with section header, app library, and media being three of those options
Tad F.
Exactly what I was thinking
here is what I do when a user wants to annotate a photo. Here is the photo with the "menu fab":
Mark M.
I don't recall the Material Components for Android library having FAM support for its FAB, though there at least were third-party libraries offering FABs and FAMs
Tad F.
And here is what happens when they tap it:
I just wrote all the logic for the fly out/fly in myself.
Mark M.
cool! lotta options, though
Tad F.
Yeah - I have a rather elaborate help system that assists them through creating their first annotated photo, hopefully that is helpful!
So back to my problem - rather than the "add media" FAB launching the chooser, I suppose I could do the same as above, with the five options flying out and they pick one, and then it folds itself back...
It's just a little non-standard.
For a picker
Mark M.
agreed
Tad F.
Thanks for helping me think through it - I think it is a better solution than exporting the activity stubs.
Mark M.
the most reliable solution for you to do the picker that you want is to render it yourself, using queryIntentActivities() on PackageManager to find out what all handles those public Intent structures, so you know what options to show in your sheet
9:10 AM
Mark M.
the downside is that on Android 11+ you will need to have a <queries> element in your manifest to tell Android that you want to be able to do that, for those particular Intent structures
basically, Google is trying to crack down on the privacy issues tied into being able to know what other apps are around
Tad F.
Yes, right now I'm determining whether there is anything on the device that can take a photo or video, and only adding those intents if there is.
I did make the assumption that a file chooser would always be available.
Is that not a valid assumption?
Mark M.
not necessarily -- on a multi-user device, the particular user will not always have access to that (e.g., child on a restricted profile, employee on a restricted device)
Tad F.
OK good point.
Mark M.
so, you have a few options, which generally will be more work, but give you more control and limit the risks of making an overly-complex request for a share sheet
9:15 AM
Tad F.
Yeah, given I am doing the FAM in the photo annotation area of the app, I'll just incorporate it here as well.
Thanks for your help!
Mark M.
you're welcome!
Tad F.
Btw - are you on AS 4.2?
I generally don't update until at least RC1, but was curious how it is behaving
Mark M.
my "daily driver" is 4.1.2 -- I also have the long-named canary around for Compose work
I played with AS 4.2 through its canary releases, also for Compose
Tad F.
I feel like the editor has gotten slower over the last few releases - seems like it is doing on *lot* of background work these days...
Mark M.
yeah, I can see that, though it helps encourage you to keep file sizes down... :-)
Tad F.
I have an 8 core laptop with 32GB of ram and reasonably fast disk, and it still seems sluggish at times...
Good point, I must admit that my "InTouchUtils.java" file (all my public static methods) has gotten pretty large
It takes AS a good 5-7 seconds to do its lint scan on the whole thing.
Mark M.
oof
9:20 AM
Mark M.
and bear in mind that Google is Kotlin-first, which means their optimization work may tend to affect Kotlin source more than Java source
a lot will be language-independent, but not necessarily everything
Tad F.
Yeah - leaning Kotlin is next on the list, once we get this app out to public beta
Do you enjoy it more than Java? Feel you're more productive? Or just you know you need to do it since Google is pushing it so hard?
Mark M.
at this point, I like it better than Java 7/8
now, Java has proceeded far from there, and I am not up on all of its changes, so I cannot comment on modern Java
Tad F.
OK - gonna sign off now, thanks again!
Mark M.
happy to help!
9:30 AM
Mark M.
OK, that's a wrap for today's chat -- next one is Saturday at 4pm US Eastern
have a pleasant day!
Tad F.
has left the room
Mark M.
turned off guest access

Tuesday, March 2

 

Office Hours

People in this transcript

  • 957458041@qq.com
  • Mark Murphy
  • Tad Frysinger