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

Commit 99162817 authored by Tony Huang's avatar Tony Huang
Browse files

Migrate Bubbles to wm-shell (2/n)

Remove sysui dependency and dagger in Bubble and BubbleData class.

Bug: 161980186
Test: atest SystemUITests
Change-Id: Ic66787e194414e5a4b8c98226598bbf274a285a9
parent 4a681f2c
Loading
Loading
Loading
Loading
+99 −30
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Person;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -35,16 +36,18 @@ import android.graphics.Bitmap;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Parcelable;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;

/**
@@ -169,11 +172,10 @@ class Bubble implements BubbleViewProvider {
    }

    @VisibleForTesting(visibility = PRIVATE)
    Bubble(@NonNull final NotificationEntry e,
    Bubble(@NonNull final BubbleEntry entry,
            @Nullable final BubbleController.NotificationSuppressionChangedListener listener,
            final BubbleController.PendingIntentCanceledListener intentCancelListener) {
        Objects.requireNonNull(e);
        mKey = e.getKey();
        mKey = entry.getKey();
        mSuppressionListener = listener;
        mIntentCancelListener = intent -> {
            if (mIntent != null) {
@@ -181,7 +183,7 @@ class Bubble implements BubbleViewProvider {
            }
            intentCancelListener.onPendingIntentCanceled(this);
        };
        setEntry(e);
        setEntry(entry);
    }

    @Override
@@ -294,8 +296,8 @@ class Bubble implements BubbleViewProvider {
    }

    /**
     * Sets whether this bubble is considered visually interruptive. Normally pulled from the
     * {@link NotificationEntry}, this method is purely for testing.
     * Sets whether this bubble is considered visually interruptive. This method is purely for
     * testing.
     */
    @VisibleForTesting
    void setVisuallyInterruptiveForTest(boolean visuallyInterruptive) {
@@ -388,30 +390,28 @@ class Bubble implements BubbleViewProvider {
    /**
     * Sets the entry associated with this bubble.
     */
    void setEntry(@NonNull final NotificationEntry entry) {
    void setEntry(@NonNull final BubbleEntry entry) {
        Objects.requireNonNull(entry);
        Objects.requireNonNull(entry.getSbn());
        mLastUpdated = entry.getSbn().getPostTime();
        mIsBubble = entry.getSbn().getNotification().isBubbleNotification();
        mPackageName = entry.getSbn().getPackageName();
        mUser = entry.getSbn().getUser();
        mLastUpdated = entry.getStatusBarNotification().getPostTime();
        mIsBubble = entry.getStatusBarNotification().getNotification().isBubbleNotification();
        mPackageName = entry.getStatusBarNotification().getPackageName();
        mUser = entry.getStatusBarNotification().getUser();
        mTitle = getTitle(entry);
        mIsClearable = entry.isClearable();
        mShouldSuppressNotificationDot = entry.shouldSuppressNotificationDot();
        mShouldSuppressNotificationList = entry.shouldSuppressNotificationList();
        mShouldSuppressPeek = entry.shouldSuppressPeek();
        mChannelId = entry.getSbn().getNotification().getChannelId();
        mNotificationId = entry.getSbn().getId();
        mAppUid = entry.getSbn().getUid();
        mInstanceId = entry.getSbn().getInstanceId();
        mFlyoutMessage = BubbleViewInfoTask.extractFlyoutMessage(entry);
        mShortcutInfo = (entry.getRanking() != null ? entry.getRanking().getShortcutInfo() : null);
        mMetadataShortcutId = (entry.getBubbleMetadata() != null
                ? entry.getBubbleMetadata().getShortcutId() : null);
        mChannelId = entry.getStatusBarNotification().getNotification().getChannelId();
        mNotificationId = entry.getStatusBarNotification().getId();
        mAppUid = entry.getStatusBarNotification().getUid();
        mInstanceId = entry.getStatusBarNotification().getInstanceId();
        mFlyoutMessage = extractFlyoutMessage(entry);
        if (entry.getRanking() != null) {
            mShortcutInfo = entry.getRanking().getShortcutInfo();
            mIsVisuallyInterruptive = entry.getRanking().visuallyInterruptive();
            if (entry.getRanking().getChannel() != null) {
                mIsImportantConversation =
                        entry.getRanking().getChannel().isImportantConversation();
            }
        }
        if (entry.getBubbleMetadata() != null) {
            mMetadataShortcutId = entry.getBubbleMetadata().getShortcutId();
            mFlags = entry.getBubbleMetadata().getFlags();
            mDesiredHeight = entry.getBubbleMetadata().getDesiredHeight();
            mDesiredHeightResId = entry.getBubbleMetadata().getDesiredHeightResId();
@@ -433,8 +433,11 @@ class Bubble implements BubbleViewProvider {
            }
            mDeleteIntent = entry.getBubbleMetadata().getDeleteIntent();
        }
        mIsImportantConversation =
                entry.getChannel() != null && entry.getChannel().isImportantConversation();

        mIsClearable = entry.isClearable();
        mShouldSuppressNotificationDot = entry.shouldSuppressNotificationDot();
        mShouldSuppressNotificationList = entry.shouldSuppressNotificationList();
        mShouldSuppressPeek = entry.shouldSuppressPeek();
    }

    @Nullable
@@ -735,9 +738,75 @@ class Bubble implements BubbleViewProvider {
    }

    @Nullable
    private static String getTitle(@NonNull final NotificationEntry e) {
        final CharSequence titleCharSeq = e.getSbn().getNotification().extras.getCharSequence(
                Notification.EXTRA_TITLE);
    private static String getTitle(@NonNull final BubbleEntry e) {
        final CharSequence titleCharSeq = e.getStatusBarNotification()
                .getNotification().extras.getCharSequence(Notification.EXTRA_TITLE);
        return titleCharSeq == null ? null : titleCharSeq.toString();
    }

    /**
     * Returns our best guess for the most relevant text summary of the latest update to this
     * notification, based on its type. Returns null if there should not be an update message.
     */
    @NonNull
    static Bubble.FlyoutMessage extractFlyoutMessage(BubbleEntry entry) {
        Objects.requireNonNull(entry);
        final Notification underlyingNotif = entry.getStatusBarNotification().getNotification();
        final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle();

        Bubble.FlyoutMessage bubbleMessage = new Bubble.FlyoutMessage();
        bubbleMessage.isGroupChat = underlyingNotif.extras.getBoolean(
                Notification.EXTRA_IS_GROUP_CONVERSATION);
        try {
            if (Notification.BigTextStyle.class.equals(style)) {
                // Return the big text, it is big so probably important. If it's not there use the
                // normal text.
                CharSequence bigText =
                        underlyingNotif.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
                bubbleMessage.message = !TextUtils.isEmpty(bigText)
                        ? bigText
                        : underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
                return bubbleMessage;
            } else if (Notification.MessagingStyle.class.equals(style)) {
                final List<Notification.MessagingStyle.Message> messages =
                        Notification.MessagingStyle.Message.getMessagesFromBundleArray(
                                (Parcelable[]) underlyingNotif.extras.get(
                                        Notification.EXTRA_MESSAGES));

                final Notification.MessagingStyle.Message latestMessage =
                        Notification.MessagingStyle.findLatestIncomingMessage(messages);
                if (latestMessage != null) {
                    bubbleMessage.message = latestMessage.getText();
                    Person sender = latestMessage.getSenderPerson();
                    bubbleMessage.senderName = sender != null ? sender.getName() : null;
                    bubbleMessage.senderAvatar = null;
                    bubbleMessage.senderIcon = sender != null ? sender.getIcon() : null;
                    return bubbleMessage;
                }
            } else if (Notification.InboxStyle.class.equals(style)) {
                CharSequence[] lines =
                        underlyingNotif.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);

                // Return the last line since it should be the most recent.
                if (lines != null && lines.length > 0) {
                    bubbleMessage.message = lines[lines.length - 1];
                    return bubbleMessage;
                }
            } else if (Notification.MediaStyle.class.equals(style)) {
                // Return nothing, media updates aren't typically useful as a text update.
                return bubbleMessage;
            } else {
                // Default to text extra.
                bubbleMessage.message =
                        underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
                return bubbleMessage;
            }
        } catch (ClassCastException | NullPointerException | ArrayIndexOutOfBoundsException e) {
            // No use crashing, we'll just return null and the caller will assume there's no update
            // message.
            e.printStackTrace();
        }

        return bubbleMessage;
    }
}
+67 −9
Original line number Diff line number Diff line
@@ -345,7 +345,42 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
    /**
     * Injected constructor. See {@link BubbleModule}.
     */
    public BubbleController(Context context,
    public static BubbleController create(Context context,
            NotificationShadeWindowController notificationShadeWindowController,
            StatusBarStateController statusBarStateController,
            ShadeController shadeController,
            @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
            ConfigurationController configurationController,
            NotificationInterruptStateProvider interruptionStateProvider,
            ZenModeController zenModeController,
            NotificationLockscreenUserManager notifUserManager,
            NotificationGroupManagerLegacy groupManager,
            NotificationEntryManager entryManager,
            NotifPipeline notifPipeline,
            FeatureFlags featureFlags,
            DumpManager dumpManager,
            FloatingContentCoordinator floatingContentCoordinator,
            BubbleDataRepository dataRepository,
            SysUiState sysUiState,
            INotificationManager notificationManager,
            @Nullable IStatusBarService statusBarService,
            WindowManager windowManager,
            WindowManagerShellWrapper windowManagerShellWrapper,
            LauncherApps launcherApps) {
        return new BubbleController(context, notificationShadeWindowController,
                statusBarStateController, shadeController, new BubbleData(context), synchronizer,
                configurationController, interruptionStateProvider, zenModeController,
                notifUserManager, groupManager, entryManager, notifPipeline, featureFlags,
                dumpManager, floatingContentCoordinator, dataRepository, sysUiState,
                notificationManager, statusBarService, windowManager, windowManagerShellWrapper,
                launcherApps);
    }

    /**
     * Testing constructor.
     */
    @VisibleForTesting
    BubbleController(Context context,
            NotificationShadeWindowController notificationShadeWindowController,
            StatusBarStateController statusBarStateController,
            ShadeController shadeController,
@@ -1120,9 +1155,10 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
                && mBubbleData.hasOverflowBubbleWithKey(notif.getKey())) {
            // Update the bubble but don't promote it out of overflow
            Bubble b = mBubbleData.getOverflowBubbleWithKey(notif.getKey());
            b.setEntry(notif);
            b.setEntry(notifToBubbleEntry(notif));
        } else {
            Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */);
            Bubble bubble = mBubbleData.getOrCreateBubble(
                    notifToBubbleEntry(notif), null /* persistedBubble */);
            inflateAndAdd(bubble, suppressFlyout, showInShade);
        }
    }
@@ -1208,8 +1244,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
            mBubbleData.removeSuppressedSummary(groupKey);

            // Remove any associated bubble children with the summary
            final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(
                    groupKey, mNotificationEntryManager);
            final List<Bubble> bubbleChildren = getBubblesInGroup(groupKey);
            for (int i = 0; i < bubbleChildren.size(); i++) {
                removeBubble(bubbleChildren.get(i).getKey(), DISMISS_GROUP_CANCELLED);
            }
@@ -1255,6 +1290,25 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
        }
    }

    /**
     * Retrieves any bubbles that are part of the notification group represented by the provided
     * group key.
     */
    private ArrayList<Bubble> getBubblesInGroup(@Nullable String groupKey) {
        ArrayList<Bubble> bubbleChildren = new ArrayList<>();
        if (groupKey == null) {
            return bubbleChildren;
        }
        for (Bubble bubble : mBubbleData.getActiveBubbles()) {
            final NotificationEntry entry =
                    mNotificationEntryManager.getPendingOrActiveNotif(bubble.getKey());
            if (entry != null && groupKey.equals(entry.getSbn().getGroupKey())) {
                bubbleChildren.add(bubble);
            }
        }
        return bubbleChildren;
    }

    private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble,
            final boolean autoExpand) {
        Objects.requireNonNull(entry);
@@ -1365,8 +1419,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
                }
                if (entry != null) {
                    final String groupKey = entry.getSbn().getGroupKey();
                    if (mBubbleData.getBubblesInGroup(
                            groupKey, mNotificationEntryManager).isEmpty()) {
                    if (getBubblesInGroup(groupKey).isEmpty()) {
                        // Time to potentially remove the summary
                        for (NotifCallback cb : mCallbacks) {
                            cb.maybeCancelSummary(entry);
@@ -1449,8 +1502,7 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
        }

        String groupKey = entry.getSbn().getGroupKey();
        ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(
                groupKey, mNotificationEntryManager);
        ArrayList<Bubble> bubbleChildren = getBubblesInGroup(groupKey);
        boolean isSuppressedSummary = (mBubbleData.isSummarySuppressed(groupKey)
                && mBubbleData.getSummaryKey(groupKey).equals(entry.getKey()));
        boolean isSummary = entry.getSbn().getNotification().isGroupSummary();
@@ -1694,4 +1746,10 @@ public class BubbleController implements Bubbles, ConfigurationController.Config
            }
        }
    }

    static BubbleEntry notifToBubbleEntry(NotificationEntry e) {
        return new BubbleEntry(e.getSbn(), e.getRanking(), e.isClearable(),
                e.shouldSuppressNotificationDot(), e.shouldSuppressNotificationList(),
                e.shouldSuppressPeek());
    }
}
+11 −30
Original line number Diff line number Diff line
@@ -36,8 +36,6 @@ import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController.DismissReason;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -52,8 +50,6 @@ import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;

