Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a2f55df authored by Bernardo Rufino's avatar Bernardo Rufino Committed by Automerger Merge Worker
Browse files

Merge "Refactor ToastPresenter to perform show()/hide()" into rvc-dev am: 918db9ec

Change-Id: Ia5ac0240db4a040590e8d3f451e5dba03344946c
parents 702d2fce 918db9ec
Loading
Loading
Loading
Loading
+18 −54
Original line number Original line Diff line number Diff line
@@ -117,7 +117,6 @@ public class Toast {
    private final Binder mToken;
    private final Binder mToken;
    private final Context mContext;
    private final Context mContext;
    private final Handler mHandler;
    private final Handler mHandler;
    private final ToastPresenter mPresenter;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    final TN mTN;
    final TN mTN;
    @UnsupportedAppUsage
    @UnsupportedAppUsage
@@ -165,8 +164,8 @@ public class Toast {
        looper = getLooper(looper);
        looper = getLooper(looper);
        mHandler = new Handler(looper);
        mHandler = new Handler(looper);
        mCallbacks = new ArrayList<>();
        mCallbacks = new ArrayList<>();
        mPresenter = new ToastPresenter(context, AccessibilityManager.getInstance(context));
        mTN = new TN(context, context.getPackageName(), mToken,
        mTN = new TN(mPresenter, context.getPackageName(), mToken, mCallbacks, looper);
                mCallbacks, looper);
        mTN.mY = context.getResources().getDimensionPixelSize(
        mTN.mY = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.toast_y_offset);
                com.android.internal.R.dimen.toast_y_offset);
        mTN.mGravity = context.getResources().getInteger(
        mTN.mGravity = context.getResources().getInteger(
@@ -496,7 +495,7 @@ public class Toast {
            return result;
            return result;
        } else {
        } else {
            Toast result = new Toast(context, looper);
            Toast result = new Toast(context, looper);
            View v = result.mPresenter.getTextToastView(text);
            View v = ToastPresenter.getTextToastView(context, text);
            result.mNextView = v;
            result.mNextView = v;
            result.mDuration = duration;
            result.mDuration = duration;


@@ -565,13 +564,14 @@ public class Toast {
        if (sService != null) {
        if (sService != null) {
            return sService;
            return sService;
        }
        }
        sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification"));
        sService = INotificationManager.Stub.asInterface(
                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
        return sService;
        return sService;
    }
    }


    private static class TN extends ITransientNotification.Stub {
    private static class TN extends ITransientNotification.Stub {
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
        private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
        private final WindowManager.LayoutParams mParams;


        private static final int SHOW = 0;
        private static final int SHOW = 0;
        private static final int HIDE = 1;
        private static final int HIDE = 1;
@@ -608,9 +608,13 @@ public class Toast {
         * The parameter {@code callbacks} is not copied and is accessed with itself as its own
         * The parameter {@code callbacks} is not copied and is accessed with itself as its own
         * lock.
         * lock.
         */
         */
        TN(ToastPresenter presenter, String packageName, Binder token, List<Callback> callbacks,
        TN(Context context, String packageName, Binder token, List<Callback> callbacks,
                @Nullable Looper looper) {
                @Nullable Looper looper) {
            mPresenter = presenter;
            WindowManager windowManager = context.getSystemService(WindowManager.class);
            AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context);
            mPresenter = new ToastPresenter(context, windowManager, accessibilityManager,
                    getService(), packageName);
            mParams = mPresenter.getLayoutParams();
            mPackageName = packageName;
            mPackageName = packageName;
            mToken = token;
            mToken = token;
            mCallbacks = callbacks;
            mCallbacks = callbacks;
@@ -645,8 +649,6 @@ public class Toast {
                    }
                    }
                }
                }
            };
            };

            presenter.startLayoutParams(mParams, packageName);
        }
        }


        private List<Callback> getCallbacks() {
        private List<Callback> getCallbacks() {
@@ -691,31 +693,9 @@ public class Toast {
                // remove the old view if necessary
                // remove the old view if necessary
                handleHide();
                handleHide();
                mView = mNextView;
                mView = mNextView;
                Context context = mView.getContext().getApplicationContext();
                mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY,
                if (context == null) {
                        mHorizontalMargin, mVerticalMargin,
                    context = mView.getContext();
                        new CallbackBinder(getCallbacks(), mHandler));
                }
                mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
                mPresenter.adjustLayoutParams(mParams, windowToken, mDuration, mGravity, mX, mY,
                        mHorizontalMargin, mVerticalMargin);
                if (mView.getParent() != null) {
                    if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                    mWM.removeView(mView);
                }
                if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
                // Since the notification manager service cancels the token right
                // after it notifies us to cancel the toast there is an inherent
                // race and we may attempt to add a window after the token has been
                // invalidated. Let us hedge against that.
                try {
                    mWM.addView(mView, mParams);
                    mPresenter.trySendAccessibilityEvent(mView, mPackageName);
                    for (Callback callback : getCallbacks()) {
                        callback.onToastShown();
                    }
                } catch (WindowManager.BadTokenException e) {
                    /* ignore */
                }
            }
            }
        }
        }


