Merge "Group chat flyout support"
This commit is contained in:
committed by
Android (Google) Code Review
commit
38de36f46e
@@ -15,25 +15,50 @@
|
||||
-->
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:id="@+id/bubble_flyout_text_container"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:clipToPadding="false"
|
||||
android:paddingLeft="@dimen/bubble_flyout_padding_x"
|
||||
android:paddingRight="@dimen/bubble_flyout_padding_x"
|
||||
android:clipChildren="false"
|
||||
android:paddingStart="@dimen/bubble_flyout_padding_x"
|
||||
android:paddingEnd="@dimen/bubble_flyout_padding_x"
|
||||
android:paddingTop="@dimen/bubble_flyout_padding_y"
|
||||
android:paddingBottom="@dimen/bubble_flyout_padding_y"
|
||||
android:translationZ="@dimen/bubble_flyout_elevation">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bubble_flyout_text"
|
||||
<ImageView
|
||||
android:id="@+id/bubble_flyout_avatar"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginEnd="@dimen/bubble_flyout_avatar_message_space"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_create_bubble"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@*android:string/config_bodyFontFamily"
|
||||
android:maxLines="2"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
|
||||
android:orientation="vertical">
|
||||
|
||||
</FrameLayout>
|
||||
<TextView
|
||||
android:id="@+id/bubble_flyout_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bubble_flyout_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@*android:string/config_bodyFontFamily"
|
||||
android:maxLines="2"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
||||
@@ -1097,13 +1097,15 @@
|
||||
<!-- How much the bubble flyout text container is elevated. -->
|
||||
<dimen name="bubble_flyout_elevation">4dp</dimen>
|
||||
<!-- How much padding is around the left and right sides of the flyout text. -->
|
||||
<dimen name="bubble_flyout_padding_x">16dp</dimen>
|
||||
<dimen name="bubble_flyout_padding_x">12dp</dimen>
|
||||
<!-- How much padding is around the top and bottom of the flyout text. -->
|
||||
<dimen name="bubble_flyout_padding_y">8dp</dimen>
|
||||
<dimen name="bubble_flyout_padding_y">10dp</dimen>
|
||||
<!-- Size of the triangle that points from the flyout to the bubble stack. -->
|
||||
<dimen name="bubble_flyout_pointer_size">6dp</dimen>
|
||||
<!-- How much space to leave between the flyout (tip of the arrow) and the bubble stack. -->
|
||||
<dimen name="bubble_flyout_space_from_bubble">8dp</dimen>
|
||||
<!-- How much space to leave between the flyout text and the avatar displayed in the flyout. -->
|
||||
<dimen name="bubble_flyout_avatar_message_space">6dp</dimen>
|
||||
<!-- Padding between status bar and bubbles when displayed in expanded state -->
|
||||
<dimen name="bubble_padding_top">16dp</dimen>
|
||||
<!-- Size of individual bubbles. -->
|
||||
|
||||
@@ -32,20 +32,17 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -85,6 +82,18 @@ class Bubble {
|
||||
/** Whether flyout text should be suppressed, regardless of any other flags or state. */
|
||||
private boolean mSuppressFlyout;
|
||||
|
||||
/**
|
||||
* Presentational info about the flyout.
|
||||
*/
|
||||
public static class FlyoutMessage {
|
||||
@Nullable public Drawable senderAvatar;
|
||||
@Nullable public CharSequence senderName;
|
||||
@Nullable public CharSequence message;
|
||||
@Nullable public boolean isGroupChat;
|
||||
}
|
||||
|
||||
private FlyoutMessage mFlyoutMessage;
|
||||
|
||||
public static String groupId(NotificationEntry entry) {
|
||||
UserHandle user = entry.getSbn().getUser();
|
||||
return user.getIdentifier() + "|" + entry.getSbn().getPackageName();
|
||||
@@ -194,6 +203,7 @@ class Bubble {
|
||||
|
||||
mShortcutInfo = info.shortcutInfo;
|
||||
mAppName = info.appName;
|
||||
mFlyoutMessage = info.flyoutMessage;
|
||||
|
||||
mExpandedView.update(this);
|
||||
mIconView.update(this, info.badgedBubbleImage, info.dotColor, info.dotPath);
|
||||
@@ -307,6 +317,10 @@ class Bubble {
|
||||
mSuppressFlyout = suppressFlyout;
|
||||
}
|
||||
|
||||
FlyoutMessage getFlyoutMessage() {
|
||||
return mFlyoutMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the notification for this bubble is a foreground service. It shows that this
|
||||
* is an ongoing bubble.
|
||||
@@ -368,72 +382,6 @@ class Bubble {
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns our best guess for the most relevant text summary of the latest update to this
|
||||
* notification, based on its type. Returns null if there should not be an update message.
|
||||
*/
|
||||
CharSequence getUpdateMessage(Context context) {
|
||||
final Notification underlyingNotif = mEntry.getSbn().getNotification();
|
||||
final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle();
|
||||
|
||||
try {
|
||||
if (Notification.BigTextStyle.class.equals(style)) {
|
||||
// Return the big text, it is big so probably important. If it's not there use the
|
||||
// normal text.
|
||||
CharSequence bigText =
|
||||
underlyingNotif.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
|
||||
return !TextUtils.isEmpty(bigText)
|
||||
? bigText
|
||||
: underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
|
||||
} else if (Notification.MessagingStyle.class.equals(style)) {
|
||||
final List<Notification.MessagingStyle.Message> messages =
|
||||
Notification.MessagingStyle.Message.getMessagesFromBundleArray(
|
||||
(Parcelable[]) underlyingNotif.extras.get(
|
||||
Notification.EXTRA_MESSAGES));
|
||||
|
||||
final Notification.MessagingStyle.Message latestMessage =
|
||||
Notification.MessagingStyle.findLatestIncomingMessage(messages);
|
||||
|
||||
if (latestMessage != null) {
|
||||
final CharSequence personName = latestMessage.getSenderPerson() != null
|
||||
? latestMessage.getSenderPerson().getName()
|
||||
: null;
|
||||
|
||||
// Prepend the sender name if available since group chats also use messaging
|
||||
// style.
|
||||
if (!TextUtils.isEmpty(personName)) {
|
||||
return context.getResources().getString(
|
||||
R.string.notification_summary_message_format,
|
||||
personName,
|
||||
latestMessage.getText());
|
||||
} else {
|
||||
return latestMessage.getText();
|
||||
}
|
||||
}
|
||||
} else if (Notification.InboxStyle.class.equals(style)) {
|
||||
CharSequence[] lines =
|
||||
underlyingNotif.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
|
||||
|
||||
// Return the last line since it should be the most recent.
|
||||
if (lines != null && lines.length > 0) {
|
||||
return lines[lines.length - 1];
|
||||
}
|
||||
} else if (Notification.MediaStyle.class.equals(style)) {
|
||||
// Return nothing, media updates aren't typically useful as a text update.
|
||||
return null;
|
||||
} else {
|
||||
// Default to text extra.
|
||||
return underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
|
||||
}
|
||||
} catch (ClassCastException | NullPointerException | ArrayIndexOutOfBoundsException e) {
|
||||
// No use crashing, we'll just return null and the caller will assume there's no update
|
||||
// message.
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getDimenForPackageUser(Context context, int resId, String pkg, int userId) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
Resources r;
|
||||
|
||||
@@ -32,11 +32,13 @@ import android.graphics.Path;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.ShapeDrawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -65,7 +67,9 @@ public class BubbleFlyoutView extends FrameLayout {
|
||||
private final float mCornerRadius;
|
||||
|
||||
private final ViewGroup mFlyoutTextContainer;
|
||||
private final TextView mFlyoutText;
|
||||
private final ImageView mSenderAvatar;
|
||||
private final TextView mSenderText;
|
||||
private final TextView mMessageText;
|
||||
|
||||
/** Values related to the 'new' dot which we use to figure out where to collapse the flyout. */
|
||||
private final float mNewDotRadius;
|
||||
@@ -142,7 +146,9 @@ public class BubbleFlyoutView extends FrameLayout {
|
||||
LayoutInflater.from(context).inflate(R.layout.bubble_flyout, this, true);
|
||||
|
||||
mFlyoutTextContainer = findViewById(R.id.bubble_flyout_text_container);
|
||||
mFlyoutText = mFlyoutTextContainer.findViewById(R.id.bubble_flyout_text);
|
||||
mSenderText = findViewById(R.id.bubble_flyout_name);
|
||||
mSenderAvatar = findViewById(R.id.bubble_flyout_avatar);
|
||||
mMessageText = mFlyoutTextContainer.findViewById(R.id.bubble_flyout_text);
|
||||
|
||||
final Resources res = getResources();
|
||||
mFlyoutPadding = res.getDimensionPixelSize(R.dimen.bubble_flyout_padding_x);
|
||||
@@ -204,9 +210,34 @@ public class BubbleFlyoutView extends FrameLayout {
|
||||
|
||||
/** Configures the flyout, collapsed into to dot form. */
|
||||
void setupFlyoutStartingAsDot(
|
||||
CharSequence updateMessage, PointF stackPos, float parentWidth,
|
||||
boolean arrowPointingLeft, int dotColor, @Nullable Runnable onLayoutComplete,
|
||||
@Nullable Runnable onHide, float[] dotCenter, boolean hideDot) {
|
||||
Bubble.FlyoutMessage flyoutMessage,
|
||||
PointF stackPos,
|
||||
float parentWidth,
|
||||
boolean arrowPointingLeft,
|
||||
int dotColor,
|
||||
@Nullable Runnable onLayoutComplete,
|
||||
@Nullable Runnable onHide,
|
||||
float[] dotCenter,
|
||||
boolean hideDot) {
|
||||
|
||||
if (flyoutMessage.senderAvatar != null && flyoutMessage.isGroupChat) {
|
||||
mSenderAvatar.setVisibility(VISIBLE);
|
||||
mSenderAvatar.setImageDrawable(flyoutMessage.senderAvatar);
|
||||
} else {
|
||||
mSenderAvatar.setVisibility(GONE);
|
||||
mSenderAvatar.setTranslationX(0);
|
||||
mMessageText.setTranslationX(0);
|
||||
mSenderText.setTranslationX(0);
|
||||
}
|
||||
|
||||
// Name visibility
|
||||
if (!TextUtils.isEmpty(flyoutMessage.senderName)) {
|
||||
mSenderText.setText(flyoutMessage.senderName);
|
||||
mSenderText.setVisibility(VISIBLE);
|
||||
} else {
|
||||
mSenderText.setVisibility(GONE);
|
||||
}
|
||||
|
||||
mArrowPointingLeft = arrowPointingLeft;
|
||||
mDotColor = dotColor;
|
||||
mOnHide = onHide;
|
||||
@@ -217,15 +248,15 @@ public class BubbleFlyoutView extends FrameLayout {
|
||||
// Set the flyout TextView's max width in terms of percent, and then subtract out the
|
||||
// padding so that the entire flyout view will be the desired width (rather than the
|
||||
// TextView being the desired width + extra padding).
|
||||
mFlyoutText.setMaxWidth(
|
||||
mMessageText.setMaxWidth(
|
||||
(int) (parentWidth * FLYOUT_MAX_WIDTH_PERCENT) - mFlyoutPadding * 2);
|
||||
mFlyoutText.setText(updateMessage);
|
||||
mMessageText.setText(flyoutMessage.message);
|
||||
|
||||
// Wait for the TextView to lay out so we know its line count.
|
||||
post(() -> {
|
||||
float restingTranslationY;
|
||||
// Multi line flyouts get top-aligned to the bubble.
|
||||
if (mFlyoutText.getLineCount() > 1) {
|
||||
if (mMessageText.getLineCount() > 1) {
|
||||
restingTranslationY = stackPos.y + mBubbleIconTopPadding;
|
||||
} else {
|
||||
// Single line flyouts are vertically centered with respect to the bubble.
|
||||
@@ -289,11 +320,20 @@ public class BubbleFlyoutView extends FrameLayout {
|
||||
mPercentStillFlyout = (1f - mPercentTransitionedToDot);
|
||||
|
||||
// Move and fade out the text.
|
||||
mFlyoutText.setTranslationX(
|
||||
(mArrowPointingLeft ? -getWidth() : getWidth()) * mPercentTransitionedToDot);
|
||||
mFlyoutText.setAlpha(clampPercentage(
|
||||
final float translationX = mPercentTransitionedToDot
|
||||
* (mArrowPointingLeft ? -getWidth() : getWidth());
|
||||
final float alpha = clampPercentage(
|
||||
(mPercentStillFlyout - (1f - BubbleStackView.FLYOUT_DRAG_PERCENT_DISMISS))
|
||||
/ BubbleStackView.FLYOUT_DRAG_PERCENT_DISMISS));
|
||||
/ BubbleStackView.FLYOUT_DRAG_PERCENT_DISMISS);
|
||||
|
||||
mMessageText.setTranslationX(translationX);
|
||||
mMessageText.setAlpha(alpha);
|
||||
|
||||
mSenderText.setTranslationX(translationX);
|
||||
mSenderText.setAlpha(alpha);
|
||||
|
||||
mSenderAvatar.setTranslationX(translationX);
|
||||
mSenderAvatar.setAlpha(alpha);
|
||||
|
||||
// Reduce the elevation towards that of the topmost bubble.
|
||||
setTranslationZ(
|
||||
|
||||
@@ -1377,9 +1377,10 @@ public class BubbleStackView extends FrameLayout {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void animateInFlyoutForBubble(Bubble bubble) {
|
||||
final CharSequence updateMessage = bubble.getUpdateMessage(getContext());
|
||||
Bubble.FlyoutMessage flyoutMessage = bubble.getFlyoutMessage();
|
||||
final BadgedImageView bubbleView = bubble.getIconView();
|
||||
if (updateMessage == null
|
||||
if (flyoutMessage == null
|
||||
|| flyoutMessage.message == null
|
||||
|| !bubble.showFlyout()
|
||||
|| isExpanded()
|
||||
|| mIsExpansionAnimating
|
||||
@@ -1432,8 +1433,8 @@ public class BubbleStackView extends FrameLayout {
|
||||
};
|
||||
mFlyout.postDelayed(mAnimateInFlyout, 200);
|
||||
};
|
||||
mFlyout.setupFlyoutStartingAsDot(
|
||||
updateMessage, mStackAnimationController.getStackPosition(), getWidth(),
|
||||
mFlyout.setupFlyoutStartingAsDot(flyoutMessage,
|
||||
mStackAnimationController.getStackPosition(), getWidth(),
|
||||
mStackAnimationController.isStackOnLeftSide(),
|
||||
bubble.getIconView().getDotColor() /* dotColor */,
|
||||
expandFlyoutAfterDelay /* onLayoutComplete */,
|
||||
|
||||
@@ -21,6 +21,9 @@ import static com.android.systemui.bubbles.BadgedImageView.WHITE_SCRIM_ALPHA;
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
|
||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Notification;
|
||||
import android.app.Person;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -31,7 +34,9 @@ import android.graphics.Matrix;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Parcelable;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.PathParser;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -41,8 +46,10 @@ import androidx.annotation.Nullable;
|
||||
import com.android.internal.graphics.ColorUtils;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Simple task to inflate views & load necessary info to display a bubble.
|
||||
@@ -98,6 +105,9 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Info necessary to render a bubble.
|
||||
*/
|
||||
static class BubbleViewInfo {
|
||||
BadgedImageView imageView;
|
||||
BubbleExpandedView expandedView;
|
||||
@@ -106,6 +116,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
Bitmap badgedBubbleImage;
|
||||
int dotColor;
|
||||
Path dotPath;
|
||||
Bubble.FlyoutMessage flyoutMessage;
|
||||
|
||||
@Nullable
|
||||
static BubbleViewInfo populate(Context c, BubbleStackView stackView,
|
||||
@@ -184,7 +195,80 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
||||
info.dotPath = iconPath;
|
||||
info.dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
|
||||
Color.WHITE, WHITE_SCRIM_ALPHA);
|
||||
|
||||
// Flyout
|
||||
info.flyoutMessage = extractFlyoutMessage(c, b.getEntry());
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns our best guess for the most relevant text summary of the latest update to this
|
||||
* notification, based on its type. Returns null if there should not be an update message.
|
||||
*/
|
||||
@NonNull
|
||||
static Bubble.FlyoutMessage extractFlyoutMessage(Context context,
|
||||
NotificationEntry entry) {
|
||||
final Notification underlyingNotif = entry.getSbn().getNotification();
|
||||
final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle();
|
||||
|
||||
Bubble.FlyoutMessage bubbleMessage = new Bubble.FlyoutMessage();
|
||||
bubbleMessage.isGroupChat = underlyingNotif.extras.getBoolean(
|
||||
Notification.EXTRA_IS_GROUP_CONVERSATION);
|
||||
try {
|
||||
if (Notification.BigTextStyle.class.equals(style)) {
|
||||
// Return the big text, it is big so probably important. If it's not there use the
|
||||
// normal text.
|
||||
CharSequence bigText =
|
||||
underlyingNotif.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
|
||||
bubbleMessage.message = !TextUtils.isEmpty(bigText)
|
||||
? bigText
|
||||
: underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
|
||||
return bubbleMessage;
|
||||
} else if (Notification.MessagingStyle.class.equals(style)) {
|
||||
final List<Notification.MessagingStyle.Message> messages =
|
||||
Notification.MessagingStyle.Message.getMessagesFromBundleArray(
|
||||
(Parcelable[]) underlyingNotif.extras.get(
|
||||
Notification.EXTRA_MESSAGES));
|
||||
|
||||
final Notification.MessagingStyle.Message latestMessage =
|
||||
Notification.MessagingStyle.findLatestIncomingMessage(messages);
|
||||
if (latestMessage != null) {
|
||||
bubbleMessage.message = latestMessage.getText();
|
||||
Person sender = latestMessage.getSenderPerson();
|
||||
bubbleMessage.senderName = sender != null
|
||||
? sender.getName()
|
||||
: null;
|
||||
bubbleMessage.senderAvatar = sender != null
|
||||
? sender.getIcon().loadDrawable(context)
|
||||
: null;
|
||||
return bubbleMessage;
|
||||
}
|
||||
} else if (Notification.InboxStyle.class.equals(style)) {
|
||||
CharSequence[] lines =
|
||||
underlyingNotif.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
|
||||
|
||||
// Return the last line since it should be the most recent.
|
||||
if (lines != null && lines.length > 0) {
|
||||
bubbleMessage.message = lines[lines.length - 1];
|
||||
return bubbleMessage;
|
||||
}
|
||||
} else if (Notification.MediaStyle.class.equals(style)) {
|
||||
// Return nothing, media updates aren't typically useful as a text update.
|
||||
return bubbleMessage;
|
||||
} else {
|
||||
// Default to text extra.
|
||||
bubbleMessage.message =
|
||||
underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
|
||||
return bubbleMessage;
|
||||
}
|
||||
} catch (ClassCastException | NullPointerException | ArrayIndexOutOfBoundsException e) {
|
||||
// No use crashing, we'll just return null and the caller will assume there's no update
|
||||
// message.
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return bubbleMessage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,14 +45,22 @@ import org.mockito.MockitoAnnotations;
|
||||
public class BubbleFlyoutViewTest extends SysuiTestCase {
|
||||
private BubbleFlyoutView mFlyout;
|
||||
private TextView mFlyoutText;
|
||||
private TextView mSenderName;
|
||||
private float[] mDotCenter = new float[2];
|
||||
private Bubble.FlyoutMessage mFlyoutMessage;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mFlyoutMessage = new Bubble.FlyoutMessage();
|
||||
mFlyoutMessage.senderName = "Josh";
|
||||
mFlyoutMessage.message = "Hello";
|
||||
|
||||
mFlyout = new BubbleFlyoutView(getContext());
|
||||
|
||||
mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text);
|
||||
mSenderName = mFlyout.findViewById(R.id.bubble_flyout_name);
|
||||
mDotCenter[0] = 30;
|
||||
mDotCenter[1] = 30;
|
||||
}
|
||||
@@ -60,19 +68,21 @@ public class BubbleFlyoutViewTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testShowFlyout_isVisible() {
|
||||
mFlyout.setupFlyoutStartingAsDot(
|
||||
"Hello", new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
|
||||
mFlyoutMessage,
|
||||
new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
|
||||
false);
|
||||
mFlyout.setVisibility(View.VISIBLE);
|
||||
|
||||
assertEquals("Hello", mFlyoutText.getText());
|
||||
assertEquals("Josh", mSenderName.getText());
|
||||
assertEquals(View.VISIBLE, mFlyout.getVisibility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlyoutHide_runsCallback() {
|
||||
Runnable after = Mockito.mock(Runnable.class);
|
||||
mFlyout.setupFlyoutStartingAsDot(
|
||||
"Hello", new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter,
|
||||
mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
|
||||
new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter,
|
||||
false);
|
||||
mFlyout.hideFlyout();
|
||||
|
||||
@@ -81,8 +91,8 @@ public class BubbleFlyoutViewTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testSetCollapsePercent() {
|
||||
mFlyout.setupFlyoutStartingAsDot(
|
||||
"Hello", new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
|
||||
mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
|
||||
new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
|
||||
false);
|
||||
mFlyout.setVisibility(View.VISIBLE);
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ public class BubbleTest extends SysuiTestCase {
|
||||
private Notification mNotif;
|
||||
|
||||
private NotificationEntry mEntry;
|
||||
private Bubble mBubble;
|
||||
private Bundle mExtras;
|
||||
|
||||
@Before
|
||||
@@ -58,7 +57,6 @@ public class BubbleTest extends SysuiTestCase {
|
||||
mEntry = new NotificationEntryBuilder()
|
||||
.setNotification(mNotif)
|
||||
.build();
|
||||
mBubble = new Bubble(mEntry);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -66,7 +64,8 @@ public class BubbleTest extends SysuiTestCase {
|
||||
final String msg = "Hello there!";
|
||||
doReturn(Notification.Style.class).when(mNotif).getNotificationStyle();
|
||||
mExtras.putCharSequence(Notification.EXTRA_TEXT, msg);
|
||||
assertEquals(msg, mBubble.getUpdateMessage(mContext));
|
||||
assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mContext,
|
||||
mEntry).message);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -77,7 +76,8 @@ public class BubbleTest extends SysuiTestCase {
|
||||
mExtras.putCharSequence(Notification.EXTRA_BIG_TEXT, msg);
|
||||
|
||||
// Should be big text, not the small text.
|
||||
assertEquals(msg, mBubble.getUpdateMessage(mContext));
|
||||
assertEquals(msg, BubbleViewInfoTask.extractFlyoutMessage(mContext,
|
||||
mEntry).message);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -85,7 +85,8 @@ public class BubbleTest extends SysuiTestCase {
|
||||
doReturn(Notification.MediaStyle.class).when(mNotif).getNotificationStyle();
|
||||
|
||||
// Media notifs don't get update messages.
|
||||
assertNull(mBubble.getUpdateMessage(mContext));
|
||||
assertNull(BubbleViewInfoTask.extractFlyoutMessage(mContext,
|
||||
mEntry).message);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,7 +101,8 @@ public class BubbleTest extends SysuiTestCase {
|
||||
"Really? I prefer them that way."});
|
||||
|
||||
// Should be the last one only.
|
||||
assertEquals("Really? I prefer them that way.", mBubble.getUpdateMessage(mContext));
|
||||
assertEquals("Really? I prefer them that way.",
|
||||
BubbleViewInfoTask.extractFlyoutMessage(mContext, mEntry).message);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,6 +117,10 @@ public class BubbleTest extends SysuiTestCase {
|
||||
"Oh, hello!", 0, "Mady").toBundle()});
|
||||
|
||||
// Should be the last one only.
|
||||
assertEquals("Mady: Oh, hello!", mBubble.getUpdateMessage(mContext));
|
||||
assertEquals("Oh, hello!",
|
||||
BubbleViewInfoTask.extractFlyoutMessage(mContext, mEntry).message);
|
||||
assertEquals("Mady",
|
||||
BubbleViewInfoTask.extractFlyoutMessage(mContext,
|
||||
mEntry).senderName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user