Skip to content

Android Custom Notification Layout

Chris Scott edited this page Sep 19, 2019 · 24 revisions

The BackgroundGeolocation Android SDK runs as a foreground-service, which requires a persistent notification. If the default notification doesn't suit your needs (eg: you want to add custom buttons), you can design your own notification layout:

Step 1 — Add appcompat to Gradle dependencies:

📂 app/build.gradle:

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'                   // or higher
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'   // or higher
+   implementation "androidx.appcompat:appcompat:${rootProject.ext.appCompatVersion}"
}

Step 2 — Create a custom layout file:

Open your application in Android Studio. Select File->New->XML->Layout XML file:

Enter any layout name. Your file will be created in the folder app/res/layouts:

Step 3 — Edit your layout:

Even if you have no experience with Android Layouts, it doesn't take much to figure out the basics. You'll mostly be adding <TextView />, <ImageView /> and <Button /> elements. The key thing to be aware of is the android:id of these elements and how these are referenced from BackgroundGeolocation.notification configuration: your android:id must be prefixed with the word notification (eg: notificationText). There is one exception: applicationName, which the plugin will automatically render your Android application name.

Layout Special Elements

When BackgroundGeolocation renders your custom notification layout, it will be querying for the following elements addressed by their android:id. When found, their content will be updated from the corresponding "Data-source":

Layout element android:id Data-source
applicationName Application name from AndroidManifest
notificationTitle notification.title
notificationText notification.text
notificationSmallIcon notification.smallIcon
notificationLargeIcon notification.largeIcon
bg.BackgroundGeolocation.ready(bg.Config(
  notification: bg.Notification(
    layout: "my_notification_layout",  // <-- custom layout xml file
    title: "The Notification Title", 
    text: "The Notification Text",     
    smallIcon: "mipmap/my_small_icon", // <-- defaults to app icon
    largeIcon: "mipmap/my_large_icon"
  )
));

Custom <TextView /> Elements

You can declare your own custom <TextView /> elements and render data into them using the notification.strings parameter.

<TextView
    android:id="@+id/myCustomElement"  // <-- myCustomElement
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="notificationTitle" />

You can provide data to your custom elements using the notification.strings configuration parameter:

bg.BackgroundGeolocation.ready(bg.Config(
  notification: bg.Notification(
    strings: {
      'myCustomElement': 'My Custom Element Text'
    }
  )
));

Custom <Button /> Elements:

You can declare your own custom <Button /> elements and register click-listeners upon them using the notification.actions parameter:

<Button
    android:id="@+id/notificationButtonFoo" // <-- notificationButtonFoo
    style="@style/Widget.AppCompat.Button.Small"
    android:layout_width="60dp"
    android:layout_height="40dp"
    android:text="Foo" />

Register listeners for your button using notification.actions:

bg.BackgroundGeolocation.ready(bg.Config(
  notification: bg.Notification(
    actions: [  // <-- register button listeners
      'notificationButtonFoo',
      'notificationButtonBar'
    ]
  )
));

// Listen to custom button clicks:
bg.BackgroundGeolocation.onNotificationAction((buttonId) {
  // Listen to custom notification button clicks (notification.actions)
  print('[onNotificationAction] - $buttonId');
  switch(buttonId) {
    case 'notificationButtonFoo':
      // Handle button click on [Foo]
      break;
    case 'notificationButtonBar':
      // Handle button click on [Bar]
      break;
  }
});

Sample Layout

As a starting-point for your custom layout, copy the following content into your new file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="135dp"
    android:gravity="start"
    android:adjustViewBounds="true"
    android:orientation="vertical"
    android:padding="15dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="15dp"
        android:gravity="center"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/notificationSmallIcon"
            android:layout_width="16dp"
            android:layout_height="16dp"
            android:tint="@android:color/background_dark"
            tools:srcCompat="@tools:sample/avatars" />

        <TextView
            android:id="@+id/applicationName"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingLeft="10dp"
            android:text="applicationName"
            android:textAppearance="@style/TextAppearance.Compat.Notification.Title"
            android:textColor="#888888"
            android:textSize="12sp" />
    </LinearLayout>

    <TextView
        android:id="@+id/notificationTitle"
        style="@style/TextAppearance.Compat.Notification.Title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="notificationTitle"
        android:textSize="14sp" />

    <TextView
        android:id="@+id/notificationText"
        style="@style/TextAppearance.Compat.Notification.Line2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="notificationText"
        android:textSize="14sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="right"
        android:orientation="horizontal">

        <Button
            android:id="@+id/notificationButtonFoo"
            style="@style/Widget.AppCompat.Button.Small"
            android:layout_width="60dp"
            android:layout_height="40dp"
            android:text="FooA" />

        <Button
            android:id="@+id/notificationButtonBar"
            style="@style/Widget.AppCompat.Button.Small"
            android:layout_width="60dp"
            android:layout_height="40dp"
            android:text="Bar" />
    </LinearLayout>
</LinearLayout>

Step 3 — Using your custom layout:

bg.BackgroundGeolocation.ready(bg.Config(
  notification: bg.Notification(
    title: 'The title',
    text: 'The text',
    layout: 'notification_layout',
    actions: [
      'notificationButtonFoo',  // <-- register button click-listeners
      'notificationButtonBar'
    ],
    strings: {
      'myCustomTextBox1': 'custom TextBox element'
    }
  )
));

// Listen to custom notification button clicks (notification.actions)
bg.BackgroundGeolocation.onNotificationAction((buttonId) {
  // Listen to custom notification button clicks (notification.actions)
  print('[onNotificationAction] - $buttonId');
  switch(buttonId) {
    case 'notificationButtonFoo':
      // Handle button click on [Foo]
      break;
    case 'notificationButtonBar':
      // Handle button click on [Bar]
      break;
  }
});