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

Commit 358a6676 authored by Mady Mellor's avatar Mady Mellor Committed by Android (Google) Code Review
Browse files

Merge changes from topic "background_bubbles"

* changes:
  Inflate & make bitmaps for bubble views in background
  Cleanup to make loading bubble info in background easier
parents 8fd3df39 3df7ab00
Loading
Loading
Loading
Loading
+15 −90
Original line number Diff line number Diff line
@@ -16,22 +16,15 @@
package com.android.systemui.bubbles;

import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
import android.util.PathParser;
import android.widget.ImageView;

import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.DotRenderer;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -46,9 +39,9 @@ import com.android.systemui.R;
public class BadgedImageView extends ImageView {

    /** Same value as Launcher3 dot code */
    private static final float WHITE_SCRIM_ALPHA = 0.54f;
    public static final float WHITE_SCRIM_ALPHA = 0.54f;
    /** Same as value in Launcher3 IconShape */
    private static final int DEFAULT_PATH_SIZE = 100;
    public static final int DEFAULT_PATH_SIZE = 100;

    static final int DOT_STATE_DEFAULT = 0;
    static final int DOT_STATE_SUPPRESSED_FOR_FLYOUT = 1;
@@ -58,7 +51,6 @@ public class BadgedImageView extends ImageView {
    private int mCurrentDotState = DOT_STATE_SUPPRESSED_FOR_FLYOUT;

    private Bubble mBubble;
    private BubbleIconFactory mBubbleIconFactory;

    private int mIconBitmapSize;
    private DotRenderer mDotRenderer;
@@ -94,6 +86,18 @@ public class BadgedImageView extends ImageView {
        mDotRenderer = new DotRenderer(mIconBitmapSize, iconPath, DEFAULT_PATH_SIZE);
    }

    /**
     * Updates the view with provided info.
     */
    public void update(Bubble bubble, Bitmap bubbleImage, int dotColor, Path dotPath) {
        mBubble = bubble;
        setImageBitmap(bubbleImage);
        setDotState(DOT_STATE_SUPPRESSED_FOR_FLYOUT);
        mDotColor = dotColor;
        drawDot(dotPath);
        animateDot();
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
@@ -139,14 +143,6 @@ public class BadgedImageView extends ImageView {
        invalidate();
    }

    /**
     * The colour to use for the dot.
     */
    void setDotColor(int color) {
        mDotColor = ColorUtils.setAlphaComponent(color, 255 /* alpha */);
        invalidate();
    }

    /**
     * @param iconPath The new icon path to use when calculating dot position.
     */
@@ -186,25 +182,6 @@ public class BadgedImageView extends ImageView {
        return new float[]{dotCenterX, dotCenterY};
    }

    /**
     * Populates this view with a bubble.
     * <p>
     * This should only be called when a new bubble is being set on the view, updates to the
     * current bubble should use {@link #update(Bubble)}.
     *
     * @param bubble the bubble to display in this view.
     */
    public void setBubble(Bubble bubble) {
        mBubble = bubble;
    }

    /**
     * @param factory Factory for creating normalized bubble icons.
     */
    public void setBubbleIconFactory(BubbleIconFactory factory) {
        mBubbleIconFactory = factory;
    }

    /**
     * The key for the {@link Bubble} associated with this view, if one exists.
     */
@@ -213,15 +190,6 @@ public class BadgedImageView extends ImageView {
        return (mBubble != null) ? mBubble.getKey() : null;
    }

    /**
     * Updates the UI based on the bubble, updates badge and animates messages as needed.
     */
    public void update(Bubble bubble) {
        mBubble = bubble;
        setDotState(DOT_STATE_SUPPRESSED_FOR_FLYOUT);
        updateViews();
    }

    int getDotColor() {
        return mDotColor;
    }
@@ -277,47 +245,4 @@ public class BadgedImageView extends ImageView {
                    }
                }).start();
    }

    void updateViews() {
        if (mBubble == null || mBubbleIconFactory == null) {
            return;
        }

        Drawable bubbleDrawable = getBubbleDrawable(mContext);
        BitmapInfo badgeBitmapInfo = mBubbleIconFactory.getBadgedBitmap(mBubble);
        BitmapInfo bubbleBitmapInfo = mBubbleIconFactory.getBubbleBitmap(bubbleDrawable,
                badgeBitmapInfo);
        setImageBitmap(bubbleBitmapInfo.icon);

        // Update badge.
        mDotColor = ColorUtils.blendARGB(badgeBitmapInfo.color, Color.WHITE, WHITE_SCRIM_ALPHA);
        setDotColor(mDotColor);

        // Update dot.
        Path iconPath = PathParser.createPathFromPathData(
                getResources().getString(com.android.internal.R.string.config_icon_mask));
        Matrix matrix = new Matrix();
        float scale = mBubbleIconFactory.getNormalizer().getScale(bubbleDrawable,
                null /* outBounds */, null /* path */, null /* outMaskShape */);
        float radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f;
        matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
                radius /* pivot y */);
        iconPath.transform(matrix);
        drawDot(iconPath);

        animateDot();
    }

    Drawable getBubbleDrawable(Context context) {
        if (mBubble.getShortcutInfo() != null && mBubble.usingShortcutInfo()) {
            LauncherApps launcherApps =
                    (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);
            int density = getContext().getResources().getConfiguration().densityDpi;
            return launcherApps.getShortcutIconDrawable(mBubble.getShortcutInfo(), density);
        } else {
            Notification.BubbleMetadata metadata = mBubble.getEntry().getBubbleMetadata();
            Icon ic = metadata.getIcon();
            return ic.loadDrawable(context);
        }
    }
}
+80 −83
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.systemui.bubbles;


