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

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

Merge "Remove bubbles if their shortcuts are removed or if the app is uninstalled." into rvc-dev

parents 0a327227 33477397
Loading
Loading
Loading
Loading
+51 −4
Original line number Diff line number Diff line
@@ -52,13 +52,16 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.ZenModeConfig;
@@ -130,7 +133,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
            DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
            DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
            DISMISS_OVERFLOW_MAX_REACHED})
            DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED})
    @Target({FIELD, LOCAL_VARIABLE, PARAMETER})
    @interface DismissReason {}

@@ -145,6 +148,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    static final int DISMISS_GROUP_CANCELLED = 9;
    static final int DISMISS_INVALID_INTENT = 10;
    static final int DISMISS_OVERFLOW_MAX_REACHED = 11;
    static final int DISMISS_SHORTCUT_REMOVED = 12;
    static final int DISMISS_PACKAGE_REMOVED = 13;

    private final Context mContext;
    private final NotificationEntryManager mNotificationEntryManager;
@@ -334,7 +339,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
            SysUiState sysUiState,
            INotificationManager notificationManager,
            @Nullable IStatusBarService statusBarService,
            WindowManager windowManager) {
            WindowManager windowManager,
            LauncherApps launcherApps) {
        dumpManager.registerDumpable(TAG, this);
        mContext = context;
        mShadeController = shadeController;
@@ -426,6 +432,47 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
                });

        mBubbleIconFactory = new BubbleIconFactory(context);

        launcherApps.registerCallback(new LauncherApps.Callback() {
            @Override
            public void onPackageAdded(String s, UserHandle userHandle) {}

            @Override
            public void onPackageChanged(String s, UserHandle userHandle) {}

            @Override
            public void onPackageRemoved(String s, UserHandle userHandle) {
                // Remove bubbles with this package name, since it has been uninstalled and attempts
                // to open a bubble from an uninstalled app can cause issues.
                mBubbleData.removeBubblesWithPackageName(s, DISMISS_PACKAGE_REMOVED);
            }

            @Override
            public void onPackagesAvailable(String[] strings, UserHandle userHandle,
                    boolean b) {

            }

            @Override
            public void onPackagesUnavailable(String[] packages, UserHandle userHandle,
                    boolean b) {
                for (String packageName : packages) {
                    // Remove bubbles from unavailable apps. This can occur when the app is on
                    // external storage that has been removed.
                    mBubbleData.removeBubblesWithPackageName(packageName, DISMISS_PACKAGE_REMOVED);
                }
            }

            @Override
            public void onShortcutsChanged(String packageName, List<ShortcutInfo> validShortcuts,
                    UserHandle user) {
                super.onShortcutsChanged(packageName, validShortcuts, user);

                // Remove bubbles whose shortcuts aren't in the latest list of valid shortcuts.
                mBubbleData.removeBubblesWithInvalidShortcuts(
                        packageName, validShortcuts, DISMISS_SHORTCUT_REMOVED);
            }
        });
    }

    /**
@@ -1102,7 +1149,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    @MainThread
    void removeBubble(String key, int reason) {
        if (mBubbleData.hasAnyBubbleWithKey(key)) {
            mBubbleData.notificationEntryRemoved(key, reason);
            mBubbleData.dismissBubbleWithKey(key, reason);
        }
    }

@@ -1160,7 +1207,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
            rankingMap.getRanking(key, mTmpRanking);
            boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
            if (isActiveBubble && !mTmpRanking.canBubble()) {
                mBubbleData.notificationEntryRemoved(entry.getKey(),
                mBubbleData.dismissBubbleWithKey(entry.getKey(),
                        BubbleController.DISMISS_BLOCKED);
            } else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
                entry.setFlagBubble(true);
+65 −5
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME
import android.annotation.NonNull;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.util.Log;
import android.util.Pair;
import android.view.View;
@@ -42,8 +43,12 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;

import javax.inject.Inject;
import javax.inject.Singleton;
@@ -286,9 +291,9 @@ public class BubbleData {
    }

    /**
     * Called when a notification associated with a bubble is removed.
     * Dismisses the bubble with the matching key, if it exists.
     */
    public void notificationEntryRemoved(String key, @DismissReason int reason) {
    public void dismissBubbleWithKey(String key, @DismissReason int reason) {
        if (DEBUG_BUBBLE_DATA) {
            Log.d(TAG, "notificationEntryRemoved: key=" + key + " reason=" + reason);
        }
@@ -349,6 +354,44 @@ public class BubbleData {
        return bubbleChildren;
    }

    /**
     * Removes bubbles from the given package whose shortcut are not in the provided list of valid
     * shortcuts.
     */
    public void removeBubblesWithInvalidShortcuts(
            String packageName, List<ShortcutInfo> validShortcuts, int reason) {

        final Set<String> validShortcutIds = new HashSet<String>();
        for (ShortcutInfo info : validShortcuts) {
            validShortcutIds.add(info.getId());
        }

        final Predicate<Bubble> invalidBubblesFromPackage = bubble ->
                packageName.equals(bubble.getPackageName())
                        && (bubble.getShortcutInfo() == null
                            || !bubble.getShortcutInfo().isEnabled()
                            || !validShortcutIds.contains(bubble.getShortcutInfo().getId()));

        final Consumer<Bubble> removeBubble = bubble ->
                dismissBubbleWithKey(bubble.getKey(), reason);

        performActionOnBubblesMatching(getBubbles(), invalidBubblesFromPackage, removeBubble);
        performActionOnBubblesMatching(
                getOverflowBubbles(), invalidBubblesFromPackage, removeBubble);
    }

    /** Dismisses all bubbles from the given package. */
    public void removeBubblesWithPackageName(String packageName, int reason) {
        final Predicate<Bubble> bubbleMatchesPackage = bubble ->
                bubble.getPackageName().equals(packageName);

        final Consumer<Bubble> removeBubble = bubble ->
                dismissBubbleWithKey(bubble.getKey(), reason);

        performActionOnBubblesMatching(getBubbles(), bubbleMatchesPackage, removeBubble);
        performActionOnBubblesMatching(getOverflowBubbles(), bubbleMatchesPackage, removeBubble);
    }

    private void doAdd(Bubble bubble) {
        if (DEBUG_BUBBLE_DATA) {
            Log.d(TAG, "doAdd: " + bubble);
@@ -388,6 +431,21 @@ public class BubbleData {
        }
    }

    /** Runs the given action on Bubbles that match the given predicate. */
    private void performActionOnBubblesMatching(
            List<Bubble> bubbles, Predicate<Bubble> predicate, Consumer<Bubble> action) {
        final List<Bubble> matchingBubbles = new ArrayList<>();
        for (Bubble bubble : bubbles) {
            if (predicate.test(bubble)) {
                matchingBubbles.add(bubble);
            }
        }

        for (Bubble matchingBubble : matchingBubbles) {
            action.accept(matchingBubble);
        }
    }

    private void doRemove(String key, @DismissReason int reason) {
        if (DEBUG_BUBBLE_DATA) {
            Log.d(TAG, "doRemove: " + key);
@@ -402,7 +460,9 @@ public class BubbleData {
                && (reason == BubbleController.DISMISS_NOTIF_CANCEL
                    || reason == BubbleController.DISMISS_GROUP_CANCELLED
                    || reason == BubbleController.DISMISS_NO_LONGER_BUBBLE
                || reason == BubbleController.DISMISS_BLOCKED)) {
                    || reason == BubbleController.DISMISS_BLOCKED
                    || reason == BubbleController.DISMISS_SHORTCUT_REMOVED
                    || reason == BubbleController.DISMISS_PACKAGE_REMOVED)) {

                Bubble b = getOverflowBubbleWithKey(key);
                if (DEBUG_BUBBLE_DATA) {
+1 −1
Original line number Diff line number Diff line
@@ -2232,7 +2232,7 @@ public class BubbleStackView extends FrameLayout

    private void dismissBubbleIfExists(@Nullable Bubble bubble) {
        if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
            mBubbleData.notificationEntryRemoved(
            mBubbleData.dismissBubbleWithKey(
                    bubble.getKey(), BubbleController.DISMISS_USER_GESTURE);
        }
    }
+5 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.bubbles.dagger;

import android.app.INotificationManager;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.view.WindowManager;

import com.android.internal.statusbar.IStatusBarService;
@@ -72,7 +73,8 @@ public interface BubbleModule {
            SysUiState sysUiState,
            INotificationManager notifManager,
            IStatusBarService statusBarService,
            WindowManager windowManager) {
            WindowManager windowManager,
            LauncherApps launcherApps) {
        return new BubbleController(
                context,
                notificationShadeWindowController,
@@ -94,6 +96,7 @@ public interface BubbleModule {
                sysUiState,
                notifManager,
                statusBarService,
                windowManager);
                windowManager,
                launcherApps);
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.pm.LauncherApps;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.face.FaceManager;
import android.os.Handler;
@@ -179,6 +180,8 @@ public class BubbleControllerTest extends SysuiTestCase {
    private NotificationShadeWindowView mNotificationShadeWindowView;
    @Mock
    private IStatusBarService mStatusBarService;
    @Mock
    private LauncherApps mLauncherApps;

    private BubbleData mBubbleData;

@@ -256,7 +259,8 @@ public class BubbleControllerTest extends SysuiTestCase {
                mSysUiState,
                mock(INotificationManager.class),
                mStatusBarService,
                mWindowManager);
                mWindowManager,
                mLauncherApps);
        mBubbleController.setExpandListener(mBubbleExpandListener);

        // Get a reference to the BubbleController's entry listener
Loading