Android Slices with Kotlin: Getting Started

At Google I/O 2018, Google announced a new way to present UI templates that can display rich, dynamic and interactive content from your app within the Google Search app and, later, in other places such as the Google Assistant.

Those UI templates are called . The templates are great for many reasons:

  • Slices can help users to get information or take instant action outside of an app screen.
  • Slices make your users re-engage with your app in a relevant context.
  • Slices are built into Jetpack and can extend all the way back to Android Kitkat API 19.

Slices are in beta release at the time of writing this tutorial, but you can get developing with them today!

Getting Started

In this tutorial you are going to build a Slice template for a raywenderlich.com Bookstore app. The Slice will display some book covers with titles and prices, as well as a notification icon to enable or disable the app notification. Here’s what the end product will look like:

Finished Slice

Prerequisites: For this tutorial, you need basic knowledge of Android programming and familiarity with Kotlin and Android Studio. Knowledge of content providers and URIs is helpful but not required.

If you’re completely new to Android, you might want to first check out Beginning Android Development Part One. If you need to catch up on Kotlin, you can check out Kotlin for Android: An Introduction.

To follow along with this tutorial, you’ll need to use Android Studio 3.1.3 or later and Kotlin 1.2.30 or later.

Start by downloading the materials for this tutorial using the Download Materials button at the top or bottom of this page. Fire up Android Studio and import the starter project. For the most part, you will create your own classes. You will need to find AndroidManifest.xml to add code, so make sure you can locate that.

If you have not downloaded the SDK for Android API Level 28 previously, you’ll have to do that to run the app. If you already have Android API 28 set up, you can skip the following four steps and go right to building and running the app.

  1. Select Tools ▸ SDK Manager, or click the SDK Manager icon in toolbar.
  2. In the SDK Platforms tab, select Android API 28. You may need to select “Show Package Details” to see it.
    In the SDK Platforms tab, select Android 28.

    In the SDK Platforms tab, select Android SDK Platform 28.

  3. In the SDK Tools tab, select Android SDK Build-Tools 28-rc2 or higher. Again, you may need to select “Show Package Details.”
    In the SDK Tools tab, select Android SDK Build-Tools 28-rc2

    In the SDK Tools tab, select Android SDK Build-Tools 28-rc2

  4. Click OK to begin install.

Once the SDK is installed, build and run the app. It is a bookstore app, and it shows the available books on https://store.raywenderlich.com/.

Bookstore app

Slice Viewer

Android Teacher
Slices need a viewer or presenter to display their content.

The Google Search app is one of the suitable presenters to show your Slice template. When the user types a word in the search bar, the Slice you’ve created might present related information to the user’s search keyword.

For example, if the user types words such as “ride” or “ride car,” Slices from installed apps like Careem or Uber could show to let the user request a car even without opening the corresponding app; that full experience can be achieved by App Actions and Slices.

Displaying Your Slice With Slice Viewers

Bear in mind that presenters may make a light customization to your Slices to match their design requirements, e.g., font style, font size and/or colors. Icons in your Slice, for example, will be tinted with the accent color of the presenter app.

You will use a Slice Viewer app to display the Slice from your Bookstore app. The Slice Viewer app uses your slice Uri to view it on what’s called its surface, and on a first time request of your Slice, the user will be asked to grant a permission to the viewer.

Installing the Slice Viewer App

Install the SliceViewer.apk, which can be found in the downloaded materials for this tutorial, on a real device or emulator, then open the app. You can install the APK file by dragging and dropping the file onto the emulator if you’re using one or running adb install -r -t SliceViewer.apk from the terminal while in that directory. The Slice Viewer app looks like this:

Slice Viewer app

Creating the BookstoreSliceProvider Class

The starter project already includes the Slices core and builders libraries as dependencies in the app’s build.gradle file, so you can get started right away building your Slice:


implementation "androidx.slice:slice-core:1.0.0-beta01"
implementation "androidx.slice:slice-builders:1.0.0-beta01"

Create a new Kotlin class named BookstoreSliceProvider and make it inherit from the androidx.slice.SliceProvider class. Use the androidx option if available for any imports that you need to add for the rest of the tutorial.


import androidx.slice.SliceProvider

class BookstoreSliceProvider: SliceProvider() {

}

