Kembali ke Dev Logs

OSS Contributions / 7 menit baca

Making Amaze Discoverable as a File Manager on Android TV

This article covers the analysis and fix for Amaze File Manager issue #4079, where Amaze was installed on Android TV but other applications still reported that no file manager was available.

Status at the time of writing: the implementation and local verification are complete and ready for a pull request. The change is not part of an official release until it has been reviewed and merged by the maintainers.

Summary

The problem occurred because Amaze only advertised ACTION_GET_CONTENT as a file-selection contract. Some Android TV applications and firmware use ACTION_OPEN_DOCUMENT when looking for a file picker. Android therefore did not include Amaze among the matching handlers even though the application was installed.

The fix has three parts:

  1. Advertise ACTION_OPEN_DOCUMENT on MainActivity.
  2. Route that action through Amaze's existing file-selection flow.
  3. Add regression tests for manifest resolution and file-picking mode.

Tests on two physical devices showed Amaze alongside Material Files in the Android resolver. After selecting ALWAYS, a subsequent OPEN_DOCUMENT request launched Amaze directly without showing the resolver again.

The Android TV Problem

The issue reporter used Android TV devices, including devices such as Chromecast, that do not always ship with a file manager. Amaze could be installed and launched normally, but other applications continued to claim that no file manager was installed.

Material Files was discovered on the same device. This difference suggested that the problem was not TV launcher support, but the intent contracts advertised by each application.

Android does not provide a universal system role named “default file manager.” In the context of this issue, the term means that:

  • Amaze is discovered as a document-selection handler;
  • Amaze appears in the Android resolver;
  • the user can select ALWAYS so matching intents are routed directly to Amaze;
  • the selected file is returned to the calling application.

Root Cause Investigation

Before the fix, MainActivity already supported several relevant intents:

  • MAIN, LAUNCHER, and LEANBACK_LAUNCHER for normal startup;
  • ACTION_GET_CONTENT for file selection;
  • VIEW for opening supported files;
  • SEND and SEND_MULTIPLE for sharing files.

However, the manifest did not advertise ACTION_OPEN_DOCUMENT. The MainActivity implementation also enabled result-returning mode only when it received ACTION_GET_CONTENT.

Adding an intent filter alone would not be sufficient. If Amaze appeared in the resolver without entering file-picker mode, selecting a file could open it normally instead of returning it to the caller.

The root cause therefore had two parts:

  1. Discovery: Android could not find Amaze for ACTION_OPEN_DOCUMENT.
  2. Behavior: MainActivity did not recognize ACTION_OPEN_DOCUMENT as a request to select and return a file.

Implementing the Fix

1. Advertising ACTION_OPEN_DOCUMENT

The following filter was added to MainActivity:

<intent-filter>
    <action android:name="android.intent.action.OPEN_DOCUMENT" />
    <data android:mimeType="*/*" />
    <category android:name="android.intent.category.OPENABLE" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

