Merge "Only show app icon + limit 2 lines toast on targetSdk S+" into sc-dev am: f010ed6344

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14718053

Change-Id: Ib7445aa3ce46376221344d681710820e5f5eeac6
This commit is contained in:
TreeHugger Robot
2021-05-26 21:28:47 +00:00
committed by Automerger Merge Worker
6 changed files with 167 additions and 79 deletions

View File

@@ -38,8 +38,6 @@
<!-- The new animations to/from lockscreen and AOD! --> <!-- The new animations to/from lockscreen and AOD! -->
<bool name="flag_lockscreen_animations">false</bool> <bool name="flag_lockscreen_animations">false</bool>
<bool name="flag_toast_style">false</bool>
<bool name="flag_pm_lite">false</bool> <bool name="flag_pm_lite">false</bool>
<bool name="flag_alarm_tile">false</bool> <bool name="flag_alarm_tile">false</bool>

View File

@@ -61,10 +61,6 @@ public class FeatureFlags {
return mFlagReader.isEnabled(R.bool.flag_conversations); return mFlagReader.isEnabled(R.bool.flag_conversations);
} }
public boolean isToastStyleEnabled() {
return mFlagReader.isEnabled(R.bool.flag_toast_style);
}
public boolean isMonetEnabled() { public boolean isMonetEnabled() {
return mFlagReader.isEnabled(R.bool.flag_monet); return mFlagReader.isEnabled(R.bool.flag_monet);
} }

View File