Implementing the SliceProvider Class

The SliceProvider class is your only way to expose your Slice to other apps, and it decides which Slice will be exposed to the viewer.

The SliceProvider class is a subclass of the ContentProvider class. Content providers are one of the primary building blocks of Android applications. They encapsulate data and provide it to applications through the single ContentResolver interface. You can use content providers if you need to share data between multiple apps. For example, Contacts data is used by multiple apps and is stored in a content provider. Learn more about content providers from here.

Add two methods to your BookstoreSliceProvider, along with a companion object. You’ll add the createBookstoreSlice() function shortly:


// 1
override fun onCreateSliceProvider(): Boolean {
 // 2
 return true
}

// 3
override fun onBindSlice(sliceUri: Uri): Slice? {
 //4
 val path = sliceUri.path
 when (path) {
 // 5
   "/$BOOKSTORE_PATH" -> return createBookstoreSlice(sliceUri)
 }
 // 6
 return null
}

companion object {
   // 7
  const val BOOKSTORE_PATH = "book_store"
}

Here, you:

  1. Implement onCreateSliceProvider() to initialize your Slice provider on startup. Do not put long running operations here or your app launch will be delayed, and the first Slice that binds with the viewer will be delayed, too.
  2. Return true if the provider was successfully loaded, false otherwise.
  3. Create your Slice inside the body of onBindSlice(). You should create and return your Slice as quickly as possible. If you want to make network requests or I/O operations, do so in the background to keep your Slice UI responsive. If your background operation is done and you want to update your Slice with the new data, call contentResolver.notifyChange(uri) with the Slice URI, and Android will invoke onBindSlice() for you.
  4. Get the path from the URI.
  5. Check if that path is the path of your Slice and return the bookstore Slice if true.
  6. Return null in case you have no Slice for this path.
  7. Create a String constant as a bookstore path.

Slice providers must be registered in the app Android manifest, so declare BookstoreSliceProvider in the AndroidManifest.xml file as a child of the application element.


<provider
  android:name=".BookstoreSliceProvider"
  android:authorities="com.raywenderlich.android.bookstore"
  android:exported="true"
  android:grantUriPermissions="true"/>

You’ve marked the Slice provider as exported so that it is made available to Slice viewers.

Creating the Bookstore Slice

Slices are list of rows that are constructed using a ListBuilder, a type of SliceBuilder.

Slice Builders

Slide Builders

At the time of writing of this tutorial, Android provides five different Slice builders to build different types of rows with different designs and functionalities: HeaderBuilder, RowBuilder, GridRowBuilder, RangeBuilder, and InputRangeBuilder.

To create your “bookstore Slice” design, you will use:

  • ListBuilder as the main builder of your Slice.
  • HeaderBuilder to set a header with title and subtitle.
  • GridRowBuilder to add a row of cells.
  • CellBuilder to add a cell; each cell has an image, title and text.

Add the createBookstoreSlice() method to BookstoreSliceProvider:


private fun createBookstoreSlice(sliceUri: Uri): Slice {
  // 1
  return ListBuilder(context, sliceUri, ListBuilder.INFINITY)
      // 2
      .setHeader {
        it.apply {
          // 3
          title = "Bookstore"
          // 4
          subtitle = "raywenderlich.com" // large mode
          summary = "raywenderlich.com" //small mode
          // 5
          primaryAction = createOpenBookStoreAction()
        }
      }
      // 6
      .build()
}

Also, add the createOpenBookStoreAction() method that returns a SliceAction for the action to take when a user interacts with your Slice:


private fun createOpenBookStoreAction(): SliceAction {
  val pIntent = BookstoreActivity.buildPendingIntent(context)
    return SliceAction(pIntent, createIcon(R.drawable.logo_raywenderlich),
        "Open  Book Store")
}

In the above, you:

  1. Construct a ListBuilder by passing a context object, the Slice Uri and the lifetime of the content in this Slice. For your case, pass ListBuilder.INFINITY for the lifetime to make the content live forever. ListBuilder is the first builder you need to use to start building a new Slice, and it allows you to add different types of rows that are displayed in a list.
  2. Set a HeaderBuilder to display a header as a first row in your Slice template. HeaderBuilder allows you to add title, subtitle, summary subtitle and/or primary action to the header.
  3. Set a title for the header
  4. Set a subtitle and summary for the header.
  5. Set the primaryAction for the header.
  6. Call the build() method to build your Slice.

