Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 761884ce authored by Gustav Sennton's avatar Gustav Sennton
Browse files

Add Notification.Builder.setAllowSystemGeneratedContextualActions().

If an app doesn't add any smart replies or smart (contextual) actions to
their (message) notifications the Android platform fills in smart
replies and actions for the app.
With this CL we add a way to opt out of system generated contextual
actions.

Bug: 119765729
Test: atest NotificationContentViewTest
Change-Id: I6190fd197f74b8353f7113f2d8ba86068c2b78ab
parent 5c4f2149
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -5229,6 +5229,7 @@ package android.app {
    ctor public Notification(android.os.Parcel);
    method public android.app.Notification clone();
    method public int describeContents();
    method public boolean getAllowSystemGeneratedContextualActions();
    method public android.app.PendingIntent getAppOverlayIntent();
    method public int getBadgeIconType();
    method public java.lang.String getChannelId();
@@ -5460,6 +5461,7 @@ package android.app {
    method public android.app.Notification.Style getStyle();
    method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
    method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
    method public android.app.Notification.Builder setAllowSystemGeneratedContextualActions(boolean);
    method public android.app.Notification.Builder setAppOverlayIntent(android.app.PendingIntent);
    method public android.app.Notification.Builder setAutoCancel(boolean);
    method public android.app.Notification.Builder setBadgeIconType(int);
+23 −0
Original line number Diff line number Diff line
@@ -1337,6 +1337,11 @@ public class Notification implements Parcelable
    public static final int BADGE_ICON_LARGE = 2;
    private int mBadgeIcon = BADGE_ICON_NONE;

    /**
     * Determines whether the platform can generate contextual actions for a notification.
     */
    private boolean mAllowSystemGeneratedContextualActions = true;

    /**
     * Structure to encapsulate a named action that can be shown as part of this notification.
     * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
@@ -2238,6 +2243,8 @@ public class Notification implements Parcelable
        if (parcel.readInt() != 0) {
            mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel);
        }

        mAllowSystemGeneratedContextualActions = parcel.readBoolean();
    }

    @Override
@@ -2353,6 +2360,7 @@ public class Notification implements Parcelable
        that.mSettingsText = this.mSettingsText;
        that.mGroupAlertBehavior = this.mGroupAlertBehavior;
        that.mAppOverlayIntent = this.mAppOverlayIntent;
        that.mAllowSystemGeneratedContextualActions = this.mAllowSystemGeneratedContextualActions;

        if (!heavy) {
            that.lightenPayload(); // will clean out extras
@@ -2681,6 +2689,8 @@ public class Notification implements Parcelable
            parcel.writeInt(0);
        }

        parcel.writeBoolean(mAllowSystemGeneratedContextualActions);

        // mUsesStandardHeader is not written because it should be recomputed in listeners
    }

@@ -3101,6 +3111,10 @@ public class Notification implements Parcelable
        return mAppOverlayIntent;
    }

    public boolean getAllowSystemGeneratedContextualActions() {
        return mAllowSystemGeneratedContextualActions;
    }

    /**
     * The small icon representing this notification in the status bar and content view.
     *
@@ -5656,6 +5670,15 @@ public class Notification implements Parcelable
            return new Builder(builderContext, n);
        }

        /**
         * Determines whether the platform can generate contextual actions for a notification.
         * By default this is true.
         */
        public Builder setAllowSystemGeneratedContextualActions(boolean allowed) {
            mN.mAllowSystemGeneratedContextualActions = allowed;
            return this;
        }

        /**
         * @deprecated Use {@link #build()} instead.
         */
+7 −2
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import com.android.systemui.statusbar.policy.RemoteInputView;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyView;

import java.util.Collections;
import java.util.List;

/**
@@ -1322,6 +1323,10 @@ public class NotificationContentView extends FrameLayout {
        List<Notification.Action> appGeneratedSmartActions = notification.getContextualActions();
        boolean appGeneratedSmartActionsExist = !appGeneratedSmartActions.isEmpty();

        List<Notification.Action> sysGeneratedSmartActions =
                notification.getAllowSystemGeneratedContextualActions()
                        ? entry.systemGeneratedSmartActions : Collections.emptyList();

        if (appGeneratedSmartRepliesExist) {
            return new SmartRepliesAndActions(remoteInputActionPair.first,
                    remoteInputActionPair.second.actionIntent,
@@ -1338,11 +1343,11 @@ public class NotificationContentView extends FrameLayout {
            return new SmartRepliesAndActions(freeformRemoteInputActionPair.first,
                    freeformRemoteInputActionPair.second.actionIntent,
                    entry.smartReplies,
                    entry.systemGeneratedSmartActions,
                    sysGeneratedSmartActions,
                    freeformRemoteInputActionPair);
        }
        // App didn't generate anything, and there are no NAS-generated smart replies.
        return new SmartRepliesAndActions(null, null, null, entry.systemGeneratedSmartActions,
        return new SmartRepliesAndActions(null, null, null, sysGeneratedSmartActions,
                freeformRemoteInputActionPair);
    }

+19 −1
Original line number Diff line number Diff line
@@ -106,7 +106,8 @@ public class NotificationContentViewTest extends SysuiTestCase {
        mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());

        // Smart replies
        // Smart replies and actions
        when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(true);
        when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
        mEntry = new NotificationData.Entry(mStatusBarNotification);
        when(mSmartReplyConstants.isEnabled()).thenReturn(true);
@@ -299,6 +300,23 @@ public class NotificationContentViewTest extends SysuiTestCase {
        assertThat(repliesAndActions.smartActions, equalTo(appGenSmartActions));
    }

    @Test
    public void chooseSmartRepliesAndActions_disallowSysGenSmartActions() {
        // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
        // actions.
        setupAppGeneratedReplies(null);

        when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(false);

        mEntry.systemGeneratedSmartActions =
                createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
        NotificationContentView.SmartRepliesAndActions repliesAndActions =
                NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);

        assertThat(repliesAndActions.smartReplies, equalTo(null));
        assertThat(repliesAndActions.smartActions, is(empty()));
    }

    private Notification.Action.Builder createActionBuilder(String actionTitle) {
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
                new Intent(TEST_ACTION), 0);