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

Commit e0341487 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Don't allow foreground notis to be blocked inline.

Offer a 'minimize' option instead.

Also I'm changing the guts, do a little layout
cleanup in the confirmation dialog.

Change-Id: I9f2ef824d1f322752bc4161356f16a5dae166caf
Fixes: 73898083
Fixes: 73657862
Fixes: 73657452
Test: runtest systemui-notification
parent 0b4626aa
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@

    <!-- Package Info -->
    <RelativeLayout
        android:id="@+id/header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipChildren="false"
@@ -139,6 +140,12 @@
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                style="@style/TextAppearance.NotificationInfo.Button"/>
            <TextView
                android:id="@+id/minimize"
                android:text="@string/inline_minimize_button"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                style="@style/TextAppearance.NotificationInfo.Button" />
            <TextView
                android:id="@+id/keep"
                android:text="@string/inline_keep_button"
@@ -157,10 +164,11 @@
        android:visibility="gone"
        android:orientation="horizontal" >
        <TextView
            android:id="@+id/confirmation_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/notification_channel_disabled"
            style="@style/TextAppearance.NotificationInfo.Secondary.Warning"/>
            style="@style/TextAppearance.NotificationInfo.Confirmation"/>
        <TextView
            android:id="@+id/undo"
            android:layout_width="wrap_content"
+6 −0
Original line number Diff line number Diff line
@@ -1526,6 +1526,9 @@
    <!-- Notification Inline Controls: Shown when a channel's notifications are currently blocked -->
    <string name="notification_channel_disabled">You won\'t see these notifications anymore</string>

    <!-- Notification inline controls: Shown when a channel's notifications are minimized -->
    <string name="notification_channel_minimized">These notifications will be minimized</string>

    <!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
    <string name="inline_blocking_helper">You usually dismiss these notifications.
    \nKeep showing them?</string>
@@ -1539,6 +1542,9 @@
    <!-- Notification inline controls: keep getting notifications button -->
    <string name="inline_keep_button">Keep showing</string>

    <!-- Notification inline controls: minimize notifications button -->
    <string name="inline_minimize_button">Minimize</string>

    <!-- Notification Inline controls: continue receiving notifications prompt, app level -->
    <string name="inline_keep_showing_app">Keep showing notifications from this app?</string>

+6 −0
Original line number Diff line number Diff line
@@ -459,6 +459,12 @@
        <item name="android:alpha">0.87</item>
    </style>

    <style name="TextAppearance.NotificationInfo.Confirmation">
        <item name="android:textColor">?android:attr/textColorPrimary</item>
        <item name="android:textSize">14sp</item>
        <item name="android:alpha">0.87</item>
    </style>

    <style name="TextAppearance.NotificationInfo.Secondary">
        <item name="android:textColor">?android:attr/textColorPrimary</item>
        <item name="android:textSize">14sp</item>
+27 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.statusbar;

import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;

import android.animation.Animator;
@@ -39,6 +40,7 @@ import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -73,6 +75,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
    private boolean mNonblockable;
    private StatusBarNotification mSbn;
    private AnimatorSet mExpandAnimation;
    private boolean mIsForeground;

    private CheckSaveListener mCheckSaveListener;
    private OnSettingsClickListener mOnSettingsClickListener;