Letting the Slice Viewer Show Your Slice

You neeed to set up a run configuration to show your Slice on the top of the viewer surface by launching the Slice Viewer app using your Slice URI.

Follow these steps to do this:

  1. In Android Studio, select Run ▸ Edit Configurations.
  2. In the top-left corner, click the Plus button and select Android App.
  3. Edit Configuration

  4. Enter Bookstore Slice in the Name field.
  5. Select your app module in the Module dropdown.
  6. Under Launch Options, select URL from the Launch dropdown.
  7. Enter your Slice URI in the URL field.
  8. slice-content://com.raywenderlich.android.bookstore/book_store

    Slice URI

  9. Click OK. Build and run using this configuration; you will see a screen like this:
  10. Slice Viewer

  11. Tap on the Slice Viewer item; you will see a screen like this:
  12. Slice View item

    Note: The Slice Viewer app can show your Slice if and only if it has permission to access your Slice URI.

  13. Tap on the ALLOW button to grant the permission, then you will see a screen like this:
  14. Granting permission

Using GridRowBuilder to Display Books

Add the following code to your ListBuilder right before .build() to add a row of cells:


//...
// 1
.addGridRow {
  it.apply {
    // 2
    val books = Bookstore.getBooks()
    for (book in books) {
      // 3
      addCell {
        it.apply {
          // 4
          addImage(createIcon(book.cover), ListBuilder.SMALL_IMAGE)
          // 5
          addTitleText(book.title)
          // 6
          addText(book.price)
          // 7
         contentIntent = BookstoreActivity.buildPendingIntent(context, book.url)
        }
      }
    }
  }
}
//...

Also add the createIcon() method to the class:


private fun createIcon(@DrawableRes resId: Int) = IconCompat.createWithResource(context, resId)

In the above, you:

  1. Add a new GridRowBuilder.
  2. Get the books list from the data store.
  3. For every book in the list, add a new cell to the row.
  4. Add the book cover as an image to the cell.
  5. Add the book title as titleText for the cell.
  6. Add the book price as text for the cell.
  7. Set the PendingIntent to be invoked by the primary action if the user taps on this cell in the row.

Build and run the Bookstore Slice configuration; you will see a screen like this:

Slice with grid

Adding a Notification Icon

You can add a notification icon to your Slice to let users enable or disable notifications from your Bookstore app.

Add this addAction() before .build(), and add the getToggleNotificationAction() to the class. You’ll create a the BookstoreSliceBroadcastReceiver in a moment.


...
// 1
.addAction(getToggleNotificationAction())
...

private fun getToggleNotificationAction(): SliceAction {
  // 2
  val pIntent = BookstoreSliceBroadcastReceiver.getToggleNotificationPendingIntent(context)
  // 3
  val iconResId = NotificationSettings.getIcon()
  // 4
  return SliceAction(pIntent, createIcon(iconResId), "Toggle Notification")
}

Here, you:

  1. Add a SliceAction to the ListBuilder.
  2. Get a pendingIntent from a broadcast receiver called BookstoreSliceBroadcastReceiver. This broadcast receiver handles broadcasts when the user taps on the notification icon in your remote Slice.
  3. Get the notification icon resource ID based on the notification state (enabled or disabled).
  4. Create and return a new SliceAction with three parameters (pIntent, actionIcon, actionTitle).

Note: To send and receive data from your remote Slice to your app, you need to create a BroadcastReceiver!

Create the BookstoreSliceBroadcastReceiver class:


class BookstoreSliceBroadcastReceiver : BroadcastReceiver() {
  // 1
  override fun onReceive(context: Context, intent: Intent) {
    // 2
    val action = intent.action
    // 3
    if (ACTION_TOGGLE_NOTIFICATION == action) {
      // 4
      NotificationSettings.toggleNotification()
      // 5
      val uri = Utility.getUri(context, BookstoreSliceProvider.BOOKSTORE_PATH)
      // 6
      context.contentResolver.notifyChange(uri, null)
    }
  }

