Skip to content

Commit

Permalink
Merge feature/live-update -> main (#1249)
Browse files Browse the repository at this point in the history
  • Loading branch information
jyaganeh committed May 22, 2023
1 parent 4be988e commit 12c009f
Show file tree
Hide file tree
Showing 51 changed files with 3,363 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -30,6 +30,7 @@ captures/
.idea/misc.xml
.idea/kotlinScripting.xml
.idea/compiler.xml
.idea/kotlinc.xml

# Android Studio 3 in .gitignore file.
.idea/caches/build_file_checksums.ser
Expand Down
6 changes: 0 additions & 6 deletions .idea/kotlinc.xml

This file was deleted.

1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Expand Up @@ -120,6 +120,7 @@ androidx-preferencektx = { module = "androidx.preference:preference-ktx", versio
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerview" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidx-room" }
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "androidx-room" }
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx-room" }
androidx-room-testing = { module = "androidx.room:room-testing", version.ref = "androidx-room" }
androidx-startup-runtime = { module = "androidx.startup:startup-runtime", version.ref = "androidx-startup" }
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" }
Expand Down
3 changes: 3 additions & 0 deletions sample/build.gradle
Expand Up @@ -67,6 +67,9 @@ dependencies {
// Airship Automation (In-App)
implementation project(':urbanairship-automation')

// Airship Live Updates
implementation project(':urbanairship-live-update')

// Airship location
implementation project(':urbanairship-location')
// Allows Airship location services to use Fused Location
Expand Down
37 changes: 37 additions & 0 deletions sample/src/main/java/com/urbanairship/sample/CustomLiveUpdate.java
@@ -0,0 +1,37 @@
package com.urbanairship.sample;

import android.content.Context;
import android.util.Log;

import com.urbanairship.json.JsonMap;
import com.urbanairship.liveupdate.LiveUpdate;
import com.urbanairship.liveupdate.LiveUpdateEvent;
import com.urbanairship.liveupdate.LiveUpdateCustomHandler;
import com.urbanairship.liveupdate.LiveUpdateResult;

import org.jetbrains.annotations.NotNull;

import androidx.annotation.NonNull;

// TODO(live-update): Implement a custom live update handler to feed data to a widget.
public class CustomLiveUpdate implements LiveUpdateCustomHandler {
@Override
@NotNull
public LiveUpdateResult<Void> onUpdate(@NonNull Context context, @NonNull LiveUpdateEvent event, @NonNull LiveUpdate update) {

Log.d("CustomLiveUpdate", "onUpdate: action=" + event + ", update=" + update);

if (event == LiveUpdateEvent.END) {
// Dismiss the live update on STOP. The default behavior will leave the Live Update
// active until the dismissal time is reached.
return LiveUpdateResult.cancel();
}

JsonMap content = update.getContent();
int teamOneScore = content.opt("team_one_score").getInt(0);
int teamTwoScore = content.opt("team_two_score").getInt(0);
String statusUpdate = content.opt("status_update").optString();

return LiveUpdateResult.ok();
}
}
19 changes: 19 additions & 0 deletions sample/src/main/java/com/urbanairship/sample/SampleAutopilot.java
Expand Up @@ -10,10 +10,15 @@
import com.urbanairship.AirshipConfigOptions;
import com.urbanairship.Autopilot;
import com.urbanairship.UAirship;
import com.urbanairship.liveupdate.LiveUpdateManager;
import com.urbanairship.messagecenter.MessageCenter;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationChannelCompat;
import androidx.core.app.NotificationManagerCompat;

import static androidx.core.app.NotificationManagerCompat.IMPORTANCE_HIGH;

/**
* Autopilot that enables user notifications on first run.
Expand All @@ -36,6 +41,20 @@ public void onAirshipReady(@NonNull UAirship airship) {
airship.getPushManager().setUserNotificationsEnabled(true);
}

// Create notification channel for Live Updates.
NotificationChannelCompat sportsChannel =
new NotificationChannelCompat.Builder("sports", IMPORTANCE_HIGH)
.setDescription("Live sports updates!")
.setName("Sports!")
.setVibrationEnabled(false)
.build();

Context context = UAirship.getApplicationContext();
NotificationManagerCompat.from(context).createNotificationChannel(sportsChannel);

// Register handlers for Live Updates.
LiveUpdateManager.shared().register("sports", new SampleLiveUpdate());

MessageCenter.shared().setOnShowMessageCenterListener(messageId -> {
// Use an implicit navigation deep link for now as explicit deep links are broken
// with multi navigation host fragments
Expand Down
70 changes: 70 additions & 0 deletions sample/src/main/java/com/urbanairship/sample/SampleLiveUpdate.java
@@ -0,0 +1,70 @@
package com.urbanairship.sample;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;

import com.urbanairship.Logger;
import com.urbanairship.json.JsonMap;
import com.urbanairship.liveupdate.LiveUpdate;
import com.urbanairship.liveupdate.LiveUpdateEvent;
import com.urbanairship.liveupdate.LiveUpdateNotificationHandler;
import com.urbanairship.liveupdate.LiveUpdateResult;
import com.urbanairship.util.PendingIntentCompat;

import org.jetbrains.annotations.NotNull;

import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;


public class SampleLiveUpdate implements LiveUpdateNotificationHandler {
@Override
@NotNull
public LiveUpdateResult<NotificationCompat.Builder> onUpdate(@NonNull Context context, @NonNull LiveUpdateEvent event, @NonNull LiveUpdate update) {

Logger.debug("SampleLiveUpdate - onUpdate: action=" + event + ", update=" + update);

if (event == LiveUpdateEvent.END) {
// Dismiss the live update on STOP. The default behavior will leave the Live Update
// in the notification tray until the dismissal time is reached or the user dismisses it.
return LiveUpdateResult.cancel();
}

JsonMap content = update.getContent();
int teamOneScore = content.opt("team_one_score").getInt(0);
int teamTwoScore = content.opt("team_two_score").getInt(0);
String statusUpdate = content.opt("status_update").optString();

RemoteViews bigLayout = new RemoteViews(context.getPackageName(), R.layout.live_update_notification_big);
bigLayout.setTextViewText(R.id.teamOneScore, String.valueOf(teamOneScore));
bigLayout.setTextViewText(R.id.teamTwoScore, String.valueOf(teamTwoScore));
bigLayout.setTextViewText(R.id.statusUpdate, statusUpdate);

RemoteViews smallLayout = new RemoteViews(context.getPackageName(), R.layout.live_update_notification_small);
smallLayout.setTextViewText(R.id.teamOneScore, String.valueOf(teamOneScore));
smallLayout.setTextViewText(R.id.teamTwoScore, String.valueOf(teamTwoScore));

Intent launchIntent = context.getPackageManager()
.getLaunchIntentForPackage(context.getPackageName())
.addCategory(update.getName())
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP)
.setPackage(null);

PendingIntent contentIntent = PendingIntentCompat.getActivity(
context, 0, launchIntent, PendingIntent.FLAG_IMMUTABLE);

NotificationCompat.Builder builder =
new NotificationCompat.Builder(context, "sports")
.setSmallIcon(R.drawable.ic_notification)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_EVENT)
.setStyle(new NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(smallLayout)
.setCustomBigContentView(bigLayout)
.setContentIntent(contentIntent);

return LiveUpdateResult.ok(builder);
}
}
Expand Up @@ -10,9 +10,13 @@

import com.urbanairship.actions.ActionRunRequest;
import com.urbanairship.actions.ClipboardAction;
import com.urbanairship.json.JsonMap;
import com.urbanairship.liveupdate.LiveUpdateManager;
import com.urbanairship.sample.R;
import com.urbanairship.sample.databinding.FragmentHomeBinding;

import java.util.concurrent.atomic.AtomicInteger;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
Expand Down Expand Up @@ -42,6 +46,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
});
});

setupLiveUpdateTestButtons(binding);

return binding.getRoot();
}

Expand All @@ -52,4 +58,68 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
NavigationUI.setupWithNavController(toolbar, Navigation.findNavController(view));
}

// TODO: Replace with something less hacky when backend is ready to send real Live Updates.
// Should live update stuff even be on the home screen? Could be in settings instead...
private void setupLiveUpdateTestButtons(FragmentHomeBinding binding) {
AtomicInteger score1 = new AtomicInteger();
AtomicInteger score2 = new AtomicInteger();

// Start button
binding.startLiveUpdate.setOnClickListener(v -> {
JsonMap content = JsonMap.newBuilder()
.put("team_one_score", 0)
.put("team_two_score", 0)
.put("status_update", "Match start!")
.build();

LiveUpdateManager.shared().start("foxes-tigers", "sports", content);
});

// +1 Foxes button
binding.updateLiveUpdate1.setOnClickListener(v -> {
JsonMap content = JsonMap.newBuilder()
.put("team_one_score", score1.getAndIncrement())
.put("team_two_score", score2.get())
.put("status_update", "Foxes score!")
.build();

LiveUpdateManager.shared().update("foxes-tigers", content);
});

// +1 Tigers button
binding.updateLiveUpdate2.setOnClickListener(v -> {
JsonMap content = JsonMap.newBuilder()
.put("team_one_score", score1.get())
.put("team_two_score", score2.getAndIncrement())
.put("status_update", "Tigers score!")
.build();

LiveUpdateManager.shared().update("foxes-tigers", content);
});

// Stop button
binding.stopLiveUpdate.setOnClickListener(v -> {
int s1 = score1.get();
int s2 = score2.get();
String status;
if (s1 == s2) {
status = "It's a tie!";
} else if (s1 > s2) {
status = "Foxes win!";
} else {
status = "Tigers win!";
}

JsonMap content = JsonMap.newBuilder()
.put("teamOneScore", s1)
.put("team_two_score", s2)
.put("status_update", status)
.build();

LiveUpdateManager.shared().stop("foxes-tigers", content);

score1.set(0);
score2.set(0);
});
}
}
21 changes: 21 additions & 0 deletions sample/src/main/res/drawable/foxes.xml
@@ -0,0 +1,21 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:pathData="M41.143,29.917C41.171,29.917 41.171,29.917 41.198,29.917L44.931,30.553C42.138,27.263 41.088,25.742 37.797,23.641C37.936,23.115 38.212,22.452 38.488,21.788C41.502,14.323 39.954,11.751 37.41,7.382C35.336,10.562 34.949,11.558 29.475,14.876C27.401,16.12 25.438,17.281 24,18.995C22.562,17.281 20.599,16.092 18.553,14.848C13.134,11.585 12.747,10.618 10.618,7.355C8.074,11.724 6.525,14.295 9.539,21.76C9.816,22.452 10.092,23.088 10.23,23.613C6.94,25.714 5.889,27.235 3.097,30.525L6.829,29.889C6.857,29.889 6.857,29.889 6.885,29.889C6.359,30.664 6.083,31.134 4.617,33.401C7.134,33.318 15.29,32.378 18.608,38.848C19.714,39.207 22.866,40.23 24,40.59C25.825,40.009 28.341,39.18 29.419,38.848C32.599,32.405 41.005,33.318 43.41,33.401C41.945,31.134 41.668,30.691 41.143,29.917Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M24,20.766C23.862,20.766 23.723,20.766 23.585,20.766C20.876,16.508 14.212,15.429 10.673,10.038C6.995,16.37 11.751,21.568 11.751,24.333C10.839,24.941 8.654,26.13 6.608,28.563C7.742,28.37 9.594,28.701 9.594,28.701C9.594,28.701 8.765,29.531 7.217,31.964C16.479,31.632 19.604,37.771 19.604,37.771L24.028,39.208L28.452,37.771C28.452,37.771 31.576,31.632 40.839,31.964C39.29,29.531 38.461,28.701 38.461,28.701C38.461,28.701 40.341,28.397 41.447,28.563C39.401,26.13 37.217,24.941 36.304,24.333C36.304,21.568 41.032,16.397 37.355,10.038C33.843,15.429 27.18,16.535 24.47,20.794C24.304,20.766 24.138,20.766 24,20.766Z"
android:fillColor="#E94C16"/>
<path
android:pathData="M19.272,34.203C15.733,30.83 10.507,29.917 10.507,29.917C10.507,29.917 11.834,28.203 12.636,27.594C12.276,28.203 12.138,29.253 12.138,29.253C12.138,29.253 16.756,30.194 20.074,33.512C19.742,33.733 19.493,33.982 19.272,34.203ZM24,37.382C24,37.382 26.599,36.332 27.18,36.028C27.18,36.028 27.594,35.005 27.235,33.76C26.571,33.622 25.991,33.622 25.521,33.65C25.604,33.76 25.631,33.843 25.631,33.954C25.631,34.562 24.415,35.115 24,35.115C23.585,35.115 22.369,34.562 22.369,33.954C22.369,33.843 22.424,33.733 22.479,33.65C22.009,33.622 21.428,33.622 20.765,33.76C20.406,34.977 20.82,36.028 20.82,36.028C21.428,36.304 24,37.382 24,37.382ZM17.779,23.945C17.779,23.889 17.779,23.862 17.779,23.806C17.17,21.263 12.193,18.525 12.193,18.525C12.193,18.525 14.378,20.378 14.627,22.369C13.631,21.152 12.663,20.903 12.663,20.903C12.663,20.903 13.493,22.313 13.852,23.641C13.852,23.641 15.65,23.53 16.673,24.028H16.645C17.005,24 17.392,23.945 17.779,23.945ZM31.355,24.028C32.35,23.53 34.175,23.641 34.175,23.641C34.535,22.286 35.364,20.903 35.364,20.903C35.364,20.903 34.396,21.152 33.401,22.369C33.65,20.378 35.834,18.525 35.834,18.525C35.834,18.525 30.885,21.263 30.277,23.806C30.277,23.862 30.277,23.889 30.277,23.945C30.663,23.972 31.051,24 31.41,24.055C31.382,24.055 31.355,24.055 31.355,24.028ZM28.728,34.203C32.267,30.83 37.493,29.917 37.493,29.917C37.493,29.917 36.166,28.203 35.364,27.594C35.723,28.203 35.862,29.253 35.862,29.253C35.862,29.253 31.244,30.194 27.926,33.512C28.258,33.733 28.535,33.982 28.728,34.203Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M22.037,29.918C22.009,29.973 21.954,30.029 21.899,30.111C21.677,30.416 21.207,31.107 20.931,31.854C20.848,31.494 20.765,31.162 20.682,30.886C19.106,31.245 17.143,30.001 17.53,27.623C18.691,28.812 21.235,27.844 22.037,29.918ZM24,33.098C23.087,33.098 22.369,33.485 22.369,33.955C22.369,34.563 23.585,35.116 24,35.116C24.415,35.116 25.631,34.563 25.631,33.955C25.659,33.485 24.912,33.098 24,33.098ZM25.991,29.918C26.018,29.973 26.074,30.029 26.129,30.111C26.35,30.416 26.82,31.135 27.097,31.854C27.18,31.494 27.263,31.162 27.346,30.886C28.922,31.245 30.885,30.001 30.498,27.623C29.309,28.812 26.765,27.844 25.991,29.918ZM40.811,31.936C31.548,31.605 28.424,37.743 28.424,37.743L24,39.181L19.576,37.743C19.576,37.743 16.452,31.605 7.189,31.936C8.737,29.503 9.567,28.674 9.567,28.674C9.567,28.674 7.687,28.37 6.581,28.535C8.654,26.13 10.811,24.913 11.751,24.333C11.751,21.568 7.023,16.397 10.7,10.038C14.212,15.429 20.876,16.535 23.585,20.794C23.723,20.794 23.862,20.794 24,20.794C24.138,20.794 24.277,20.794 24.415,20.794C27.124,16.535 33.788,15.429 37.299,10.038C40.977,16.397 36.249,21.568 36.249,24.333C37.161,24.941 39.346,26.13 41.392,28.563C40.258,28.37 38.405,28.701 38.405,28.701C38.405,28.701 39.263,29.503 40.811,31.936ZM35.392,27.623C36.415,27.402 37.576,27.485 37.576,27.485C37.576,27.485 34.977,25.107 31.355,24.056C32.35,23.559 34.175,23.669 34.175,23.669C34.535,22.314 35.364,20.932 35.364,20.932C35.364,20.932 34.396,21.181 33.401,22.397C33.65,20.406 35.834,18.554 35.834,18.554C35.834,18.554 30.857,21.291 30.277,23.835C29.585,19.273 36.829,16.84 36.691,13.605C33.373,16.591 28.645,18.194 26.323,20.904C28.23,21.844 28.507,22.674 28.507,22.674C28.479,22.674 26.931,22.093 24.028,22.093C21.124,22.093 19.576,22.674 19.548,22.674C19.548,22.674 19.825,21.844 21.733,20.904C19.41,18.194 14.682,16.563 11.364,13.577C11.226,16.812 18.47,19.245 17.779,23.807C17.198,21.264 12.193,18.526 12.193,18.526C12.193,18.526 14.378,20.379 14.627,22.37C13.631,21.153 12.664,20.904 12.664,20.904C12.664,20.904 13.493,22.314 13.852,23.642C13.852,23.642 15.65,23.531 16.673,24.029C13.051,25.107 10.424,27.457 10.424,27.457C10.424,27.457 11.613,27.374 12.636,27.623C11.834,28.204 10.507,29.918 10.507,29.918C10.507,29.918 15.733,30.83 19.272,34.204C19.687,33.761 20.267,33.291 21.069,32.987C20.184,34.508 20.793,36.029 20.793,36.029C21.401,36.333 23.972,37.383 23.972,37.383C23.972,37.383 26.571,36.333 27.152,36.029C27.152,36.029 27.76,34.508 26.876,32.987C27.677,33.319 28.258,33.761 28.673,34.204C32.212,30.83 37.438,29.918 37.438,29.918C37.438,29.918 36.166,28.204 35.392,27.623Z"
android:fillColor="#181716"/>
<path
android:pathData="M20.489,29.862C19.548,30.83 18.774,29.723 19.078,29.309C19.161,29.613 19.687,30.166 20.489,29.862ZM27.511,29.862C28.452,30.83 29.226,29.723 28.922,29.309C28.866,29.613 28.313,30.166 27.511,29.862Z"
android:fillColor="#ffffff"/>
</vector>

0 comments on commit 12c009f

Please sign in to comment.