@@ -84,7 +87,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
        closeControls(v);
    };

    private OnClickListener mOnStopNotifications = v -> {
    private OnClickListener mOnStopMinNotifications = v -> {
        swapContent(false);
    };

@@ -150,6 +153,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
        mSingleNotificationChannel = notificationChannel;
        mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
        mNegativeUserSentiment = negativeUserSentiment;
        mIsForeground =
                (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;

        int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
                pkg, mAppUid, false /* includeDeleted */);
@@ -290,14 +295,23 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G

    private void bindButtons() {
        View block =  findViewById(R.id.block);
        block.setOnClickListener(mOnStopNotifications);
        block.setOnClickListener(mOnStopMinNotifications);
        TextView keep = findViewById(R.id.keep);
        keep.setOnClickListener(mOnKeepShowing);
        findViewById(R.id.undo).setOnClickListener(mOnUndo);
        View minimize = findViewById(R.id.minimize);
        minimize.setOnClickListener(mOnStopMinNotifications);

        if (mNonblockable) {
            keep.setText(R.string.notification_done);
            block.setVisibility(GONE);
            minimize.setVisibility(GONE);
        } else if (mIsForeground) {
            block.setVisibility(GONE);
            minimize.setVisibility(VISIBLE);
        } else if (!mIsForeground) {
            block.setVisibility(VISIBLE);
            minimize.setVisibility(GONE);
        }

        // app settings link
@@ -306,7 +320,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
                mSbn.getId(), mSbn.getTag());
        if (settingsIntent != null
                && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
            settingsLinkView.setVisibility(View.VISIBLE);
            settingsLinkView.setVisibility(VISIBLE);
            settingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
                    mSbn.getNotification().getSettingsText()));
            settingsLinkView.setOnClickListener((View view) -> {
@@ -322,14 +336,21 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
            mExpandAnimation.cancel();
        }

        View prompt = findViewById(R.id.prompt);
        ViewGroup confirmation = findViewById(R.id.confirmation);
        TextView confirmationText = findViewById(R.id.confirmation_text);
        View header = findViewById(R.id.header);

        if (showPrompt) {
            mChosenImportance = mStartingUserImportance;
        } else if (mIsForeground) {
            mChosenImportance = IMPORTANCE_MIN;
            confirmationText.setText(R.string.notification_channel_minimized);
        } else {
            mChosenImportance = IMPORTANCE_NONE;
            confirmationText.setText(R.string.notification_channel_disabled);
        }

        View prompt = findViewById(R.id.prompt);
        View confirmation = findViewById(R.id.confirmation);
        ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
                prompt.getAlpha(), showPrompt ? 1f : 0f);
        promptAnim.setInterpolator(showPrompt ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
@@ -339,6 +360,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G

        prompt.setVisibility(showPrompt ? VISIBLE : GONE);
        confirmation.setVisibility(showPrompt ? GONE : VISIBLE);
        header.setVisibility(showPrompt ? VISIBLE : GONE);

        mExpandAnimation = new AnimatorSet();
        mExpandAnimation.playTogether(promptAnim, confirmAnim);
+156 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar;

import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
import static android.view.View.GONE;
@@ -147,6 +149,7 @@ public class NotificationInfoTest extends SysuiTestCase {
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
        final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
        assertTrue(textView.getText().toString().contains("App Name"));
        assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
    }

    @Test
@@ -212,6 +215,27 @@ public class NotificationInfoTest extends SysuiTestCase {
        assertEquals(VISIBLE, textView.getVisibility());
    }

    @Test
    public void testBindNotification_BlockButton() throws Exception {
       mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
        final View block = mNotificationInfo.findViewById(R.id.block);
        final View minimize = mNotificationInfo.findViewById(R.id.minimize);
        assertEquals(VISIBLE, block.getVisibility());
        assertEquals(GONE, minimize.getVisibility());
    }

    @Test
    public void testBindNotification_MinButton() throws Exception {
        mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
        final View block = mNotificationInfo.findViewById(R.id.block);
        final View minimize = mNotificationInfo.findViewById(R.id.minimize);
        assertEquals(GONE, block.getVisibility());
        assertEquals(VISIBLE, minimize.getVisibility());
    }

    @Test
    public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
@@ -323,6 +347,18 @@ public class NotificationInfoTest extends SysuiTestCase {
                anyString(), eq(TEST_UID), any());
    }

    @Test
    public void testDoesNotUpdateNotificationChannelAfterImportanceChangedMin()
            throws Exception {
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);

        mNotificationInfo.findViewById(R.id.minimize).performClick();
        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                anyString(), eq(TEST_UID), any());
    }

    @Test
    public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged()
            throws Exception {
@@ -377,6 +413,39 @@ public class NotificationInfoTest extends SysuiTestCase {
                anyString(), eq(TEST_UID), updated.capture());
        assertTrue((updated.getValue().getUserLockedFields()
                & USER_LOCKED_IMPORTANCE) != 0);
        assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance());
    }

    @Test
    public void testNonBlockableAppDoesNotBecomeMin() throws Exception {
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
                null, Collections.singleton(TEST_PACKAGE_NAME));
        mNotificationInfo.findViewById(R.id.minimize).performClick();
        waitForUndoButton();
        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                anyString(), eq(TEST_UID), any());
    }

    @Test
    public void testMinChangedCallsUpdateNotificationChannel() throws Exception {
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
        mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);

        mNotificationInfo.findViewById(R.id.minimize).performClick();
        waitForUndoButton();
        mNotificationInfo.handleCloseControls(true, false);

        ArgumentCaptor<NotificationChannel> updated =
                ArgumentCaptor.forClass(NotificationChannel.class);
        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
                anyString(), eq(TEST_UID), updated.capture());
        assertTrue((updated.getValue().getUserLockedFields()
                & USER_LOCKED_IMPORTANCE) != 0);
        assertEquals(IMPORTANCE_MIN, updated.getValue().getImportance());
    }

    @Test