  companion object {
    // 7
    const val ACTION_TOGGLE_NOTIFICATION = "com.raywenderlich.bookstore.ACTION_TOGGLE_NOTIFICATION"
    // 8
    fun getToggleNotificationPendingIntent(context: Context): PendingIntent {
      // 9
      val intent = Intent(context, BookstoreSliceBroadcastReceiver::class.java)
      // 10
      intent.action = ACTION_TOGGLE_NOTIFICATION
      // 11
      return PendingIntent.getBroadcast(context, 0, intent, FLAG_UPDATE_CURRENT)
    }
  }
}

Here, you:

  1. Implement onReceive() to receive broadcasts.
  2. Get the action of the received broadcast.
  3. Check if the action is equal to your ACTION_TOGGLE_NOTIFICATION.
  4. Toggle the notification state.
  5. Get the URI of the Bookstore Slice.
  6. Notify the URI to update all of the presented Slices.
  7. Create an action string constant to use with the toggle notification broadcast.
  8. Create a method to get a PendingIntent to toggle the notification.
  9. Create new intent for BookstoreSliceBroadcastReceiver.
  10. Set the intent action to ACTION_TOGGLE_NOTIFICATION.
  11. Return a broadcast PendingIntent with the intent you just created.

Next, declare BookstoreSliceBroadcastReceiver in the AndroidManifest.xml file as a child of the application element.


<receiver android:name=".BookstoreSliceBroadcastReceiver"/>

Build and run; you will see a screen like this:

Slice with icon

Try to enable the notifications by tapping on the notification icon in your Slice; doing so will broadcast the notification toggle action to the BookstoreSliceBroadcastReceiver.

Open the Bookstore app and notice that the notification icon in the floating button is updated, as seen below:

Updated notification icon

Setting the Accent Color

You can set an accent color to tint all of the tintable items within the ListBuilder such as:

  • The icon in the primary action, which will be displayed in the shortcut mode.
  • Any icons in your slice.
  • Widgets: Switch, SeekBar and ProgressBar.

Add the following line to your ListBuilder before .build():


.setAccentColor(ContextCompat.getColor(context, R.color.colorAccent))

Build and run again. Notice that the notification icon color is changed from the accent color of the Slice Viewer app to the accent color you have set:

Notification icon color

Display Modes

Slice viewers can display Slices in three display modes:

  • Large: The whole slice will be displayed.
  • Small: Only the header of the slice will be displayed.
  • Shortcut: Only the icon of the primary action of the header will be displayed.
  • You’ve aleady made your Slice compatible with the three modes by adding the following a summary to the Slice header within the apply block. The summary will be shown in the small mode instead of the subtitle.

    Note: If you have not set a header to your ListBuilder, the first row added to your ListBuilder is displayed instead.

    Build and run in the Slice Viewer app.

    Put your Slice in Small mode by tapping on the right-top icon in the Slice Viewer app and select small; you will see a screen like this:

    Small mode

    Put your Slice in the Shortcut mode by tapping on the right-top icon in the Slice Viewer app and select shortcut; you will see a screen like this:

    Shortcut mode

    And with that, you have finished your Slices tutorial!

    Congratulations

    Where to Go From Here?

    You can download the completed project using the Download Materials button at the top or bottom of this tutorial.

    Note: You’ll need to complete the instructions in the Slice viewer and Let the Slice viewer show your Slice sections to be able to run the final project.

    During this tutorial you learned how to:

    • Create a Slice for a bookstore app.
    • Show the Slice on the surface of the Slice Viewer app.
    • Make the Slice interactive by adding a notification icon to let the user enable or disable notification without opening the app.
    • Make the Slice compatible with the different display modes.
    • Update the Slice with new data.

    While you have learned how to incorporate Slices, note that, as of the writing this tutorial, the official Android documentation states: “Slices will start appearing soon for users, but you can start building today.”

    You may also find it helpful to learn about RangeBuilder, which you can read about here.

    And since Slices are a way to enhance App Actions, you may want to know more about App Actions, which you can learn about here.

    Feel free to share your feedback or ask any questions in the comments below or in the forums!

    Download Materials



    Source link https://www.raywenderlich.com/195472/android-slices-getting-started

    LEAVE A REPLY

    Please enter your comment!
    Please enter your name here