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

Commit 628cb936 authored by Tony Mak's avatar Tony Mak
Browse files

Allow NotificationAssistantService to suggest smart actions

Here is the flow:
NAS generates Adjustment -> NMS convert this to RankingUpdate ->
SystemUI.NotificationListener receives the RankingUpdate in either
onNotificationPosted / onNotificationRankingUpdate (Depend on does NAS
provides the adjustment before the notification is en-queued) ->
NotificationEntryManager determines the need of reinflation ->
NotificationInflater inflates / reinflates the view with these
extra bits like smart actions.

Note: We do re-inflation here as simply adding a button to the existing
notification view seems problematic. For example, if the original
notification does not have any action, we will need to inflate the
template with the action container.

Screenshot:
https://hsv.googleplex.com/5731489463402496

Test: atest SystemUITests
Test: atest com.android.server.notification.NotificationAdjustmentExtractorTest
Test: Modify ExtServices to provide adjustment in
      createEnqueuedNotificationAdjustment, post a notification with
      a entity in a sample app, observed the notification is updated.
      (Testing the onNotificationPosted flow)
Test: Modify ExtServices to provide adjustment in onNotificationPosted
      by calling adjustNotification. Post a notification with
      a entity in a sample app, observed the notification is updated.
      (Testing the onRankingUpdated flow)
Test: Repeat the above test, but explicitly make the RowInflaterTask
      slow by inserting Thread.sleep. This can test the onRankingUpdated
      flow when the row is not yet inflated.

BUG: 110527159

Change-Id: I98aee3ac62f60b189ea92ac9fc000127325dfead
parent ce774071
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4664,6 +4664,7 @@ package android.service.notification {
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
    field public static final java.lang.String KEY_PEOPLE = "key_people";
    field public static final java.lang.String KEY_SMART_ACTIONS = "key_smart_actions";
    field public static final java.lang.String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
    field public static final java.lang.String KEY_USER_SENTIMENT = "key_user_sentiment";
  }
+1 −0
Original line number Diff line number Diff line
@@ -1041,6 +1041,7 @@ package android.service.notification {
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
    field public static final java.lang.String KEY_PEOPLE = "key_people";
    field public static final java.lang.String KEY_SMART_ACTIONS = "key_smart_actions";
    field public static final java.lang.String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
    field public static final java.lang.String KEY_USER_SENTIMENT = "key_user_sentiment";
  }
