Merge "Fix Toast memory leaks" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
6488edd6ab
@@ -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;
|
||||||
|
|
||||||
@@ -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();
|
||||||
|
|
||||||
@@ -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;
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
@@ -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<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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.
|
||||||
*
|
*
|
||||||
@@ -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() {
|
||||||
@@ -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;
|
||||||
@@ -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);
|
||||||
@@ -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;
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user