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

Commit 52af6db2 authored by Bernardo Rufino's avatar Bernardo Rufino
Browse files

Use IBinder token for indexing toasts instead of ITransientNotification

In preparation for text toasts, which won't contain a
ITransientNotification object associated with them, indexing toasts
by an IBinder token provided by the app.

Bug: 144754526
Bug: 128611929
Test: atest android.widget.cts.ToastTest
Change-Id: I8ec649066154f59bc28bcb49bb6f156eadb796d8
parent adb9ce4f
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -46,12 +46,10 @@ interface INotificationManager

    void clearData(String pkg, int uid, boolean fromApp);
    // TODO: Replace parameter (ITransientNotification callback) with (CharSequence text)
    void enqueueTextToast(String pkg, ITransientNotification callback, int duration, int displayId);
    @UnsupportedAppUsage
    void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId);
    @UnsupportedAppUsage
    void cancelToast(String pkg, ITransientNotification callback);
    void finishToken(String pkg, ITransientNotification callback);
    void enqueueTextToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId);
    void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId);
    void cancelToast(String pkg, IBinder token);
    void finishToken(String pkg, IBinder token);

    void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
            in Notification notification, int userId);
+13 −8
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -100,7 +101,8 @@ public class Toast {
     */
    public static final int LENGTH_LONG = 1;

    final Context mContext;
    private final Binder mToken;
    private final Context mContext;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    final TN mTN;
    @UnsupportedAppUsage
@@ -126,7 +128,8 @@ public class Toast {
     */
    public Toast(@NonNull Context context, @Nullable Looper looper) {
        mContext = context;
        mTN = new TN(context.getPackageName(), looper);
        mToken = new Binder();
        mTN = new TN(context.getPackageName(), mToken, looper);
        mTN.mY = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.toast_y_offset);
        mTN.mGravity = context.getResources().getInteger(
@@ -149,9 +152,9 @@ public class Toast {

        try {
            if (mIsCustomToast) {
                service.enqueueToast(pkg, tn, mDuration, displayId);
                service.enqueueToast(pkg, mToken, tn, mDuration, displayId);
            } else {
                service.enqueueTextToast(pkg, tn, mDuration, displayId);
                service.enqueueTextToast(pkg, mToken, tn, mDuration, displayId);
            }
        } catch (RemoteException e) {
            // Empty
@@ -416,7 +419,8 @@ public class Toast {

        WindowManager mWM;

        String mPackageName;
        final String mPackageName;
        final Binder mToken;

        @GuardedBy("mCallbacks")
        private final List<Callback> mCallbacks = new ArrayList<>();
@@ -424,7 +428,7 @@ public class Toast {
        static final long SHORT_DURATION_TIMEOUT = 4000;
        static final long LONG_DURATION_TIMEOUT = 7000;

        TN(String packageName, @Nullable Looper looper) {
        TN(String packageName, Binder token, @Nullable Looper looper) {
            // XXX This should be changed to use a Dialog, with a Theme.Toast
            // defined that sets up the layout params appropriately.
            final WindowManager.LayoutParams params = mParams;
@@ -440,6 +444,7 @@ public class Toast {
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

            mPackageName = packageName;
            mToken = token;

            if (looper == null) {
                // Use Looper.myLooper() if looper is not specified.
@@ -471,7 +476,7 @@ public class Toast {
                            // handleShow()
                            mNextView = null;
                            try {
                                getService().cancelToast(mPackageName, TN.this);
                                getService().cancelToast(mPackageName, mToken);
                            } catch (RemoteException e) {
                            }
                            break;
@@ -601,7 +606,7 @@ public class Toast {
                // Now that we've removed the view it's safe for the server to release
                // the resources.
                try {
                    getService().finishToken(mPackageName, this);
                    getService().finishToken(mPackageName, mToken);
                } catch (RemoteException e) {
                }

+50 −47
Original line number Diff line number Diff line
@@ -843,20 +843,22 @@ public class NotificationManagerService extends SystemService {

    private static final class ToastRecord
    {
        final int pid;
        final String pkg;
        final ITransientNotification callback;
        int duration;
        int displayId;
        Binder token;

        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
                Binder token, int displayId) {
        public final int pid;
        public final String pkg;
        public final IBinder token;
        public final ITransientNotification callback;
        public int duration;
        public int displayId;
        public Binder windowToken;

        ToastRecord(int pid, String pkg, IBinder token, ITransientNotification callback,
                int duration, Binder windowToken, int displayId) {
            this.pid = pid;
            this.pkg = pkg;
            this.token = token;
            this.callback = callback;
            this.duration = duration;
            this.token = token;
            this.windowToken = windowToken;
            this.displayId = displayId;
        }

@@ -875,8 +877,10 @@ public class NotificationManagerService extends SystemService {
            return "ToastRecord{"
                + Integer.toHexString(System.identityHashCode(this))
                + " pkg=" + pkg
                + " token=" + token
                + " callback=" + callback
                + " duration=" + duration;
                + " duration=" + duration
                + "}";
        }
    }

@@ -2558,26 +2562,27 @@ public class NotificationManagerService extends SystemService {
        // ============================================================================

        @Override
        public void enqueueTextToast(String pkg, ITransientNotification callback, int duration,
                int displayId) {
            enqueueToast(pkg, callback, duration, displayId, false);
        public void enqueueTextToast(String pkg, IBinder token, ITransientNotification callback,
                int duration, int displayId) {
            enqueueToast(pkg, token, callback, duration, displayId, false);
        }

        @Override
        public void enqueueToast(String pkg, ITransientNotification callback, int duration,
                int displayId) {
            enqueueToast(pkg, callback, duration, displayId, true);
        public void enqueueToast(String pkg, IBinder token, ITransientNotification callback,
                int duration, int displayId) {
            enqueueToast(pkg, token, callback, duration, displayId, true);
        }

        private void enqueueToast(String pkg, ITransientNotification callback, int duration,
                int displayId, boolean isCustomToast) {
        private void enqueueToast(String pkg, IBinder token, ITransientNotification callback,
                int duration, int displayId, boolean isCustomToast) {
            if (DBG) {
                Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
                        + " duration=" + duration + " displayId=" + displayId);
            }

            if (pkg == null || callback == null) {
                Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback);
            if (pkg == null || callback == null || token == null) {
                Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback + " token="
                        + token);
                return ;
            }

@@ -2635,7 +2640,7 @@ public class NotificationManagerService extends SystemService {
                long callingId = Binder.clearCallingIdentity();
                try {
                    ToastRecord record;
                    int index = indexOfToastLocked(pkg, callback);
                    int index = indexOfToastLocked(pkg, token);
                    // If it's already in the queue, we update it in place, we don't
                    // move it to the end of the queue.
                    if (index >= 0) {
@@ -2660,10 +2665,10 @@ public class NotificationManagerService extends SystemService {
                            }
                        }

                        Binder token = new Binder();
                        mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, displayId);
                        record = new ToastRecord(callingPid, pkg, callback, duration, token,
                                displayId);
                        Binder windowToken = new Binder();
                        mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId);
                        record = new ToastRecord(callingPid, pkg, token, callback, duration,
                                windowToken, displayId);
                        mToastQueue.add(record);
                        index = mToastQueue.size() - 1;
                        keepProcessAliveIfNeededLocked(callingPid);
@@ -2682,23 +2687,23 @@ public class NotificationManagerService extends SystemService {
        }

        @Override
        public void cancelToast(String pkg, ITransientNotification callback) {
            Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
        public void cancelToast(String pkg, IBinder token) {
            Slog.i(TAG, "cancelToast pkg=" + pkg + " token=" + token);

            if (pkg == null || callback == null) {
                Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
            if (pkg == null || token == null) {
                Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " token=" + token);
                return ;
            }

            synchronized (mToastQueue) {
                long callingId = Binder.clearCallingIdentity();
                try {
                    int index = indexOfToastLocked(pkg, callback);
                    int index = indexOfToastLocked(pkg, token);
                    if (index >= 0) {
                        cancelToastLocked(index);
                    } else {
                        Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
                                + " callback=" + callback);
                                + " token=" + token);
                    }
                } finally {
                    Binder.restoreCallingIdentity(callingId);
@@ -2707,17 +2712,17 @@ public class NotificationManagerService extends SystemService {
        }

        @Override
        public void finishToken(String pkg, ITransientNotification callback) {
        public void finishToken(String pkg, IBinder token) {
            synchronized (mToastQueue) {
                long callingId = Binder.clearCallingIdentity();
                try {
                    int index = indexOfToastLocked(pkg, callback);
                    int index = indexOfToastLocked(pkg, token);
                    if (index >= 0) {
                        ToastRecord record = mToastQueue.get(index);
                        finishTokenLocked(record.token, record.displayId);
                        finishWindowTokenLocked(record.windowToken, record.displayId);
                    } else {
                        Slog.w(TAG, "Toast already killed. pkg=" + pkg
                                + " callback=" + callback);
                                + " token=" + token);
                    }
                } finally {
                    Binder.restoreCallingIdentity(callingId);
@@ -6753,7 +6758,7 @@ public class NotificationManagerService extends SystemService {
        while (record != null) {
            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
            try {
                record.callback.show(record.token);
                record.callback.show(record.windowToken);
                scheduleDurationReachedLocked(record);
                return;
            } catch (RemoteException e) {
@@ -6788,7 +6793,7 @@ public class NotificationManagerService extends SystemService {

        ToastRecord lastToast = mToastQueue.remove(index);

        mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
        mWindowManagerInternal.removeWindowToken(lastToast.windowToken, false /* removeWindows */,
                lastToast.displayId);
        // We passed 'false' for 'removeWindows' so that the client has time to stop
        // rendering (as hide above is a one-way message), otherwise we could crash
@@ -6806,7 +6811,7 @@ public class NotificationManagerService extends SystemService {
        }
    }

    void finishTokenLocked(IBinder t, int displayId) {
    void finishWindowTokenLocked(IBinder t, int displayId) {
        mHandler.removeCallbacksAndMessages(t);
        // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
        // remaining surfaces as either the client has called finishToken indicating
@@ -6831,9 +6836,9 @@ public class NotificationManagerService extends SystemService {

    private void handleDurationReached(ToastRecord record)
    {
        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " token=" + record.token);
        synchronized (mToastQueue) {
            int index = indexOfToastLocked(record.pkg, record.callback);
            int index = indexOfToastLocked(record.pkg, record.token);
            if (index >= 0) {
                cancelToastLocked(index);
            }
@@ -6850,21 +6855,19 @@ public class NotificationManagerService extends SystemService {

    private void handleKillTokenTimeout(ToastRecord record)
    {
        if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.token);
        if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.windowToken);
        synchronized (mToastQueue) {
            finishTokenLocked(record.token, record.displayId);
            finishWindowTokenLocked(record.windowToken, record.displayId);
        }
    }

    @GuardedBy("mToastQueue")
    int indexOfToastLocked(String pkg, ITransientNotification callback)
    {
        IBinder cbak = callback.asBinder();
    int indexOfToastLocked(String pkg, IBinder token) {
        ArrayList<ToastRecord> list = mToastQueue;
        int len = list.size();
        for (int i=0; i<len; i++) {
            ToastRecord r = list.get(i);
            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
            if (r.pkg.equals(pkg) && r.token == token) {
                return i;
            }
        }
+4 −4
Original line number Diff line number Diff line
@@ -4397,7 +4397,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_FOREGROUND);

        // enqueue toast -> toast should still enqueue
        ((INotificationManager)mService.mService).enqueueToast(testPackage,
        ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
                new TestableToastCallback(), 2000, 0);
        assertEquals(1, mService.mToastQueue.size());
    }
@@ -4417,7 +4417,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_LOW);

        // enqueue toast -> no toasts enqueued
        ((INotificationManager)mService.mService).enqueueToast(testPackage,
        ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
                new TestableToastCallback(), 2000, 0);
        assertEquals(0, mService.mToastQueue.size());
    }
@@ -4440,7 +4440,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_GONE);

        // enqueue toast -> no toasts enqueued
        ((INotificationManager)mService.mService).enqueueToast(testPackage,
        ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
                new TestableToastCallback(), 2000, 0);
        assertEquals(0, mService.mToastQueue.size());
    }
@@ -4463,7 +4463,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_GONE);

        // enqueue toast -> system toast can still be enqueued
        ((INotificationManager)mService.mService).enqueueToast(testPackage,
        ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
                new TestableToastCallback(), 2000, 0);
        assertEquals(1, mService.mToastQueue.size());
    }