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.