+6 −0
Original line number Diff line number Diff line
@@ -64,6 +64,12 @@ public final class Adjustment implements Parcelable {
     */
    public static final String KEY_USER_SENTIMENT = "key_user_sentiment";

    /**
     * Data type: ArrayList of {@link android.app.Notification.Action}.
     * Used to suggest extra actions for a notification.
     */
    public static final String KEY_SMART_ACTIONS = "key_smart_actions";

    /**
     * Create a notification adjustment.
     *
+30 −2
Original line number Diff line number Diff line
@@ -1426,6 +1426,7 @@ public abstract class NotificationListenerService extends Service {
        private boolean mShowBadge;
        private @UserSentiment int mUserSentiment = USER_SENTIMENT_NEUTRAL;
        private boolean mHidden;
        private ArrayList<Notification.Action> mSmartActions;

        public Ranking() {}

@@ -1555,6 +1556,13 @@ public abstract class NotificationListenerService extends Service {
            return mSnoozeCriteria;
        }

        /**
         * @hide
         */
        public List<Notification.Action> getSmartActions() {
            return mSmartActions;
        }

        /**
         * Returns whether this notification can be displayed as a badge.
         *
@@ -1583,7 +1591,7 @@ public abstract class NotificationListenerService extends Service {
                CharSequence explanation, String overrideGroupKey,
                NotificationChannel channel, ArrayList<String> overridePeople,
                ArrayList<SnoozeCriterion> snoozeCriteria, boolean showBadge,
                int userSentiment, boolean hidden) {
                int userSentiment, boolean hidden, ArrayList<Notification.Action> smartActions) {
            mKey = key;
            mRank = rank;
            mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
@@ -1599,6 +1607,7 @@ public abstract class NotificationListenerService extends Service {
            mShowBadge = showBadge;
            mUserSentiment = userSentiment;
            mHidden = hidden;
            mSmartActions = smartActions;
        }

        /**
@@ -1648,6 +1657,7 @@ public abstract class NotificationListenerService extends Service {
        private ArrayMap<String, Boolean> mShowBadge;
        private ArrayMap<String, Integer> mUserSentiment;
        private ArrayMap<String, Boolean> mHidden;
        private ArrayMap<String, ArrayList<Notification.Action>> mSmartActions;

        private RankingMap(NotificationRankingUpdate rankingUpdate) {
            mRankingUpdate = rankingUpdate;
@@ -1676,7 +1686,7 @@ public abstract class NotificationListenerService extends Service {
                    getVisibilityOverride(key), getSuppressedVisualEffects(key),
                    getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key),
                    getChannel(key), getOverridePeople(key), getSnoozeCriteria(key),
                    getShowBadge(key), getUserSentiment(key), getHidden(key));
                    getShowBadge(key), getUserSentiment(key), getHidden(key), getSmartActions(key));
            return rank >= 0;
        }

@@ -1814,6 +1824,15 @@ public abstract class NotificationListenerService extends Service {
            return hidden == null ? false : hidden.booleanValue();
        }

        private ArrayList<Notification.Action> getSmartActions(String key) {
            synchronized (this) {
                if (mSmartActions == null) {
                    buildSmartActions();
                }
            }
            return mSmartActions.get(key);
        }

        // Locked by 'this'
        private void buildRanksLocked() {
            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
@@ -1931,6 +1950,15 @@ public abstract class NotificationListenerService extends Service {
            }
        }

        // Locked by 'this'
        private void buildSmartActions() {
            Bundle smartActions = mRankingUpdate.getSmartActions();
            mSmartActions = new ArrayMap<>(smartActions.size());
            for (String key : smartActions.keySet()) {
                mSmartActions.put(key, smartActions.getParcelableArrayList(key));
            }
        }

        // ----------- Parcelable

        @Override
+9 −1
Original line number Diff line number Diff line
@@ -37,12 +37,13 @@ public class NotificationRankingUpdate implements Parcelable {
    private final Bundle mShowBadge;
    private final Bundle mUserSentiment;
    private final Bundle mHidden;
    private final Bundle mSmartActions;

    public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
            Bundle visibilityOverrides, Bundle suppressedVisualEffects,
            int[] importance, Bundle explanation, Bundle overrideGroupKeys,
            Bundle channels, Bundle overridePeople, Bundle snoozeCriteria,
            Bundle showBadge, Bundle userSentiment, Bundle hidden) {
            Bundle showBadge, Bundle userSentiment, Bundle hidden, Bundle smartActions) {
        mKeys = keys;
        mInterceptedKeys = interceptedKeys;
        mVisibilityOverrides = visibilityOverrides;
@@ -56,6 +57,7 @@ public class NotificationRankingUpdate implements Parcelable {
        mShowBadge = showBadge;
        mUserSentiment = userSentiment;
        mHidden = hidden;
        mSmartActions = smartActions;
    }

    public NotificationRankingUpdate(Parcel in) {
@@ -73,6 +75,7 @@ public class NotificationRankingUpdate implements Parcelable {
        mShowBadge = in.readBundle();
        mUserSentiment = in.readBundle();
        mHidden = in.readBundle();
        mSmartActions = in.readBundle();
    }

    @Override
@@ -95,6 +98,7 @@ public class NotificationRankingUpdate implements Parcelable {
        out.writeBundle(mShowBadge);
        out.writeBundle(mUserSentiment);
        out.writeBundle(mHidden);
        out.writeBundle(mSmartActions);
    }

    public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -159,4 +163,8 @@ public class NotificationRankingUpdate implements Parcelable {
    public Bundle getHidden() {
        return mHidden;
    }

    public Bundle getSmartActions() {
        return mSmartActions;
    }
}
Loading