Skip to content

Add InterruptionLevel to notification trigger API #4205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions firebase-appdistribution-api/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package com.google.firebase.appdistribution {
method @NonNull public com.google.android.gms.tasks.Task<com.google.firebase.appdistribution.AppDistributionRelease> checkForNewRelease();
method @NonNull public static com.google.firebase.appdistribution.FirebaseAppDistribution getInstance();
method public boolean isTesterSignedIn();
method public void showFeedbackNotification(int, int);
method public void showFeedbackNotification(@NonNull CharSequence, int);
method public void showFeedbackNotification(int, @NonNull com.google.firebase.appdistribution.InterruptionLevel);
method public void showFeedbackNotification(@NonNull CharSequence, @NonNull com.google.firebase.appdistribution.InterruptionLevel);
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> signInTester();
method public void signOutTester();
method public void startFeedback(int);
Expand Down Expand Up @@ -49,6 +49,14 @@ package com.google.firebase.appdistribution {
enum_constant public static final com.google.firebase.appdistribution.FirebaseAppDistributionException.Status UPDATE_NOT_AVAILABLE;
}

public enum InterruptionLevel {
enum_constant public static final com.google.firebase.appdistribution.InterruptionLevel DEFAULT;
enum_constant public static final com.google.firebase.appdistribution.InterruptionLevel HIGH;
enum_constant public static final com.google.firebase.appdistribution.InterruptionLevel LOW;
enum_constant public static final com.google.firebase.appdistribution.InterruptionLevel MAX;
enum_constant public static final com.google.firebase.appdistribution.InterruptionLevel MIN;
}

