Loading core/java/android/widget/Toast.java +17 −10 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ import com.android.internal.annotations.GuardedBy; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; Loading Loading @@ -205,7 +206,7 @@ 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 = mNextView; tn.mNextView = new WeakReference<>(mNextView); final boolean isUiContext = mContext.isUiContext(); final boolean isUiContext = mContext.isUiContext(); final int displayId = mContext.getDisplayId(); final int displayId = mContext.getDisplayId(); Loading Loading @@ -622,7 +623,7 @@ 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) View mNextView; WeakReference<View> mNextView; int mDuration; int mDuration; WindowManager mWM; WindowManager mWM; Loading @@ -632,7 +633,7 @@ public class Toast { private final ToastPresenter mPresenter; private final ToastPresenter mPresenter; @GuardedBy("mCallbacks") @GuardedBy("mCallbacks") private final List<Callback> mCallbacks; private final WeakReference<List<Callback>> mCallbacks; /** /** * Creates a {@link ITransientNotification} object. * Creates a {@link ITransientNotification} object. Loading @@ -649,7 +650,7 @@ public class Toast { mParams = mPresenter.getLayoutParams(); mParams = mPresenter.getLayoutParams(); mPackageName = packageName; mPackageName = packageName; mToken = token; mToken = token; mCallbacks = callbacks; mCallbacks = new WeakReference<>(callbacks); mHandler = new Handler(looper, null) { mHandler = new Handler(looper, null) { @Override @Override Loading Loading @@ -685,7 +686,11 @@ public class Toast { private List<Callback> getCallbacks() { private List<Callback> getCallbacks() { synchronized (mCallbacks) { synchronized (mCallbacks) { return new ArrayList<>(mCallbacks); if (mCallbacks.get() != null) { return new ArrayList<>(mCallbacks.get()); } else { return new ArrayList<>(); } } } } } Loading Loading @@ -721,15 +726,17 @@ public class Toast { if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { return; return; } } if (mView != mNextView) { if (mNextView != null && mView != mNextView.get()) { // remove the old view if necessary // remove the old view if necessary handleHide(); handleHide(); mView = mNextView; mView = mNextView.get(); 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, new CallbackBinder(getCallbacks(), mHandler)); new CallbackBinder(getCallbacks(), mHandler)); } } } } } @UnsupportedAppUsage @UnsupportedAppUsage public void handleHide() { public void handleHide() { Loading core/java/android/widget/ToastPresenter.java +31 −19 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,8 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import java.lang.ref.WeakReference; /** /** * Class responsible for toast presentation inside app's process and in system UI. * Class responsible for toast presentation inside app's process and in system UI. * * Loading Loading @@ -87,25 +89,33 @@ public class ToastPresenter { return view; return view; } } private final Context mContext; private final Resources mResources; private final Resources mResources; private final WindowManager mWindowManager; private final WeakReference<WindowManager> mWindowManager; private final IAccessibilityManager mAccessibilityManager; private final WeakReference<AccessibilityManager> mAccessibilityManager; private final INotificationManager mNotificationManager; private final INotificationManager mNotificationManager; private final String mPackageName; private final String mPackageName; private final String mContextPackageName; private final WindowManager.LayoutParams mParams; private final WindowManager.LayoutParams mParams; @Nullable private View mView; @Nullable private View mView; @Nullable private IBinder mToken; @Nullable private IBinder mToken; public ToastPresenter(Context context, IAccessibilityManager accessibilityManager, public ToastPresenter(Context context, IAccessibilityManager accessibilityManager, INotificationManager notificationManager, String packageName) { INotificationManager notificationManager, String packageName) { mContext = context; mResources = context.getResources(); mResources = context.getResources(); mWindowManager = context.getSystemService(WindowManager.class); mWindowManager = new WeakReference<>(context.getSystemService(WindowManager.class)); mNotificationManager = notificationManager; mNotificationManager = notificationManager; mPackageName = packageName; mPackageName = packageName; mAccessibilityManager = accessibilityManager; mContextPackageName = context.getPackageName(); mParams = createLayoutParams(); mParams = createLayoutParams(); // We obtain AccessibilityManager manually via its constructor instead of using method // AccessibilityManager.getInstance() for 2 reasons: // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior. // 2. getInstance() caches the instance for the process even if we pass a different // context to it. This is problematic for multi-user because callers can pass a context // created via Context.createContextAsUser(). mAccessibilityManager = new WeakReference<>( new AccessibilityManager(context, accessibilityManager, context.getUserId())); } } public String getPackageName() { public String getPackageName() { Loading Loading @@ -173,7 +183,7 @@ public class ToastPresenter { params.y = yOffset; params.y = yOffset; params.horizontalMargin = horizontalMargin; params.horizontalMargin = horizontalMargin; params.verticalMargin = verticalMargin; params.verticalMargin = verticalMargin; params.packageName = mContext.getPackageName(); params.packageName = mContextPackageName; params.hideTimeoutMilliseconds = params.hideTimeoutMilliseconds = (duration == Toast.LENGTH_LONG) ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; (duration == Toast.LENGTH_LONG) ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; params.token = windowToken; params.token = windowToken; Loading Loading @@ -270,8 +280,9 @@ public class ToastPresenter { public void hide(@Nullable ITransientNotificationCallback callback) { public void hide(@Nullable ITransientNotificationCallback callback) { checkState(mView != null, "No toast to hide."); checkState(mView != null, "No toast to hide."); if (mView.getParent() != null) { final WindowManager windowManager = mWindowManager.get(); mWindowManager.removeViewImmediate(mView); if (mView.getParent() != null && windowManager != null) { windowManager.removeViewImmediate(mView); } } try { try { mNotificationManager.finishToken(mPackageName, mToken); mNotificationManager.finishToken(mPackageName, mToken); Loading @@ -295,14 +306,11 @@ public class ToastPresenter { * enabled. * enabled. */ */ public void trySendAccessibilityEvent(View view, String packageName) { public void trySendAccessibilityEvent(View view, String packageName) { // We obtain AccessibilityManager manually via its constructor instead of using method final AccessibilityManager accessibilityManager = mAccessibilityManager.get(); // AccessibilityManager.getInstance() for 2 reasons: if (accessibilityManager == null) { // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior. return; // 2. getInstance() caches the instance for the process even if we pass a different } // context to it. This is problematic for multi-user because callers can pass a context // created via Context.createContextAsUser(). final AccessibilityManager accessibilityManager = new AccessibilityManager(mContext, mAccessibilityManager, mContext.getUserId()); if (!accessibilityManager.isEnabled()) { if (!accessibilityManager.isEnabled()) { accessibilityManager.removeClient(); accessibilityManager.removeClient(); return; return; Loading @@ -320,11 +328,15 @@ public class ToastPresenter { } } private void addToastView() { private void addToastView() { final WindowManager windowManager = mWindowManager.get(); if (windowManager == null) { return; } if (mView.getParent() != null) { if (mView.getParent() != null) { mWindowManager.removeView(mView); windowManager.removeView(mView); } } try { try { mWindowManager.addView(mView, mParams); windowManager.addView(mView, mParams); } catch (WindowManager.BadTokenException e) { } catch (WindowManager.BadTokenException e) { // Since the notification manager service cancels the token right after it notifies us // 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 // to cancel the toast there is an inherent race and we may attempt to add a window Loading Loading
core/java/android/widget/Toast.java +17 −10 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ import com.android.internal.annotations.GuardedBy; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; Loading Loading @@ -205,7 +206,7 @@ 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 = mNextView; tn.mNextView = new WeakReference<>(mNextView); final boolean isUiContext = mContext.isUiContext(); final boolean isUiContext = mContext.isUiContext(); final int displayId = mContext.getDisplayId(); final int displayId = mContext.getDisplayId(); Loading Loading @@ -622,7 +623,7 @@ 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) View mNextView; WeakReference<View> mNextView; int mDuration; int mDuration; WindowManager mWM; WindowManager mWM; Loading @@ -632,7 +633,7 @@ public class Toast { private final ToastPresenter mPresenter; private final ToastPresenter mPresenter; @GuardedBy("mCallbacks") @GuardedBy("mCallbacks") private final List<Callback> mCallbacks; private final WeakReference<List<Callback>> mCallbacks; /** /** * Creates a {@link ITransientNotification} object. * Creates a {@link ITransientNotification} object. Loading @@ -649,7 +650,7 @@ public class Toast { mParams = mPresenter.getLayoutParams(); mParams = mPresenter.getLayoutParams(); mPackageName = packageName; mPackageName = packageName; mToken = token; mToken = token; mCallbacks = callbacks; mCallbacks = new WeakReference<>(callbacks); mHandler = new Handler(looper, null) { mHandler = new Handler(looper, null) { @Override @Override Loading Loading @@ -685,7 +686,11 @@ public class Toast { private List<Callback> getCallbacks() { private List<Callback> getCallbacks() { synchronized (mCallbacks) { synchronized (mCallbacks) { return new ArrayList<>(mCallbacks); if (mCallbacks.get() != null) { return new ArrayList<>(mCallbacks.get()); } else { return new ArrayList<>(); } } } } } Loading Loading @@ -721,15 +726,17 @@ public class Toast { if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { return; return; } } if (mView != mNextView) { if (mNextView != null && mView != mNextView.get()) { // remove the old view if necessary // remove the old view if necessary handleHide(); handleHide(); mView = mNextView; mView = mNextView.get(); 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, new CallbackBinder(getCallbacks(), mHandler)); new CallbackBinder(getCallbacks(), mHandler)); } } } } } @UnsupportedAppUsage @UnsupportedAppUsage public void handleHide() { public void handleHide() { Loading
core/java/android/widget/ToastPresenter.java +31 −19 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,8 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import java.lang.ref.WeakReference; /** /** * Class responsible for toast presentation inside app's process and in system UI. * Class responsible for toast presentation inside app's process and in system UI. * * Loading Loading @@ -87,25 +89,33 @@ public class ToastPresenter { return view; return view; } } private final Context mContext; private final Resources mResources; private final Resources mResources; private final WindowManager mWindowManager; private final WeakReference<WindowManager> mWindowManager; private final IAccessibilityManager mAccessibilityManager; private final WeakReference<AccessibilityManager> mAccessibilityManager; private final INotificationManager mNotificationManager; private final INotificationManager mNotificationManager; private final String mPackageName; private final String mPackageName; private final String mContextPackageName; private final WindowManager.LayoutParams mParams; private final WindowManager.LayoutParams mParams; @Nullable private View mView; @Nullable private View mView; @Nullable private IBinder mToken; @Nullable private IBinder mToken; public ToastPresenter(Context context, IAccessibilityManager accessibilityManager, public ToastPresenter(Context context, IAccessibilityManager accessibilityManager, INotificationManager notificationManager, String packageName) { INotificationManager notificationManager, String packageName) { mContext = context; mResources = context.getResources(); mResources = context.getResources(); mWindowManager = context.getSystemService(WindowManager.class); mWindowManager = new WeakReference<>(context.getSystemService(WindowManager.class)); mNotificationManager = notificationManager; mNotificationManager = notificationManager; mPackageName = packageName; mPackageName = packageName; mAccessibilityManager = accessibilityManager; mContextPackageName = context.getPackageName(); mParams = createLayoutParams(); mParams = createLayoutParams(); // We obtain AccessibilityManager manually via its constructor instead of using method // AccessibilityManager.getInstance() for 2 reasons: // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior. // 2. getInstance() caches the instance for the process even if we pass a different // context to it. This is problematic for multi-user because callers can pass a context // created via Context.createContextAsUser(). mAccessibilityManager = new WeakReference<>( new AccessibilityManager(context, accessibilityManager, context.getUserId())); } } public String getPackageName() { public String getPackageName() { Loading Loading @@ -173,7 +183,7 @@ public class ToastPresenter { params.y = yOffset; params.y = yOffset; params.horizontalMargin = horizontalMargin; params.horizontalMargin = horizontalMargin; params.verticalMargin = verticalMargin; params.verticalMargin = verticalMargin; params.packageName = mContext.getPackageName(); params.packageName = mContextPackageName; params.hideTimeoutMilliseconds = params.hideTimeoutMilliseconds = (duration == Toast.LENGTH_LONG) ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; (duration == Toast.LENGTH_LONG) ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; params.token = windowToken; params.token = windowToken; Loading Loading @@ -270,8 +280,9 @@ public class ToastPresenter { public void hide(@Nullable ITransientNotificationCallback callback) { public void hide(@Nullable ITransientNotificationCallback callback) { checkState(mView != null, "No toast to hide."); checkState(mView != null, "No toast to hide."); if (mView.getParent() != null) { final WindowManager windowManager = mWindowManager.get(); mWindowManager.removeViewImmediate(mView); if (mView.getParent() != null && windowManager != null) { windowManager.removeViewImmediate(mView); } } try { try { mNotificationManager.finishToken(mPackageName, mToken); mNotificationManager.finishToken(mPackageName, mToken); Loading @@ -295,14 +306,11 @@ public class ToastPresenter { * enabled. * enabled. */ */ public void trySendAccessibilityEvent(View view, String packageName) { public void trySendAccessibilityEvent(View view, String packageName) { // We obtain AccessibilityManager manually via its constructor instead of using method final AccessibilityManager accessibilityManager = mAccessibilityManager.get(); // AccessibilityManager.getInstance() for 2 reasons: if (accessibilityManager == null) { // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior. return; // 2. getInstance() caches the instance for the process even if we pass a different } // context to it. This is problematic for multi-user because callers can pass a context // created via Context.createContextAsUser(). final AccessibilityManager accessibilityManager = new AccessibilityManager(mContext, mAccessibilityManager, mContext.getUserId()); if (!accessibilityManager.isEnabled()) { if (!accessibilityManager.isEnabled()) { accessibilityManager.removeClient(); accessibilityManager.removeClient(); return; return; Loading @@ -320,11 +328,15 @@ public class ToastPresenter { } } private void addToastView() { private void addToastView() { final WindowManager windowManager = mWindowManager.get(); if (windowManager == null) { return; } if (mView.getParent() != null) { if (mView.getParent() != null) { mWindowManager.removeView(mView); windowManager.removeView(mView); } } try { try { mWindowManager.addView(mView, mParams); windowManager.addView(mView, mParams); } catch (WindowManager.BadTokenException e) { } catch (WindowManager.BadTokenException e) { // Since the notification manager service cancels the token right after it notifies us // 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 // to cancel the toast there is an inherent race and we may attempt to add a window Loading