Merge "Refactor smart reply inflation functionality into its own class."
This commit is contained in:
committed by
Android (Google) Code Review
commit
cf60b4c4f4
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.row;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
@@ -28,7 +27,6 @@ import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.NotificationHeaderView;
|
||||
import android.view.View;
|
||||
@@ -39,7 +37,6 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.ContrastColorUtil;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
@@ -52,13 +49,14 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
|
||||
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
|
||||
import com.android.systemui.statusbar.phone.NotificationGroupManager;
|
||||
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
|
||||
import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
|
||||
import com.android.systemui.statusbar.policy.RemoteInputView;
|
||||
import com.android.systemui.statusbar.policy.SmartReplyConstants;
|
||||
import com.android.systemui.statusbar.policy.SmartReplyView;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A frame layout containing the actual payload of the notification, including the contracted,
|
||||
@@ -1319,7 +1317,7 @@ public class NotificationContentView extends FrameLayout {
|
||||
}
|
||||
|
||||
SmartRepliesAndActions smartRepliesAndActions =
|
||||
chooseSmartRepliesAndActions(mSmartReplyConstants, entry);
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, entry);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, String.format("Adding suggestions for %s, %d actions, and %d replies.",
|
||||
entry.notification.getKey(),
|
||||
@@ -1328,86 +1326,10 @@ public class NotificationContentView extends FrameLayout {
|
||||
smartRepliesAndActions.smartReplies == null ? 0 :
|
||||
smartRepliesAndActions.smartReplies.choices.length));
|
||||
}
|
||||
|
||||
applyRemoteInput(entry, smartRepliesAndActions.hasFreeformRemoteInput);
|
||||
applyRemoteInput(entry, InflatedSmartReplies.hasFreeformRemoteInput(entry));
|
||||
applySmartReplyView(smartRepliesAndActions, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Chose what smart replies and smart actions to display. App generated suggestions take
|
||||
* precedence. So if the app provides any smart replies, we don't show any
|
||||
* replies or actions generated by the NotificationAssistantService (NAS), and if the app
|
||||
* provides any smart actions we also don't show any NAS-generated replies or actions.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static SmartRepliesAndActions chooseSmartRepliesAndActions(
|
||||
SmartReplyConstants smartReplyConstants,
|
||||
final NotificationEntry entry) {
|
||||
Notification notification = entry.notification.getNotification();
|
||||
Pair<RemoteInput, Notification.Action> remoteInputActionPair =
|
||||
notification.findRemoteInputActionPair(false /* freeform */);
|
||||
Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair =
|
||||
notification.findRemoteInputActionPair(true /* freeform */);
|
||||
|
||||
if (!smartReplyConstants.isEnabled()) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Smart suggestions not enabled, not adding suggestions for "
|
||||
+ entry.notification.getKey());
|
||||
}
|
||||
return new SmartRepliesAndActions(null, null, freeformRemoteInputActionPair != null);
|
||||
}
|
||||
// Only use smart replies from the app if they target P or above. We have this check because
|
||||
// the smart reply API has been used for other things (Wearables) in the past. The API to
|
||||
// add smart actions is new in Q so it doesn't require a target-sdk check.
|
||||
boolean enableAppGeneratedSmartReplies = (!smartReplyConstants.requiresTargetingP()
|
||||
|| entry.targetSdk >= Build.VERSION_CODES.P);
|
||||
|
||||
boolean appGeneratedSmartRepliesExist =
|
||||
enableAppGeneratedSmartReplies
|
||||
&& remoteInputActionPair != null
|
||||
&& !ArrayUtils.isEmpty(remoteInputActionPair.first.getChoices())
|
||||
&& remoteInputActionPair.second.actionIntent != null;
|
||||
|
||||
List<Notification.Action> appGeneratedSmartActions = notification.getContextualActions();
|
||||
boolean appGeneratedSmartActionsExist = !appGeneratedSmartActions.isEmpty();
|
||||
|
||||
SmartReplyView.SmartReplies smartReplies = null;
|
||||
SmartReplyView.SmartActions smartActions = null;
|
||||
if (appGeneratedSmartRepliesExist) {
|
||||
smartReplies = new SmartReplyView.SmartReplies(
|
||||
remoteInputActionPair.first.getChoices(),
|
||||
remoteInputActionPair.first,
|
||||
remoteInputActionPair.second.actionIntent,
|
||||
false /* fromAssistant */);
|
||||
}
|
||||
if (appGeneratedSmartActionsExist) {
|
||||
smartActions = new SmartReplyView.SmartActions(appGeneratedSmartActions,
|
||||
false /* fromAssistant */);
|
||||
}
|
||||
// Apps didn't provide any smart replies / actions, use those from NAS (if any).
|
||||
if (!appGeneratedSmartRepliesExist && !appGeneratedSmartActionsExist) {
|
||||
boolean useGeneratedReplies = !ArrayUtils.isEmpty(entry.systemGeneratedSmartReplies)
|
||||
&& freeformRemoteInputActionPair != null
|
||||
&& freeformRemoteInputActionPair.second.getAllowGeneratedReplies()
|
||||
&& freeformRemoteInputActionPair.second.actionIntent != null;
|
||||
if (useGeneratedReplies) {
|
||||
smartReplies = new SmartReplyView.SmartReplies(
|
||||
entry.systemGeneratedSmartReplies,
|
||||
freeformRemoteInputActionPair.first,
|
||||
freeformRemoteInputActionPair.second.actionIntent,
|
||||
true /* fromAssistant */);
|
||||
}
|
||||
boolean useSmartActions = !ArrayUtils.isEmpty(entry.systemGeneratedSmartActions)
|
||||
&& notification.getAllowSystemGeneratedContextualActions();
|
||||
if (useSmartActions) {
|
||||
smartActions = new SmartReplyView.SmartActions(
|
||||
entry.systemGeneratedSmartActions, true /* fromAssistant */);
|
||||
}
|
||||
}
|
||||
return new SmartRepliesAndActions(
|
||||
smartReplies, smartActions, freeformRemoteInputActionPair != null);
|
||||
}
|
||||
|
||||
private void applyRemoteInput(NotificationEntry entry, boolean hasFreeformRemoteInput) {
|
||||
View bigContentView = mExpandedChild;
|
||||
if (bigContentView != null) {
|
||||
@@ -1546,26 +1468,11 @@ public class NotificationContentView extends FrameLayout {
|
||||
return null;
|
||||
}
|
||||
LinearLayout smartReplyContainer = (LinearLayout) smartReplyContainerCandidate;
|
||||
// If there are no smart replies and no smart actions - early out.
|
||||
if (smartRepliesAndActions.smartReplies == null
|
||||
&& smartRepliesAndActions.smartActions == null) {
|
||||
smartReplyContainer.setVisibility(View.GONE);
|
||||
return null;
|
||||
}
|
||||
// If we are showing the spinner we don't want to add the buttons.
|
||||
boolean showingSpinner = entry.notification.getNotification()
|
||||
.extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
|
||||
if (showingSpinner) {
|
||||
smartReplyContainer.setVisibility(View.GONE);
|
||||
return null;
|
||||
}
|
||||
// If we are keeping the notification around while sending we don't want to add the buttons.
|
||||
boolean hideSmartReplies = entry.notification.getNotification()
|
||||
.extras.getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false);
|
||||
if (hideSmartReplies) {
|
||||
if (!InflatedSmartReplies.shouldShowSmartReplyView(entry, smartRepliesAndActions)) {
|
||||
smartReplyContainer.setVisibility(View.GONE);
|
||||
return null;
|
||||
}
|
||||
|
||||
SmartReplyView smartReplyView = null;
|
||||
if (smartReplyContainer.getChildCount() == 0) {
|
||||
smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer);
|
||||
@@ -2005,22 +1912,4 @@ public class NotificationContentView extends FrameLayout {
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static class SmartRepliesAndActions {
|
||||
@Nullable
|
||||
public final SmartReplyView.SmartReplies smartReplies;
|
||||
@Nullable
|
||||
public final SmartReplyView.SmartActions smartActions;
|
||||
public final boolean hasFreeformRemoteInput;
|
||||
|
||||
SmartRepliesAndActions(
|
||||
@Nullable SmartReplyView.SmartReplies smartReplies,
|
||||
@Nullable SmartReplyView.SmartActions smartActions,
|
||||
boolean hasFreeformRemoteInput) {
|
||||
this.smartReplies = smartReplies;
|
||||
this.smartActions = smartActions;
|
||||
this.hasFreeformRemoteInput = hasFreeformRemoteInput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* 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.android.systemui.statusbar.policy;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Notification;
|
||||
import android.app.RemoteInput;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holder for inflated smart replies and actions. These objects should be inflated on a background
|
||||
* thread, to later be accessed and modified on the (performance critical) UI thread.
|
||||
*/
|
||||
public class InflatedSmartReplies {
|
||||
private static final String TAG = "InflatedSmartReplies";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private InflatedSmartReplies() { }
|
||||
|
||||
/**
|
||||
* Returns whether we should show the smart reply view and its smart suggestions.
|
||||
*/
|
||||
public static boolean shouldShowSmartReplyView(
|
||||
NotificationEntry entry,
|
||||
SmartRepliesAndActions smartRepliesAndActions) {
|
||||
if (smartRepliesAndActions.smartReplies == null
|
||||
&& smartRepliesAndActions.smartActions == null) {
|
||||
// There are no smart replies and no smart actions.
|
||||
return false;
|
||||
}
|
||||
// If we are showing the spinner we don't want to add the buttons.
|
||||
boolean showingSpinner = entry.notification.getNotification()
|
||||
.extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
|
||||
if (showingSpinner) {
|
||||
return false;
|
||||
}
|
||||
// If we are keeping the notification around while sending we don't want to add the buttons.
|
||||
boolean hideSmartReplies = entry.notification.getNotification()
|
||||
.extras.getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false);
|
||||
if (hideSmartReplies) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chose what smart replies and smart actions to display. App generated suggestions take
|
||||
* precedence. So if the app provides any smart replies, we don't show any
|
||||
* replies or actions generated by the NotificationAssistantService (NAS), and if the app
|
||||
* provides any smart actions we also don't show any NAS-generated replies or actions.
|
||||
*/
|
||||
@NonNull
|
||||
public static SmartRepliesAndActions chooseSmartRepliesAndActions(
|
||||
SmartReplyConstants smartReplyConstants,
|
||||
final NotificationEntry entry) {
|
||||
Notification notification = entry.notification.getNotification();
|
||||
Pair<RemoteInput, Notification.Action> remoteInputActionPair =
|
||||
notification.findRemoteInputActionPair(false /* freeform */);
|
||||
Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair =
|
||||
notification.findRemoteInputActionPair(true /* freeform */);
|
||||
|
||||
if (!smartReplyConstants.isEnabled()) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Smart suggestions not enabled, not adding suggestions for "
|
||||
+ entry.notification.getKey());
|
||||
}
|
||||
return new SmartRepliesAndActions(null, null);
|
||||
}
|
||||
// Only use smart replies from the app if they target P or above. We have this check because
|
||||
// the smart reply API has been used for other things (Wearables) in the past. The API to
|
||||
// add smart actions is new in Q so it doesn't require a target-sdk check.
|
||||
boolean enableAppGeneratedSmartReplies = (!smartReplyConstants.requiresTargetingP()
|
||||
|| entry.targetSdk >= Build.VERSION_CODES.P);
|
||||
|
||||
boolean appGeneratedSmartRepliesExist =
|
||||
enableAppGeneratedSmartReplies
|
||||
&& remoteInputActionPair != null
|
||||
&& !ArrayUtils.isEmpty(remoteInputActionPair.first.getChoices())
|
||||
&& remoteInputActionPair.second.actionIntent != null;
|
||||
|
||||
List<Notification.Action> appGeneratedSmartActions = notification.getContextualActions();
|
||||
boolean appGeneratedSmartActionsExist = !appGeneratedSmartActions.isEmpty();
|
||||
|
||||
SmartReplyView.SmartReplies smartReplies = null;
|
||||
SmartReplyView.SmartActions smartActions = null;
|
||||
if (appGeneratedSmartRepliesExist) {
|
||||
smartReplies = new SmartReplyView.SmartReplies(
|
||||
remoteInputActionPair.first.getChoices(),
|
||||
remoteInputActionPair.first,
|
||||
remoteInputActionPair.second.actionIntent,
|
||||
false /* fromAssistant */);
|
||||
}
|
||||
if (appGeneratedSmartActionsExist) {
|
||||
smartActions = new SmartReplyView.SmartActions(appGeneratedSmartActions,
|
||||
false /* fromAssistant */);
|
||||
}
|
||||
// Apps didn't provide any smart replies / actions, use those from NAS (if any).
|
||||
if (!appGeneratedSmartRepliesExist && !appGeneratedSmartActionsExist) {
|
||||
boolean useGeneratedReplies = !ArrayUtils.isEmpty(entry.systemGeneratedSmartReplies)
|
||||
&& freeformRemoteInputActionPair != null
|
||||
&& freeformRemoteInputActionPair.second.getAllowGeneratedReplies()
|
||||
&& freeformRemoteInputActionPair.second.actionIntent != null;
|
||||
if (useGeneratedReplies) {
|
||||
smartReplies = new SmartReplyView.SmartReplies(
|
||||
entry.systemGeneratedSmartReplies,
|
||||
freeformRemoteInputActionPair.first,
|
||||
freeformRemoteInputActionPair.second.actionIntent,
|
||||
true /* fromAssistant */);
|
||||
}
|
||||
boolean useSmartActions = !ArrayUtils.isEmpty(entry.systemGeneratedSmartActions)
|
||||
&& notification.getAllowSystemGeneratedContextualActions();
|
||||
if (useSmartActions) {
|
||||
smartActions = new SmartReplyView.SmartActions(
|
||||
entry.systemGeneratedSmartActions, true /* fromAssistant */);
|
||||
}
|
||||
}
|
||||
return new SmartRepliesAndActions(smartReplies, smartActions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link Notification} represented by entry has a free-form remote input.
|
||||
* Such an input can be used e.g. to implement smart reply buttons - by passing the replies
|
||||
* through the remote input.
|
||||
*/
|
||||
public static boolean hasFreeformRemoteInput(NotificationEntry entry) {
|
||||
Notification notification = entry.notification.getNotification();
|
||||
return null != notification.findRemoteInputActionPair(true /* freeform */);
|
||||
}
|
||||
|
||||
/**
|
||||
* A storage for smart replies and smart action.
|
||||
*/
|
||||
public static class SmartRepliesAndActions {
|
||||
@Nullable public final SmartReplyView.SmartReplies smartReplies;
|
||||
@Nullable public final SmartReplyView.SmartActions smartActions;
|
||||
|
||||
SmartRepliesAndActions(
|
||||
@Nullable SmartReplyView.SmartReplies smartReplies,
|
||||
@Nullable SmartReplyView.SmartActions smartActions) {
|
||||
this.smartReplies = smartReplies;
|
||||
this.smartActions = smartActions;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification.row;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
@@ -31,62 +29,31 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.support.test.annotation.UiThreadTest;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Pair;
|
||||
import android.view.NotificationHeaderView;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.policy.SmartReplyConstants;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NotificationContentViewTest extends SysuiTestCase {
|
||||
|
||||
private static final String TEST_ACTION = "com.android.SMART_REPLY_VIEW_ACTION";
|
||||
|
||||
NotificationContentView mView;
|
||||
|
||||
@Mock
|
||||
SmartReplyConstants mSmartReplyConstants;
|
||||
@Mock
|
||||
StatusBarNotification mStatusBarNotification;
|
||||
@Mock
|
||||
Notification mNotification;
|
||||
NotificationEntry mEntry;
|
||||
@Mock
|
||||
RemoteInput mRemoteInput;
|
||||
@Mock
|
||||
RemoteInput mFreeFormRemoteInput;
|
||||
|
||||
private Icon mActionIcon;
|
||||
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mView = new NotificationContentView(mContext, null);
|
||||
ExpandableNotificationRow row = new ExpandableNotificationRow(mContext, null);
|
||||
ExpandableNotificationRow mockRow = spy(row);
|
||||
@@ -103,13 +70,6 @@ public class NotificationContentViewTest extends SysuiTestCase {
|
||||
|
||||
mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
||||
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
|
||||
|
||||
// Smart replies and actions
|
||||
when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(true);
|
||||
when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
|
||||
mEntry = new NotificationEntry(mStatusBarNotification);
|
||||
when(mSmartReplyConstants.isEnabled()).thenReturn(true);
|
||||
mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
|
||||
}
|
||||
|
||||
private View createViewWithHeight(int height) {
|
||||
@@ -158,204 +118,4 @@ public class NotificationContentViewTest extends SysuiTestCase {
|
||||
verify(mockAmbient, never()).showAppOpsIcons(ops);
|
||||
verify(mockHeadsUp, times(1)).showAppOpsIcons(any());
|
||||
}
|
||||
|
||||
private void setupAppGeneratedReplies(CharSequence[] smartReplies) {
|
||||
setupAppGeneratedReplies(smartReplies, true /* allowSystemGeneratedReplies */);
|
||||
}
|
||||
|
||||
private void setupAppGeneratedReplies(
|
||||
CharSequence[] smartReplies, boolean allowSystemGeneratedReplies) {
|
||||
PendingIntent pendingIntent =
|
||||
PendingIntent.getBroadcast(mContext, 0, new Intent(TEST_ACTION), 0);
|
||||
Notification.Action action =
|
||||
new Notification.Action.Builder(null, "Test Action", pendingIntent).build();
|
||||
when(mRemoteInput.getChoices()).thenReturn(smartReplies);
|
||||
Pair<RemoteInput, Notification.Action> remoteInputActionPair =
|
||||
Pair.create(mRemoteInput, action);
|
||||
when(mNotification.findRemoteInputActionPair(false)).thenReturn(remoteInputActionPair);
|
||||
|
||||
Notification.Action freeFormRemoteInputAction =
|
||||
createActionBuilder("Freeform Test Action")
|
||||
.setAllowGeneratedReplies(allowSystemGeneratedReplies)
|
||||
.build();
|
||||
Pair<RemoteInput, Notification.Action> freeFormRemoteInputActionPair =
|
||||
Pair.create(mFreeFormRemoteInput, freeFormRemoteInputAction);
|
||||
when(mNotification.findRemoteInputActionPair(true)).thenReturn(
|
||||
freeFormRemoteInputActionPair);
|
||||
|
||||
when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
|
||||
}
|
||||
|
||||
private void setupAppGeneratedSuggestions(
|
||||
CharSequence[] smartReplies, List<Notification.Action> smartActions) {
|
||||
setupAppGeneratedReplies(smartReplies);
|
||||
when(mNotification.getContextualActions()).thenReturn(smartActions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_smartRepliesOff_noAppGeneratedSmartSuggestions() {
|
||||
CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
|
||||
List<Notification.Action> smartActions =
|
||||
createActions(new String[] {"Test Action 1", "Test Action 2"});
|
||||
setupAppGeneratedSuggestions(smartReplies, smartActions);
|
||||
when(mSmartReplyConstants.isEnabled()).thenReturn(false);
|
||||
|
||||
NotificationContentView.SmartRepliesAndActions repliesAndActions =
|
||||
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_smartRepliesOff_noSystemGeneratedSmartSuggestions() {
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
mEntry.systemGeneratedSmartActions =
|
||||
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
|
||||
when(mSmartReplyConstants.isEnabled()).thenReturn(false);
|
||||
|
||||
NotificationContentView.SmartRepliesAndActions repliesAndActions =
|
||||
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_appGeneratedSmartReplies() {
|
||||
CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
|
||||
setupAppGeneratedReplies(smartReplies);
|
||||
|
||||
NotificationContentView.SmartRepliesAndActions repliesAndActions =
|
||||
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(smartReplies);
|
||||
assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_appGeneratedSmartRepliesAndActions() {
|
||||
CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
|
||||
List<Notification.Action> smartActions =
|
||||
createActions(new String[] {"Test Action 1", "Test Action 2"});
|
||||
setupAppGeneratedSuggestions(smartReplies, smartActions);
|
||||
|
||||
NotificationContentView.SmartRepliesAndActions repliesAndActions =
|
||||
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(smartReplies);
|
||||
assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse();
|
||||
assertThat(repliesAndActions.smartActions.actions).isEqualTo(smartActions);
|
||||
assertThat(repliesAndActions.smartActions.fromAssistant).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_sysGeneratedSmartReplies() {
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// replies.
|
||||
setupAppGeneratedReplies(null /* smartReplies */);
|
||||
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
NotificationContentView.SmartRepliesAndActions repliesAndActions =
|
||||
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(
|
||||
mEntry.systemGeneratedSmartReplies);
|
||||
assertThat(repliesAndActions.smartReplies.fromAssistant).isTrue();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_noSysGeneratedSmartRepliesIfNotAllowed() {
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// replies.
|
||||
setupAppGeneratedReplies(null /* smartReplies */, false /* allowSystemGeneratedReplies */);
|
||||
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
NotificationContentView.SmartRepliesAndActions repliesAndActions =
|
||||
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_sysGeneratedSmartActions() {
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// actions.
|
||||
setupAppGeneratedReplies(null /* smartReplies */);
|
||||
|
||||
mEntry.systemGeneratedSmartActions =
|
||||
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
|
||||
NotificationContentView.SmartRepliesAndActions repliesAndActions =
|
||||
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
assertThat(repliesAndActions.smartActions.actions)
|
||||
.isEqualTo(mEntry.systemGeneratedSmartActions);
|
||||
assertThat(repliesAndActions.smartActions.fromAssistant).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_appGenPreferredOverSysGen() {
|
||||
CharSequence[] appGenSmartReplies = new String[] {"Reply1", "Reply2"};
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// replies.
|
||||
List<Notification.Action> appGenSmartActions =
|
||||
createActions(new String[] {"Test Action 1", "Test Action 2"});
|
||||
setupAppGeneratedSuggestions(appGenSmartReplies, appGenSmartActions);
|
||||
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
mEntry.systemGeneratedSmartActions =
|
||||
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
|
||||
|
||||
NotificationContentView.SmartRepliesAndActions repliesAndActions =
|
||||
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(appGenSmartReplies);
|
||||
assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse();
|
||||
assertThat(repliesAndActions.smartActions.actions).isEqualTo(appGenSmartActions);
|
||||
assertThat(repliesAndActions.smartActions.fromAssistant).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_disallowSysGenSmartActions() {
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// actions.
|
||||
setupAppGeneratedReplies(null /* smartReplies */, false /* allowSystemGeneratedReplies */);
|
||||
when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(false);
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
mEntry.systemGeneratedSmartActions =
|
||||
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
|
||||
|
||||
NotificationContentView.SmartRepliesAndActions repliesAndActions =
|
||||
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
}
|
||||
|
||||
private Notification.Action.Builder createActionBuilder(String actionTitle) {
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
|
||||
new Intent(TEST_ACTION), 0);
|
||||
return new Notification.Action.Builder(mActionIcon, actionTitle, pendingIntent);
|
||||
}
|
||||
|
||||
private Notification.Action createAction(String actionTitle) {
|
||||
return createActionBuilder(actionTitle).build();
|
||||
}
|
||||
|
||||
private List<Notification.Action> createActions(String[] actionTitles) {
|
||||
List<Notification.Action> actions = new ArrayList<>();
|
||||
for (String title : actionTitles) {
|
||||
actions.add(createAction(title));
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* 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.android.systemui.statusbar.policy;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.support.test.annotation.UiThreadTest;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class InflatedSmartRepliesTest extends SysuiTestCase {
|
||||
|
||||
private static final String TEST_ACTION = "com.android.SMART_REPLY_VIEW_ACTION";
|
||||
|
||||
@Mock
|
||||
SmartReplyConstants mSmartReplyConstants;
|
||||
@Mock
|
||||
StatusBarNotification mStatusBarNotification;
|
||||
@Mock
|
||||
Notification mNotification;
|
||||
NotificationEntry mEntry;
|
||||
@Mock
|
||||
RemoteInput mRemoteInput;
|
||||
@Mock
|
||||
RemoteInput mFreeFormRemoteInput;
|
||||
|
||||
private Icon mActionIcon;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(true);
|
||||
when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
|
||||
mEntry = new NotificationEntry(mStatusBarNotification);
|
||||
when(mSmartReplyConstants.isEnabled()).thenReturn(true);
|
||||
mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_smartRepliesOff_noAppGeneratedSmartSuggestions() {
|
||||
CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
|
||||
List<Notification.Action> smartActions =
|
||||
createActions(new String[] {"Test Action 1", "Test Action 2"});
|
||||
setupAppGeneratedSuggestions(smartReplies, smartActions);
|
||||
when(mSmartReplyConstants.isEnabled()).thenReturn(false);
|
||||
|
||||
SmartRepliesAndActions repliesAndActions =
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_smartRepliesOff_noSystemGeneratedSmartSuggestions() {
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
mEntry.systemGeneratedSmartActions =
|
||||
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
|
||||
when(mSmartReplyConstants.isEnabled()).thenReturn(false);
|
||||
|
||||
SmartRepliesAndActions repliesAndActions =
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_appGeneratedSmartReplies() {
|
||||
CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
|
||||
setupAppGeneratedReplies(smartReplies);
|
||||
|
||||
SmartRepliesAndActions repliesAndActions =
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(smartReplies);
|
||||
assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_appGeneratedSmartRepliesAndActions() {
|
||||
CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
|
||||
List<Notification.Action> smartActions =
|
||||
createActions(new String[] {"Test Action 1", "Test Action 2"});
|
||||
setupAppGeneratedSuggestions(smartReplies, smartActions);
|
||||
|
||||
SmartRepliesAndActions repliesAndActions =
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(smartReplies);
|
||||
assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse();
|
||||
assertThat(repliesAndActions.smartActions.actions).isEqualTo(smartActions);
|
||||
assertThat(repliesAndActions.smartActions.fromAssistant).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_sysGeneratedSmartReplies() {
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// replies.
|
||||
setupAppGeneratedReplies(null /* smartReplies */);
|
||||
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
SmartRepliesAndActions repliesAndActions =
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(
|
||||
mEntry.systemGeneratedSmartReplies);
|
||||
assertThat(repliesAndActions.smartReplies.fromAssistant).isTrue();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_noSysGeneratedSmartRepliesIfNotAllowed() {
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// replies.
|
||||
setupAppGeneratedReplies(null /* smartReplies */, false /* allowSystemGeneratedReplies */);
|
||||
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
SmartRepliesAndActions repliesAndActions =
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_sysGeneratedSmartActions() {
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// actions.
|
||||
setupAppGeneratedReplies(null /* smartReplies */);
|
||||
|
||||
mEntry.systemGeneratedSmartActions =
|
||||
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
|
||||
SmartRepliesAndActions repliesAndActions =
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
assertThat(repliesAndActions.smartActions.actions)
|
||||
.isEqualTo(mEntry.systemGeneratedSmartActions);
|
||||
assertThat(repliesAndActions.smartActions.fromAssistant).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_appGenPreferredOverSysGen() {
|
||||
CharSequence[] appGenSmartReplies = new String[] {"Reply1", "Reply2"};
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// replies.
|
||||
List<Notification.Action> appGenSmartActions =
|
||||
createActions(new String[] {"Test Action 1", "Test Action 2"});
|
||||
setupAppGeneratedSuggestions(appGenSmartReplies, appGenSmartActions);
|
||||
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
mEntry.systemGeneratedSmartActions =
|
||||
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
|
||||
|
||||
SmartRepliesAndActions repliesAndActions =
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(appGenSmartReplies);
|
||||
assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse();
|
||||
assertThat(repliesAndActions.smartActions.actions).isEqualTo(appGenSmartActions);
|
||||
assertThat(repliesAndActions.smartActions.fromAssistant).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chooseSmartRepliesAndActions_disallowSysGenSmartActions() {
|
||||
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
|
||||
// actions.
|
||||
setupAppGeneratedReplies(null /* smartReplies */, false /* allowSystemGeneratedReplies */);
|
||||
when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(false);
|
||||
mEntry.systemGeneratedSmartReplies =
|
||||
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
|
||||
mEntry.systemGeneratedSmartActions =
|
||||
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
|
||||
|
||||
SmartRepliesAndActions repliesAndActions =
|
||||
InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
|
||||
|
||||
assertThat(repliesAndActions.smartActions).isNull();
|
||||
assertThat(repliesAndActions.smartReplies).isNull();
|
||||
}
|
||||
|
||||
private void setupAppGeneratedReplies(CharSequence[] smartReplies) {
|
||||
setupAppGeneratedReplies(smartReplies, true /* allowSystemGeneratedReplies */);
|
||||
}
|
||||
|
||||
private void setupAppGeneratedReplies(
|
||||
CharSequence[] smartReplies, boolean allowSystemGeneratedReplies) {
|
||||
PendingIntent pendingIntent =
|
||||
PendingIntent.getBroadcast(mContext, 0, new Intent(TEST_ACTION), 0);
|
||||
Notification.Action action =
|
||||
new Notification.Action.Builder(null, "Test Action", pendingIntent).build();
|
||||
when(mRemoteInput.getChoices()).thenReturn(smartReplies);
|
||||
Pair<RemoteInput, Notification.Action> remoteInputActionPair =
|
||||
Pair.create(mRemoteInput, action);
|
||||
when(mNotification.findRemoteInputActionPair(false)).thenReturn(remoteInputActionPair);
|
||||
|
||||
Notification.Action freeFormRemoteInputAction =
|
||||
createActionBuilder("Freeform Test Action")
|
||||
.setAllowGeneratedReplies(allowSystemGeneratedReplies)
|
||||
.build();
|
||||
Pair<RemoteInput, Notification.Action> freeFormRemoteInputActionPair =
|
||||
Pair.create(mFreeFormRemoteInput, freeFormRemoteInputAction);
|
||||
when(mNotification.findRemoteInputActionPair(true)).thenReturn(
|
||||
freeFormRemoteInputActionPair);
|
||||
|
||||
when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
|
||||
}
|
||||
|
||||
private void setupAppGeneratedSuggestions(
|
||||
CharSequence[] smartReplies, List<Notification.Action> smartActions) {
|
||||
setupAppGeneratedReplies(smartReplies);
|
||||
when(mNotification.getContextualActions()).thenReturn(smartActions);
|
||||
}
|
||||
|
||||
private Notification.Action.Builder createActionBuilder(String actionTitle) {
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
|
||||
new Intent(TEST_ACTION), 0);
|
||||
return new Notification.Action.Builder(mActionIcon, actionTitle, pendingIntent);
|
||||
}
|
||||
|
||||
private Notification.Action createAction(String actionTitle) {
|
||||
return createActionBuilder(actionTitle).build();
|
||||
}
|
||||
|
||||
private List<Notification.Action> createActions(String[] actionTitles) {
|
||||
List<Notification.Action> actions = new ArrayList<>();
|
||||
for (String title : actionTitles) {
|
||||
actions.add(createAction(title));
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user