The / MIME type allows the filter to match callers requesting any file type. Android can also match it when a caller requests a more specific type such as image/*.

2. Using one helper for file-picker intents

Action recognition was centralized in a small helper:

private static boolean isFilePickerIntent(@Nullable String actionIntent) {
  return Intent.ACTION_GET_CONTENT.equals(actionIntent)
      || Intent.ACTION_OPEN_DOCUMENT.equals(actionIntent);
}

The helper is used by both permission handling and checkForExternalIntent(). As a result, GET_CONTENT and OPEN_DOCUMENT share the same behavior without duplicating conditions.

Using the existing Intent.ACTION_* constants also avoids introducing hardcoded action strings. This change adds no new user-facing text.

3. Reusing the existing URI result flow

Amaze already had a mechanism to:

  • enable mReturnIntent;
  • select one or more files;
  • create URIs for selected files;
  • grant read permission;
  • return the result and finish the Activity.

The fix reuses this mechanism instead of creating a second file picker. This keeps the change small and preserves the existing GET_CONTENT behavior.

Why Not Add OPEN_DOCUMENT_TREE?

ACTION_OPEN_DOCUMENT_TREE selects a directory tree rather than a file. It has a different result contract and normally requires a tree URI and persistable permissions.

ACTION_CREATE_DOCUMENT and a full DocumentsProvider implementation are also separate features with a much larger scope.

Issue #4079 can be reproduced through ACTION_OPEN_DOCUMENT. Advertising additional contracts without fully implementing them could make Amaze appear for workflows it cannot correctly complete.

Regression Tests

The new tests verify two essential behaviors:

  1. Package manager resolution finds MainActivity for ACTION_OPEN_DOCUMENT, the OPENABLE category, and the / MIME type.
  2. Launching the Activity with ACTION_OPEN_DOCUMENT enables mReturnIntent without enabling ringtone-picker mode.

Related result tests also verify that:

  • selecting one file returns one URI;
  • selecting multiple files returns a collection of URIs;
  • null results or files that cannot be converted do not crash the application.

The local verification commands were:

./gradlew :app:testFdroidDebugUnitTest \
  --tests com.amaze.filemanager.ui.activities.MainActivityTest \
  --tests com.amaze.filemanager.ui.fragments.MainFragmentReturnIntentResultsTest

./gradlew spotlessCheck
./gradlew assembledebug assembleFdroidDebug
```

The targeted tests, formatting check, and both builds completed successfully.

Physical Device Verification

The fix was tested on two devices running different Android versions:

DeviceSystemAPIResult
Polytron PLD 43S883MBNAndroid TV 7.1.225Passed
Amlogic Media Player Android BoxAndroid 928Passed

Testing used the F-Droid debug variant:

adb install -r app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk

Inspecting resolver registration

The installed manifest was inspected with:

adb shell dumpsys package com.amaze.filemanager.debug \
  | sed -n '/Activity Resolver Table:/,/Receiver Resolver Table:/p' \
  | rg -C 6 'OPEN_DOCUMENT|GET_CONTENT'

The picker was then launched with:

adb shell "am start -W \
  -a android.intent.action.OPEN_DOCUMENT \
  -c android.intent.category.OPENABLE \
  -t '*/*'"

The complete remote command is passed as one string so that the device shell does not expand the / wildcard.

On the API 28 Android Box, the resolver displayed Amaze Debug alongside Material Files. This is direct evidence that Amaze was discovered for the previously unsupported contract.

Verifying the default handler

Amaze was selected in the resolver and the ALWAYS button was used. The next request produced:

Activity: com.amaze.filemanager.debug/com.amaze.filemanager.ui.activities.MainActivity

ResolverActivity was no longer shown. Amaze had become the default handler for that action, category, and MIME-type combination.

Successful Test Scenarios

Manual verification covered:

  • a cold OPEN_DOCUMENT request with /;
  • OPEN_DOCUMENT with specific MIME types such as image/* and PDF;
  • the existing GET_CONTENT flow;
  • single-file selection;
  • selecting two files with EXTRA_ALLOW_MULTIPLE;
  • delivering an intent to an existing MainActivity instance;
  • D-pad navigation;
  • cancellation with the Back button;
  • selecting a file after Amaze became the default handler;
  • logcat inspection for crashes and ANRs.

An APK was selected as a document on the Android Box. Amaze finished and returned to the launcher without opening the package installer. This matters because file-picker mode must return a file as a result rather than execute it.

The tests found no:

  • FATAL EXCEPTION;
  • ANR;
  • SecurityException;
  • unintended image viewer, media player, or package installer launch.

An ADB shell command is not an Activity caller that can directly inspect the returned result URI. The shape of single- and multiple-selection results is therefore also covered by Robolectric tests. Testing with the reporter's original calling application remains a useful additional check when that application is available.

Impact and Regression Risk

The implementation changes only:

app/src/main/AndroidManifest.xml
app/src/main/java/com/amaze/filemanager/ui/activities/MainActivity.java
app/src/test/java/com/amaze/filemanager/ui/activities/MainActivityTest.kt

There are no UI, database, data-model, filesystem-operation, or launcher-navigation changes. GET_CONTENT, normal launcher startup, and LEANBACK_LAUNCHER retain their existing behavior.

The primary risk is advertising an action that the application cannot actually complete. The fix addresses this by routing OPEN_DOCUMENT through the URI-returning flow and adding tests that confirm file-picker mode is active.

Conclusion

Issue #4079 was not caused by Amaze being unable to run on Android TV. It was caused by an incomplete set of advertised file-picker intent contracts. By adding ACTION_OPEN_DOCUMENT and routing it through the existing result flow, Amaze can be discovered, selected, and configured as the default matching handler on the tested Android TV and Android Box devices.

The implementation is small, covered by regression tests, passes builds and formatting checks, and has been verified on two physical devices. The remaining contribution steps are opening the pull request, waiting for repository CI, and addressing maintainer review.

References