public interface OnProgressListener {
method public void onProgressUpdate(@NonNull com.google.firebase.appdistribution.UpdateProgress);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
package com.google.firebase.appdistribution;

import android.app.Activity;
import android.app.NotificationChannel;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import com.google.android.gms.tasks.Task;
import com.google.firebase.FirebaseApp;
import com.google.firebase.appdistribution.internal.FirebaseAppDistributionProxy;
Expand Down Expand Up @@ -202,17 +200,14 @@ public interface FirebaseAppDistribution {
* <li>Starts a full screen activity for the tester to compose and submit the feedback
* </ol>
*
* <p>On Android 8 and above, the notification will be created in its own notification channel.
*
* @param infoTextResourceId string resource ID of text to display to the tester before collecting
* feedback data (e.g. Terms and Conditions)
* @param importance the level of interruption for the feedback notification channel. Once the
* channel's importance is set it cannot be changed except by the user. See {@link
* NotificationChannel#setImportance}. On platforms below Android 8, the importance will be
* translated into a comparable notification priority (see {@link
* NotificationCompat.Builder#setPriority}).
* @param interruptionLevel the level of interruption for the feedback notification. On platforms
* below Android 8, this corresponds to a notification channel importance and once set cannot
* be changed except by the user.
*/
void showFeedbackNotification(int infoTextResourceId, int importance);
void showFeedbackNotification(
int infoTextResourceId, @NonNull InterruptionLevel interruptionLevel);

/**
* Displays a notification that, when tapped, will take a screenshot of the current activity, then
Expand All @@ -233,17 +228,14 @@ public interface FirebaseAppDistribution {
* <li>Starts a full screen activity for the tester to compose and submit the feedback
* </ol>
*
* <p>On Android 8 and above, the notification will be created in its own notification channel.
*
* @param infoText text to display to the tester before collecting feedback data (e.g. Terms and
* Conditions)
* @param importance the level of interruption for the feedback notification channel. Once the
* channel's importance is set it cannot be changed except by the user. See {@link
* NotificationChannel#setImportance}. On platforms below Android 8, the importance will be
* translated into a comparable notification priority (see {@link
* NotificationCompat.Builder#setPriority}).
* @param interruptionLevel the level of interruption for the feedback notification. On platforms
* below Android 8, this corresponds to a notification channel importance and once set cannot
* be changed except by the user.
*/
void showFeedbackNotification(@NonNull CharSequence infoText, int importance);
void showFeedbackNotification(
@NonNull CharSequence infoText, @NonNull InterruptionLevel interruptionLevel);

/**
* Hides the notification shown with {@link #showFeedbackNotification}.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.firebase.appdistribution;

import android.app.NotificationManager;
import androidx.core.app.NotificationCompat;

/** An enum specifying the level of interruption of a notification when it is created. */
public enum InterruptionLevel {

/**
* Minimum interruption level.
*
* <p>Translates to {@link NotificationManager#IMPORTANCE_MIN} on Android O+ and {@link
* NotificationCompat#PRIORITY_MIN} on older platforms.
*/
MIN(NotificationManager.IMPORTANCE_MIN, NotificationCompat.PRIORITY_MIN),

/**
* Low interruption level.
*
* <p>Translates to {@link NotificationManager#IMPORTANCE_LOW} on Android O+ and {@link
* NotificationCompat#PRIORITY_LOW} on older platforms.
*/
LOW(NotificationManager.IMPORTANCE_LOW, NotificationCompat.PRIORITY_LOW),

/**
* Default interruption level.
*
* <p>Translates to {@link NotificationManager#IMPORTANCE_DEFAULT} on Android O+ and {@link
* NotificationCompat#PRIORITY_DEFAULT} on older platforms.
*/
DEFAULT(NotificationManager.IMPORTANCE_DEFAULT, NotificationCompat.PRIORITY_DEFAULT),

/**
* High interruption level.
*
* <p>Translates to {@link NotificationManager#IMPORTANCE_HIGH} on Android O+ and {@link
* NotificationCompat#PRIORITY_HIGH} on older platforms.
*/
HIGH(NotificationManager.IMPORTANCE_HIGH, NotificationCompat.PRIORITY_HIGH),

/**
* Maximum interruption level.
*
* <p>Translates to {@link NotificationManager#IMPORTANCE_HIGH} on Android O+ and {@link
* NotificationCompat#PRIORITY_MAX} on older platforms.
*/
MAX(NotificationManager.IMPORTANCE_HIGH, NotificationCompat.PRIORITY_MAX);

/**
* The notification channel importance corresponding to this interruption level on Android O+.
*
* @hide
*/
public final int channelImportance;

/**
* The notification priority corresponding to this interruption level on older platforms.
*
* @hide
*/
public final int notificationPriority;

InterruptionLevel(int channelImportance, int notificationPriority) {
this.channelImportance = channelImportance;
this.notificationPriority = notificationPriority;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.firebase.appdistribution.AppDistributionRelease;
import com.google.firebase.appdistribution.FirebaseAppDistribution;
import com.google.firebase.appdistribution.FirebaseAppDistributionException;
import com.google.firebase.appdistribution.InterruptionLevel;
import com.google.firebase.appdistribution.UpdateTask;
import com.google.firebase.inject.Provider;

Expand Down Expand Up @@ -95,13 +96,15 @@ public void startFeedback(@NonNull CharSequence infoText, @Nullable Uri screensh
}

@Override
public void showFeedbackNotification(int infoTextResourceId, int importance) {
delegate.showFeedbackNotification(infoTextResourceId, importance);
public void showFeedbackNotification(
int infoTextResourceId, @NonNull InterruptionLevel interruptionLevel) {
delegate.showFeedbackNotification(infoTextResourceId, interruptionLevel);
}

@Override
public void showFeedbackNotification(@NonNull CharSequence infoText, int importance) {
delegate.showFeedbackNotification(infoText, importance);
public void showFeedbackNotification(
@NonNull CharSequence infoText, @NonNull InterruptionLevel interruptionLevel) {
delegate.showFeedbackNotification(infoText, interruptionLevel);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.google.firebase.appdistribution.FirebaseAppDistribution;
import com.google.firebase.appdistribution.FirebaseAppDistributionException;
import com.google.firebase.appdistribution.FirebaseAppDistributionException.Status;
import com.google.firebase.appdistribution.InterruptionLevel;
import com.google.firebase.appdistribution.OnProgressListener;
import com.google.firebase.appdistribution.UpdateTask;
import java.util.concurrent.Executor;
Expand Down Expand Up @@ -85,10 +86,12 @@ public void startFeedback(int infoTextResourceId, @Nullable Uri screenshotUri) {
public void startFeedback(@NonNull CharSequence infoText, @Nullable Uri screenshotUri) {}

@Override
public void showFeedbackNotification(int infoTextResourceId, int importance) {}
public void showFeedbackNotification(
int infoTextResourceId, @NonNull InterruptionLevel interruptionLevel) {}

@Override
public void showFeedbackNotification(@NonNull CharSequence infoText, int importance) {}
public void showFeedbackNotification(
@NonNull CharSequence infoText, @NonNull InterruptionLevel interruptionLevel) {}

@Override
public void cancelFeedbackNotification() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.google.firebase.appdistribution.FirebaseAppDistribution;
import com.google.firebase.appdistribution.FirebaseAppDistributionException;
import com.google.firebase.appdistribution.FirebaseAppDistributionException.Status;
import com.google.firebase.appdistribution.InterruptionLevel;
import com.google.firebase.appdistribution.UpdateProgress;
import com.google.firebase.appdistribution.UpdateStatus;
import com.google.firebase.appdistribution.UpdateTask;
Expand Down Expand Up @@ -352,13 +353,15 @@ public void startFeedback(@NonNull CharSequence infoText, @Nullable Uri screensh
}

@Override
public void showFeedbackNotification(int infoTextResourceId, int importance) {
showFeedbackNotification(getText(infoTextResourceId), importance);
public void showFeedbackNotification(
int infoTextResourceId, @NonNull InterruptionLevel interruptionLevel) {
showFeedbackNotification(getText(infoTextResourceId), interruptionLevel);
}

@Override
public void showFeedbackNotification(@NonNull CharSequence infoText, int importance) {
notificationsManager.showFeedbackNotification(infoText, importance);
public void showFeedbackNotification(
@NonNull CharSequence infoText, @NonNull InterruptionLevel interruptionLevel) {
notificationsManager.showFeedbackNotification(infoText, interruptionLevel);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
Expand All @@ -29,6 +28,7 @@
import androidx.annotation.VisibleForTesting;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import com.google.firebase.appdistribution.InterruptionLevel;

class FirebaseAppDistributionNotificationsManager {
private static final String TAG = "FirebaseAppDistributionNotificationsManager";
Expand Down Expand Up @@ -78,7 +78,7 @@ void showAppUpdateNotification(long totalBytes, long downloadedBytes, int string
Notification.APP_UPDATE,
R.string.app_update_notification_channel_name,
R.string.app_update_notification_channel_description,
NotificationManager.IMPORTANCE_DEFAULT);
InterruptionLevel.DEFAULT);
}

if (!notificationManager.areNotificationsEnabled()) {
Expand Down Expand Up @@ -129,7 +129,8 @@ private static int getPendingIntentFlags(int baseFlags) {
: baseFlags;
}

public void showFeedbackNotification(@NonNull CharSequence infoText, int importance) {
public void showFeedbackNotification(
@NonNull CharSequence infoText, @NonNull InterruptionLevel interruptionLevel) {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Expand All @@ -138,7 +139,7 @@ public void showFeedbackNotification(@NonNull CharSequence infoText, int importa
Notification.FEEDBACK,
R.string.feedback_notification_channel_name,
R.string.feedback_notification_channel_description,
importance);
interruptionLevel);
}

if (!notificationManager.areNotificationsEnabled()) {
Expand All @@ -161,7 +162,7 @@ public void showFeedbackNotification(@NonNull CharSequence infoText, int importa
.setSmallIcon(appIconSource.getNonAdaptiveIconOrDefault(context))
.setContentTitle(context.getString(R.string.feedback_notification_title))
.setContentText(context.getString(R.string.feedback_notification_text, appLabel))
.setPriority(convertImportanceToPriority(importance))
.setPriority(interruptionLevel.notificationPriority)
.setOngoing(true)
.setOnlyAlertOnce(true)
.setAutoCancel(false)
Expand All @@ -177,31 +178,15 @@ public void cancelFeedbackNotification() {
.cancel(Notification.FEEDBACK.tag, Notification.FEEDBACK.id);
}

private int convertImportanceToPriority(int importance) {
switch (importance) {
case NotificationManagerCompat.IMPORTANCE_MIN:
return NotificationCompat.PRIORITY_MIN;
case NotificationManagerCompat.IMPORTANCE_LOW:
return NotificationCompat.PRIORITY_LOW;
case NotificationManagerCompat.IMPORTANCE_HIGH:
return NotificationCompat.PRIORITY_HIGH;
case NotificationManagerCompat.IMPORTANCE_MAX:
return NotificationCompat.PRIORITY_MAX;
case NotificationManagerCompat.IMPORTANCE_UNSPECIFIED:
case NotificationManagerCompat.IMPORTANCE_NONE:
case NotificationManagerCompat.IMPORTANCE_DEFAULT:
default:
return NotificationCompat.PRIORITY_DEFAULT;
}
}

@RequiresApi(Build.VERSION_CODES.O)
private void createChannel(Notification notification, int name, int description, int importance) {
private void createChannel(
Notification notification, int name, int description, InterruptionLevel interruptionLevel) {
notificationManager.createNotificationChannelGroup(
new NotificationChannelGroup(
CHANNEL_GROUP_ID, context.getString(R.string.notifications_group_name)));
NotificationChannel channel =
new NotificationChannel(notification.channelId, context.getString(name), importance);
new NotificationChannel(
notification.channelId, context.getString(name), interruptionLevel.channelImportance);
channel.setDescription(context.getString(description));
channel.setGroup(CHANNEL_GROUP_ID);
// Register the channel with the system; you can't change the importance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import android.content.Intent;
import androidx.test.core.app.ApplicationProvider;
import com.google.firebase.FirebaseApp;
import com.google.firebase.appdistribution.InterruptionLevel;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -110,7 +111,7 @@ public void showAppUpdateNotification_withZeroTotalBytes_shows0Percent() {
@Test
public void showFeedbackNotification_createsGroupAndChannel() {
firebaseAppDistributionNotificationsManager.showFeedbackNotification(
"Terms and conditions", IMPORTANCE_HIGH);
"Terms and conditions", InterruptionLevel.HIGH);
assertThat(shadowOf(notificationManager).getNotificationChannelGroup(CHANNEL_GROUP_ID))
.isNotNull();
assertThat(shadowOf(notificationManager).getNotificationChannels()).hasSize(1);
Expand All @@ -123,7 +124,7 @@ public void showFeedbackNotification_createsGroupAndChannel() {
@Test
public void showFeedbackNotification_setsIntentToScreenshotActivity() {
firebaseAppDistributionNotificationsManager.showFeedbackNotification(
"Terms and conditions", IMPORTANCE_HIGH);
"Terms and conditions", InterruptionLevel.HIGH);
assertThat(shadowOf(notificationManager).size()).isEqualTo(1);
Notification notification =
shadowOf(notificationManager).getNotification(FEEDBACK.tag, FEEDBACK.id);
Expand All @@ -141,7 +142,7 @@ public void showFeedbackNotification_setsIntentToScreenshotActivity() {
@Test
public void showFeedbackNotification_convertsImportanceToPriority() {
firebaseAppDistributionNotificationsManager.showFeedbackNotification(
"Terms and conditions", IMPORTANCE_HIGH);
"Terms and conditions", InterruptionLevel.HIGH);
assertThat(shadowOf(notificationManager).size()).isEqualTo(1);
Notification notification =
shadowOf(notificationManager).getNotification(FEEDBACK.tag, FEEDBACK.id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import androidx.core.widget.doOnTextChanged
import com.google.android.gms.tasks.Task
import com.google.android.material.textfield.TextInputLayout
import com.google.firebase.appdistribution.AppDistributionRelease
import com.google.firebase.appdistribution.InterruptionLevel
import com.google.firebase.appdistribution.UpdateProgress
import com.google.firebase.appdistribution.ktx.appDistribution
import com.google.firebase.ktx.Firebase
Expand Down Expand Up @@ -94,7 +95,7 @@ class MainActivity : AppCompatActivity() {
disableAllFeedbackTriggers()
Log.i(TAG, "Enabling notification trigger (SDK)")
firebaseAppDistribution.showFeedbackNotification(
R.string.termsAndConditions, NotificationManagerCompat.IMPORTANCE_HIGH)
R.string.termsAndConditions, InterruptionLevel.HIGH)
}
FeedbackTrigger.CUSTOM_NOTIFICATION.label -> {
disableAllFeedbackTriggers()
Expand Down