'Android Slice Provider Failed to find provider info

I'm trying to build a Slice host app A that can display Slices defined at uris provided by other apps, lets say one other app B. I know this functionality is possible because the SliceViewer.apk works fine here: https://developer.android.com/guide/slices/getting-started

A's fragment that is loading the slice into a SliceView

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)

            val sliceView = view.findViewById<SliceView>(R.id.slice)

            context?.let { ctx ->

                val uri = Uri.parse("content://org.test.plugin2/")
                val intent = Intent(Intent.ACTION_VIEW, uri).apply {
                    //component = ComponentName("org.test.plugin2", "org.test.plugin2.MySliceProvider")
                    //setPackage("org.test.plugin2")
                }

                SliceLiveData.fromIntent(ctx, intent).observe(viewLifecycleOwner) { slice ->
                    sliceView.slice = slice
                }
            }
        }

App B provider manifest definition:

<provider
            android:name=".MySliceProvider"
            android:authorities="org.test.plugin2"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.app.slice.category.SLICE" />

                <data
                    android:host="plugin2.test.org"
                    android:pathPrefix="/"
                    android:scheme="https" />
            </intent-filter>
        </provider>

App B's Slice provider implementation:

class MySliceProvider : SliceProvider() {
    /**
     * Instantiate any required objects. Return true if the provider was successfully created,
     * false otherwise.
     */
    override fun onCreateSliceProvider(): Boolean {
        return true
    }

    /**
     * Converts URL to content URI (i.e. content://org.test.plugin2...)
     */
    override fun onMapIntentToUri(intent: Intent): Uri {
        // Note: implementing this is only required if you plan on catching URL requests.
        // This is an example solution.
        var uriBuilder: Uri.Builder = Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
        if (intent == null) return uriBuilder.build()
        val data = intent.data
        val dataPath = data?.path
        if (data != null && dataPath != null) {
            val path = dataPath.replace("/", "")
            uriBuilder = uriBuilder.path(path)
        }
        val context = context
        if (context != null) {
            uriBuilder = uriBuilder.authority(context.packageName)
        }
        return uriBuilder.build()
    }

    /**
     * Construct the Slice and bind data if available.
     */
    override fun onBindSlice(sliceUri: Uri): Slice? {     
        val context = context ?: return null
        return createHelloWorldSlice(context, sliceUri)
    }

    private fun createHelloWorldSlice(context: Context, sliceUri: Uri): Slice {
        return list(context, sliceUri, ListBuilder.INFINITY) {
            header {
                title = "Hello World"
            }
        }
    }
}

Slice dependencies

 implementation 'androidx.slice:slice-view:1.1.0-alpha02'
 implementation 'androidx.slice:slice-builders-ktx:1.0.0-alpha6'
 implementation 'androidx.annotation:annotation:1.4.0-alpha02'

From my understanding of the documentation the Hello world row should be populating in my app's fragment layout using the Slice View, here is the layout just for record:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent">

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <androidx.slice.widget.SliceView
                android:id="@+id/slice"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="@dimen/margin_medium"
                android:layout_marginEnd="@dimen/margin_medium"
                android:layout_marginStart="@dimen/margin_medium"
                android:layout_marginTop="@dimen/margin_medium"
                android:background="@color/cardview_light_background"
                android:elevation="@dimen/slice_elevation"
                android:paddingEnd="@dimen/margin_small"
                android:paddingStart="@dimen/margin_small" />
        </FrameLayout>
    </ScrollView>

</androidx.constraintlayout.widget.ConstraintLayout>

I'm also seeing

E/ActivityThread: Failed to find provider info for org.test.plugin2

I can reproduce this by installing app A (host), installing app B (plugin with Slice Provider), switching back to A and I see the error message, and no slice!

Which seems to be the underlying issue. As you can see in the commented code I tried to explicitly set the package name and component which did not help.

Any help or alternative suggestion is much appreciated, thanks.



Solution 1:[1]

Decrementing the targetSdk from 31 to 27 fixed this. Looking at this code from SliceProvider:

  @Nullable
    @Override
    public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
        if (Build.VERSION.SDK_INT < 19 || Build.VERSION.SDK_INT >= 28) return null;
        if (extras == null) return null;
        return getSliceProviderCompat().call(method, arg, extras);
    }

Then there's this comment above the function: "Handles the call to SliceProvider. This function is unsupported for sdk < 19. For sdk 28 and above the call is handled by android.app.slice.SliceProvider"

Not sure exactly how its handled because it is working for SDK 28 as well.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1