@@ -22,16 +22,19 @@ import android.annotation.Nullable;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.ToastPresenter;
import com.android.internal.R; import com.android.internal.R;
import com.android.launcher3.icons.IconFactory; import com.android.launcher3.icons.IconFactory;
@@ -52,7 +55,6 @@ public class SystemUIToast implements ToastPlugin.Toast {
private final String mPackageName; private final String mPackageName;
private final int mUserId; private final int mUserId;
private final LayoutInflater mLayoutInflater; private final LayoutInflater mLayoutInflater;
private final boolean mToastStyleEnabled;
final int mDefaultX = 0; final int mDefaultX = 0;
final int mDefaultHorizontalMargin = 0; final int mDefaultHorizontalMargin = 0;
@@ -66,15 +68,14 @@ public class SystemUIToast implements ToastPlugin.Toast {
@Nullable private final Animator mOutAnimator; @Nullable private final Animator mOutAnimator;
SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text, SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
String packageName, int userId, boolean toastStyleEnabled, int orientation) { String packageName, int userId, int orientation) {
this(layoutInflater, context, text, null, packageName, userId, this(layoutInflater, context, text, null, packageName, userId,
toastStyleEnabled, orientation); orientation);
} }
SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text, SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
ToastPlugin.Toast pluginToast, String packageName, int userId, ToastPlugin.Toast pluginToast, String packageName, int userId,
boolean toastStyleEnabled, int orientation) { int orientation) {
mToastStyleEnabled = toastStyleEnabled;
mLayoutInflater = layoutInflater; mLayoutInflater = layoutInflater;
mContext = context; mContext = context;
mText = text; mText = text;
@@ -167,23 +168,45 @@ public class SystemUIToast implements ToastPlugin.Toast {
return mPluginToast.getView(); return mPluginToast.getView();
} }
View toastView; final View toastView = mLayoutInflater.inflate(
if (mToastStyleEnabled) {
toastView = mLayoutInflater.inflate(
com.android.systemui.R.layout.text_toast, null); com.android.systemui.R.layout.text_toast, null);
((TextView) toastView.findViewById(com.android.systemui.R.id.text)).setText(mText); final TextView textView = toastView.findViewById(com.android.systemui.R.id.text);
final ImageView iconView = toastView.findViewById(com.android.systemui.R.id.icon);
textView.setText(mText);
Drawable icon = getBadgedIcon(mContext, mPackageName, mUserId); ApplicationInfo appInfo = null;
if (icon == null) { try {
toastView.findViewById(com.android.systemui.R.id.icon).setVisibility(View.GONE); appInfo = mContext.getPackageManager()
} else { .getApplicationInfoAsUser(mPackageName, 0, mUserId);
((ImageView) toastView.findViewById(com.android.systemui.R.id.icon)) } catch (PackageManager.NameNotFoundException e) {
.setImageDrawable(icon); Log.e(TAG, "Package name not found package=" + mPackageName
} + " user=" + mUserId);
} else {
toastView = ToastPresenter.getTextToastView(mContext, mText);
} }
if (appInfo != null && appInfo.targetSdkVersion < Build.VERSION_CODES.S) {
// no two-line limit
textView.setMaxLines(Integer.MAX_VALUE);
// no app icon
toastView.findViewById(com.android.systemui.R.id.icon).setVisibility(View.GONE);
} else {
Drawable icon = getBadgedIcon(mContext, mPackageName, mUserId);
if (icon == null) {
iconView.setVisibility(View.GONE);
} else {
iconView.setImageDrawable(icon);
if (appInfo.labelRes != 0) {
try {
Resources res = mContext.getPackageManager().getResourcesForApplication(
appInfo,
new Configuration(mContext.getResources().getConfiguration()));
iconView.setContentDescription(res.getString(appInfo.labelRes));
} catch (PackageManager.NameNotFoundException e) {
Log.d(TAG, "Cannot find application resources for icon label.");
}
}
}
}
return toastView; return toastView;
} }
@@ -205,18 +228,14 @@ public class SystemUIToast implements ToastPlugin.Toast {
return mPluginToast.getInAnimation(); return mPluginToast.getInAnimation();
} }
return mToastStyleEnabled return ToastDefaultAnimation.Companion.toastIn(getView());
? ToastDefaultAnimation.Companion.toastIn(getView())
: null;
} }
private Animator createOutAnimator() { private Animator createOutAnimator() {
if (isPluginToast() && mPluginToast.getOutAnimation() != null) { if (isPluginToast() && mPluginToast.getOutAnimation() != null) {
return mPluginToast.getOutAnimation(); return mPluginToast.getOutAnimation();
} }
return mToastStyleEnabled return ToastDefaultAnimation.Companion.toastOut(getView());
? ToastDefaultAnimation.Companion.toastOut(getView())
: null;
} }
/** /**
@@ -225,6 +244,10 @@ public class SystemUIToast implements ToastPlugin.Toast {
*/ */
public static Drawable getBadgedIcon(@NonNull Context context, String packageName, public static Drawable getBadgedIcon(@NonNull Context context, String packageName,
int userId) { int userId) {
if (!(context.getApplicationContext() instanceof Application)) {
return null;
}
final ApplicationsState appState = final ApplicationsState appState =
ApplicationsState.getInstance((Application) context.getApplicationContext()); ApplicationsState.getInstance((Application) context.getApplicationContext());
if (!appState.isUserAdded(userId)) { if (!appState.isUserAdded(userId)) {

View File

@@ -27,7 +27,6 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.ToastPlugin; import com.android.systemui.plugins.ToastPlugin;
import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.FeatureFlags;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -43,17 +42,14 @@ public class ToastFactory implements Dumpable {
// only one ToastPlugin can be connected at a time. // only one ToastPlugin can be connected at a time.
private ToastPlugin mPlugin; private ToastPlugin mPlugin;
private final LayoutInflater mLayoutInflater; private final LayoutInflater mLayoutInflater;
private final boolean mToastStyleEnabled;
@Inject @Inject
public ToastFactory( public ToastFactory(
LayoutInflater layoutInflater, LayoutInflater layoutInflater,
PluginManager pluginManager, PluginManager pluginManager,
DumpManager dumpManager, DumpManager dumpManager) {
FeatureFlags featureFlags) {
mLayoutInflater = layoutInflater; mLayoutInflater = layoutInflater;
dumpManager.registerDumpable("ToastFactory", this); dumpManager.registerDumpable("ToastFactory", this);
mToastStyleEnabled = featureFlags.isToastStyleEnabled();
pluginManager.addPluginListener( pluginManager.addPluginListener(
new PluginListener<ToastPlugin>() { new PluginListener<ToastPlugin>() {
@Override @Override
@@ -77,10 +73,10 @@ public class ToastFactory implements Dumpable {
int userId, int orientation) { int userId, int orientation) {
if (isPluginAvailable()) { if (isPluginAvailable()) {
return new SystemUIToast(mLayoutInflater, context, text, mPlugin.createToast(text, return new SystemUIToast(mLayoutInflater, context, text, mPlugin.createToast(text,
packageName, userId), packageName, userId, mToastStyleEnabled, orientation); packageName, userId), packageName, userId, orientation);
} }
return new SystemUIToast(mLayoutInflater, context, text, packageName, userId, return new SystemUIToast(mLayoutInflater, context, text, packageName, userId,
mToastStyleEnabled, orientation); orientation);
} }
private boolean isPluginAvailable() { private boolean isPluginAvailable() {
@@ -91,6 +87,5 @@ public class ToastFactory implements Dumpable {
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("ToastFactory:"); pw.println("ToastFactory:");
pw.println(" mAttachedPlugin=" + mPlugin); pw.println(" mAttachedPlugin=" + mPlugin);
pw.println(" mToastStyleEnabled=" + mToastStyleEnabled);
} }
} }

View File

@@ -19,6 +19,7 @@ package com.android.systemui.toast;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.MainThread; import android.annotation.MainThread;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
@@ -34,7 +35,8 @@ import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager; import android.view.accessibility.IAccessibilityManager;
import android.widget.ToastPresenter; import android.widget.ToastPresenter;
import com.android.internal.annotations.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.systemui.SystemUI; import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue;
@@ -60,11 +62,11 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
private final AccessibilityManager mAccessibilityManager; private final AccessibilityManager mAccessibilityManager;
private final ToastFactory mToastFactory; private final ToastFactory mToastFactory;
private final ToastLogger mToastLogger; private final ToastLogger mToastLogger;
private SystemUIToast mToast;
@Nullable private ToastPresenter mPresenter; @Nullable private ToastPresenter mPresenter;
@Nullable private ITransientNotificationCallback mCallback; @Nullable private ITransientNotificationCallback mCallback;
private ToastOutAnimatorListener mToastOutAnimatorListener; private ToastOutAnimatorListener mToastOutAnimatorListener;
@VisibleForTesting SystemUIToast mToast;
private int mOrientation = ORIENTATION_PORTRAIT; private int mOrientation = ORIENTATION_PORTRAIT;
@Inject @Inject
@@ -191,7 +193,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
/** /**
* Once the out animation for a toast is finished, start showing the next toast. * Once the out animation for a toast is finished, start showing the next toast.
*/ */
class ToastOutAnimatorListener implements Animator.AnimatorListener { class ToastOutAnimatorListener extends AnimatorListenerAdapter {
final ToastPresenter mPrevPresenter; final ToastPresenter mPrevPresenter;
final ITransientNotificationCallback mPrevCallback; final ITransientNotificationCallback mPrevCallback;
@Nullable Runnable mShowNextToastRunnable; @Nullable Runnable mShowNextToastRunnable;
@@ -209,10 +211,6 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
mShowNextToastRunnable = runnable; mShowNextToastRunnable = runnable;
} }
@Override
public void onAnimationStart(Animator animation) {
}
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
mPrevPresenter.hide(mPrevCallback); mPrevPresenter.hide(mPrevCallback);
@@ -221,15 +219,5 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
} }
mToastOutAnimatorListener = null; mToastOutAnimatorListener = null;
} }
@Override
public void onAnimationCancel(Animator animation) {
onAnimationEnd(animation);
}
@Override
public void onAnimationRepeat(Animator animation) {
}
} }
} }

View File

@@ -17,7 +17,6 @@
package com.android.systemui.toast; package com.android.systemui.toast;
import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
import static android.widget.ToastPresenter.TEXT_TOAST_LAYOUT;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
@@ -31,13 +30,20 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.Application;
import android.app.INotificationManager; import android.app.INotificationManager;
import android.app.ITransientNotificationCallback; import android.app.ITransientNotificationCallback;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Binder; import android.os.Binder;
import android.os.Build;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -47,12 +53,11 @@ import android.view.accessibility.IAccessibilityManager;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import android.widget.ToastPresenter;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.internal.util.IntPair; import com.android.internal.util.IntPair;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpManager;
import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginManager;
@@ -70,6 +75,7 @@ import org.mockito.stubbing.Answer;
@SmallTest @SmallTest
@RunWith(AndroidTestingRunner.class) @RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class ToastUITest extends SysuiTestCase { public class ToastUITest extends SysuiTestCase {
private static final int ANDROID_UID = 1000; private static final int ANDROID_UID = 1000;
private static final int SYSTEMUI_UID = 10140; private static final int SYSTEMUI_UID = 10140;
@@ -85,12 +91,14 @@ public class ToastUITest extends SysuiTestCase {
private static final Binder WINDOW_TOKEN_2 = new Binder(); private static final Binder WINDOW_TOKEN_2 = new Binder();
private static final String TEXT = "Hello World"; private static final String TEXT = "Hello World";
private static final int MESSAGE_RES_ID = R.id.message; private static final int MESSAGE_RES_ID = R.id.text;
private Context mContextSpy; private Context mContextSpy;
private ToastUI mToastUI; private ToastUI mToastUI;
@Mock private LayoutInflater mLayoutInflater; private View mToastView;
@Mock private Application mApplication;
@Mock private CommandQueue mCommandQueue; @Mock private CommandQueue mCommandQueue;
@Mock private LayoutInflater mLayoutInflater;
@Mock private WindowManager mWindowManager; @Mock private WindowManager mWindowManager;
@Mock private INotificationManager mNotificationManager; @Mock private INotificationManager mNotificationManager;
@Mock private IAccessibilityManager mAccessibilityManager; @Mock private IAccessibilityManager mAccessibilityManager;
@@ -98,6 +106,7 @@ public class ToastUITest extends SysuiTestCase {
@Mock private DumpManager mDumpManager; @Mock private DumpManager mDumpManager;
@Mock private ToastLogger mToastLogger; @Mock private ToastLogger mToastLogger;
@Mock private FeatureFlags mFeatureFlags; @Mock private FeatureFlags mFeatureFlags;
@Mock private PackageManager mPackageManager;
@Mock private ITransientNotificationCallback mCallback; @Mock private ITransientNotificationCallback mCallback;
@Captor private ArgumentCaptor<View> mViewCaptor; @Captor private ArgumentCaptor<View> mViewCaptor;
@@ -106,29 +115,33 @@ public class ToastUITest extends SysuiTestCase {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
when(mLayoutInflater.inflate(eq(TEXT_TOAST_LAYOUT), any())).thenReturn( mToastView = LayoutInflater.from(mContext).inflate(R.layout.text_toast, null);
ToastPresenter.getTextToastView(mContext, TEXT)); when(mLayoutInflater.inflate(anyInt(), eq(null))).thenReturn(mToastView);
when(mFeatureFlags.isToastStyleEnabled()).thenReturn(false);
mContext.addMockSystemService(WindowManager.class, mWindowManager); mContext.addMockSystemService(WindowManager.class, mWindowManager);
mContextSpy = spy(mContext); mContextSpy = spy(mContext);
when(mContextSpy.getPackageManager()).thenReturn(mPackageManager);
doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt()); doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
mToastUI = new ToastUI(
doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt()); mContextSpy,
mToastUI = new ToastUI(mContextSpy, mCommandQueue, mNotificationManager, mCommandQueue,
mAccessibilityManager, new ToastFactory(mLayoutInflater, mPluginManager, mNotificationManager,
mDumpManager, mFeatureFlags), mToastLogger); mAccessibilityManager,
new ToastFactory(
mLayoutInflater,
mPluginManager,
mDumpManager),
mToastLogger);
} }
@Test @Test
public void testStart_addToastUIAsCallbackToCommandQueue() throws Exception { public void testStart_addToastUIAsCallbackToCommandQueue() {
mToastUI.start(); mToastUI.start();
verify(mCommandQueue).addCallback(mToastUI); verify(mCommandQueue).addCallback(mToastUI);
} }
@Test @Test
public void testShowToast_addsCorrectViewToWindowManager() throws Exception { public void testShowToast_addsCorrectViewToWindowManager() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
null); null);
@@ -138,7 +151,7 @@ public class ToastUITest extends SysuiTestCase {
} }
@Test @Test
public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() throws Exception { public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
null); null);
@@ -217,9 +230,14 @@ public class ToastUITest extends SysuiTestCase {
public void testHideToast_removesView() throws Exception { public void testHideToast_removesView() throws Exception {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback); mCallback);
View view = verifyWmAddViewAndAttachToParent(); final SystemUIToast toast = mToastUI.mToast;
View view = verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1); mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
if (toast.getOutAnimation() != null) {
assertThat(toast.getOutAnimation().isRunning()).isTrue();
toast.getOutAnimation().cancel(); // if applicable, try to finish anim early
}
verify(mWindowManager).removeViewImmediate(view); verify(mWindowManager).removeViewImmediate(view);
} }
@@ -228,51 +246,81 @@ public class ToastUITest extends SysuiTestCase {
public void testHideToast_finishesToken() throws Exception { public void testHideToast_finishesToken() throws Exception {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback); mCallback);
final SystemUIToast toast = mToastUI.mToast;
verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1); mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
if (toast.getOutAnimation() != null) {
assertThat(toast.getOutAnimation().isRunning()).isTrue();
toast.getOutAnimation().cancel(); // if applicable, try to finish anim early
}
verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1); verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
} }
@Test @Test
public void testHideToast_callsCallback() throws Exception { public void testHideToast_callsCallback() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback); mCallback);
final SystemUIToast toast = mToastUI.mToast;
verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1); mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
if (toast.getOutAnimation() != null) {
assertThat(toast.getOutAnimation().isRunning()).isTrue();
toast.getOutAnimation().cancel();
}
verify(mCallback).onToastHidden(); verify(mCallback).onToastHidden();
} }
@Test @Test
public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws Exception { public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback); mCallback);
final SystemUIToast toast = mToastUI.mToast;
verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_2); mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_2);
if (toast.getOutAnimation() != null) {
assertThat(toast.getOutAnimation().isRunning()).isFalse();
}
verify(mCallback, never()).onToastHidden(); verify(mCallback, never()).onToastHidden();
} }
@Test @Test
public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws Exception { public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback); mCallback);
final SystemUIToast toast = mToastUI.mToast;
verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_2, TOKEN_1); mToastUI.hideToast(PACKAGE_NAME_2, TOKEN_1);
if (toast.getOutAnimation() != null) {
assertThat(toast.getOutAnimation().isRunning()).isFalse();
}
verify(mCallback, never()).onToastHidden(); verify(mCallback, never()).onToastHidden();
} }
@Test @Test
public void testShowToast_afterShowToast_hidesCurrentToast() throws Exception { public void testShowToast_afterShowToast_hidesCurrentToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback); mCallback);
View view = verifyWmAddViewAndAttachToParent(); final SystemUIToast toast = mToastUI.mToast;
View view = verifyWmAddViewAndAttachToParent();
mToastUI.showToast(UID_2, PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG, mToastUI.showToast(UID_2, PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG,
null); null);
if (toast.getOutAnimation() != null) {
assertThat(toast.getOutAnimation().isRunning()).isTrue();
toast.getOutAnimation().cancel(); // end early if applicable
}
verify(mWindowManager).removeViewImmediate(view); verify(mWindowManager).removeViewImmediate(view);
verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1); verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
verify(mCallback).onToastHidden(); verify(mCallback).onToastHidden();
@@ -286,10 +334,49 @@ public class ToastUITest extends SysuiTestCase {
verify(mToastLogger).logOnShowToast(UID_1, PACKAGE_NAME_1, TEXT, TOKEN_1.toString()); verify(mToastLogger).logOnShowToast(UID_1, PACKAGE_NAME_1, TEXT, TOKEN_1.toString());
} }
@Test
public void testShowToast_targetsPreS_unlimitedLines_noAppIcon()
throws PackageManager.NameNotFoundException {
// GIVEN the application targets R
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
when(mPackageManager.getApplicationInfoAsUser(PACKAGE_NAME_1, 0,
UserHandle.getUserHandleForUid(UID_1).getIdentifier())).thenReturn(applicationInfo);
// WHEN the package posts a toast
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
// THEN the view can have unlimited lines
assertThat(((TextView) mToastUI.mToast.getView()
.findViewById(com.android.systemui.R.id.text))
.getMaxLines()).isEqualTo(Integer.MAX_VALUE);
}
@Test
public void testShowToast_targetsS_twoLineLimit_noAppIcon()
throws PackageManager.NameNotFoundException {
// GIVEN the application targets S
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = Build.VERSION_CODES.S;
when(mPackageManager.getApplicationInfoAsUser(PACKAGE_NAME_1, 0,
UserHandle.getUserHandleForUid(UID_1).getIdentifier())).thenReturn(applicationInfo);
// WHEN the package posts a toast
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
// THEN the view is limited to 2 lines
assertThat(((TextView) mToastUI.mToast.getView()
.findViewById(com.android.systemui.R.id.text))
.getMaxLines()).isEqualTo(2);
}
@Test @Test
public void testHideToast_logs() { public void testHideToast_logs() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback); mCallback);
verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1); mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
verify(mToastLogger).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString()); verify(mToastLogger).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
} }
@@ -298,6 +385,7 @@ public class ToastUITest extends SysuiTestCase {
public void testHideToast_error_noLog() { public void testHideToast_error_noLog() {
// no toast was shown, so this hide is invalid // no toast was shown, so this hide is invalid
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1); mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
assertThat(mToastUI.mToast).isNull();
verify(mToastLogger, never()).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString()); verify(mToastLogger, never()).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
} }