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

Commit b40a6c09 authored by Alexander Roederer's avatar Alexander Roederer
Browse files

Add new Notif flag on DirectReply and SmartReply

Adds a new flag to a Notification object when the notification is direct
replied or smart replied. This flag will be used as part of moving
lifetime extension to NotificationManagerService, to prevent
cancelation in NMS.

Bug: 230652175
Test: atest NotificationRecordTest
Change-Id: Id00321044aede13833f3066c7ba493d54e514620
parent a670dbbb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -12214,6 +12214,7 @@ package android.service.notification {
    method public boolean hasExpanded();
    method public boolean hasInteracted();
    method public boolean hasSeen();
    method @FlaggedApi("android.app.lifetime_extension_refactor") public boolean hasSmartReplied();
    method public boolean hasSnoozed();
    method public boolean hasViewedSettings();
    method public void setDirectReplied();
@@ -12221,6 +12222,7 @@ package android.service.notification {
    method public void setDismissalSurface(int);
    method public void setExpanded();
    method public void setSeen();
    method @FlaggedApi("android.app.lifetime_extension_refactor") public void setSmartReplied();
    method public void setSnoozed();
    method public void setViewedSettings();
    method public void writeToParcel(android.os.Parcel, int);
+10 −0
Original line number Diff line number Diff line
@@ -745,6 +745,16 @@ public class Notification implements Parcelable
    @TestApi
    public static final int FLAG_USER_INITIATED_JOB = 0x00008000;
    /**
     * Bit to be bitwise-ored into the {@link #flags} field that should be
     * set if this notification has been lifetime extended due to a direct reply.
     *
     * This flag is for internal use only; applications cannot set this flag directly.
     * @hide
     */
    @FlaggedApi(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
    public static final int FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY = 0x00010000;
    private static final List<Class<? extends Style>> PLATFORM_STYLE_CLASSES = Arrays.asList(
            BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
            DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class,
+35 −0
Original line number Diff line number Diff line
@@ -15,10 +15,12 @@
 */
package android.service.notification;

import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.Flags;
import android.app.RemoteInput;
import android.os.Parcel;
import android.os.Parcelable;
@@ -36,6 +38,7 @@ public final class NotificationStats implements Parcelable {
    private boolean mSeen;
    private boolean mExpanded;
    private boolean mDirectReplied;
    private boolean mSmartReplied;
    private boolean mSnoozed;
    private boolean mViewedSettings;
    private boolean mInteracted;
@@ -125,6 +128,9 @@ public final class NotificationStats implements Parcelable {
        mSeen = in.readByte() != 0;
        mExpanded = in.readByte() != 0;
        mDirectReplied = in.readByte() != 0;
        if (Flags.lifetimeExtensionRefactor()) {
            mSmartReplied = in.readByte() != 0;
        }
        mSnoozed = in.readByte() != 0;
        mViewedSettings = in.readByte() != 0;
        mInteracted = in.readByte() != 0;
@@ -137,6 +143,9 @@ public final class NotificationStats implements Parcelable {
        dest.writeByte((byte) (mSeen ? 1 : 0));
        dest.writeByte((byte) (mExpanded ? 1 : 0));
        dest.writeByte((byte) (mDirectReplied ? 1 : 0));
        if (Flags.lifetimeExtensionRefactor()) {
            dest.writeByte((byte) (mSmartReplied ? 1 : 0));
        }
        dest.writeByte((byte) (mSnoozed ? 1 : 0));
        dest.writeByte((byte) (mViewedSettings ? 1 : 0));
        dest.writeByte((byte) (mInteracted ? 1 : 0));
@@ -209,6 +218,23 @@ public final class NotificationStats implements Parcelable {
        mInteracted = true;
    }

    /**
     * Returns whether the user has replied to a notification that has a smart reply at least once.
     */
    @FlaggedApi(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
    public boolean hasSmartReplied() {
        return mSmartReplied;
    }

    /**
     * Records that the user has replied to a notification that has a smart reply at least once.
     */
    @FlaggedApi(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
    public void setSmartReplied() {
        mSmartReplied = true;
        mInteracted = true;
    }

    /**
     * Returns whether the user has snoozed this notification at least once.
     */
@@ -286,6 +312,9 @@ public final class NotificationStats implements Parcelable {
        if (mSeen != that.mSeen) return false;
        if (mExpanded != that.mExpanded) return false;
        if (mDirectReplied != that.mDirectReplied) return false;
        if (Flags.lifetimeExtensionRefactor()) {
            if (mSmartReplied != that.mSmartReplied) return false;
        }
        if (mSnoozed != that.mSnoozed) return false;
        if (mViewedSettings != that.mViewedSettings) return false;
        if (mInteracted != that.mInteracted) return false;
@@ -297,6 +326,9 @@ public final class NotificationStats implements Parcelable {
        int result = (mSeen ? 1 : 0);
        result = 31 * result + (mExpanded ? 1 : 0);
        result = 31 * result + (mDirectReplied ? 1 : 0);
        if (Flags.lifetimeExtensionRefactor()) {
            result = 31 * result + (mSmartReplied ? 1 : 0);
        }
        result = 31 * result + (mSnoozed ? 1 : 0);
        result = 31 * result + (mViewedSettings ? 1 : 0);
        result = 31 * result + (mInteracted ? 1 : 0);
@@ -311,6 +343,9 @@ public final class NotificationStats implements Parcelable {
        sb.append("mSeen=").append(mSeen);
        sb.append(", mExpanded=").append(mExpanded);
        sb.append(", mDirectReplied=").append(mDirectReplied);
        if (Flags.lifetimeExtensionRefactor()) {
            sb.append(", mSmartReplied=").append(mSmartReplied);
        }
        sb.append(", mSnoozed=").append(mSnoozed);
        sb.append(", mViewedSettings=").append(mViewedSettings);
        sb.append(", mInteracted=").append(mInteracted);
+19 −0
Original line number Diff line number Diff line
@@ -24,7 +24,9 @@ import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;

import android.annotation.FlaggedApi;
import android.annotation.Nullable;
import android.app.Flags;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -1257,10 +1259,27 @@ public final class NotificationRecord {
        mStats.setExpanded();
    }

    /** Run when the notification is direct replied. */
    public void recordDirectReplied() {
        if (Flags.lifetimeExtensionRefactor()) {
            // Mark the NotificationRecord as lifetime extended.
            Notification notification = getSbn().getNotification();
            notification.flags |= Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
        }

        mStats.setDirectReplied();
    }


    /** Run when the notification is smart replied. */
    @FlaggedApi(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
    public void recordSmartReplied() {
        Notification notification = getSbn().getNotification();
        notification.flags |= Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;

        mStats.setSmartReplied();
    }

    public void recordDismissalSurface(@NotificationStats.DismissalSurface int surface) {
        mStats.setDismissalSurface(surface);
    }
+40 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import static android.service.notification.NotificationListenerService.Ranking.U
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;

import static com.google.common.truth.Truth.assertThat;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -44,6 +46,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.app.ActivityManager;
import android.app.Flags;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
@@ -64,6 +67,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.Vibrator;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.StatusBarNotification;
@@ -80,6 +84,7 @@ import com.android.server.UiServiceTestCase;
import com.android.server.uri.UriGrantsManagerInternal;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -122,6 +127,9 @@ public class NotificationRecordTest extends UiServiceTestCase {
    private static final NotificationRecord.Light CUSTOM_LIGHT =
            new NotificationRecord.Light(1, 2, 3);

    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
@@ -651,6 +659,7 @@ public class NotificationRecordTest extends UiServiceTestCase {

    @Test
    public void testNotificationStats() {
        mSetFlagsRule.enableFlags(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                false /* lights */, false /* defaultLights */, groupId /* group */);
@@ -690,6 +699,37 @@ public class NotificationRecordTest extends UiServiceTestCase {

        record.recordDirectReplied();
        assertTrue(record.getStats().hasDirectReplied());

        record.recordSmartReplied();
        assertThat(record.getStats().hasSmartReplied()).isTrue();
    }

    @Test
    public void testDirectRepliedAddsLifetimeExtensionFlag() {
        mSetFlagsRule.enableFlags(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);

        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                false /* lights */, false /* defaultLights */, groupId /* group */);
        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);

        record.recordDirectReplied();
        assertThat(record.getSbn().getNotification().flags
                & Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
    }

    @Test
    public void testSmartRepliedAddsLifetimeExtensionFlag() {
        mSetFlagsRule.enableFlags(Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);

        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                false /* lights */, false /* defaultLights */, groupId /* group */);
        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);

        record.recordSmartReplied();
        assertThat(record.getSbn().getNotification().flags
                & Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0);
    }

    @Test