import javax.inject.Inject;

/**
 * Keeps track of active bubbles.
 */
@@ -154,12 +150,11 @@ public class BubbleData {
     * associated with it). This list is used to check if the summary should be hidden from the
     * shade.
     *
     * Key: group key of the NotificationEntry
     * Value: key of the NotificationEntry
     * Key: group key of the notification
     * Value: key of the notification
     */
    private HashMap<String, String> mSuppressedGroupKeys = new HashMap<>();

    @Inject
    public BubbleData(Context context) {
        mContext = context;
        mBubbles = new ArrayList<>();
@@ -205,6 +200,11 @@ public class BubbleData {
        return mSelectedBubble;
    }

    /** Return a read-only current active bubble lists. */
    public List<Bubble> getActiveBubbles() {
        return Collections.unmodifiableList(mBubbles);
    }

    public void setExpanded(boolean expanded) {
        if (DEBUG_BUBBLE_DATA) {
            Log.d(TAG, "setExpanded: " + expanded);
@@ -235,8 +235,8 @@ public class BubbleData {
     * @param persistedBubble The bubble to use, only non-null if it's a bubble being promoted from
     *              the overflow that was persisted over reboot.
     */
    Bubble getOrCreateBubble(NotificationEntry entry, Bubble persistedBubble) {
        String key = entry != null ? entry.getKey() : persistedBubble.getKey();
    public Bubble getOrCreateBubble(BubbleEntry entry, Bubble persistedBubble) {
        String key = persistedBubble != null ? persistedBubble.getKey() : entry.getKey();
        Bubble bubbleToReturn = getBubbleInStackWithKey(key);

        if (bubbleToReturn == null) {
@@ -266,7 +266,7 @@ public class BubbleData {
    /**
     * When this method is called it is expected that all info in the bubble has completed loading.
     * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context,
     * BubbleStackView, BubbleIconFactory).
     * BubbleStackView, BubbleIconFactory, boolean).
     */
    void notificationEntryUpdated(Bubble bubble, boolean suppressFlyout, boolean showInShade) {
        if (DEBUG_BUBBLE_DATA) {
@@ -329,7 +329,7 @@ public class BubbleData {
     * Retrieves the notif entry key of the summary associated with the provided group key.
     *
     * @param groupKey the group to look up
     * @return the key for the {@link NotificationEntry} that is the summary of this group.
     * @return the key for the notification that is the summary of this group.
     */
    String getSummaryKey(String groupKey) {
        return mSuppressedGroupKeys.get(groupKey);
@@ -349,25 +349,6 @@ public class BubbleData {
        return mSuppressedGroupKeys.containsKey(groupKey);
    }

    /**
     * Retrieves any bubbles that are part of the notification group represented by the provided
     * group key.
     */
    ArrayList<Bubble> getBubblesInGroup(@Nullable String groupKey, @NonNull
            NotificationEntryManager nem) {
        ArrayList<Bubble> bubbleChildren = new ArrayList<>();
        if (groupKey == null) {
            return bubbleChildren;
        }
        for (Bubble b : mBubbles) {
            final NotificationEntry entry = nem.getPendingOrActiveNotif(b.getKey());
            if (entry != null && groupKey.equals(entry.getSbn().getGroupKey())) {
                bubbleChildren.add(b);
            }
        }
        return bubbleChildren;
    }

    /**
     * Removes bubbles from the given package whose shortcut are not in the provided list of valid
     * shortcuts.
+98 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.bubbles;

import android.app.Notification.BubbleMetadata;
import android.app.NotificationManager.Policy;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.StatusBarNotification;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * Represents a notification with needed data and flag for bubbles.
 *
 * @see Bubble
 */
public class BubbleEntry {

    private StatusBarNotification mSbn;
    private Ranking mRanking;

    private boolean mIsClearable;
    private boolean mShouldSuppressNotificationDot;
    private boolean mShouldSuppressNotificationList;
    private boolean mShouldSuppressPeek;

    public BubbleEntry(@NonNull StatusBarNotification sbn,
            Ranking ranking, boolean isClearable, boolean shouldSuppressNotificationDot,
            boolean shouldSuppressNotificationList, boolean shouldSuppressPeek) {
        mSbn = sbn;
        mRanking = ranking;

        mIsClearable = isClearable;
        mShouldSuppressNotificationDot = shouldSuppressNotificationDot;
        mShouldSuppressNotificationList = shouldSuppressNotificationList;
        mShouldSuppressPeek = shouldSuppressPeek;
    }

    /** @return the {@link StatusBarNotification} for this entry. */
    @NonNull
    public StatusBarNotification getStatusBarNotification() {
        return mSbn;
    }

    /** @return the {@link Ranking} for this entry. */
    public Ranking getRanking() {
        return mRanking;
    }

    /** @return the key in the {@link StatusBarNotification}. */
    public String getKey() {
        return mSbn.getKey();
    }

    /** @return the {@link BubbleMetadata} in the {@link StatusBarNotification}. */
    @Nullable
    public BubbleMetadata getBubbleMetadata() {
        return getStatusBarNotification().getNotification().getBubbleMetadata();
    }

    /** @return true if this notification is clearable. */
    public boolean isClearable() {
        return mIsClearable;
    }

    /** @return true if {@link Policy#SUPPRESSED_EFFECT_BADGE} set for this notification. */
    public boolean shouldSuppressNotificationDot() {
        return mShouldSuppressNotificationDot;
    }

    /**
     * @return true if {@link Policy#SUPPRESSED_EFFECT_NOTIFICATION_LIST}
     * set for this notification.
     */
    public boolean shouldSuppressNotificationList() {
        return mShouldSuppressNotificationList;
    }

    /** @return true if {@link Policy#SUPPRESSED_EFFECT_PEEK} set for this notification. */
    public boolean shouldSuppressPeek() {
        return mShouldSuppressPeek;
    }
}
+0 −73

File changed.

Preview size limit exceeded, changes collapsed.

Loading