import static android.os.AsyncTask.Status.FINISHED;
import static android.view.Display.INVALID_DISPLAY;

import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
@@ -26,20 +27,17 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
@@ -59,19 +57,19 @@ class Bubble {
    private NotificationEntry mEntry;
    private final String mKey;
    private final String mGroupId;

    private long mLastUpdated;
    private long mLastAccessed;

    // Items that are typically loaded later
    private String mAppName;
    private Drawable mUserBadgedAppIcon;
    private ShortcutInfo mShortcutInfo;

    private boolean mInflated;
    private BadgedImageView mIconView;
    private BubbleExpandedView mExpandedView;
    private BubbleIconFactory mBubbleIconFactory;

    private long mLastUpdated;
    private long mLastAccessed;

    private boolean mIsUserCreated;
    private boolean mInflated;
    private BubbleViewInfoTask mInflationTask;
    private boolean mInflateSynchronously;

    /**
     * Whether this notification should be shown in the shade when it is also displayed as a bubble.
@@ -94,37 +92,11 @@ class Bubble {

    /** Used in tests when no UI is required. */
    @VisibleForTesting(visibility = PRIVATE)
    Bubble(Context context, NotificationEntry e) {
    Bubble(NotificationEntry e) {
        mEntry = e;
        mKey = e.getKey();
        mLastUpdated = e.getSbn().getPostTime();
        mGroupId = groupId(e);

        String shortcutId = e.getSbn().getNotification().getShortcutId();
        if (BubbleExperimentConfig.useShortcutInfoToBubble(context)
                && shortcutId != null) {
            mShortcutInfo = BubbleExperimentConfig.getShortcutInfo(context,
                    e.getSbn().getPackageName(),
                    e.getSbn().getUser(), shortcutId);
        }

        PackageManager pm = context.getPackageManager();
        ApplicationInfo info;
        try {
            info = pm.getApplicationInfo(
                mEntry.getSbn().getPackageName(),
                PackageManager.MATCH_UNINSTALLED_PACKAGES
                    | PackageManager.MATCH_DISABLED_COMPONENTS
                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                    | PackageManager.MATCH_DIRECT_BOOT_AWARE);
            if (info != null) {
                mAppName = String.valueOf(pm.getApplicationLabel(info));
            }
            Drawable appIcon = pm.getApplicationIcon(mEntry.getSbn().getPackageName());
            mUserBadgedAppIcon = pm.getUserBadgedIcon(appIcon, mEntry.getSbn().getUser());
        } catch (PackageManager.NameNotFoundException unused) {
            mAppName = mEntry.getSbn().getPackageName();
        }
    }

    public String getKey() {
@@ -143,41 +115,22 @@ class Bubble {
        return mEntry.getSbn().getPackageName();
    }

    @Nullable
    public String getAppName() {
        return mAppName;
    }

    Drawable getUserBadgedAppIcon() {
        return mUserBadgedAppIcon;
    }

    @Nullable
    public ShortcutInfo getShortcutInfo() {
        return mShortcutInfo;
    }

    /**
     * Whether shortcut information should be used to populate the bubble.
     * <p>
     * To populate the activity use {@link LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)}.
     * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
     */
    public boolean usingShortcutInfo() {
        return BubbleExperimentConfig.isShortcutIntent(getBubbleIntent());
    }

    void setBubbleIconFactory(BubbleIconFactory factory) {
        mBubbleIconFactory = factory;
    }

    boolean isInflated() {
        return mInflated;
    }

    @Nullable
    BadgedImageView getIconView() {
        return mIconView;
    }

    @Nullable
    BubbleExpandedView getExpandedView() {
        return mExpandedView;
    }
@@ -188,22 +141,64 @@ class Bubble {
        }
    }

    void inflate(LayoutInflater inflater, BubbleStackView stackView) {
        if (mInflated) {
            return;
    /**
     * Sets whether to perform inflation on the same thread as the caller. This method should only
     * be used in tests, not in production.
     */
    @VisibleForTesting
    void setInflateSynchronously(boolean inflateSynchronously) {
        mInflateSynchronously = inflateSynchronously;
    }

    /**
     * Starts a task to inflate & load any necessary information to display a bubble.
     *
     * @param callback the callback to notify one the bubble is ready to be displayed.
     * @param context the context for the bubble.
     * @param stackView the stackView the bubble is eventually added to.
     * @param iconFactory the iconfactory use to create badged images for the bubble.
     */
    void inflate(BubbleViewInfoTask.Callback callback,
            Context context,
            BubbleStackView stackView,
            BubbleIconFactory iconFactory) {
        if (isBubbleLoading()) {
            mInflationTask.cancel(true /* mayInterruptIfRunning */);
        }
        mInflationTask = new BubbleViewInfoTask(this,
                context,
                stackView,
                iconFactory,
                callback);
        if (mInflateSynchronously) {
            mInflationTask.onPostExecute(mInflationTask.doInBackground());
        } else {
            mInflationTask.execute();
        }
    }

    private boolean isBubbleLoading() {
        return mInflationTask != null && mInflationTask.getStatus() != FINISHED;
    }
        mIconView = (BadgedImageView) inflater.inflate(
                R.layout.bubble_view, stackView, false /* attachToRoot */);
        mIconView.setBubbleIconFactory(mBubbleIconFactory);
        mIconView.setBubble(this);

        mExpandedView = (BubbleExpandedView) inflater.inflate(
                R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
        mExpandedView.setBubble(this, stackView);
    boolean isInflated() {
        return mInflated;
    }

    void setViewInfo(BubbleViewInfoTask.BubbleViewInfo info) {
        if (!isInflated()) {
            mIconView = info.imageView;
            mExpandedView = info.expandedView;
            mInflated = true;
        }

        mShortcutInfo = info.shortcutInfo;
        mAppName = info.appName;

        mExpandedView.update(this);
        mIconView.update(this, info.badgedBubbleImage, info.dotColor, info.dotPath);
    }

    /**
     * Set visibility of bubble in the expanded state.
     *
@@ -218,13 +213,12 @@ class Bubble {
        }
    }

    void updateEntry(NotificationEntry entry) {
    /**
     * Sets the entry associated with this bubble.
     */
    void setEntry(NotificationEntry entry) {
        mEntry = entry;
        mLastUpdated = entry.getSbn().getPostTime();
        if (mInflated) {
            mIconView.update(this);
            mExpandedView.update(this);
        }
    }

    /**
@@ -241,13 +235,6 @@ class Bubble {
        return mLastUpdated;
    }

    /**
     * @return the timestamp in milliseconds when this bubble was last displayed in expanded state
     */
    long getLastAccessTime() {
        return mLastAccessed;
    }

    /**
     * @return the display id of the virtual display on which bubble contents is drawn.
     */
@@ -352,6 +339,16 @@ class Bubble {
        }
    }

    /**
     * Whether shortcut information should be used to populate the bubble.
     * <p>
     * To populate the activity use {@link LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)}.
     * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
     */
    boolean usingShortcutInfo() {
        return BubbleExperimentConfig.isShortcutIntent(getBubbleIntent());
    }

    @Nullable
    PendingIntent getBubbleIntent() {
        Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
+33 −19
Original line number Diff line number Diff line
@@ -150,6 +150,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi

    private BubbleData mBubbleData;
    @Nullable private BubbleStackView mStackView;
    private BubbleIconFactory mBubbleIconFactory;

    // Tracks the id of the current (foreground) user.
    private int mCurrentUserId;
@@ -183,6 +184,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    /** Last known orientation, used to detect orientation changes in {@link #onConfigChanged}. */
    private int mOrientation = Configuration.ORIENTATION_UNDEFINED;

    private boolean mInflateSynchronously;

    /**
     * Listener to be notified when some states of the bubbles change.
     */
@@ -352,6 +355,16 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        mUserBlockedBubbles = new HashSet<>();

        mScreenshotHelper = new ScreenshotHelper(context);
        mBubbleIconFactory = new BubbleIconFactory(context);
    }

    /**
     * Sets whether to perform inflation on the same thread as the caller. This method should only
     * be used in tests, not in production.
     */
    @VisibleForTesting
    void setInflateSynchronously(boolean inflateSynchronously) {
        mInflateSynchronously = inflateSynchronously;
    }

    /**
@@ -415,16 +428,23 @@ public class BubbleController implements ConfigurationController.ConfigurationLi

    @Override
    public void onUiModeChanged() {
        if (mStackView != null) {
            mStackView.onThemeChanged();
        }
        updateForThemeChanges();
    }

    @Override
    public void onOverlayChanged() {
        updateForThemeChanges();
    }

    private void updateForThemeChanges() {
        if (mStackView != null) {
            mStackView.onThemeChanged();
        }
        mBubbleIconFactory = new BubbleIconFactory(mContext);
        for (Bubble b: mBubbleData.getBubbles()) {
            // Reload each bubble
            b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory);
        }
    }

    @Override
@@ -508,14 +528,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        return (isSummary && isSuppressedSummary) || isBubbleAndSuppressed;
    }

    void selectBubble(Bubble bubble) {
        mBubbleData.setSelectedBubble(bubble);
    }

    @VisibleForTesting
    void selectBubble(String key) {
        Bubble bubble = mBubbleData.getBubbleWithKey(key);
        selectBubble(bubble);
        mBubbleData.setSelectedBubble(bubble);
    }

    /**
@@ -562,11 +578,19 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    }

    void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
        if (mStackView == null) {
            // Lazy init stack view when a bubble is created
            ensureStackViewCreated();
        }
        // If this is an interruptive notif, mark that it's interrupted
        if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
            notif.setInterruption();
        }
        mBubbleData.notificationEntryUpdated(notif, suppressFlyout, showInShade);
        Bubble bubble = mBubbleData.getOrCreateBubble(notif);
        bubble.setInflateSynchronously(mInflateSynchronously);
        bubble.inflate(
                b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade),
                mContext, mStackView, mBubbleIconFactory);
    }

    /**
@@ -783,16 +807,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi

        @Override
        public void applyUpdate(BubbleData.Update update) {
            if (mStackView == null && update.addedBubble != null) {
                // Lazy init stack view when the first bubble is added.
                ensureStackViewCreated();
            }

            // If not yet initialized, ignore all other changes.
            if (mStackView == null) {
                return;
            }

            if (update.addedBubble != null) {
                mStackView.addBubble(update.addedBubble);
            }
+27 −10
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.util.Pair;
import androidx.annotation.Nullable;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController.DismissReason;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;

@@ -48,7 +49,6 @@ import java.util.Objects;

import javax.inject.Inject;
import javax.inject.Singleton;
import com.android.systemui.R;

/**
 * Keeps track of active bubbles.
@@ -180,28 +180,44 @@ public class BubbleData {
        dispatchPendingChanges();
    }

    void notificationEntryUpdated(NotificationEntry entry, boolean suppressFlyout,
            boolean showInShade) {
    /**
     * Constructs a new bubble or returns an existing one. Does not add new bubbles to
     * bubble data, must go through {@link #notificationEntryUpdated(Bubble, boolean, boolean)}
     * for that.
     */
    Bubble getOrCreateBubble(NotificationEntry entry) {
        Bubble bubble = getBubbleWithKey(entry.getKey());
        if (bubble == null) {
            bubble = new Bubble(entry);
        } else {
            bubble.setEntry(entry);
        }
        return bubble;
    }

    /**
     * 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).
     */
    void notificationEntryUpdated(Bubble bubble, boolean suppressFlyout, boolean showInShade) {
        if (DEBUG_BUBBLE_DATA) {
            Log.d(TAG, "notificationEntryUpdated: " + entry);
            Log.d(TAG, "notificationEntryUpdated: " + bubble);
        }

        Bubble bubble = getBubbleWithKey(entry.getKey());
        suppressFlyout |= !shouldShowFlyout(entry);
        Bubble prevBubble = getBubbleWithKey(bubble.getKey());
        suppressFlyout |= !shouldShowFlyout(bubble.getEntry());

        if (bubble == null) {
        if (prevBubble == null) {
            // Create a new bubble
            bubble = new Bubble(mContext, entry);
            bubble.setSuppressFlyout(suppressFlyout);
            doAdd(bubble);
            trim();
        } else {
            // Updates an existing bubble
            bubble.updateEntry(entry);
            bubble.setSuppressFlyout(suppressFlyout);
            doUpdate(bubble);
        }

        if (bubble.shouldAutoExpand()) {
            setSelectedBubbleInternal(bubble);
            if (!mExpanded) {
@@ -214,6 +230,7 @@ public class BubbleData {
        bubble.setShowInShade(!isBubbleExpandedAndSelected && showInShade);
        bubble.setShowDot(!isBubbleExpandedAndSelected /* show */, true /* animate */);
        dispatchPendingChanges();

    }

    public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) {
+26 −54
Original line number Diff line number Diff line
@@ -99,7 +99,6 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
    private int mExpandedViewTouchSlop;

    private Bubble mBubble;
    private String mAppName;

    private BubbleController mBubbleController = Dependency.get(BubbleController.class);
    private WindowManager mWindowManager;
@@ -339,26 +338,41 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
        }
    }

    void setStackView(BubbleStackView stackView) {
        mStackView = stackView;
    }

    /**
     * Sets the bubble used to populate this view.
     */
    public void setBubble(Bubble bubble, BubbleStackView stackView) {
    void update(Bubble bubble) {
        if (DEBUG_BUBBLE_EXPANDED_VIEW) {
            Log.d(TAG, "setBubble: bubble=" + (bubble != null ? bubble.getKey() : "null"));
            Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null"));
        }
        mStackView = stackView;
        boolean isNew = mBubble == null;
        if (isNew || bubble.getKey().equals(mBubble.getKey())) {
            mBubble = bubble;
        mAppName = bubble.getAppName();
            mSettingsIcon.setContentDescription(getResources().getString(
                    R.string.bubbles_settings_button_description, bubble.getAppName()));

            if (isNew) {
                mBubbleIntent = mBubble.getBubbleIntent();
                if (mBubbleIntent != null) {
                    setContentVisibility(false);
                    mActivityView.setVisibility(VISIBLE);
                }
            }
            applyThemeAttrs();
        showSettingsIcon();
        updateExpandedView();
        } else {
            Log.w(TAG, "Trying to update entry with different key, new bubble: "
                    + bubble.getKey() + " old bubble: " + bubble.getKey());
        }
    }

    /**
     * Lets activity view know it should be shown / populated.
     * Lets activity view know it should be shown / populated with activity content.
     */
    public void populateExpandedView() {
    void populateExpandedView() {
        if (DEBUG_BUBBLE_EXPANDED_VIEW) {
            Log.d(TAG, "populateExpandedView: "
                    + "bubble=" + getBubbleKey());
@@ -371,38 +385,6 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
        }
    }

    /**
     * Updates the bubble backing this view. This will not re-populate ActivityView, it will
     * only update the deep-links in the title, and the height of the view.
     */
    public void update(Bubble bubble) {
        if (DEBUG_BUBBLE_EXPANDED_VIEW) {
            Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null"));
        }
        if (bubble.getKey().equals(mBubble.getKey())) {
            mBubble = bubble;
            updateSettingsContentDescription();
            updateHeight();
        } else {
            Log.w(TAG, "Trying to update entry with different key, new bubble: "
                    + bubble.getKey() + " old bubble: " + bubble.getKey());
        }
    }

    private void updateExpandedView() {
        if (DEBUG_BUBBLE_EXPANDED_VIEW) {
            Log.d(TAG, "updateExpandedView: bubble="
                    + getBubbleKey());
        }

        mBubbleIntent = mBubble.getBubbleIntent();
        if (mBubbleIntent != null) {
            setContentVisibility(false);
            mActivityView.setVisibility(VISIBLE);
        }
        updateView();
    }

    boolean performBackPressIfNeeded() {
        if (!usingActivityView()) {
            return false;
@@ -490,16 +472,6 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
        }
    }

    private void updateSettingsContentDescription() {
        mSettingsIcon.setContentDescription(getResources().getString(
                R.string.bubbles_settings_button_description, mAppName));
    }

    void showSettingsIcon() {
        updateSettingsContentDescription();
        mSettingsIcon.setVisibility(VISIBLE);
    }

    /**
     * Update appearance of the expanded view being displayed.
     */
Loading