@@ -723,25 +703,9 @@ public class Toast {
        public void handleHide() {
        public void handleHide() {
            if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
            if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
            if (mView != null) {
            if (mView != null) {
                // note: checking parent() just to make sure the view has
                checkState(mView == mPresenter.getView(),
                // been added...  i have seen cases where we get here when
                        "Trying to hide toast view different than the last one displayed");
                // the view isn't yet added, so let's try not to crash.
                mPresenter.hide(new CallbackBinder(getCallbacks(), mHandler));
                if (mView.getParent() != null) {
                    if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                    mWM.removeViewImmediate(mView);
                }


                // Now that we've removed the view it's safe for the server to release
                // the resources.
                try {
                    getService().finishToken(mPackageName, mToken);
                } catch (RemoteException e) {
                }

                for (Callback callback : getCallbacks()) {
                    callback.onToastHidden();
                }
                mView = null;
                mView = null;
            }
            }
        }
        }
+126 −14
Original line number Original line Diff line number Diff line
@@ -16,11 +16,18 @@


package android.widget;
package android.widget;


import static com.android.internal.util.Preconditions.checkState;

import android.annotation.Nullable;
import android.app.INotificationManager;
import android.app.ITransientNotificationCallback;
import android.content.Context;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.Gravity;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View;
@@ -37,41 +44,94 @@ import com.android.internal.util.ArrayUtils;
 * @hide
 * @hide
 */
 */
public class ToastPresenter {
public class ToastPresenter {
    private static final String TAG = "ToastPresenter";
    private static final String WINDOW_TITLE = "Toast";
    private static final long SHORT_DURATION_TIMEOUT = 4000;
    private static final long SHORT_DURATION_TIMEOUT = 4000;
    private static final long LONG_DURATION_TIMEOUT = 7000;
    private static final long LONG_DURATION_TIMEOUT = 7000;


    /**
     * Returns the default text toast view for message {@code text}.
     */
    public static View getTextToastView(Context context, CharSequence text) {
        View view = LayoutInflater.from(context).inflate(
                R.layout.transient_notification, null);
        TextView textView = view.findViewById(com.android.internal.R.id.message);
        textView.setText(text);
        return view;
    }

    private final Context mContext;
    private final Context mContext;
    private final Resources mResources;
    private final Resources mResources;
    private final WindowManager mWindowManager;
    private final AccessibilityManager mAccessibilityManager;
    private final AccessibilityManager mAccessibilityManager;
    private final INotificationManager mNotificationManager;
    private final String mPackageName;
    private final WindowManager.LayoutParams mParams;
    @Nullable private View mView;
    @Nullable private IBinder mToken;


    public ToastPresenter(Context context, AccessibilityManager accessibilityManager) {
    public ToastPresenter(Context context, WindowManager windowManager,
            AccessibilityManager accessibilityManager,
            INotificationManager notificationManager, String packageName) {
        mContext = context;
        mContext = context;
        mResources = context.getResources();
        mResources = context.getResources();
        mWindowManager = windowManager;
        mAccessibilityManager = accessibilityManager;
        mAccessibilityManager = accessibilityManager;
        mNotificationManager = notificationManager;
        mPackageName = packageName;
        mParams = createLayoutParams();
    }

    public String getPackageName() {
        return mPackageName;
    }

    public WindowManager.LayoutParams getLayoutParams() {
        return mParams;
    }

    /**
     * Returns the {@link View} being shown at the moment or {@code null} if no toast is being
     * displayed.
     */
    @Nullable
    public View getView() {
        return mView;
    }

    /**
     * Returns the {@link IBinder} token used to display the toast or {@code null} if there is no
     * toast being shown at the moment.
     */
    @Nullable
    public IBinder getToken() {
        return mToken;
    }
    }


    /**
    /**
     * Initializes {@code params} with default values for toasts.
     * Creates {@link WindowManager.LayoutParams} with default values for toasts.
     */
     */
    public void startLayoutParams(WindowManager.LayoutParams params, String packageName) {
    private WindowManager.LayoutParams createLayoutParams() {
        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.format = PixelFormat.TRANSLUCENT;
        params.format = PixelFormat.TRANSLUCENT;
        params.windowAnimations = R.style.Animation_Toast;
        params.windowAnimations = R.style.Animation_Toast;
        params.type = WindowManager.LayoutParams.TYPE_TOAST;
        params.type = WindowManager.LayoutParams.TYPE_TOAST;
        params.setFitInsetsIgnoringVisibility(true);
        params.setFitInsetsIgnoringVisibility(true);
        params.setTitle("Toast");
        params.setTitle(WINDOW_TITLE);
        params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
        params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
        setShowForAllUsersIfApplicable(params, packageName);
        setShowForAllUsersIfApplicable(params, mPackageName);
        return params;
    }
    }


    /**
    /**
     * Customizes {@code params} according to other parameters, ready to be passed to {@link
     * Customizes {@code params} according to other parameters, ready to be passed to {@link
     * WindowManager#addView(View, ViewGroup.LayoutParams)}.
     * WindowManager#addView(View, ViewGroup.LayoutParams)}.
     */
     */
    public void adjustLayoutParams(WindowManager.LayoutParams params, IBinder windowToken,
    private void adjustLayoutParams(WindowManager.LayoutParams params, IBinder windowToken,
            int duration, int gravity, int xOffset, int yOffset, float horizontalMargin,
            int duration, int gravity, int xOffset, int yOffset, float horizontalMargin,
            float verticalMargin) {
            float verticalMargin) {
        Configuration config = mResources.getConfiguration();
        Configuration config = mResources.getConfiguration();
@@ -97,7 +157,7 @@ public class ToastPresenter {
     * Sets {@link WindowManager.LayoutParams#SYSTEM_FLAG_SHOW_FOR_ALL_USERS} flag if {@code
     * Sets {@link WindowManager.LayoutParams#SYSTEM_FLAG_SHOW_FOR_ALL_USERS} flag if {@code
     * packageName} is a cross-user package.
     * packageName} is a cross-user package.
     *
     *
     * Implementation note:
     * <p>Implementation note:
     *     This code is safe to be executed in SystemUI and the app's process:
     *     This code is safe to be executed in SystemUI and the app's process:
     *         <li>SystemUI: It's running on a trusted domain so apps can't tamper with it. SystemUI
     *         <li>SystemUI: It's running on a trusted domain so apps can't tamper with it. SystemUI
     *             has the permission INTERNAL_SYSTEM_WINDOW needed by the flag, so SystemUI can add
     *             has the permission INTERNAL_SYSTEM_WINDOW needed by the flag, so SystemUI can add
@@ -120,14 +180,66 @@ public class ToastPresenter {
    }
    }


    /**
    /**
     * Returns the default text toast view for message {@code text}.
     * Shows the toast in {@code view} with the parameters passed and callback {@code callback}.
     */
     */
    public View getTextToastView(CharSequence text) {
    public void show(View view, IBinder token, IBinder windowToken, int duration, int gravity,
        View view = LayoutInflater.from(mContext).inflate(
            int xOffset, int yOffset, float horizontalMargin, float verticalMargin,
                R.layout.transient_notification, null);
            @Nullable ITransientNotificationCallback callback) {
        TextView textView = view.findViewById(com.android.internal.R.id.message);
        checkState(mView == null, "Only one toast at a time is allowed, call hide() first.");
        textView.setText(text);
        mView = view;
        return view;
        mToken = token;

        adjustLayoutParams(mParams, windowToken, duration, gravity, xOffset, yOffset,
                horizontalMargin, verticalMargin);
        if (mView.getParent() != null) {
            mWindowManager.removeView(mView);
        }
        try {
            mWindowManager.addView(mView, mParams);
        } catch (WindowManager.BadTokenException e) {
            // Since the notification manager service cancels the token right after it notifies us
            // to cancel the toast there is an inherent race and we may attempt to add a window
            // after the token has been invalidated. Let us hedge against that.
            Log.w(TAG, "Error while attempting to show toast from " + mPackageName, e);
            return;
        }
        trySendAccessibilityEvent(mView, mPackageName);
        if (callback != null) {
            try {
                callback.onToastShown();
            } catch (RemoteException e) {
                Log.w(TAG, "Error calling back " + mPackageName + " to notify onToastShow()", e);
            }
        }
    }

    /**
     * Hides toast that was shown using {@link #show(View, IBinder, IBinder, int,
     * int, int, int, float, float, ITransientNotificationCallback)}.
     *
     * <p>This method has to be called on the same thread on which {@link #show(View, IBinder,
     * IBinder, int, int, int, int, float, float, ITransientNotificationCallback)} was called.
     */
    public void hide(@Nullable ITransientNotificationCallback callback) {
        checkState(mView != null, "No toast to hide.");

        if (mView.getParent() != null) {
            mWindowManager.removeViewImmediate(mView);
        }
        try {
            mNotificationManager.finishToken(mPackageName, mToken);
        } catch (RemoteException e) {
            Log.w(TAG, "Error finishing toast window token from package " + mPackageName, e);
        }
        if (callback != null) {
            try {
                callback.onToastHidden();
            } catch (RemoteException e) {
                Log.w(TAG, "Error calling back " + mPackageName + " to notify onToastHide()", e);
            }
        }
        mView = null;
        mToken = null;
    }
    }


    /**
    /**
+18 −78
Original line number Original line Diff line number Diff line
@@ -21,15 +21,13 @@ import android.annotation.Nullable;
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.res.Resources;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.util.Log;
import android.util.Log;
import android.view.View;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import android.widget.ToastPresenter;
import android.widget.ToastPresenter;


import com.android.internal.R;
import com.android.internal.R;
@@ -49,18 +47,14 @@ import javax.inject.Singleton;
public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
    private static final String TAG = "ToastUI";
    private static final String TAG = "ToastUI";


    /**
     * Values taken from {@link Toast}.
     */
    private static final long DURATION_SHORT = 4000;
    private static final long DURATION_LONG = 7000;

    private final CommandQueue mCommandQueue;
    private final CommandQueue mCommandQueue;
    private final WindowManager mWindowManager;
    private final WindowManager mWindowManager;
    private final INotificationManager mNotificationManager;
    private final INotificationManager mNotificationManager;
    private final AccessibilityManager mAccessibilityManager;
    private final AccessibilityManager mAccessibilityManager;
    private final ToastPresenter mPresenter;
    private final int mGravity;
    private ToastEntry mCurrentToast;
    private final int mY;
    @Nullable private ToastPresenter mPresenter;
    @Nullable private ITransientNotificationCallback mCallback;


    @Inject
    @Inject
    public ToastUI(Context context, CommandQueue commandQueue) {
    public ToastUI(Context context, CommandQueue commandQueue) {
@@ -79,7 +73,9 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
        mWindowManager = windowManager;
        mWindowManager = windowManager;
        mNotificationManager = notificationManager;
        mNotificationManager = notificationManager;
        mAccessibilityManager = accessibilityManager;
        mAccessibilityManager = accessibilityManager;
        mPresenter = new ToastPresenter(context, accessibilityManager);
        Resources resources = mContext.getResources();
        mGravity = resources.getInteger(R.integer.config_toastDefaultGravity);
        mY = resources.getDimensionPixelSize(R.dimen.toast_y_offset);
    }
    }


    @Override
    @Override
@@ -91,33 +87,21 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
    @MainThread
    @MainThread
    public void showToast(String packageName, IBinder token, CharSequence text,
    public void showToast(String packageName, IBinder token, CharSequence text,
            IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
            IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
        if (mCurrentToast != null) {
        if (mPresenter != null) {
            hideCurrentToast();
            hideCurrentToast();
        }
        }
        View view = mPresenter.getTextToastView(text);
        View view = ToastPresenter.getTextToastView(mContext, text);
        LayoutParams params = getLayoutParams(packageName, windowToken, duration);
        mCallback = callback;
        mCurrentToast = new ToastEntry(packageName, token, view, windowToken, callback);
        mPresenter = new ToastPresenter(mContext, mWindowManager, mAccessibilityManager,
        try {
                mNotificationManager, packageName);
            mWindowManager.addView(view, params);
        mPresenter.show(view, token, windowToken, duration, mGravity, 0, mY, 0, 0, mCallback);
        } catch (WindowManager.BadTokenException e) {
            Log.w(TAG, "Error while attempting to show toast from " + packageName, e);
            return;
        }
        mPresenter.trySendAccessibilityEvent(view, packageName);
        if (callback != null) {
            try {
                callback.onToastShown();
            } catch (RemoteException e) {
                Log.w(TAG, "Error calling back " + packageName + " to notify onToastShow()", e);
            }
        }
    }
    }


    @Override
    @Override
    @MainThread
    @MainThread
    public void hideToast(String packageName, IBinder token) {
    public void hideToast(String packageName, IBinder token) {
        if (mCurrentToast == null || !Objects.equals(mCurrentToast.packageName, packageName)
        if (mPresenter == null || !Objects.equals(mPresenter.getPackageName(), packageName)
                || !Objects.equals(mCurrentToast.token, token)) {
                || !Objects.equals(mPresenter.getToken(), token)) {
            Log.w(TAG, "Attempt to hide non-current toast from package " + packageName);
            Log.w(TAG, "Attempt to hide non-current toast from package " + packageName);
            return;
            return;
        }
        }
@@ -126,51 +110,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {


    @MainThread
    @MainThread
    private void hideCurrentToast() {
    private void hideCurrentToast() {
        if (mCurrentToast.view.getParent() != null) {
        mPresenter.hide(mCallback);
            mWindowManager.removeViewImmediate(mCurrentToast.view);
        mPresenter = null;
        }
        String packageName = mCurrentToast.packageName;
        try {
            mNotificationManager.finishToken(packageName, mCurrentToast.windowToken);
        } catch (RemoteException e) {
            Log.w(TAG, "Error finishing toast window token from package " + packageName, e);
        }
        if (mCurrentToast.callback != null) {
            try {
                mCurrentToast.callback.onToastHidden();
            } catch (RemoteException e) {
                Log.w(TAG, "Error calling back " + packageName + " to notify onToastHide()", e);
            }
        }
        mCurrentToast = null;
    }

    private LayoutParams getLayoutParams(String packageName, IBinder windowToken, int duration) {
        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        mPresenter.startLayoutParams(params, packageName);
        int gravity = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_toastDefaultGravity);
        int yOffset = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
        mPresenter.adjustLayoutParams(params, windowToken, duration, gravity, 0, yOffset, 0, 0);
        return params;
    }

    private static class ToastEntry {
        public final String packageName;
        public final IBinder token;
        public final View view;
        public final IBinder windowToken;

        @Nullable
        public final ITransientNotificationCallback callback;

        private ToastEntry(String packageName, IBinder token, View view, IBinder windowToken,
                @Nullable ITransientNotificationCallback callback) {
            this.packageName = packageName;
            this.token = token;
            this.view = view;
            this.windowToken = windowToken;
            this.callback = callback;
        }
    }
    }
}
}
+2 −2
Original line number Original line Diff line number Diff line
@@ -176,7 +176,7 @@ public class ToastUITest extends SysuiTestCase {


        mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
        mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);


        verify(mNotificationManager).finishToken(PACKAGE_NAME_1, WINDOW_TOKEN_1);
        verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
    }
    }


    @Test
    @Test
@@ -218,7 +218,7 @@ public class ToastUITest extends SysuiTestCase {
        mToastUI.showToast(PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG, null);
        mToastUI.showToast(PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG, null);


        verify(mWindowManager).removeViewImmediate(view);
        verify(mWindowManager).removeViewImmediate(view);
        verify(mNotificationManager).finishToken(PACKAGE_NAME_1, WINDOW_TOKEN_1);
        verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
        verify(mCallback).onToastHidden();
        verify(mCallback).onToastHidden();
    }
    }