diff options
| author | 2019-02-05 18:12:53 -0800 | |
|---|---|---|
| committer | 2019-02-12 11:33:49 -0800 | |
| commit | 3dff9e6d65c36e9ee55e01eb8c22693d521ddd19 (patch) | |
| tree | 10cb48365099a062466c29acbce838e83dce4eb3 | |
| parent | ade169ae157dfdd0ad29a9e2355f849154367cfa (diff) | |
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
8 files changed, 492 insertions, 387 deletions
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 000000000000..4778434e2052 --- /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 41bc1b29075c..a67e1b7032c6 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.ActivityTaskManager; 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.collection.NotificationEntry; 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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe 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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe @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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe mActivityTaskManager = ActivityTaskManager.getService(); mTaskStackListener = new BubbleTaskStackListener(); ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); + + mBubbleData = BubbleData.getInstance(); } /** @@ -219,8 +201,11 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe * 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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe 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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe * @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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe 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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe */ @MainThread void removeBubble(String key) { - BubbleView bv = mBubbles.remove(key); - if (mStackView != null && bv != null) { - mStackView.removeBubble(bv); - bv.destroyActivityView(mStackView); - } - - NotificationEntry entry = bv != null ? bv.getEntry() : null; - if (entry != null) { - entry.setBubbleDismissed(true); - mNotificationEntryManager.updateNotifications(); + if (mStackView != null) { + mStackView.removeBubble(key); } + 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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe && 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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe 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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe 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 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe 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 000000000000..89b0de85e18d --- /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 976a766dcc09..3389c46f66b7 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.AttributeSet; 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 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList // 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 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList 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 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList 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 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList 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 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList } updateHeaderView(); updatePermissionView(); + updateExpandedView(); + mActivityView.setCallback(mStateCallback); } private void updateHeaderView() { @@ -225,6 +299,34 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList } } + 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 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList } /** + * 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 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList 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 2b344f6cf195..8bc83d4c852b 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 @@ package com.android.systemui.bubbles; 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.util.StatsLog; 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.ExpandedAnimationController; 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F public BubbleStackView(Context context) { super(context); + mBubbleData = BubbleData.getInstance(); + mInflater = LayoutInflater.from(context); mTouchHandler = new BubbleTouchHandler(context); setOnTouchListener(mTouchHandler); @@ -154,7 +156,6 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F } /** + * 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F * 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F /** * 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F /** * 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F /** * 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F @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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F + 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F } 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F /** * 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F * 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 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F 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 22cd2fcc3e72..7d3c0f85c0f7 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 @@ class BubbleTouchHandler implements View.OnTouchListener { } 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 @@ class BubbleTouchHandler implements View.OnTouchListener { 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 74ddc8f6b8fc..1a4b19940e34 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.Icon; 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 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati 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 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati // 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 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati updateViews(); } - /** * @return the {@link ExpandableNotificationRow} view to display notification content when the * bubble is expanded. @@ -235,88 +218,6 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati 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 class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati 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 2742577db860..d9315f937867 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 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mNotificationEntryManager, atLeastOnce()) .addNotificationEntryListener(mEntryListenerCaptor.capture()); mEntryListener = mEntryListenerCaptor.getValue(); + + // Reset the data + BubbleData.getInstance().clear(); } @Test @@ -207,12 +210,12 @@ public class BubbleControllerTest extends SysuiTestCase { 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 @@ public class BubbleControllerTest extends SysuiTestCase { 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); |