Move ActivityView into BubbleExpandedView
This is initial work that needs to come before moving bubbles to the
bottom of the screen and enabling horizontal swiping.
* Moves ActivityView out of BubbleView and into BubblExpandedView
* New 'bubble' object that wraps the notification entry and the two
bubble views (icon + expanded), this is utilized by BubbleStackView
* BubbleData is the knower of bubbles and used by BubbleController &
BubbleStackView as source of truth
Bug: 123543995
Test: atest BubbleControllerTest (existing tests all pass)
Change-Id: I710d908e78ed2aef6a0e482b70c21fa0640d250c
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
new file mode 100644
index 0000000..4778434
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 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.view.LayoutInflater;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/**
+ * Encapsulates the data and UI elements of a bubble.
+ */
+class Bubble {
+
+ public BubbleView iconView;
+ public BubbleExpandedView expandedView;
+ public String key;
+ public NotificationEntry entry;
+
+ Bubble(NotificationEntry e, LayoutInflater inflater, BubbleStackView stackView,
+ BubbleExpandedView.OnBubbleBlockedListener listener) {
+ entry = e;
+ key = entry.key;
+
+ iconView = (BubbleView) inflater.inflate(
+ R.layout.bubble_view, stackView, false /* attachToRoot */);
+ iconView.setNotif(entry);
+
+ expandedView = (BubbleExpandedView) inflater.inflate(
+ R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
+ expandedView.setEntry(entry, stackView);
+
+ expandedView.setOnBlockedListener(listener);
+ }
+
+ public void setEntry(NotificationEntry entry) {
+ key = entry.key;
+ iconView.update(entry);
+ // TODO: should also update the expanded view here (e.g. height change)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 41bc1b2..a67e1b7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -16,10 +16,6 @@
package com.android.systemui.bubbles;
-import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
-import static android.util.StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
-import static android.util.StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
-import static android.util.StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -33,21 +29,14 @@
import android.app.IActivityTaskManager;
import android.app.INotificationManager;
import android.app.Notification;
-import android.app.PendingIntent;
import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
-import android.util.Log;
-import android.util.StatsLog;
import android.view.Display;
-import android.view.LayoutInflater;
import android.view.ViewGroup;
-import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.annotation.MainThread;
@@ -66,10 +55,7 @@
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -105,11 +91,9 @@
private final BubbleTaskStackListener mTaskStackListener;
private BubbleStateChangeListener mStateChangeListener;
private BubbleExpandListener mExpandListener;
- private LayoutInflater mInflater;
- private final Map<String, BubbleView> mBubbles = new HashMap<>();
+ private BubbleData mBubbleData;
private BubbleStackView mStackView;
- private final Point mDisplaySize;
// Bubbles get added to the status bar view
private final StatusBarWindowController mStatusBarWindowController;
@@ -168,10 +152,6 @@
@Inject
public BubbleController(Context context, StatusBarWindowController statusBarWindowController) {
mContext = context;
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- mDisplaySize = new Point();
- wm.getDefaultDisplay().getSize(mDisplaySize);
- mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
@@ -190,6 +170,8 @@
mActivityTaskManager = ActivityTaskManager.getService();
mTaskStackListener = new BubbleTaskStackListener();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+
+ mBubbleData = BubbleData.getInstance();
}
/**
@@ -219,8 +201,11 @@
* screen (e.g. if on AOD).
*/
public boolean hasBubbles() {
- for (BubbleView bv : mBubbles.values()) {
- if (!bv.getEntry().isBubbleDismissed()) {
+ if (mStackView == null) {
+ return false;
+ }
+ for (Bubble bubble : mBubbleData.getBubbles()) {
+ if (!bubble.entry.isBubbleDismissed()) {
return true;
}
}
@@ -250,10 +235,6 @@
if (mStackView == null) {
return;
}
- Set<String> keys = mBubbles.keySet();
- for (String key: keys) {
- mBubbles.get(key).getEntry().setBubbleDismissed(true);
- }
mStackView.stackDismissed();
updateVisibility();
@@ -267,10 +248,9 @@
* @param updatePosition whether this update should promote the bubble to the top of the stack.
*/
public void updateBubble(NotificationEntry notif, boolean updatePosition) {
- if (mBubbles.containsKey(notif.key)) {
+ if (mStackView != null && mBubbleData.getBubble(notif.key) != null) {
// It's an update
- BubbleView bubble = mBubbles.get(notif.key);
- mStackView.updateBubble(bubble, notif, updatePosition);
+ mStackView.updateBubble(notif, updatePosition);
} else {
if (mStackView == null) {
mStackView = new BubbleStackView(mContext);
@@ -286,15 +266,7 @@
mStackView.setOnBlockedListener(this);
}
// It's new
- BubbleView bubble = (BubbleView) mInflater.inflate(
- R.layout.bubble_view, mStackView, false /* attachToRoot */);
- bubble.setNotif(notif);
- PendingIntent bubbleIntent = getValidBubbleIntent(notif);
- if (bubbleIntent != null) {
- bubble.setBubbleIntent(bubbleIntent);
- }
- mBubbles.put(bubble.getKey(), bubble);
- mStackView.addBubble(bubble);
+ mStackView.addBubble(notif);
}
updateVisibility();
}
@@ -306,25 +278,18 @@
*/
@MainThread
void removeBubble(String key) {
- BubbleView bv = mBubbles.remove(key);
- if (mStackView != null && bv != null) {
- mStackView.removeBubble(bv);
- bv.destroyActivityView(mStackView);
+ if (mStackView != null) {
+ mStackView.removeBubble(key);
}
-
- NotificationEntry entry = bv != null ? bv.getEntry() : null;
- if (entry != null) {
- entry.setBubbleDismissed(true);
- mNotificationEntryManager.updateNotifications();
- }
+ mNotificationEntryManager.updateNotifications();
updateVisibility();
}
@Override
public void onBubbleBlocked(NotificationEntry entry) {
- Object[] bubbles = mBubbles.values().toArray();
+ Object[] bubbles = mBubbleData.getBubbles().toArray();
for (int i = 0; i < bubbles.length; i++) {
- NotificationEntry e = ((BubbleView) bubbles[i]).getEntry();
+ NotificationEntry e = ((Bubble) bubbles[i]).entry;
boolean samePackage = entry.notification.getPackageName().equals(
e.notification.getPackageName());
if (samePackage) {
@@ -368,10 +333,8 @@
&& alertAgain(entry, entry.notification.getNotification())) {
entry.setShowInShadeWhenBubble(true);
entry.setBubbleDismissed(false); // updates come back as bubbles even if dismissed
- if (mBubbles.containsKey(entry.key)) {
- mBubbles.get(entry.key).updateDotVisibility();
- }
updateBubble(entry, true /* updatePosition */);
+ mStackView.updateDotVisibility(entry.key);
}
}
@@ -383,8 +346,8 @@
return;
}
entry.setShowInShadeWhenBubble(false);
- if (mBubbles.containsKey(entry.key)) {
- mBubbles.get(entry.key).updateDotVisibility();
+ if (mStackView != null) {
+ mStackView.updateDotVisibility(entry.key);
}
if (!removedByUser) {
// This was a cancel so we should remove the bubble
@@ -441,65 +404,6 @@
return mStackView;
}
- @Nullable
- private PendingIntent getValidBubbleIntent(NotificationEntry notif) {
- Notification notification = notif.notification.getNotification();
- String packageName = notif.notification.getPackageName();
- Notification.BubbleMetadata data = notif.getBubbleMetadata();
- if (data != null && canLaunchInActivityView(data.getIntent(),
- true /* enable logging for bubbles */, packageName)) {
- return data.getIntent();
- }
- if (shouldUseContentIntent(mContext)
- && canLaunchInActivityView(notification.contentIntent,
- false /* disable logging for notifications */, packageName)) {
- Log.d(TAG, "[addBubble " + notif.key
- + "]: No appOverlayIntent, using contentIntent.");
- return notification.contentIntent;
- }
- Log.d(TAG, "[addBubble " + notif.key + "]: No supported intent for ActivityView.");
- return null;
- }
-
- /**
- * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
- *
- * @param intent the pending intent of the bubble.
- * @param enableLogging whether bubble developer error should be logged.
- * @param packageName the notification package name for this bubble.
- * @return
- */
- private boolean canLaunchInActivityView(PendingIntent intent, boolean enableLogging,
- String packageName) {
- if (intent == null) {
- return false;
- }
- ActivityInfo info =
- intent.getIntent().resolveActivityInfo(mContext.getPackageManager(), 0);
- if (info == null) {
- if (enableLogging) {
- StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
- BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
- }
- return false;
- }
- if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
- if (enableLogging) {
- StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
- BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
- }
- return false;
- }
- if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
- if (enableLogging) {
- StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
- BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
- }
- return false;
- }
- return (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
- }
-
/**
* Whether the notification has been developer configured to bubble and is allowed by the user.
*/
@@ -620,7 +524,7 @@
ENABLE_AUTO_BUBBLE_ALL, 0) != 0;
}
- private static boolean shouldUseContentIntent(Context context) {
+ static boolean shouldUseContentIntent(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
ENABLE_BUBBLE_CONTENT_INTENT, 0) != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
new file mode 100644
index 0000000..89b0de8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 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 androidx.annotation.Nullable;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import java.util.Collection;
+import java.util.HashMap;
+
+/**
+ * Keeps track of active bubbles.
+ */
+class BubbleData {
+
+ private HashMap<String, Bubble> mBubbles = new HashMap<>();
+
+ private static BubbleData sBubbleData = null;
+
+ private BubbleData() {}
+
+ public static BubbleData getInstance() {
+ if (sBubbleData == null) {
+ sBubbleData = new BubbleData();
+ }
+ return sBubbleData;
+ }
+
+ /**
+ * The set of bubbles.
+ */
+ public Collection<Bubble> getBubbles() {
+ return mBubbles.values();
+ }
+
+ @Nullable
+ public Bubble getBubble(String key) {
+ return mBubbles.get(key);
+ }
+
+ public void addBubble(Bubble b) {
+ mBubbles.put(b.key, b);
+ }
+
+ @Nullable
+ public Bubble removeBubble(String key) {
+ return mBubbles.remove(key);
+ }
+
+ public void updateBubble(String key, NotificationEntry newEntry) {
+ Bubble oldBubble = mBubbles.get(key);
+ if (oldBubble != null) {
+ oldBubble.setEntry(newEntry);
+ }
+ }
+
+ public void clear() {
+ mBubbles.clear();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 976a766..3389c46 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -16,19 +16,28 @@
package com.android.systemui.bubbles;
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
+
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.annotation.Nullable;
+import android.app.ActivityView;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Insets;
+import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.os.RemoteException;
@@ -39,16 +48,21 @@
import android.util.Log;
import android.util.StatsLog;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.TriangleShape;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
/**
* Container for the expanded bubble view, handles rendering the caret and header of the view.
@@ -68,8 +82,15 @@
// Permission view
private View mPermissionView;
- // The view that is being displayed for the expanded state
- private View mExpandedView;
+ // Views for expanded state
+ private ExpandableNotificationRow mNotifRow;
+ private ActivityView mActivityView;
+
+ private boolean mActivityViewReady = false;
+ private PendingIntent mBubbleIntent;
+
+ private int mBubbleHeight;
+ private int mDefaultHeight;
private NotificationEntry mEntry;
private PackageManager mPm;
@@ -77,11 +98,38 @@
private Drawable mAppIcon;
private INotificationManager mNotificationManagerService;
+ private BubbleController mBubbleController = Dependency.get(BubbleController.class);
- // Need reference to let it know to collapse when new task is launched
private BubbleStackView mStackView;
- private OnBubbleBlockedListener mOnBubbleBlockedListener;
+ private BubbleExpandedView.OnBubbleBlockedListener mOnBubbleBlockedListener;
+
+ private ActivityView.StateCallback mStateCallback = new ActivityView.StateCallback() {
+ @Override
+ public void onActivityViewReady(ActivityView view) {
+ mActivityViewReady = true;
+ mActivityView.startActivity(mBubbleIntent);
+ }
+
+ @Override
+ public void onActivityViewDestroyed(ActivityView view) {
+ mActivityViewReady = false;
+ }
+
+ /**
+ * This is only called for tasks on this ActivityView, which is also set to
+ * single-task mode -- meaning never more than one task on this display. If a task
+ * is being removed, it's the top Activity finishing and this bubble should
+ * be removed or collapsed.
+ */
+ @Override
+ public void onTaskRemovalStarted(int taskId) {
+ if (mEntry != null) {
+ // Must post because this is called from a binder thread.
+ post(() -> mBubbleController.removeBubble(mEntry.key));
+ }
+ }
+ };
public BubbleExpandedView(Context context) {
this(context, null);
@@ -99,6 +147,8 @@
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mPm = context.getPackageManager();
+ mDefaultHeight = getResources().getDimensionPixelSize(
+ R.dimen.bubble_expanded_default_height);
try {
mNotificationManagerService = INotificationManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
@@ -152,6 +202,28 @@
mPermissionView = findViewById(R.id.permission_layout);
findViewById(R.id.no_bubbles_button).setOnClickListener(this);
findViewById(R.id.yes_bubbles_button).setOnClickListener(this);
+
+ mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
+ true /* singleTaskInstance */);
+ addView(mActivityView);
+
+ mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+ ActivityView activityView = (ActivityView) view;
+ // Here we assume that the position of the ActivityView on the screen
+ // remains regardless of IME status. When we move ActivityView, the
+ // forwardedInsets should be computed not against the current location
+ // and size, but against the post-moved location and size.
+ Point displaySize = new Point();
+ view.getContext().getDisplay().getSize(displaySize);
+ int[] windowLocation = view.getLocationOnScreen();
+ final int windowBottom = windowLocation[1] + view.getHeight();
+ final int keyboardHeight = insets.getSystemWindowInsetBottom()
+ - insets.getStableInsetBottom();
+ final int insetsBottom = Math.max(0,
+ windowBottom + keyboardHeight - displaySize.y);
+ activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
+ return view.onApplyWindowInsets(insets);
+ });
}
/**
@@ -189,6 +261,8 @@
}
updateHeaderView();
updatePermissionView();
+ updateExpandedView();
+ mActivityView.setCallback(mStateCallback);
}
private void updateHeaderView() {
@@ -225,6 +299,34 @@
}
}
+ private void updateExpandedView() {
+ mBubbleIntent = getBubbleIntent(mEntry);
+ if (mBubbleIntent != null) {
+ if (mNotifRow != null) {
+ // Clear out the row if we had it previously
+ removeView(mNotifRow);
+ mNotifRow = null;
+ }
+ Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
+ mBubbleHeight = data != null && data.getDesiredHeight() > 0
+ ? data.getDesiredHeight()
+ : mDefaultHeight;
+ // XXX: enforce max / min height
+ LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
+ lp.height = mBubbleHeight;
+ mActivityView.setLayoutParams(lp);
+ mActivityView.setVisibility(VISIBLE);
+ } else {
+ // Hide activity view if we had it previously
+ mActivityView.setVisibility(GONE);
+
+ // Use notification view
+ mNotifRow = mEntry.getRow();
+ addView(mNotifRow);
+ }
+ updateView();
+ }
+
@Override
public void onClick(View view) {
if (mEntry == null) {
@@ -279,36 +381,87 @@
}
/**
+ * Update appearance of the expanded view being displayed.
+ */
+ public void updateView() {
+ if (usingActivityView()
+ && mActivityView.getVisibility() == VISIBLE
+ && mActivityView.isAttachedToWindow()) {
+ mActivityView.onLocationChanged();
+ } else if (mNotifRow != null) {
+ applyRowState(mNotifRow);
+ }
+ }
+
+ /**
* Set the x position that the tip of the triangle should point to.
*/
- public void setPointerPosition(int x) {
+ public void setPointerPosition(float x) {
// Adjust for the pointer size
- x -= (mPointerView.getWidth() / 2);
+ x -= (mPointerView.getWidth() / 2f);
mPointerView.setTranslationX(x);
}
/**
- * Set the view to display for the expanded state. Passing null will clear the view.
+ * Removes and releases an ActivityView if one was previously created for this bubble.
*/
- public void setExpandedView(View view) {
- if (mExpandedView == view) {
+ public void destroyActivityView(ViewGroup tmpParent) {
+ if (mActivityView == null) {
return;
}
- if (mExpandedView != null) {
- removeView(mExpandedView);
+ if (!mActivityViewReady) {
+ // release not needed, never initialized?
+ mActivityView = null;
+ return;
}
- mExpandedView = view;
- if (mExpandedView != null) {
- addView(mExpandedView);
+ // HACK: release() will crash if the view is not attached.
+ if (!isAttachedToWindow()) {
+ mActivityView.setVisibility(View.GONE);
+ tmpParent.addView(this);
}
+
+ mActivityView.release();
+ ((ViewGroup) getParent()).removeView(this);
+ mActivityView = null;
+ mActivityViewReady = false;
}
- /**
- * @return the view containing the expanded content, can be null.
- */
- @Nullable
- public View getExpandedView() {
- return mExpandedView;
+ private boolean usingActivityView() {
+ return mBubbleIntent != null;
+ }
+
+ private void applyRowState(ExpandableNotificationRow view) {
+ view.reset();
+ view.setHeadsUp(false);
+ view.resetTranslation();
+ view.setOnKeyguard(false);
+ view.setOnAmbient(false);
+ view.setClipBottomAmount(0);
+ view.setClipTopAmount(0);
+ view.setContentTransformationAmount(0, false);
+ view.setIconsVisible(true);
+
+ // TODO - Need to reset this (and others) when view goes back in shade, leave for now
+ // view.setTopRoundness(1, false);
+ // view.setBottomRoundness(1, false);
+
+ ExpandableViewState viewState = view.getViewState();
+ viewState = viewState == null ? new ExpandableViewState() : viewState;
+ viewState.height = view.getIntrinsicHeight();
+ viewState.gone = false;
+ viewState.hidden = false;
+ viewState.dimmed = false;
+ viewState.dark = false;
+ viewState.alpha = 1f;
+ viewState.notGoneIndex = -1;
+ viewState.xTranslation = 0;
+ viewState.yTranslation = 0;
+ viewState.zTranslation = 0;
+ viewState.scaleX = 1;
+ viewState.scaleY = 1;
+ viewState.inShelf = true;
+ viewState.headsUpIsVisible = false;
+ viewState.applyToView(view);
}
private Intent getSettingsIntent(String packageName, final int appUid) {
@@ -320,6 +473,61 @@
return intent;
}
+ @Nullable
+ private PendingIntent getBubbleIntent(NotificationEntry entry) {
+ Notification notif = entry.notification.getNotification();
+ String packageName = entry.notification.getPackageName();
+ Notification.BubbleMetadata data = notif.getBubbleMetadata();
+ if (data != null && canLaunchInActivityView(data.getIntent(), true /* enableLogging */,
+ packageName)) {
+ return data.getIntent();
+ } else if (BubbleController.shouldUseContentIntent(mContext)
+ && canLaunchInActivityView(notif.contentIntent, false /* enableLogging */,
+ packageName)) {
+ return notif.contentIntent;
+ }
+ return null;
+ }
+
+ /**
+ * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
+ *
+ * @param intent the pending intent of the bubble.
+ * @param enableLogging whether bubble developer error should be logged.
+ * @param packageName the notification package name for this bubble.
+ * @return
+ */
+ private boolean canLaunchInActivityView(PendingIntent intent, boolean enableLogging,
+ String packageName) {
+ if (intent == null) {
+ return false;
+ }
+ ActivityInfo info =
+ intent.getIntent().resolveActivityInfo(mContext.getPackageManager(), 0);
+ if (info == null) {
+ if (enableLogging) {
+ StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+ BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
+ }
+ return false;
+ }
+ if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
+ if (enableLogging) {
+ StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+ BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
+ }
+ return false;
+ }
+ if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
+ if (enableLogging) {
+ StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+ BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
+ }
+ return false;
+ }
+ return (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
+ }
+
/**
* Listener that is notified when a bubble is blocked.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 2b344f6..8bc83d4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -19,7 +19,6 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import android.app.ActivityView;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Outline;
@@ -33,13 +32,11 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
@@ -54,8 +51,6 @@
import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
import com.android.systemui.bubbles.animation.StackAnimationController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -95,22 +90,27 @@
private StackAnimationController mStackAnimationController;
private ExpandedAnimationController mExpandedAnimationController;
- private BubbleExpandedView mExpandedViewContainer;
+ private FrameLayout mExpandedViewContainer;
+
+ private BubbleData mBubbleData;
private int mBubbleSize;
private int mBubblePadding;
private int mExpandedAnimateXDistance;
private int mExpandedAnimateYDistance;
+ private Bubble mExpandedBubble;
private boolean mIsExpanded;
- private int mExpandedBubbleHeight;
+
private BubbleTouchHandler mTouchHandler;
- private BubbleView mExpandedBubble;
private BubbleController.BubbleExpandListener mExpandListener;
+ private BubbleExpandedView.OnBubbleBlockedListener mBlockedListener;
private boolean mViewUpdatedRequested = false;
private boolean mIsAnimating = false;
+ private LayoutInflater mInflater;
+
// Used for determining view / touch intersection
int[] mTempLoc = new int[2];
RectF mTempRect = new RectF();
@@ -142,7 +142,9 @@
public BubbleStackView(Context context) {
super(context);
+ mBubbleData = BubbleData.getInstance();
+ mInflater = LayoutInflater.from(context);
mTouchHandler = new BubbleTouchHandler(context);
setOnTouchListener(mTouchHandler);
@@ -154,7 +156,6 @@
mExpandedAnimateYDistance =
res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_y_distance);
- mExpandedBubbleHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mDisplaySize = new Point();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getSize(mDisplaySize);
@@ -174,9 +175,7 @@
mBubbleContainer.setClipChildren(false);
addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
- mExpandedViewContainer = (BubbleExpandedView)
- LayoutInflater.from(context).inflate(R.layout.bubble_expanded_view,
- this /* parent */, false /* attachToRoot */);
+ mExpandedViewContainer = new FrameLayout(context);
mExpandedViewContainer.setElevation(elevation);
mExpandedViewContainer.setPadding(padding, padding, padding, padding);
mExpandedViewContainer.setClipChildren(false);
@@ -218,6 +217,17 @@
}
/**
+ * Updates the visibility of the 'dot' indicating an update on the bubble.
+ * @param key the {@link NotificationEntry#key} associated with the bubble.
+ */
+ public void updateDotVisibility(String key) {
+ Bubble b = mBubbleData.getBubble(key);
+ if (b != null) {
+ b.iconView.updateDotVisibility();
+ }
+ }
+
+ /**
* Sets the listener to notify when the bubble stack is expanded.
*/
public void setExpandListener(BubbleController.BubbleExpandListener listener) {
@@ -228,7 +238,10 @@
* Sets the listener to notify when a bubble is blocked.
*/
public void setOnBlockedListener(BubbleExpandedView.OnBubbleBlockedListener listener) {
- mExpandedViewContainer.setOnBlockedListener(listener);
+ mBlockedListener = listener;
+ for (Bubble b : mBubbleData.getBubbles()) {
+ b.expandedView.setOnBlockedListener(mBlockedListener);
+ }
}
/**
@@ -241,19 +254,29 @@
/**
* The {@link BubbleView} that is expanded, null if one does not exist.
*/
- public BubbleView getExpandedBubble() {
+ BubbleView getExpandedBubbleView() {
+ return mExpandedBubble != null ? mExpandedBubble.iconView : null;
+ }
+
+ /**
+ * The {@link Bubble} that is expanded, null if one does not exist.
+ */
+ Bubble getExpandedBubble() {
return mExpandedBubble;
}
/**
* Sets the bubble that should be expanded and expands if needed.
+ *
+ * @param key the {@link NotificationEntry#key} associated with the bubble to expand.
*/
- public void setExpandedBubble(BubbleView bubbleToExpand) {
+ void setExpandedBubble(String key) {
+ Bubble bubbleToExpand = mBubbleData.getBubble(key);
if (mIsExpanded && !bubbleToExpand.equals(mExpandedBubble)) {
// Previously expanded, notify that this bubble is no longer expanded
- notifyExpansionChanged(mExpandedBubble, false /* expanded */);
+ notifyExpansionChanged(mExpandedBubble.entry, false /* expanded */);
}
- BubbleView prevBubble = mExpandedBubble;
+ Bubble prevBubble = mExpandedBubble;
mExpandedBubble = bubbleToExpand;
if (!mIsExpanded) {
// If we weren't previously expanded we should animate open.
@@ -268,8 +291,8 @@
logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
}
- mExpandedBubble.getEntry().setShowInShadeWhenBubble(false);
- notifyExpansionChanged(mExpandedBubble, true /* expanded */);
+ mExpandedBubble.entry.setShowInShadeWhenBubble(false);
+ notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */);
}
/**
@@ -280,7 +303,7 @@
for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i);
if (entry.equals(bv.getEntry())) {
- setExpandedBubble(bv);
+ setExpandedBubble(entry.key);
}
}
}
@@ -288,48 +311,67 @@
/**
* Adds a bubble to the top of the stack.
*
- * @param bubbleView the view to add to the stack.
+ * @param entry the notification to add to the stack of bubbles.
*/
- public void addBubble(BubbleView bubbleView) {
- mBubbleContainer.addView(bubbleView, 0,
+ public void addBubble(NotificationEntry entry) {
+ Bubble b = new Bubble(entry, mInflater, this /* stackView */, mBlockedListener);
+ mBubbleData.addBubble(b);
+
+ mBubbleContainer.addView(b.iconView, 0,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
- ViewClippingUtil.setClippingDeactivated(bubbleView, true, mClippingParameters);
+ ViewClippingUtil.setClippingDeactivated(b.iconView, true, mClippingParameters);
+
requestUpdate();
- logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
+ logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
}
/**
* Remove a bubble from the stack.
*/
- public void removeBubble(BubbleView bubbleView) {
- int removedIndex = mBubbleContainer.indexOfChild(bubbleView);
- mBubbleContainer.removeView(bubbleView);
+ public void removeBubble(String key) {
+ Bubble b = mBubbleData.removeBubble(key);
+ if (b == null) {
+ return;
+ }
+ b.entry.setBubbleDismissed(true);
+
+ // Remove it from the views
+ int removedIndex = mBubbleContainer.indexOfChild(b.iconView);
+ b.expandedView.destroyActivityView(this /* tmpParent */);
+ mBubbleContainer.removeView(b.iconView);
+
int bubbleCount = mBubbleContainer.getChildCount();
if (bubbleCount == 0) {
// If no bubbles remain, collapse the entire stack.
collapseStack();
return;
- } else if (bubbleView.equals(mExpandedBubble)) {
+ } else if (b.equals(mExpandedBubble)) {
// Was the current bubble just removed?
// If we have other bubbles and are expanded go to the next one or previous
// if the bubble removed was last
int nextIndex = bubbleCount > removedIndex ? removedIndex : bubbleCount - 1;
BubbleView expandedBubble = (BubbleView) mBubbleContainer.getChildAt(nextIndex);
if (mIsExpanded) {
- setExpandedBubble(expandedBubble);
+ setExpandedBubble(expandedBubble.getKey());
} else {
mExpandedBubble = null;
}
}
- logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
+ logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
}
/**
* Dismiss the stack of bubbles.
*/
public void stackDismissed() {
+ for (Bubble bubble : mBubbleData.getBubbles()) {
+ bubble.entry.setBubbleDismissed(true);
+ bubble.expandedView.destroyActivityView(this /* tmpParent */);
+ }
+ mBubbleData.clear();
collapseStack();
mBubbleContainer.removeAllViews();
+ mExpandedViewContainer.removeAllViews();
logBubbleEvent(null /* no bubble associated with bubble stack dismiss */,
StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED);
}
@@ -337,25 +379,26 @@
/**
* Updates a bubble in the stack.
*
- * @param bubbleView the view to update in the stack.
- * @param entry the entry to update it with.
+ * @param entry the entry to update in the stack.
* @param updatePosition whether this bubble should be moved to top of the stack.
*/
- public void updateBubble(BubbleView bubbleView, NotificationEntry entry,
- boolean updatePosition) {
- bubbleView.update(entry);
+ public void updateBubble(NotificationEntry entry, boolean updatePosition) {
+ Bubble b = mBubbleData.getBubble(entry.key);
+ b.iconView.update(entry);
+ // TODO: should also update the expanded view here (e.g. height change)
+
if (updatePosition && !mIsExpanded) {
// If alerting it gets promoted to top of the stack.
- if (mBubbleContainer.indexOfChild(bubbleView) != 0) {
- mBubbleContainer.moveViewTo(bubbleView, 0);
+ if (mBubbleContainer.indexOfChild(b.iconView) != 0) {
+ mBubbleContainer.moveViewTo(b.iconView, 0);
}
requestUpdate();
}
- if (mIsExpanded && bubbleView.equals(mExpandedBubble)) {
+ if (mIsExpanded && entry.equals(mExpandedBubble.entry)) {
entry.setShowInShadeWhenBubble(false);
requestUpdate();
}
- logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
+ logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
}
/**
@@ -393,7 +436,7 @@
if (mIsExpanded) {
// TODO: Save opened bubble & move it to top of stack
animateExpansion(false /* shouldExpand */);
- notifyExpansionChanged(mExpandedBubble, mIsExpanded);
+ notifyExpansionChanged(mExpandedBubble.entry, mIsExpanded);
logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
}
}
@@ -412,8 +455,8 @@
@MainThread
public void expandStack() {
if (!mIsExpanded) {
- mExpandedBubble = getTopBubble();
- setExpandedBubble(mExpandedBubble);
+ String expandedBubbleKey = getBubbleAt(0).getKey();
+ setExpandedBubble(expandedBubbleKey);
logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
}
}
@@ -459,7 +502,8 @@
final float yStart = Math.min(
mStackAnimationController.getStackPosition().y,
mExpandedAnimateYDistance);
- final float yDest = getStatusBarHeight() + mExpandedBubble.getHeight() + mBubblePadding;
+ final float yDest = getStatusBarHeight()
+ + mExpandedBubble.iconView.getHeight() + mBubblePadding;
if (shouldExpand) {
mExpandedViewContainer.setTranslationX(xStart);
@@ -484,17 +528,12 @@
+ mBubbleContainer.getPaddingStart();
}
- private void notifyExpansionChanged(BubbleView bubbleView, boolean expanded) {
+ private void notifyExpansionChanged(NotificationEntry entry, boolean expanded) {
if (mExpandListener != null) {
- NotificationEntry entry = bubbleView != null ? bubbleView.getEntry() : null;
mExpandListener.onBubbleExpandChanged(expanded, entry != null ? entry.key : null);
}
}
- private BubbleView getTopBubble() {
- return getBubbleAt(0);
- }
-
/** Return the BubbleView at the given index from the bubble container. */
public BubbleView getBubbleAt(int i) {
return mBubbleContainer.getChildCount() > i
@@ -665,31 +704,10 @@
}
private void updateExpandedBubble() {
- if (mExpandedBubble == null) {
- return;
- }
-
- mExpandedViewContainer.setEntry(mExpandedBubble.getEntry(), this);
- if (mExpandedBubble.hasAppOverlayIntent()) {
- // Bubble with activity view expanded state
- ActivityView expandedView = mExpandedBubble.getActivityView();
- // XXX: gets added to linear layout
- expandedView.setLayoutParams(new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, mExpandedBubbleHeight));
-
- mExpandedViewContainer.setExpandedView(expandedView);
- } else {
- // Bubble with notification view expanded state
- ExpandableNotificationRow row = mExpandedBubble.getRowView();
- if (row.getParent() != null) {
- // Row might still be in the shade when we expand
- ((ViewGroup) row.getParent()).removeView(row);
- }
- if (mIsExpanded) {
- mExpandedViewContainer.setExpandedView(row);
- } else {
- mExpandedViewContainer.setExpandedView(null);
- }
+ mExpandedViewContainer.removeAllViews();
+ if (mExpandedBubble != null && mIsExpanded) {
+ mExpandedViewContainer.addView(mExpandedBubble.expandedView);
+ mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
}
}
@@ -697,18 +715,10 @@
Log.d(TAG, "applyCurrentState: mIsExpanded=" + mIsExpanded);
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
- if (!mIsExpanded) {
- mExpandedViewContainer.setExpandedView(null);
- } else {
- View expandedView = mExpandedViewContainer.getExpandedView();
- if (expandedView instanceof ActivityView) {
- if (expandedView.isAttachedToWindow()) {
- ((ActivityView) expandedView).onLocationChanged();
- }
- } else {
- applyRowState(mExpandedBubble.getRowView());
- }
+ if (mIsExpanded) {
+ mExpandedBubble.expandedView.updateView();
}
+
int bubbsCount = mBubbleContainer.getChildCount();
for (int i = 0; i < bubbsCount; i++) {
BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i);
@@ -730,46 +740,12 @@
private void updatePointerPosition() {
if (mExpandedBubble != null) {
- float pointerPosition = mExpandedBubble.getPosition().x
- + (mExpandedBubble.getWidth() / 2f);
- mExpandedViewContainer.setPointerPosition((int) pointerPosition);
+ float pointerPosition = mExpandedBubble.iconView.getPosition().x
+ + (mExpandedBubble.iconView.getWidth() / 2f);
+ mExpandedBubble.expandedView.setPointerPosition(pointerPosition);
}
}
- private void applyRowState(ExpandableNotificationRow view) {
- view.reset();
- view.setHeadsUp(false);
- view.resetTranslation();
- view.setOnKeyguard(false);
- view.setOnAmbient(false);
- view.setClipBottomAmount(0);
- view.setClipTopAmount(0);
- view.setContentTransformationAmount(0, false);
- view.setIconsVisible(true);
-
- // TODO - Need to reset this (and others) when view goes back in shade, leave for now
- // view.setTopRoundness(1, false);
- // view.setBottomRoundness(1, false);
-
- ExpandableViewState viewState = view.getViewState();
- viewState = viewState == null ? new ExpandableViewState() : viewState;
- viewState.height = view.getIntrinsicHeight();
- viewState.gone = false;
- viewState.hidden = false;
- viewState.dimmed = false;
- viewState.dark = false;
- viewState.alpha = 1f;
- viewState.notGoneIndex = -1;
- viewState.xTranslation = 0;
- viewState.yTranslation = 0;
- viewState.zTranslation = 0;
- viewState.scaleX = 1;
- viewState.scaleY = 1;
- viewState.inShelf = true;
- viewState.headsUpIsVisible = false;
- viewState.applyToView(view);
- }
-
/**
* @return the number of bubbles in the stack view.
*/
@@ -780,12 +756,12 @@
/**
* Finds the bubble index within the stack.
*
- * @param bubbleView the view of the bubble.
+ * @param bubble the bubble to look up.
* @return the index of the bubble view within the bubble stack. The range of the position
* is between 0 and the bubble count minus 1.
*/
- public int getBubbleIndex(BubbleView bubbleView) {
- return mBubbleContainer.indexOfChild(bubbleView);
+ int getBubbleIndex(Bubble bubble) {
+ return mBubbleContainer.indexOfChild(bubble.iconView);
}
/**
@@ -813,7 +789,7 @@
* the user interaction is not specific to one bubble.
* @param action the user interaction enum.
*/
- private void logBubbleEvent(@Nullable BubbleView bubble, int action) {
+ private void logBubbleEvent(@Nullable Bubble bubble, int action) {
if (bubble == null) {
StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
null /* package name */,
@@ -825,7 +801,7 @@
getNormalizedXPosition(),
getNormalizedYPosition());
} else {
- StatusBarNotification notification = bubble.getEntry().notification;
+ StatusBarNotification notification = bubble.entry.notification;
StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
notification.getPackageName(),
notification.getNotification().getChannelId(),
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 22cd2fc..7d3c0f8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -188,7 +188,7 @@
} else {
stack.onBubbleDragFinish(mBubbleDraggingOut, x, y, velX, velY);
}
- } else if (floatingView.equals(stack.getExpandedBubble())) {
+ } else if (floatingView.equals(stack.getExpandedBubbleView())) {
stack.collapseStack();
} else if (isBubbleStack) {
if (stack.isExpanded()) {
@@ -197,7 +197,7 @@
stack.expandStack();
}
} else {
- stack.setExpandedBubble((BubbleView) floatingView);
+ stack.setExpandedBubble(((BubbleView) floatingView).getKey());
}
cleanUpDismissTarget();
mVelocityTracker.recycle();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index 74ddc8f..1a4b1994 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -17,13 +17,9 @@
package com.android.systemui.bubbles;
import android.annotation.Nullable;
-import android.app.ActivityView;
import android.app.Notification;
-import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Color;
-import android.graphics.Insets;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -31,16 +27,10 @@
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.graphics.ColorUtils;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -62,11 +52,6 @@
private int mIconInset;
private NotificationEntry mEntry;
- private PendingIntent mAppOverlayIntent;
- private BubbleController mBubbleController;
- private ActivityView mActivityView;
- private boolean mActivityViewReady;
- private boolean mActivityViewStarted;
public BubbleView(Context context) {
this(context, null);
@@ -86,7 +71,6 @@
// XXX: can this padding just be on the view and we look it up?
mPadding = getResources().getDimensionPixelSize(R.dimen.bubble_view_padding);
mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset);
- mBubbleController = Dependency.get(BubbleController.class);
}
@Override
@@ -168,7 +152,6 @@
updateViews();
}
-
/**
* @return the {@link ExpandableNotificationRow} view to display notification content when the
* bubble is expanded.
@@ -235,88 +218,6 @@
return ColorUtils.blendARGB(defaultTint, Color.WHITE, WHITE_SCRIM_ALPHA);
}
- /**
- * @return a view used to display app overlay content when expanded.
- */
- public ActivityView getActivityView() {
- if (mActivityView == null) {
- mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
- true /* singleTaskInstance */);
- Log.d(TAG, "[getActivityView] created: " + mActivityView);
- mActivityView.setCallback(new ActivityView.StateCallback() {
- @Override
- public void onActivityViewReady(ActivityView view) {
- mActivityViewReady = true;
- mActivityView.startActivity(mAppOverlayIntent);
- }
-
- @Override
- public void onActivityViewDestroyed(ActivityView view) {
- mActivityViewReady = false;
- }
-
- /**
- * This is only called for tasks on this ActivityView, which is also set to
- * single-task mode -- meaning never more than one task on this display. If a task
- * is being removed, it's the top Activity finishing and this bubble should
- * be removed or collapsed.
- */
- @Override
- public void onTaskRemovalStarted(int taskId) {
- if (mEntry != null) {
- // Must post because this is called from a binder thread.
- post(() -> mBubbleController.removeBubble(mEntry.key));
- }
- }
- });
- mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
- ActivityView activityView = (ActivityView) view;
- // Here we assume that the position of the ActivityView on the screen
- // remains regardless of IME status. When we move ActivityView, the
- // forwardedInsets should be computed not against the current location
- // and size, but against the post-moved location and size.
- Point displaySize = new Point();
- view.getContext().getDisplay().getSize(displaySize);
- int[] windowLocation = view.getLocationOnScreen();
- final int windowBottom = windowLocation[1] + view.getHeight();
- final int keyboardHeight = insets.getSystemWindowInsetBottom()
- - insets.getStableInsetBottom();
- final int insetsBottom = Math.max(0,
- windowBottom + keyboardHeight - displaySize.y);
- activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
- return view.onApplyWindowInsets(insets);
- });
-
- }
- return mActivityView;
- }
-
- /**
- * Removes and releases an ActivityView if one was previously created for this bubble.
- */
- public void destroyActivityView(ViewGroup tmpParent) {
- if (mActivityView == null) {
- return;
- }
- if (!mActivityViewReady) {
- // release not needed, never initialized?
- mActivityView = null;
- return;
- }
- // HACK: release() will crash if the view is not attached.
- if (!mActivityView.isAttachedToWindow()) {
- mActivityView.setVisibility(View.GONE);
- tmpParent.addView(mActivityView, new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- }
-
- mActivityView.release();
-
- ((ViewGroup) mActivityView.getParent()).removeView(mActivityView);
- mActivityView = null;
- }
-
@Override
public void setPosition(float x, float y) {
setPositionX(x);
@@ -337,20 +238,4 @@
public PointF getPosition() {
return new PointF(getTranslationX(), getTranslationY());
}
-
- /**
- * @return whether an ActivityView should be used to display the content of this Bubble
- */
- public boolean hasAppOverlayIntent() {
- return mAppOverlayIntent != null;
- }
-
- public PendingIntent getAppOverlayIntent() {
- return mAppOverlayIntent;
-
- }
-
- public void setBubbleIntent(PendingIntent intent) {
- mAppOverlayIntent = intent;
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 2742577..d9315f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -112,6 +112,9 @@
verify(mNotificationEntryManager, atLeastOnce())
.addNotificationEntryListener(mEntryListenerCaptor.capture());
mEntryListener = mEntryListenerCaptor.getValue();
+
+ // Reset the data
+ BubbleData.getInstance().clear();
}
@Test
@@ -207,12 +210,12 @@
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
assertFalse(mRow2.getEntry().showInShadeWhenBubble());
// Switch which bubble is expanded
stackView.setExpandedBubble(mRow.getEntry());
- assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
assertFalse(mRow.getEntry().showInShadeWhenBubble());
// collapse for previous bubble
@@ -262,19 +265,19 @@
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
assertFalse(mRow2.getEntry().showInShadeWhenBubble());
// Dismiss currently expanded
- mBubbleController.removeBubble(stackView.getExpandedBubble().getKey());
+ mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey());
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key);
// Make sure next bubble is selected
- assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
// Dismiss that one
- mBubbleController.removeBubble(stackView.getExpandedBubble().getKey());
+ mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey());
// Make sure state changes and collapse happens
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);