Merge "Show Bubble OOBE on the first conversation bubble only" into udc-dev

This commit is contained in:
Ivan Tkachenko
2023-03-29 13:02:04 +00:00
committed by Android (Google) Code Review
4 changed files with 145 additions and 19 deletions

View File

@@ -655,6 +655,13 @@ public class Bubble implements BubbleViewProvider {
return mIsImportantConversation;
}
/**
* Whether this bubble is conversation
*/
public boolean isConversation() {
return null != mShortcutInfo;
}
/**
* Sets whether this notification should be suppressed in the shade.
*/

View File

@@ -33,7 +33,6 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -575,7 +574,7 @@ public class BubbleStackView extends FrameLayout
if (maybeShowStackEdu()) {
mShowedUserEducationInTouchListenerActive = true;
return true;
} else if (isStackEduShowing()) {
} else if (isStackEduVisible()) {
mStackEduView.hide(false /* fromExpansion */);
}
@@ -651,7 +650,7 @@ public class BubbleStackView extends FrameLayout
mExpandedAnimationController.dragBubbleOut(
v, viewInitialX + dx, viewInitialY + dy);
} else {
if (isStackEduShowing()) {
if (isStackEduVisible()) {
mStackEduView.hide(false /* fromExpansion */);
}
mStackAnimationController.moveStackFromTouch(
@@ -733,8 +732,7 @@ public class BubbleStackView extends FrameLayout
@Override
public void onMove(float dx, float dy) {
if ((mManageEduView != null && mManageEduView.getVisibility() == VISIBLE)
|| isStackEduShowing()) {
if (isManageEduVisible() || isStackEduVisible()) {
return;
}
@@ -996,7 +994,7 @@ public class BubbleStackView extends FrameLayout
mStackAnimationController.updateResources();
mBubbleOverflow.updateResources();
if (!isStackEduShowing() && mRelativeStackPositionBeforeRotation != null) {
if (!isStackEduVisible() && mRelativeStackPositionBeforeRotation != null) {
mStackAnimationController.setStackPosition(
mRelativeStackPositionBeforeRotation);
mRelativeStackPositionBeforeRotation = null;
@@ -1046,9 +1044,9 @@ public class BubbleStackView extends FrameLayout
setOnClickListener(view -> {
if (mShowingManage) {
showManageMenu(false /* show */);
} else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
} else if (isManageEduVisible()) {
mManageEduView.hide();
} else if (isStackEduShowing()) {
} else if (isStackEduVisible()) {
mStackEduView.hide(false /* isExpanding */);
} else if (mBubbleData.isExpanded()) {
mBubbleData.setExpanded(false);
@@ -1246,11 +1244,20 @@ public class BubbleStackView extends FrameLayout
updateManageButtonListener();
}
/**
* Whether the selected bubble is conversation bubble
*/
private boolean isConversationBubble() {
BubbleViewProvider bubble = mBubbleData.getSelectedBubble();
return bubble instanceof Bubble && ((Bubble) bubble).isConversation();
}
/**
* Whether the educational view should show for the expanded view "manage" menu.
*/
private boolean shouldShowManageEdu() {
if (ActivityManager.isRunningInTestHarness()) {
if (!isConversationBubble()) {
// We only show user education for conversation bubbles right now
return false;
}
final boolean seen = getPrefBoolean(ManageEducationViewKt.PREF_MANAGED_EDUCATION);
@@ -1273,11 +1280,17 @@ public class BubbleStackView extends FrameLayout
mManageEduView.show(mExpandedBubble.getExpandedView());
}
@VisibleForTesting
public boolean isManageEduVisible() {
return mManageEduView != null && mManageEduView.getVisibility() == VISIBLE;
}
/**
* Whether education view should show for the collapsed stack.
*/
private boolean shouldShowStackEdu() {
if (ActivityManager.isRunningInTestHarness()) {
if (!isConversationBubble()) {
// We only show user education for conversation bubbles right now
return false;
}
final boolean seen = getPrefBoolean(StackEducationViewKt.PREF_STACK_EDUCATION);
@@ -1310,13 +1323,14 @@ public class BubbleStackView extends FrameLayout
return mStackEduView.show(mPositioner.getDefaultStartPosition());
}
private boolean isStackEduShowing() {
@VisibleForTesting
public boolean isStackEduVisible() {
return mStackEduView != null && mStackEduView.getVisibility() == VISIBLE;
}
// Recreates & shows the education views. Call when a theme/config change happens.
private void updateUserEdu() {
if (isStackEduShowing()) {
if (isStackEduVisible()) {
removeView(mStackEduView);
mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController);
addView(mStackEduView);
@@ -1325,7 +1339,7 @@ public class BubbleStackView extends FrameLayout
mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition());
mStackEduView.show(mPositioner.getDefaultStartPosition());
}
if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
if (isManageEduVisible()) {
removeView(mManageEduView);
mManageEduView = new ManageEducationView(mContext, mPositioner);
addView(mManageEduView);
@@ -1429,7 +1443,7 @@ public class BubbleStackView extends FrameLayout
mStackAnimationController.updateResources();
mDismissView.updateResources();
mMagneticTarget.setMagneticFieldRadiusPx(mBubbleSize * 2);
if (!isStackEduShowing()) {
if (!isStackEduVisible()) {
mStackAnimationController.setStackPosition(
new RelativeStackPosition(
mPositioner.getRestingPosition(),
@@ -2013,7 +2027,7 @@ public class BubbleStackView extends FrameLayout
if (mIsExpanded) {
if (mShowingManage) {
showManageMenu(false);
} else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
} else if (isManageEduVisible()) {
mManageEduView.hide();
} else {
mBubbleData.setExpanded(false);
@@ -2158,7 +2172,7 @@ public class BubbleStackView extends FrameLayout
cancelDelayedExpandCollapseSwitchAnimations();
final boolean showVertically = mPositioner.showBubblesVertically();
mIsExpanded = true;
if (isStackEduShowing()) {
if (isStackEduVisible()) {
mStackEduView.hide(true /* fromExpansion */);
}
beforeExpandedViewAnimation();
@@ -2280,7 +2294,7 @@ public class BubbleStackView extends FrameLayout
private void animateCollapse() {
cancelDelayedExpandCollapseSwitchAnimations();
if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
if (isManageEduVisible()) {
mManageEduView.hide();
}
@@ -2677,7 +2691,7 @@ public class BubbleStackView extends FrameLayout
if (flyoutMessage == null
|| flyoutMessage.message == null
|| !bubble.showFlyout()
|| isStackEduShowing()
|| isStackEduVisible()
|| isExpanded()
|| mIsExpansionAnimating
|| mIsGestureInProgress
@@ -2800,7 +2814,7 @@ public class BubbleStackView extends FrameLayout
* them.
*/
public void getTouchableRegion(Rect outRect) {
if (isStackEduShowing()) {
if (isStackEduVisible()) {
// When user education shows then capture all touches
outRect.set(0, 0, getWidth(), getHeight());
return;

View File

@@ -29,6 +29,8 @@ import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
@@ -162,4 +164,27 @@ public class BubbleTest extends ShellTestCase {
verify(mBubbleMetadataFlagListener, never()).onBubbleMetadataFlagChanged(any());
}
@Test
public void testBubbleIsConversation_hasConversationShortcut() {
Bubble bubble = createBubbleWithShortcut();
assertThat(bubble.getShortcutInfo()).isNotNull();
assertThat(bubble.isConversation()).isTrue();
}
@Test
public void testBubbleIsConversation_hasNoShortcut() {
Bubble bubble = new Bubble(mBubbleEntry, mBubbleMetadataFlagListener, null, mMainExecutor);
assertThat(bubble.getShortcutInfo()).isNull();
assertThat(bubble.isConversation()).isFalse();
}
private Bubble createBubbleWithShortcut() {
ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext)
.setId("mockShortcutId")
.build();
return new Bubble("mockKey", shortcutInfo, 10, Resources.ID_NULL,
"mockTitle", 0 /* taskId */, "mockLocus", true /* isDismissible */,
mMainExecutor, mBubbleMetadataFlagListener);
}
}

View File

@@ -57,6 +57,7 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.pm.UserInfo;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -100,6 +101,7 @@ import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.ShadeWindowLogger;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.NotificationEntryHelper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -135,6 +137,7 @@ import com.android.wm.shell.bubbles.BubbleLogger;
import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.bubbles.BubbleViewInfoTask;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.bubbles.StackEducationViewKt;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
@@ -1668,6 +1671,60 @@ public class BubblesTest extends SysuiTestCase {
any(Bubble.class), anyBoolean(), anyBoolean());
}
@Test
public void testShowStackEdu_isNotConversationBubble() {
// Setup
setPrefBoolean(StackEducationViewKt.PREF_STACK_EDUCATION, false);
BubbleEntry bubbleEntry = createBubbleEntry(false /* isConversation */);
mBubbleController.updateBubble(bubbleEntry);
assertTrue(mBubbleController.hasBubbles());
// Click on bubble
Bubble bubble = mBubbleData.getBubbleInStackWithKey(bubbleEntry.getKey());
assertFalse(bubble.isConversation());
bubble.getIconView().callOnClick();
// Check education is not shown
BubbleStackView stackView = mBubbleController.getStackView();
assertFalse(stackView.isStackEduVisible());
}
@Test
public void testShowStackEdu_isConversationBubble() {
// Setup
setPrefBoolean(StackEducationViewKt.PREF_STACK_EDUCATION, false);
BubbleEntry bubbleEntry = createBubbleEntry(true /* isConversation */);
mBubbleController.updateBubble(bubbleEntry);
assertTrue(mBubbleController.hasBubbles());
// Click on bubble
Bubble bubble = mBubbleData.getBubbleInStackWithKey(bubbleEntry.getKey());
assertTrue(bubble.isConversation());
bubble.getIconView().callOnClick();
// Check education is shown
BubbleStackView stackView = mBubbleController.getStackView();
assertTrue(stackView.isStackEduVisible());
}
@Test
public void testShowStackEdu_isSeenConversationBubble() {
// Setup
setPrefBoolean(StackEducationViewKt.PREF_STACK_EDUCATION, true);
BubbleEntry bubbleEntry = createBubbleEntry(true /* isConversation */);
mBubbleController.updateBubble(bubbleEntry);
assertTrue(mBubbleController.hasBubbles());
// Click on bubble
Bubble bubble = mBubbleData.getBubbleInStackWithKey(bubbleEntry.getKey());
assertTrue(bubble.isConversation());
bubble.getIconView().callOnClick();
// Check education is not shown
BubbleStackView stackView = mBubbleController.getStackView();
assertFalse(stackView.isStackEduVisible());
}
@Test
public void testShowOrHideAppBubble_addsAndExpand() {
assertThat(mBubbleController.isStackExpanded()).isFalse();
@@ -1816,6 +1873,20 @@ public class BubblesTest extends SysuiTestCase {
mock(Bubbles.PendingIntentCanceledListener.class), new SyncExecutor());
}
private BubbleEntry createBubbleEntry(boolean isConversation) {
NotificationEntry notificationEntry = mNotificationTestHelper.createBubble(mDeleteIntent);
if (isConversation) {
ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext)
.setId("shortcutId")
.build();
NotificationEntryHelper.modifyRanking(notificationEntry)
.setIsConversation(true)
.setShortcutInfo(shortcutInfo)
.build();
}
return mBubblesManager.notifToBubbleEntry(notificationEntry);
}
/** Creates a context that will return a PackageManager with specific AppInfo. */
private Context setUpContextWithPackageManager(String pkg, ApplicationInfo info)
throws Exception {
@@ -1852,6 +1923,15 @@ public class BubblesTest extends SysuiTestCase {
bubbleMetadata.setFlags(flags);
}
/**
* Set preferences boolean value for key
* Used to setup global state for stack view education tests
*/
private void setPrefBoolean(String key, boolean enabled) {
mContext.getSharedPreferences(mContext.getPackageName(), Context.MODE_PRIVATE)
.edit().putBoolean(key, enabled).apply();
}
private Notification.BubbleMetadata getMetadata() {
Intent target = new Intent(mContext, BubblesTestActivity.class);
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, FLAG_MUTABLE);