Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(505)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java

Issue 1447313002: Add debug loggings to figure out a snackbar crash (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: respond to newt's comments Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkActivity.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.snackbar; 5 package org.chromium.chrome.browser.snackbar;
6 6
7 import android.annotation.TargetApi;
8 import android.app.Activity;
9 import android.content.Context;
7 import android.graphics.Rect; 10 import android.graphics.Rect;
11 import android.os.Build;
8 import android.os.Handler; 12 import android.os.Handler;
13 import android.util.AttributeSet;
9 import android.view.Gravity; 14 import android.view.Gravity;
10 import android.view.View; 15 import android.view.View;
11 import android.view.View.OnClickListener; 16 import android.view.View.OnClickListener;
12 import android.view.ViewTreeObserver.OnGlobalLayoutListener; 17 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
13 import android.view.Window; 18 import android.widget.LinearLayout;
14 19
15 import org.chromium.base.ApiCompatibilityUtils; 20 import org.chromium.base.ApiCompatibilityUtils;
16 import org.chromium.base.VisibleForTesting; 21 import org.chromium.base.VisibleForTesting;
17 import org.chromium.chrome.R; 22 import org.chromium.chrome.R;
18 import org.chromium.chrome.browser.ChromeActivity; 23 import org.chromium.chrome.browser.ChromeActivity;
19 import org.chromium.chrome.browser.device.DeviceClassManager; 24 import org.chromium.chrome.browser.device.DeviceClassManager;
20 import org.chromium.ui.UiUtils; 25 import org.chromium.ui.UiUtils;
21 import org.chromium.ui.base.DeviceFormFactor; 26 import org.chromium.ui.base.DeviceFormFactor;
22 27
23 import java.util.HashSet; 28 import java.util.HashSet;
24 import java.util.Stack; 29 import java.util.Stack;
25 30
26 /** 31 /**
27 * Manager for the snackbar showing at the bottom of activity. 32 * Manager for the snackbar showing at the bottom of activity.
28 * <p/> 33 * <p/>
29 * There should be only one SnackbarManager and one snackbar in the activity. Th e manager maintains 34 * There should be only one SnackbarManager and one snackbar in the activity. Th e manager maintains
30 * a stack to store all entries that should be displayed. When showing a new sna ckbar, old entry 35 * a stack to store all entries that should be displayed. When showing a new sna ckbar, old entry
31 * will be pushed to stack and text/button will be updated to the newest entry. 36 * will be pushed to stack and text/button will be updated to the newest entry.
32 * <p/> 37 * <p/>
33 * When action button is clicked, this manager will call 38 * When action button is clicked, this manager will call
34 * {@link SnackbarController#onAction(Object)} in corresponding listener, and sh ow the next 39 * {@link SnackbarController#onAction(Object)} in corresponding listener, and sh ow the next
35 * entry in stack. Otherwise if no action is taken by user during 40 * entry in stack. Otherwise if no action is taken by user during
36 * {@link #DEFAULT_SNACKBAR_DURATION_MS} milliseconds, it will clear the stack a nd call 41 * {@link #DEFAULT_SNACKBAR_DURATION_MS} milliseconds, it will clear the stack a nd call
37 * {@link SnackbarController#onDismissNoAction(Object)} to all listeners. 42 * {@link SnackbarController#onDismissNoAction(Object)} to all listeners.
38 */ 43 */
39 public class SnackbarManager implements OnClickListener, OnGlobalLayoutListener { 44 public class SnackbarManager implements OnClickListener, OnGlobalLayoutListener {
40 45
46 private static RuntimeException sWindowDetachTrace;
47
48 /**
49 * A {@link LinearLayout} that logs the stack trace when {@link #onDetachedF romWindow()} is
50 * called.
51 */
52 public static class WindowDismissalAwareLayout extends LinearLayout {
53 // TODO(ianwen): remove this class after crbug.com/553569 is fixed.
54 /**
55 * Constructor for XML inflation.
56 */
57 public WindowDismissalAwareLayout(Context context, AttributeSet attrs) {
58 super(context, attrs);
59 }
60
61 @Override
62 protected void onDetachedFromWindow() {
63 super.onDetachedFromWindow();
64 sWindowDetachTrace = new RuntimeException(
65 "Stacktrace for Snackbar view to be detached from window");
66 }
67 }
68
41 /** 69 /**
42 * Interface that shows the ability to provide a unified snackbar manager. 70 * Interface that shows the ability to provide a unified snackbar manager.
43 */ 71 */
44 public interface SnackbarManageable { 72 public interface SnackbarManageable {
45 /** 73 /**
46 * @return The snackbar manager that has a proper anchor view. 74 * @return The snackbar manager that has a proper anchor view.
47 */ 75 */
48 SnackbarManager getSnackbarManager(); 76 SnackbarManager getSnackbarManager();
49 } 77 }
50 78
(...skipping 24 matching lines...) Expand all
75 * Notify each SnackbarControllers instance only once immediately before the snackbar is 103 * Notify each SnackbarControllers instance only once immediately before the snackbar is
76 * dismissed. This function is likely to be used for controllers to do u ser metrics for 104 * dismissed. This function is likely to be used for controllers to do u ser metrics for
77 * dismissal. 105 * dismissal.
78 * @param isTimeout Whether this dismissal is triggered by timeout. 106 * @param isTimeout Whether this dismissal is triggered by timeout.
79 */ 107 */
80 void onDismissForEachType(boolean isTimeout); 108 void onDismissForEachType(boolean isTimeout);
81 } 109 }
82 110
83 private static final int DEFAULT_SNACKBAR_DURATION_MS = 3000; 111 private static final int DEFAULT_SNACKBAR_DURATION_MS = 3000;
84 private static final int ACCESSIBILITY_MODE_SNACKBAR_DURATION_MS = 6000; 112 private static final int ACCESSIBILITY_MODE_SNACKBAR_DURATION_MS = 6000;
113 private static final String TAG = "cr_snackbar";
85 114
86 // Used instead of the constant so tests can override the value. 115 // Used instead of the constant so tests can override the value.
87 private static int sSnackbarDurationMs = DEFAULT_SNACKBAR_DURATION_MS; 116 private static int sSnackbarDurationMs = DEFAULT_SNACKBAR_DURATION_MS;
88 private static int sAccessibilitySnackbarDurationMs = ACCESSIBILITY_MODE_SNA CKBAR_DURATION_MS; 117 private static int sAccessibilitySnackbarDurationMs = ACCESSIBILITY_MODE_SNA CKBAR_DURATION_MS;
89 118
90 private final boolean mIsTablet; 119 private final boolean mIsTablet;
91 120
121 private Activity mActivity;
92 private View mDecor; 122 private View mDecor;
93 private final Handler mUIThreadHandler; 123 private final Handler mUIThreadHandler;
94 private Stack<Snackbar> mStack = new Stack<Snackbar>(); 124 private Stack<Snackbar> mStack = new Stack<Snackbar>();
95 private SnackbarPopupWindow mPopup; 125 private SnackbarPopupWindow mPopup;
96 private final Runnable mHideRunnable = new Runnable() { 126 private final Runnable mHideRunnable = new Runnable() {
97 @Override 127 @Override
98 public void run() { 128 public void run() {
99 dismissAllSnackbars(true); 129 dismissAllSnackbars(true);
100 } 130 }
101 }; 131 };
102 132
103 // Variables used and reused in local calculations. 133 // Variables used and reused in local calculations.
104 private int[] mTempDecorPosition = new int[2]; 134 private int[] mTempDecorPosition = new int[2];
105 private Rect mTempVisibleDisplayFrame = new Rect(); 135 private Rect mTempVisibleDisplayFrame = new Rect();
106 136
107 /** 137 /**
108 * Constructs a SnackbarManager to show snackbars in the given window. 138 * Constructs a SnackbarManager to show snackbars in the given window.
109 */ 139 */
110 public SnackbarManager(Window window) { 140 public SnackbarManager(Activity activity) {
111 mDecor = window.getDecorView(); 141 mActivity = activity;
142 mDecor = activity.getWindow().getDecorView();
112 mUIThreadHandler = new Handler(); 143 mUIThreadHandler = new Handler();
113 mIsTablet = DeviceFormFactor.isTablet(mDecor.getContext()); 144 mIsTablet = DeviceFormFactor.isTablet(mDecor.getContext());
114 } 145 }
115 146
116 /** 147 /**
117 * Shows a snackbar at the bottom of the screen, or above the keyboard if th e keyboard is 148 * Shows a snackbar at the bottom of the screen, or above the keyboard if th e keyboard is
118 * visible. 149 * visible.
119 */ 150 */
120 public void showSnackbar(Snackbar snackbar) { 151 public void showSnackbar(Snackbar snackbar) {
121 int durationMs = snackbar.getDuration(); 152 int durationMs = snackbar.getDuration();
(...skipping 21 matching lines...) Expand all
143 * Warning: Calling this method might cause cascading destroy loop, because you might trigger 174 * Warning: Calling this method might cause cascading destroy loop, because you might trigger
144 * callbacks for other {@link SnackbarController}. This method is only meant to be used during 175 * callbacks for other {@link SnackbarController}. This method is only meant to be used during
145 * {@link ChromeActivity}'s destruction routine. For other purposes, use 176 * {@link ChromeActivity}'s destruction routine. For other purposes, use
146 * {@link #dismissSnackbars(SnackbarController)} instead. 177 * {@link #dismissSnackbars(SnackbarController)} instead.
147 * <p> 178 * <p>
148 * Dismisses all snackbars in stack. This will call 179 * Dismisses all snackbars in stack. This will call
149 * {@link SnackbarController#onDismissNoAction(Object)} for every closing sn ackbar. 180 * {@link SnackbarController#onDismissNoAction(Object)} for every closing sn ackbar.
150 * 181 *
151 * @param isTimeout Whether dismissal was triggered by timeout. 182 * @param isTimeout Whether dismissal was triggered by timeout.
152 */ 183 */
184 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
153 public void dismissAllSnackbars(boolean isTimeout) { 185 public void dismissAllSnackbars(boolean isTimeout) {
154 mUIThreadHandler.removeCallbacks(mHideRunnable); 186 mUIThreadHandler.removeCallbacks(mHideRunnable);
155 187
156 if (mPopup != null) { 188 if (mPopup != null) {
157 mPopup.dismiss(); 189 // TODO(ianwen): remove the try catch after crbug.com/553569 is fixe d.
190 try {
191 mPopup.dismiss();
192 } catch (IllegalArgumentException ex) {
193 if (mActivity != null) {
194 android.util.Log.d(TAG, "Activity.toString()? " + mActivity) ;
195 android.util.Log.d(TAG, "Activity is finishing? " + mActivit y.isFinishing());
196 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_ MR1) {
197 android.util.Log.d(TAG, "Activity is destroyed?" + mActi vity.isDestroyed());
198 }
199 }
200 if (sWindowDetachTrace != null) {
201 throw sWindowDetachTrace;
newt (away) 2015/11/18 01:46:54 If you throw sWindowDetachTrace then Chrome will c
Ian Wen 2015/11/18 01:56:26 Done.
202 }
203 throw ex;
204 }
205
158 mPopup = null; 206 mPopup = null;
159 } 207 }
160 208
161 HashSet<SnackbarController> controllers = new HashSet<SnackbarController >(); 209 HashSet<SnackbarController> controllers = new HashSet<SnackbarController >();
162 210
163 while (!mStack.isEmpty()) { 211 while (!mStack.isEmpty()) {
164 Snackbar snackbar = mStack.pop(); 212 Snackbar snackbar = mStack.pop();
165 if (!controllers.contains(snackbar.getController())) { 213 if (!controllers.contains(snackbar.getController())) {
166 snackbar.getController().onDismissForEachType(isTimeout); 214 snackbar.getController().onDismissForEachType(isTimeout);
167 controllers.add(snackbar.getController()); 215 controllers.add(snackbar.getController());
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 /** 344 /**
297 * Overrides the default snackbar duration with a custom value for testing. 345 * Overrides the default snackbar duration with a custom value for testing.
298 * @param durationMs The duration to use in ms. 346 * @param durationMs The duration to use in ms.
299 */ 347 */
300 @VisibleForTesting 348 @VisibleForTesting
301 public static void setDurationForTesting(int durationMs) { 349 public static void setDurationForTesting(int durationMs) {
302 sSnackbarDurationMs = durationMs; 350 sSnackbarDurationMs = durationMs;
303 sAccessibilitySnackbarDurationMs = durationMs; 351 sAccessibilitySnackbarDurationMs = durationMs;
304 } 352 }
305 } 353 }
OLDNEW
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkActivity.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698