@@ -415,6 +484,40 @@ public class NotificationInfoTest extends SysuiTestCase {
        assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
    }

    @Test
    public void testMinUndoDoesNotMinNotificationChannel() throws Exception {
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);

        mNotificationInfo.findViewById(R.id.minimize).performClick();
        waitForUndoButton();
        mNotificationInfo.findViewById(R.id.undo).performClick();
        waitForStopButton();
        mNotificationInfo.handleCloseControls(true, false);

        ArgumentCaptor<NotificationChannel> updated =
                ArgumentCaptor.forClass(NotificationChannel.class);
        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
                anyString(), eq(TEST_UID), updated.capture());
        assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
        assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
    }

    @Test
    public void testCloseControlsDoesNotUpdateiMinIfSaveIsFalse() throws Exception {
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
                Collections.singleton(TEST_PACKAGE_NAME));

        mNotificationInfo.findViewById(R.id.minimize).performClick();
        waitForUndoButton();
        mNotificationInfo.handleCloseControls(false, false);
        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
                eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
    }

    @Test
    public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
@@ -557,4 +660,57 @@ public class NotificationInfoTest extends SysuiTestCase {
    public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception {
        assertFalse(mNotificationInfo.willBeRemoved());
    }

    @Test
    public void testUndoText_min() throws Exception {
        mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
                Collections.singleton(TEST_PACKAGE_NAME));

        mNotificationInfo.findViewById(R.id.minimize).performClick();
        waitForUndoButton();
        TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
        assertTrue(confirmationText.getText().toString().contains("minimized"));
    }

    @Test
    public void testUndoText_block() throws Exception {
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
                Collections.singleton(TEST_PACKAGE_NAME));

        mNotificationInfo.findViewById(R.id.block).performClick();
        waitForUndoButton();
        TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
        assertTrue(confirmationText.getText().toString().contains("won't see"));
    }

    @Test
    public void testNoHeaderOnConfirmation() throws Exception {
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
                Collections.singleton(TEST_PACKAGE_NAME));

        mNotificationInfo.findViewById(R.id.block).performClick();
        waitForUndoButton();
        assertEquals(GONE, mNotificationInfo.findViewById(R.id.header).getVisibility());
    }

    @Test
    public void testHeaderOnUndo() throws Exception {
        mNotificationChannel.setImportance(IMPORTANCE_LOW);
        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
                Collections.singleton(TEST_PACKAGE_NAME));

        mNotificationInfo.findViewById(R.id.block).performClick();
        waitForUndoButton();
        mNotificationInfo.findViewById(R.id.undo).performClick();
        waitForStopButton();
        assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
    }
}