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

Commit 160261a5 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[Notif] Dont show blocking helper for non-blockable notifs" into pi-dev

parents e275d0bc 63411fc9
Loading
Loading
Loading
Loading
+84 −1
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.statusbar;

import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;

@@ -25,7 +24,10 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
import android.app.NotificationChannel;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Path;
@@ -39,6 +41,7 @@ import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
import android.util.MathUtils;
import android.util.Property;
import android.view.KeyEvent;
@@ -90,12 +93,17 @@ import java.util.List;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;

/**
 * View representing a notification item - this can be either the individual child notification or
 * the group summary (which contains 1 or more child notifications).
 */
public class ExpandableNotificationRow extends ActivatableNotificationView
        implements PluginListener<NotificationMenuRowPlugin> {

    private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
    private static final int COLORED_DIVIDER_ALPHA = 0x7B;
    private static final int MENU_VIEW_INDEX = 0;
    private static final String TAG = "ExpandableNotifRow";

    public interface LayoutListener {
        public void onLayout();
@@ -166,6 +174,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
    private NotificationGuts mGuts;
    private NotificationData.Entry mEntry;
    private StatusBarNotification mStatusBarNotification;
    private PackageManager mCachedPackageManager;
    private PackageInfo mCachedPackageInfo;
    private String mAppName;
    private boolean mIsHeadsUp;
    private boolean mLastChronometerRunning = true;
@@ -372,6 +382,53 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        mEntry = entry;
        mStatusBarNotification = entry.notification;
        mNotificationInflater.inflateNotificationViews();

        perhapsCachePackageInfo();
    }

    /**
     * Caches the package manager and info objects which are expensive to obtain.
     */
    private void perhapsCachePackageInfo() {
        if (mCachedPackageInfo == null) {
            mCachedPackageManager = StatusBar.getPackageManagerForUser(
                    mContext, mStatusBarNotification.getUser().getIdentifier());
            try {
                mCachedPackageInfo = mCachedPackageManager.getPackageInfo(
                        mStatusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
            } catch (PackageManager.NameNotFoundException e) {
                Log.e(TAG, "perhapsCachePackageInfo: Could not find package info");
            }
        }
    }

    /**
     * Returns whether this row is considered non-blockable (e.g. it's a non-blockable system notif,
     * covers multiple channels, or is in a whitelist).
     */
    public boolean getIsNonblockable() {
        boolean isNonblockable;

        isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
                .isNonblockablePackage(mStatusBarNotification.getPackageName());

        // Only bother with going through the children if the row is still blockable based on the
        // number of unique channels.
        if (!isNonblockable) {
            isNonblockable = getNumUniqueChannels() > 1;
        }

        // Only bother with IPC if the package is still blockable.
        if (!isNonblockable && mCachedPackageManager != null && mCachedPackageInfo != null) {
            if (com.android.settingslib.Utils.isSystemPackage(
                    mContext.getResources(), mCachedPackageManager, mCachedPackageInfo)) {
                if (mEntry.channel != null
                        && !mEntry.channel.isBlockableSystem()) {
                    isNonblockable = true;
                }
            }
        }
        return isNonblockable;
    }

    public void onNotificationUpdated() {
@@ -2019,6 +2076,32 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        updateChildrenVisibility();
        applyChildrenRoundness();
    }
    /**
     * Returns the number of channels covered by the notification row (including its children if
     * it's a summary notification).
     */
    public int getNumUniqueChannels() {
        ArraySet<NotificationChannel> channels = new ArraySet<>();

        channels.add(mEntry.channel);

        // If this is a summary, then add in the children notification channels for the
        // same user and pkg.
        if (mIsSummaryWithChildren) {
            final List<ExpandableNotificationRow> childrenRows = getNotificationChildren();
            final int numChildren = childrenRows.size();
            for (int i = 0; i < numChildren; i++) {
                final ExpandableNotificationRow childRow = childrenRows.get(i);
                final NotificationChannel childChannel = childRow.getEntry().channel;
                final StatusBarNotification childSbn = childRow.getStatusBarNotification();
                if (childSbn.getUser().equals(mStatusBarNotification.getUser()) &&
                        childSbn.getPackageName().equals(mStatusBarNotification.getPackageName())) {
                    channels.add(childChannel);
                }
            }
        }
        return channels.size();
    }

    public void updateChildrenHeaderAppearance() {
        if (mIsSummaryWithChildren) {
+24 −6
Original line number Diff line number Diff line
@@ -17,11 +17,19 @@
package com.android.systemui.statusbar;

import android.content.Context;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.support.annotation.VisibleForTesting;
import android.util.Log;

import com.android.systemui.Dependency;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.phone.StatusBar;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;

@@ -37,6 +45,7 @@ public class NotificationBlockingHelperManager {
    private final Context mContext;
    /** Row that the blocking helper will be shown in (via {@link NotificationGuts}. */
    private ExpandableNotificationRow mBlockingHelperRow;
    private Set<String> mNonBlockablePkgs;

    /**
     * Whether the notification shade/stack is expanded - used to determine blocking helper
@@ -46,6 +55,9 @@ public class NotificationBlockingHelperManager {

    public NotificationBlockingHelperManager(Context context) {
        mContext = context;
        mNonBlockablePkgs = new HashSet<>();
        Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
                com.android.internal.R.array.config_nonBlockableNotificationPackages));
    }

    /**
@@ -59,15 +71,14 @@ public class NotificationBlockingHelperManager {
     */
    boolean perhapsShowBlockingHelper(
            ExpandableNotificationRow row, NotificationMenuRowPlugin menuRow) {
        int numChildren = row.getNumberOfNotificationChildren();

        // We only show the blocking helper if:
        // - The dismissed row is a valid group (>1 or 0 children) or the only child in the group
        // - User sentiment is negative (DEBUG flag can bypass)
        // - The notification shade is fully expanded (guarantees we're not touching a HUN).
        // - User sentiment is negative
        if (DEBUG
                || row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE
        // - The row is blockable (i.e. not non-blockable)
        // - The dismissed row is a valid group (>1 or 0 children) or the only child in the group
        if ((row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE || DEBUG)
                && mIsShadeExpanded
                && !row.getIsNonblockable()
                && (!row.isChildInGroup() || row.isOnlyChildInGroup())) {
            // Dismiss any current blocking helper before continuing forward (only one can be shown
            // at a given time).
@@ -125,6 +136,13 @@ public class NotificationBlockingHelperManager {
        mIsShadeExpanded = expandedHeight > 0.0f;
    }

    /**
     * Returns whether the given package name is in the list of non-blockable packages.
     */
    public boolean isNonblockablePackage(String packageName) {
        return mNonBlockablePkgs.contains(packageName);
    }

    @VisibleForTesting
    boolean isBlockingHelperRowNull() {
        return mBlockingHelperRow == null;
+2 −35
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@ public class NotificationGutsManager implements Dumpable {
    private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";

    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
    private final Set<String> mNonBlockablePkgs;
    private final Context mContext;
    private final AccessibilityManager mAccessibilityManager;

@@ -87,10 +86,6 @@ public class NotificationGutsManager implements Dumpable {
        mContext = context;
        Resources res = context.getResources();

        mNonBlockablePkgs = new HashSet<>();
        Collections.addAll(mNonBlockablePkgs, res.getStringArray(
                com.android.internal.R.array.config_nonBlockableNotificationPackages));

        mAccessibilityManager = (AccessibilityManager)
                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
    }
@@ -279,12 +274,12 @@ public class NotificationGutsManager implements Dumpable {
                    iNotificationManager,
                    packageName,
                    row.getEntry().channel,
                    getNumNotificationChannels(row, packageName, userHandle),
                    row.getNumUniqueChannels(),
                    sbn,
                    mCheckSaveListener,
                    onSettingsClick,
                    onAppSettingsClick,
                    mNonBlockablePkgs,
                    row.getIsNonblockable(),
                    isForBlockingHelper,
                    row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE);
        } catch (RemoteException e) {
@@ -292,34 +287,6 @@ public class NotificationGutsManager implements Dumpable {
        }
    }

    /**
     * @return the number of channels covered by the notification row (including its children if
     * it's a summary notification).
     */
    private int getNumNotificationChannels(
            ExpandableNotificationRow row, String packageName, UserHandle userHandle) {
        ArraySet<NotificationChannel> channels = new ArraySet<>();

        channels.add(row.getEntry().channel);

        // If this is a summary, then add in the children notification channels for the
        // same user and pkg.
        if (row.isSummaryWithChildren()) {
            final List<ExpandableNotificationRow> childrenRows = row.getNotificationChildren();
            final int numChildren = childrenRows.size();
            for (int i = 0; i < numChildren; i++) {
                final ExpandableNotificationRow childRow = childrenRows.get(i);
                final NotificationChannel childChannel = childRow.getEntry().channel;
                final StatusBarNotification childSbn = childRow.getStatusBarNotification();
                if (childSbn.getUser().equals(userHandle) &&
                        childSbn.getPackageName().equals(packageName)) {
                    channels.add(childChannel);
                }
            }
        }
        return channels.size();
    }

    /**
     * Closes guts or notification menus that might be visible and saves any changes.
     *
+8 −26
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
@@ -49,13 +48,11 @@ import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;

import java.util.List;
import java.util.Set;

/**
 * The guts of a notification revealed when performing a long press.
@@ -74,7 +71,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
    private int mStartingUserImportance;
    private int mChosenImportance;
    private boolean mIsSingleDefaultChannel;
    private boolean mNonblockable;
    private boolean mIsNonblockable;
    private StatusBarNotification mSbn;
    private AnimatorSet mExpandAnimation;
    private boolean mIsForeground;
@@ -128,10 +125,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
            final CheckSaveListener checkSaveListener,
            final OnSettingsClickListener onSettingsClick,
            final OnAppSettingsClickListener onAppSettingsClick,
            final Set<String> nonBlockablePkgs)
            boolean isNonblockable)
            throws RemoteException {
        bindNotification(pm, iNotificationManager, pkg, notificationChannel, numChannels, sbn,
                checkSaveListener, onSettingsClick, onAppSettingsClick, nonBlockablePkgs,
                checkSaveListener, onSettingsClick, onAppSettingsClick, isNonblockable,
                false /* isBlockingHelper */,
                false /* isUserSentimentNegative */);
    }
@@ -146,7 +143,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
            CheckSaveListener checkSaveListener,
            OnSettingsClickListener onSettingsClick,
            OnAppSettingsClickListener onAppSettingsClick,
            Set<String> nonBlockablePkgs,
            boolean isNonblockable,
            boolean isForBlockingHelper,
            boolean isUserSentimentNegative)
            throws RemoteException {
@@ -162,6 +159,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
        mSingleNotificationChannel = notificationChannel;
        mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
        mNegativeUserSentiment = isUserSentimentNegative;
        mIsNonblockable = isNonblockable;
        mIsForeground =
                (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
        mIsForBlockingHelper = isForBlockingHelper;
@@ -179,22 +177,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
                    && numTotalChannels == 1;
        }

        try {
            final PackageInfo pkgInfo = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
            if (Utils.isSystemPackage(getResources(), pm, pkgInfo)) {
                if (mSingleNotificationChannel != null
                        && !mSingleNotificationChannel.isBlockableSystem()) {
                    mNonblockable = true;
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            // unlikely.
        }
        if (nonBlockablePkgs != null) {
            mNonblockable |= nonBlockablePkgs.contains(pkg);
        }
        mNonblockable |= (mNumNotificationChannels > 1);

        bindHeader();
        bindPrompt();
        bindButtons();
@@ -261,7 +243,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
    private void bindPrompt() {
        final TextView blockPrompt = findViewById(R.id.block_prompt);
        bindName();
        if (mNonblockable) {
        if (mIsNonblockable) {
            blockPrompt.setText(R.string.notification_unblockable_desc);
        } else {
            if (mNegativeUserSentiment) {
@@ -288,7 +270,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
    }

    private void saveImportance() {
        if (mNonblockable) {
        if (mIsNonblockable) {
            return;
        }
        MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
@@ -314,7 +296,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
        keep.setOnClickListener(mOnKeepShowing);
        minimize.setOnClickListener(mOnStopMinNotifications);

        if (mNonblockable) {
        if (mIsNonblockable) {
            keep.setText(R.string.notification_done);
            block.setVisibility(GONE);
            minimize.setVisibility(GONE);
+24 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.statusbar;

import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -29,6 +31,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.AppOpsManager;
import android.app.NotificationChannel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
@@ -50,6 +53,7 @@ import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.List;
import java.util.function.Consumer;

@SmallTest
@@ -274,4 +278,24 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
        mGroupRow.setBlockingHelperShowing(false);
        assertFalse(mGroupRow.isBlockingHelperShowing());
    }

    @Test
    public void testGetNumUniqueChildren_defaultChannel() {
        assertEquals(1, mGroupRow.getNumUniqueChannels());
    }

    @Test
    public void testGetNumUniqueChildren_multiChannel() {
        List<ExpandableNotificationRow> childRows =
                mGroupRow.getChildrenContainer().getNotificationChildren();
        // Give each child a unique channel id/name.
        int i = 0;
        for (ExpandableNotificationRow childRow : childRows) {
            childRow.getEntry().channel =
                    new NotificationChannel("id" + i, "dinnertime" + i, IMPORTANCE_DEFAULT);
            i++;
        }

        assertEquals(3, mGroupRow.getNumUniqueChannels());
    }
}
Loading