Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to develop Slices apps

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

How to develop Slices apps

More Decks by Daichi Furiya (Wasabeef)

Other Decks in Programming

Transcript

  1. Gradle buildscript { repositories { google() } dependencies { classpath

    'com.android.tools.build:gradle:3.2.0-alpha15' } } // ... dependencies { implementation 'androidx.slice:slice-core:1.0.0-alpha1' implementation ‘androidx.slice:slice-builders:1.0.0-alpha1' // ssIf you wanna use SliceView implementation 'androidx.slice:slice-view:1.0.0-alpha1' }
  2. AndroidManifest.xml <application ... <provider android:name=".MySliceProvider" android:authorities="jp.wasabeef.slices" android:exported="true"> <intent-filter> <action android:name="android.intent.action.VIEW"

    /> <category android:name="android.app.slice.category.SLICE" /> </intent-filter> </provider> <activity android:name=".MainActivity"> ... </activity> </application>
  3. AndroidManifest.xml <application ... <provider android:name=".MySliceProvider" android:authorities="jp.wasabeef.slices" android:exported="true"> <intent-filter> <action android:name="android.intent.action.VIEW"

    /> <category android:name="android.app.slice.category.SLICE" /> </intent-filter> </provider> <activity android:name=".MainActivity"> ... </activity> </application>
  4. AndroidManifest.xml <application ... <provider android:name=".MySliceProvider" android:authorities="jp.wasabeef.slices" android:exported="true"> <intent-filter> <action android:name="android.intent.action.VIEW"

    /> <category android:name="android.app.slice.category.SLICE" /> </intent-filter> </provider> <activity android:name=".MainActivity"> ... </activity> </application>
  5. AndroidManifest.xml <application ... <provider android:name=".MySliceProvider" android:authorities="jp.wasabeef.slices" android:exported="true"> <intent-filter> <action android:name="android.intent.action.VIEW"

    /> <category android:name="android.app.slice.category.SLICE" /> </intent-filter> </provider> <activity android:name=".MainActivity"> ... </activity> </application>
  6. SliceProvider class MySliceProvider : SliceProvider() { override fun onCreateSliceProvider(): Boolean

    = true override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path) { "/ping" -> { ListBuilder(context, sliceUri, ListBuilder.INFINITY) .addRow { it.setTitle("pong") } .build() } else -> null } } }
  7. SliceProvider class MySliceProvider : SliceProvider() { override fun onCreateSliceProvider(): Boolean

    = true override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path) { "/ping" -> { ListBuilder(context, sliceUri, ListBuilder.INFINITY) .addRow { it.setTitle("pong") } .build() } else -> null } } }
  8. SliceProvider class MySliceProvider : SliceProvider() { override fun onCreateSliceProvider(): Boolean

    = true override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path) { "/ping" -> { ListBuilder(context, sliceUri, ListBuilder.INFINITY) .addRow { it.setTitle("pong") } .build() } else -> null } } }
  9. SliceProvider class MySliceProvider : SliceProvider() { override fun onCreateSliceProvider(): Boolean

    = true override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path) { "/ping" -> { /** content://jp.wasabeef.slices/ping **/ } "/open" -> { /** content://jp.wasabeef.slices/open **/ } "/map" -> { /** content://jp.wasabeef.slices/map **/ } "/dog" -> { /** content://jp.wasabeef.slices/dog **/ } "/cat" -> { /** content://jp.wasabeef.slices/cat **/ } else -> null } } }
  10. SliceProvider class MySliceProvider : SliceProvider() { override fun onCreateSliceProvider(): Boolean

    = true override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path) { "/ping" -> { ListBuilder(context, sliceUri, ListBuilder.INFINITY) .addRow { it.setTitle("pong") } .build() } else -> null } } }
  11. SliceProvider class MySliceProvider : SliceProvider() { override fun onCreateSliceProvider(): Boolean

    = true override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path) { "/ping" -> { ListBuilder(context, sliceUri, ListBuilder.INFINITY) .addRow { it.setTitle("pong") } .build() } else -> null } } }
  12. SliceProvider class MySliceProvider : SliceProvider() { override fun onCreateSliceProvider(): Boolean

    = true override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path) { "/ping" -> { ListBuilder(context, sliceUri, ListBuilder.INFINITY) .addRow { it.setTitle("pong") } .build() } else -> null } } }
  13. Basic Sample OK $ adb shell am start -a android.intent.action.VIEW

    \ -d slice-content://jp.wasabeef.slices/ping NG $ adb shell am start -a android.intent.action.VIEW \ -d slice-content://jp.wasabeef.slices/hoge
  14. SliceAction override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path)

    { "/open" -> createOpenActivity(sliceUri) else -> null } } private fun createOpenActivity(sliceUri: Uri): Slice { return ListBuilder(context, sliceUri, ListBuilder.INFINITY) .addRow { it.apply { setTitle("Perform action in app") setPrimaryAction(createActivityAction()) } }.build() } private fun createActivityAction(): SliceAction { val intent = Intent(context, MainActivity::class.java) return SliceAction(PendingIntent.getActivity(context, 0, intent, 0), IconCompat.createWithResource(context, R.mipmap.ic_launcher), "Open MainActivity.") }
  15. SliceAction override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path)

    { "/open" -> createOpenActivity(sliceUri) else -> null } } private fun createOpenActivity(sliceUri: Uri): Slice { return ListBuilder(context, sliceUri, ListBuilder.INFINITY) .addRow { it.apply { setTitle("Perform action in app") setPrimaryAction(createActivityAction()) } }.build() } private fun createActivityAction(): SliceAction { val intent = Intent(context, MainActivity::class.java) return SliceAction(PendingIntent.getActivity(context, 0, intent, 0), IconCompat.createWithResource(context, R.mipmap.ic_launcher), "Open MainActivity.") }
  16. SliceAction package androidx.slice.core; ... /** * Interface for a slice

    action, supports tappable icons, custom toggle icons, * and default toggles. */ public interface SliceAction { @Nullable SliceAction setContentDescription(@NonNull CharSequence description); SliceAction setChecked(boolean isChecked); SliceAction setPriority(@IntRange(from = 0) int priority); @Nullable PendingIntent getAction(); @Nullable IconCompat getIcon(); @Nullable CharSequence getTitle(); @Nullable CharSequence getContentDescription(); int getPriority(); boolean isToggle(); boolean isChecked(); @SliceHints.ImageMode int getImageMode(); boolean isDefaultToggle(); }
  17. SliceAction /** * Construct a SliceAction representing a tappable icon.

    * * @param action the pending intent to invoke for this action. * @param actionIcon the icon to display for this action. * @param actionTitle the title for this action, also used for content description * if one hasn't * been set via {@link #setContentDescription(CharSequence)}. */ public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon, @NonNull CharSequence actionTitle) { this(action, actionIcon, ICON_IMAGE, actionTitle); }
  18. Primary Action Sample http://www.meg-snow.com/products/ $ adb shell am start -a

    android.intent.action.VIEW \ -d slice-content://jp.wasabeef.slices/open
  19. GridRow class MySliceProvider : SliceProvider() { override fun onCreateSliceProvider(): Boolean

    = true override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path) { "/ping" -> { ListBuilder(context, sliceUri, INFINITY) .addRow { it.setTitle("pong") } .build() } else -> null } } } http://www.meg-snow.com/products/
  20. GridRow class MySliceProvider : SliceProvider() { override fun onCreateSliceProvider(): Boolean

    = true override fun onBindSlice(sliceUri: Uri): Slice? { return when (sliceUri.path) { "/ping" -> { ListBuilder(context, sliceUri, INFINITY) .addRow { it.setTitle("pong") } .build() } else -> null } } }
  21. GridRow return ListBuilder(context, sliceUri, INFINITY) .addGridRow { it.apply { addCell

    { // title, image, intent …etc } addCell { // title, image, intent …etc } addCell { // title, image, intent …etc } } }.build() http://www.meg-snow.com/products/
  22. SliceView http://www.meg-snow.com/products/ http://www.meg-snow.com/products/ val sliceUri = Uri.parse("content://jp.wasabeef.slices/open") // Sync val

    manager = SliceManager.getInstance(context!!) sliceView.slice = manager.bindSlice(sliceUri) // Async and LiveData SliceLiveData.fromUri(context, sliceUri) .observe(this, Observer({ sliceResult -> sliceView.slice = sliceResult }))