Skip to content

Commit

Permalink
Merge pull request #1054 from square/py/toast_no_crash
Browse files Browse the repository at this point in the history
Avoid Toast crashes
  • Loading branch information
pyricau authored Jul 20, 2018
2 parents 4ad85aa + c9ebc5c commit 5073a1b
Showing 1 changed file with 87 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,26 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
import android.os.SystemClock;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import com.squareup.leakcanary.internal.FutureResult;
import com.squareup.leakcanary.internal.LeakCanaryInternals;
import java.io.File;

import static android.view.accessibility.AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
import static java.util.concurrent.TimeUnit.SECONDS;

public final class AndroidHeapDumper implements HeapDumper {
Expand Down Expand Up @@ -89,7 +97,7 @@ private void showToast(final FutureResult<Toast> waitingForToast) {
toast.setDuration(Toast.LENGTH_LONG);
LayoutInflater inflater = LayoutInflater.from(context);
toast.setView(inflater.inflate(R.layout.leak_canary_heap_dump_toast, null));
toast.show();
show(toast);
// Waiting for Idle to make sure Toast gets rendered.
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override public boolean queueIdle() {
Expand All @@ -104,8 +112,85 @@ private void showToast(final FutureResult<Toast> waitingForToast) {
private void cancelToast(final Toast toast) {
mainHandler.post(new Runnable() {
@Override public void run() {
toast.cancel();
hide(toast);
}
});
}

private void show(Toast toast) {
View view = toast.getView();
Context context = toast.getView().getContext();

WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

// We can resolve the Gravity here by using the Locale for getting
// the layout direction
Configuration config = view.getContext().getResources().getConfiguration();
int gravity = toast.getGravity();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
gravity = Gravity.getAbsoluteGravity(gravity, config.getLayoutDirection());
}

WindowManager.LayoutParams params = buildLayoutParams();
params.gravity = gravity;
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
params.horizontalWeight = 1.0f;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
params.verticalWeight = 1.0f;
}
params.x = toast.getXOffset();
params.y = toast.getYOffset();
params.verticalMargin = toast.getVerticalMargin();
params.horizontalMargin = toast.getHorizontalMargin();
params.packageName = context.getPackageName();
try {
windowManager.addView(view, params);
} catch (WindowManager.BadTokenException e) {
CanaryLog.d(e, "Could not show leak toast, the window token has been canceled");
return;
}
trySendAccessibilityEvent(view);
}

private void hide(Toast toast) {
View view = toast.getView();
if (view.getParent() != null) {
Context context = toast.getView().getContext();
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
windowManager.removeView(view);
}
}

private WindowManager.LayoutParams buildLayoutParams() {
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
params.windowAnimations = android.R.style.Animation_Toast;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.setTitle("Toast");
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
return params;
}

private void trySendAccessibilityEvent(View view) {
Context context = view.getContext();
AccessibilityManager accessibilityManager =
(AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
if (!accessibilityManager.isEnabled()) {
return;
}
// treat toasts as notifications since they are used to
// announce a transient piece of information to the user
AccessibilityEvent event = AccessibilityEvent.obtain(TYPE_NOTIFICATION_STATE_CHANGED);
event.setClassName(getClass().getName());
event.setPackageName(context.getPackageName());
view.dispatchPopulateAccessibilityEvent(event);
accessibilityManager.sendAccessibilityEvent(event);
}


}

0 comments on commit 5073a1b

Please sign in to comment.