Loading core/java/android/app/INotificationManager.aidl +2 −2 Original line number Original line Diff line number Diff line Loading @@ -50,8 +50,8 @@ interface INotificationManager void cancelAllNotifications(String pkg, int userId); void cancelAllNotifications(String pkg, int userId); void clearData(String pkg, int uid, boolean fromApp); void clearData(String pkg, int uid, boolean fromApp); void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, boolean isUiContext, int displayId, @nullable ITransientNotificationCallback callback); boolean enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, boolean isUiContext, int displayId, @nullable ITransientNotificationCallback callback); void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, boolean isUiContext, int displayId); boolean enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, boolean isUiContext, int displayId); void cancelToast(String pkg, IBinder token); void cancelToast(String pkg, IBinder token); void finishToken(String pkg, IBinder token); void finishToken(String pkg, IBinder token); Loading core/java/android/widget/Toast.java +98 −19 Original line number Original line Diff line number Diff line Loading @@ -45,8 +45,10 @@ import android.util.Log; import android.view.View; import android.view.View; import android.view.WindowManager; import android.view.WindowManager; import android.view.accessibility.IAccessibilityManager; import android.view.accessibility.IAccessibilityManager; import android.widget.flags.Flags; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -205,27 +207,41 @@ public class Toast { INotificationManager service = getService(); INotificationManager service = getService(); String pkg = mContext.getOpPackageName(); String pkg = mContext.getOpPackageName(); TN tn = mTN; TN tn = mTN; tn.mNextView = new WeakReference<>(mNextView); if (Flags.toastNoWeakref()) { tn.mNextView = mNextView; } else { tn.mNextViewWeakRef = new WeakReference<>(mNextView); } final boolean isUiContext = mContext.isUiContext(); final boolean isUiContext = mContext.isUiContext(); final int displayId = mContext.getDisplayId(); final int displayId = mContext.getDisplayId(); boolean wasEnqueued = false; try { try { if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { if (mNextView != null) { if (mNextView != null) { // It's a custom toast // It's a custom toast service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); wasEnqueued = service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); } else { } else { // It's a text toast // It's a text toast ITransientNotificationCallback callback = ITransientNotificationCallback callback = new CallbackBinder(mCallbacks, mHandler); new CallbackBinder(mCallbacks, mHandler); service.enqueueTextToast(pkg, mToken, mText, mDuration, isUiContext, displayId, wasEnqueued = service.enqueueTextToast(pkg, mToken, mText, mDuration, callback); isUiContext, displayId, callback); } } } else { } else { service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); wasEnqueued = service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); } } } catch (RemoteException e) { } catch (RemoteException e) { // Empty // Empty } finally { if (Flags.toastNoWeakref()) { if (!wasEnqueued) { tn.mNextViewWeakRef = null; tn.mNextView = null; } } } } } } Loading Loading @@ -581,6 +597,16 @@ public class Toast { } } } } /** * Get the Toast.TN ITransientNotification object * @return TN * @hide */ @VisibleForTesting public TN getTn() { return mTN; } // ======================================================================================= // ======================================================================================= // All the gunk below is the interaction with the Notification Service, which handles // All the gunk below is the interaction with the Notification Service, which handles // the proper ordering of these system-wide. // the proper ordering of these system-wide. Loading @@ -599,7 +625,11 @@ public class Toast { return sService; return sService; } } private static class TN extends ITransientNotification.Stub { /** * @hide */ @VisibleForTesting public static class TN extends ITransientNotification.Stub { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private final WindowManager.LayoutParams mParams; private final WindowManager.LayoutParams mParams; Loading @@ -620,7 +650,9 @@ public class Toast { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) View mView; View mView; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) WeakReference<View> mNextView; WeakReference<View> mNextViewWeakRef; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) View mNextView; int mDuration; int mDuration; WindowManager mWM; WindowManager mWM; Loading Loading @@ -662,14 +694,22 @@ public class Toast { handleHide(); handleHide(); // Don't do this in handleHide() because it is also invoked by // Don't do this in handleHide() because it is also invoked by // handleShow() // handleShow() if (Flags.toastNoWeakref()) { mNextView = null; mNextView = null; } else { mNextViewWeakRef = null; } break; break; } } case CANCEL: { case CANCEL: { handleHide(); handleHide(); // Don't do this in handleHide() because it is also invoked by // Don't do this in handleHide() because it is also invoked by // handleShow() // handleShow() if (Flags.toastNoWeakref()) { mNextView = null; mNextView = null; } else { mNextViewWeakRef = null; } try { try { getService().cancelToast(mPackageName, mToken); getService().cancelToast(mPackageName, mToken); } catch (RemoteException e) { } catch (RemoteException e) { Loading Loading @@ -716,17 +756,38 @@ public class Toast { } } public void handleShow(IBinder windowToken) { public void handleShow(IBinder windowToken) { if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView if (Flags.toastNoWeakref()) { if (localLOGV) { Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView=" + mNextView); + " mNextView=" + mNextView); } } else { if (localLOGV) { Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView=" + mNextViewWeakRef); } } // If a cancel/hide is pending - no need to show - at this point // If a cancel/hide is pending - no need to show - at this point // the window token is already invalid and no need to do any work. // the window token is already invalid and no need to do any work. if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { return; return; } } if (mNextView != null && mView != mNextView.get()) { if (Flags.toastNoWeakref()) { if (mNextView != null && mView != mNextView) { // remove the old view if necessary handleHide(); mView = mNextView; if (mView != null) { mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY, mHorizontalMargin, mVerticalMargin, new CallbackBinder(getCallbacks(), mHandler)); } } } else { if (mNextViewWeakRef != null && mView != mNextViewWeakRef.get()) { // remove the old view if necessary // remove the old view if necessary handleHide(); handleHide(); mView = mNextView.get(); mView = mNextViewWeakRef.get(); if (mView != null) { if (mView != null) { mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY, mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY, mHorizontalMargin, mVerticalMargin, mHorizontalMargin, mVerticalMargin, Loading @@ -734,6 +795,7 @@ public class Toast { } } } } } } } @UnsupportedAppUsage @UnsupportedAppUsage public void handleHide() { public void handleHide() { Loading @@ -745,6 +807,23 @@ public class Toast { mView = null; mView = null; } } } } /** * Get the next view to show for enqueued toasts * Custom toast views are deprecated. * @see #setView(View) * * @return next view * @hide */ @VisibleForTesting public View getNextView() { if (Flags.toastNoWeakref()) { return mNextView; } else { return (mNextViewWeakRef != null) ? mNextViewWeakRef.get() : null; } } } } /** /** Loading core/java/android/widget/flags/notification_widget_flags.aconfig +11 −1 Original line number Original line Diff line number Diff line Loading @@ -26,3 +26,13 @@ flag { purpose: PURPOSE_BUGFIX purpose: PURPOSE_BUGFIX } } } } flag { name: "toast_no_weakref" namespace: "systemui" description: "Do not use WeakReference for custom view Toast" bug: "321732224" metadata { purpose: PURPOSE_BUGFIX } } core/tests/mockingcoretests/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ android_test { "platform-test-annotations", "platform-test-annotations", "truth", "truth", "testables", "testables", "flag-junit", ], ], libs: [ libs: [ Loading core/tests/mockingcoretests/src/android/widget/OWNERS 0 → 100644 +1 −0 Original line number Original line Diff line number Diff line include /services/core/java/com/android/server/notification/OWNERS No newline at end of file Loading
core/java/android/app/INotificationManager.aidl +2 −2 Original line number Original line Diff line number Diff line Loading @@ -50,8 +50,8 @@ interface INotificationManager void cancelAllNotifications(String pkg, int userId); void cancelAllNotifications(String pkg, int userId); void clearData(String pkg, int uid, boolean fromApp); void clearData(String pkg, int uid, boolean fromApp); void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, boolean isUiContext, int displayId, @nullable ITransientNotificationCallback callback); boolean enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, boolean isUiContext, int displayId, @nullable ITransientNotificationCallback callback); void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, boolean isUiContext, int displayId); boolean enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, boolean isUiContext, int displayId); void cancelToast(String pkg, IBinder token); void cancelToast(String pkg, IBinder token); void finishToken(String pkg, IBinder token); void finishToken(String pkg, IBinder token); Loading
core/java/android/widget/Toast.java +98 −19 Original line number Original line Diff line number Diff line Loading @@ -45,8 +45,10 @@ import android.util.Log; import android.view.View; import android.view.View; import android.view.WindowManager; import android.view.WindowManager; import android.view.accessibility.IAccessibilityManager; import android.view.accessibility.IAccessibilityManager; import android.widget.flags.Flags; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -205,27 +207,41 @@ public class Toast { INotificationManager service = getService(); INotificationManager service = getService(); String pkg = mContext.getOpPackageName(); String pkg = mContext.getOpPackageName(); TN tn = mTN; TN tn = mTN; tn.mNextView = new WeakReference<>(mNextView); if (Flags.toastNoWeakref()) { tn.mNextView = mNextView; } else { tn.mNextViewWeakRef = new WeakReference<>(mNextView); } final boolean isUiContext = mContext.isUiContext(); final boolean isUiContext = mContext.isUiContext(); final int displayId = mContext.getDisplayId(); final int displayId = mContext.getDisplayId(); boolean wasEnqueued = false; try { try { if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { if (mNextView != null) { if (mNextView != null) { // It's a custom toast // It's a custom toast service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); wasEnqueued = service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); } else { } else { // It's a text toast // It's a text toast ITransientNotificationCallback callback = ITransientNotificationCallback callback = new CallbackBinder(mCallbacks, mHandler); new CallbackBinder(mCallbacks, mHandler); service.enqueueTextToast(pkg, mToken, mText, mDuration, isUiContext, displayId, wasEnqueued = service.enqueueTextToast(pkg, mToken, mText, mDuration, callback); isUiContext, displayId, callback); } } } else { } else { service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); wasEnqueued = service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); } } } catch (RemoteException e) { } catch (RemoteException e) { // Empty // Empty } finally { if (Flags.toastNoWeakref()) { if (!wasEnqueued) { tn.mNextViewWeakRef = null; tn.mNextView = null; } } } } } } Loading Loading @@ -581,6 +597,16 @@ public class Toast { } } } } /** * Get the Toast.TN ITransientNotification object * @return TN * @hide */ @VisibleForTesting public TN getTn() { return mTN; } // ======================================================================================= // ======================================================================================= // All the gunk below is the interaction with the Notification Service, which handles // All the gunk below is the interaction with the Notification Service, which handles // the proper ordering of these system-wide. // the proper ordering of these system-wide. Loading @@ -599,7 +625,11 @@ public class Toast { return sService; return sService; } } private static class TN extends ITransientNotification.Stub { /** * @hide */ @VisibleForTesting public static class TN extends ITransientNotification.Stub { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) private final WindowManager.LayoutParams mParams; private final WindowManager.LayoutParams mParams; Loading @@ -620,7 +650,9 @@ public class Toast { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) View mView; View mView; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) WeakReference<View> mNextView; WeakReference<View> mNextViewWeakRef; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) View mNextView; int mDuration; int mDuration; WindowManager mWM; WindowManager mWM; Loading Loading @@ -662,14 +694,22 @@ public class Toast { handleHide(); handleHide(); // Don't do this in handleHide() because it is also invoked by // Don't do this in handleHide() because it is also invoked by // handleShow() // handleShow() if (Flags.toastNoWeakref()) { mNextView = null; mNextView = null; } else { mNextViewWeakRef = null; } break; break; } } case CANCEL: { case CANCEL: { handleHide(); handleHide(); // Don't do this in handleHide() because it is also invoked by // Don't do this in handleHide() because it is also invoked by // handleShow() // handleShow() if (Flags.toastNoWeakref()) { mNextView = null; mNextView = null; } else { mNextViewWeakRef = null; } try { try { getService().cancelToast(mPackageName, mToken); getService().cancelToast(mPackageName, mToken); } catch (RemoteException e) { } catch (RemoteException e) { Loading Loading @@ -716,17 +756,38 @@ public class Toast { } } public void handleShow(IBinder windowToken) { public void handleShow(IBinder windowToken) { if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView if (Flags.toastNoWeakref()) { if (localLOGV) { Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView=" + mNextView); + " mNextView=" + mNextView); } } else { if (localLOGV) { Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView=" + mNextViewWeakRef); } } // If a cancel/hide is pending - no need to show - at this point // If a cancel/hide is pending - no need to show - at this point // the window token is already invalid and no need to do any work. // the window token is already invalid and no need to do any work. if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { return; return; } } if (mNextView != null && mView != mNextView.get()) { if (Flags.toastNoWeakref()) { if (mNextView != null && mView != mNextView) { // remove the old view if necessary handleHide(); mView = mNextView; if (mView != null) { mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY, mHorizontalMargin, mVerticalMargin, new CallbackBinder(getCallbacks(), mHandler)); } } } else { if (mNextViewWeakRef != null && mView != mNextViewWeakRef.get()) { // remove the old view if necessary // remove the old view if necessary handleHide(); handleHide(); mView = mNextView.get(); mView = mNextViewWeakRef.get(); if (mView != null) { if (mView != null) { mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY, mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY, mHorizontalMargin, mVerticalMargin, mHorizontalMargin, mVerticalMargin, Loading @@ -734,6 +795,7 @@ public class Toast { } } } } } } } @UnsupportedAppUsage @UnsupportedAppUsage public void handleHide() { public void handleHide() { Loading @@ -745,6 +807,23 @@ public class Toast { mView = null; mView = null; } } } } /** * Get the next view to show for enqueued toasts * Custom toast views are deprecated. * @see #setView(View) * * @return next view * @hide */ @VisibleForTesting public View getNextView() { if (Flags.toastNoWeakref()) { return mNextView; } else { return (mNextViewWeakRef != null) ? mNextViewWeakRef.get() : null; } } } } /** /** Loading
core/java/android/widget/flags/notification_widget_flags.aconfig +11 −1 Original line number Original line Diff line number Diff line Loading @@ -26,3 +26,13 @@ flag { purpose: PURPOSE_BUGFIX purpose: PURPOSE_BUGFIX } } } } flag { name: "toast_no_weakref" namespace: "systemui" description: "Do not use WeakReference for custom view Toast" bug: "321732224" metadata { purpose: PURPOSE_BUGFIX } }
core/tests/mockingcoretests/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ android_test { "platform-test-annotations", "platform-test-annotations", "truth", "truth", "testables", "testables", "flag-junit", ], ], libs: [ libs: [ Loading
core/tests/mockingcoretests/src/android/widget/OWNERS 0 → 100644 +1 −0 Original line number Original line Diff line number Diff line include /services/core/java/com/android/server/notification/OWNERS No newline at end of file