Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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.tab; | 5 package org.chromium.chrome.browser.tab; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.support.annotation.StringRes; | 8 import android.graphics.Canvas; |
| 9 import android.graphics.Paint; | |
| 10 import android.support.annotation.IntDef; | |
| 11 import android.text.Layout; | |
| 12 import android.text.SpannableString; | |
| 13 import android.text.TextUtils; | |
| 9 import android.text.method.LinkMovementMethod; | 14 import android.text.method.LinkMovementMethod; |
| 15 import android.text.style.BulletSpan; | |
| 10 import android.view.LayoutInflater; | 16 import android.view.LayoutInflater; |
| 11 import android.view.View; | 17 import android.view.View; |
| 12 import android.view.View.OnClickListener; | 18 import android.view.View.OnClickListener; |
| 13 import android.widget.Button; | 19 import android.widget.Button; |
| 14 import android.widget.TextView; | 20 import android.widget.TextView; |
| 15 | 21 |
| 22 import org.chromium.base.metrics.RecordHistogram; | |
| 16 import org.chromium.chrome.R; | 23 import org.chromium.chrome.R; |
| 17 import org.chromium.ui.text.NoUnderlineClickableSpan; | 24 import org.chromium.ui.text.NoUnderlineClickableSpan; |
| 18 import org.chromium.ui.text.SpanApplier; | 25 import org.chromium.ui.text.SpanApplier; |
| 19 import org.chromium.ui.text.SpanApplier.SpanInfo; | 26 import org.chromium.ui.text.SpanApplier.SpanInfo; |
| 20 | 27 |
| 28 import java.lang.annotation.Retention; | |
| 29 import java.lang.annotation.RetentionPolicy; | |
| 30 | |
| 21 /** | 31 /** |
| 22 * A factory class for creating the "Sad Tab" view, which is shown in place of a crashed renderer. | 32 * A factory class for creating the "Sad Tab" view, which is shown in place of a crashed renderer. |
| 23 */ | 33 */ |
| 24 public class SadTabViewFactory { | 34 public class SadTabViewFactory { |
| 35 // This IntDef backs an UMA histogram, so it should be treated as append-onl y. | |
| 36 // A native counterpart exists in sad_tab.cc. | |
| 37 @IntDef({SAD_TAB_EVENT_DISPLAYED, SAD_TAB_EVENT_BUTTON_CLICKED, | |
|
Ted C
2017/05/10 15:59:46
can we generate the enum in java from the c++ side
Theresa
2017/05/10 18:20:22
Done.
| |
| 38 SAD_TAB_EVENT_HELP_LINK_CLICKED}) | |
| 39 @Retention(RetentionPolicy.SOURCE) | |
| 40 public @interface SadTabEvent {} | |
| 41 public static final int SAD_TAB_EVENT_DISPLAYED = 0; | |
| 42 public static final int SAD_TAB_EVENT_BUTTON_CLICKED = 1; | |
| 43 public static final int SAD_TAB_EVENT_HELP_LINK_CLICKED = 2; | |
| 44 private static final int MAX_SAD_TAB_EVENT = 3; | |
| 25 | 45 |
| 26 /** | 46 /** |
| 27 * @param context Context of the resulting Sad Tab view. | 47 * @param context Context of the resulting Sad Tab view. |
| 28 * @param suggestionAction Action to be executed when user clicks "try these suggestions". | 48 * @param suggestionAction Action to be executed when user clicks "try these suggestions". |
| 29 * @param reloadButtonAction Action to be executed when Reload button is pre ssed. | 49 * @param reloadButtonAction Action to be executed when Reload button is pre ssed. |
| 30 * (e.g., refreshing the page) | 50 * (e.g., refreshing the page) |
| 31 * @param buttonTextId The string resource for the button text label. | 51 * @param showSendFeedbackView Whether to show the "send feedback" version o f the Sad Tab view. |
| 32 * @return A "Sad Tab" view instance which is used in place of a crashed ren derer. | 52 * @return A "Sad Tab" view instance which is used in place of a crashed ren derer. |
| 33 */ | 53 */ |
| 34 public static View createSadTabView( | 54 public static View createSadTabView(Context context, final OnClickListener s uggestionAction, |
| 35 Context context, final OnClickListener suggestionAction, | 55 OnClickListener reloadButtonAction, boolean showSendFeedbackView) { |
|
Ted C
2017/05/10 15:59:46
Seeing that we need to expose the UMA events to be
Theresa
2017/05/10 18:20:21
Done.
| |
| 36 OnClickListener reloadButtonAction, @StringRes int buttonTextId) { | |
| 37 // Inflate Sad tab and initialize. | 56 // Inflate Sad tab and initialize. |
| 38 LayoutInflater inflater = (LayoutInflater) context.getSystemService( | 57 LayoutInflater inflater = (LayoutInflater) context.getSystemService( |
| 39 Context.LAYOUT_INFLATER_SERVICE); | 58 Context.LAYOUT_INFLATER_SERVICE); |
| 40 View sadTabView = inflater.inflate(R.layout.sad_tab, null); | 59 View sadTabView = inflater.inflate(R.layout.sad_tab, null); |
| 41 | 60 |
| 61 TextView titleText = (TextView) sadTabView.findViewById(R.id.sad_tab_tit le); | |
| 62 int titleTextId = | |
| 63 showSendFeedbackView ? R.string.sad_tab_reload_title : R.string. sad_tab_title; | |
| 64 titleText.setText(titleTextId); | |
| 65 | |
| 66 if (showSendFeedbackView) intializeSuggestionsViews(context, sadTabView) ; | |
| 67 | |
| 42 TextView messageText = (TextView) sadTabView.findViewById(R.id.sad_tab_m essage); | 68 TextView messageText = (TextView) sadTabView.findViewById(R.id.sad_tab_m essage); |
| 43 messageText.setText(getHelpMessage(context, suggestionAction)); | 69 messageText.setText(getHelpMessage(context, suggestionAction, showSendFe edbackView)); |
| 44 messageText.setMovementMethod(LinkMovementMethod.getInstance()); | 70 messageText.setMovementMethod(LinkMovementMethod.getInstance()); |
| 45 | 71 |
| 46 Button reloadButton = (Button) sadTabView.findViewById(R.id.sad_tab_relo ad_button); | 72 Button reloadButton = (Button) sadTabView.findViewById(R.id.sad_tab_relo ad_button); |
| 73 int buttonTextId = showSendFeedbackView ? R.string.sad_tab_send_feedback _label | |
| 74 : R.string.sad_tab_reload_label; | |
| 47 reloadButton.setText(buttonTextId); | 75 reloadButton.setText(buttonTextId); |
| 48 reloadButton.setOnClickListener(reloadButtonAction); | 76 reloadButton.setOnClickListener(reloadButtonAction); |
| 49 | 77 |
| 50 return sadTabView; | 78 return sadTabView; |
| 51 } | 79 } |
| 52 | 80 |
| 53 /** | 81 /** |
| 54 * Construct and return help message to be displayed on R.id.sad_tab_message . | 82 * Construct and return help message to be displayed on R.id.sad_tab_message . |
| 55 * @param context Context of the resulting Sad Tab view. This is needed to l oad the strings. | 83 * @param context Context of the resulting Sad Tab view. This is needed to l oad the strings. |
| 56 * @param suggestionAction Action to be executed when user clicks "try these suggestions". | 84 * @param suggestionAction Action to be executed when user clicks "try these suggestions" |
| 85 * or "learn more". | |
| 57 * @return Help message to be displayed on R.id.sad_tab_message. | 86 * @return Help message to be displayed on R.id.sad_tab_message. |
| 58 */ | 87 */ |
| 59 private static CharSequence getHelpMessage( | 88 private static CharSequence getHelpMessage( |
| 60 Context context, final OnClickListener suggestionAction) { | 89 Context context, final OnClickListener suggestionAction, boolean sho wSendFeedback) { |
| 61 String helpMessage = context.getString(R.string.sad_tab_message) | 90 NoUnderlineClickableSpan linkSpan = new NoUnderlineClickableSpan() { |
| 62 + "\n\n" + context.getString(R.string.sad_tab_suggestions); | |
| 63 NoUnderlineClickableSpan span = new NoUnderlineClickableSpan() { | |
| 64 @Override | 91 @Override |
| 65 public void onClick(View view) { | 92 public void onClick(View view) { |
| 66 suggestionAction.onClick(view); | 93 suggestionAction.onClick(view); |
| 67 } | 94 } |
| 68 }; | 95 }; |
| 69 return SpanApplier.applySpans(helpMessage, new SpanInfo("<link>", "</lin k>", span)); | 96 |
| 97 if (showSendFeedback) { | |
| 98 SpannableString learnMoreLink = | |
| 99 new SpannableString(context.getString(R.string.sad_tab_reloa d_learn_more)); | |
| 100 learnMoreLink.setSpan(linkSpan, 0, learnMoreLink.length(), 0); | |
| 101 return learnMoreLink; | |
| 102 } else { | |
| 103 String helpMessage = context.getString(R.string.sad_tab_message) + " \n\n" | |
| 104 + context.getString(R.string.sad_tab_suggestions); | |
| 105 return SpanApplier.applySpans(helpMessage, new SpanInfo("<link>", "< /link>", linkSpan)); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 /** | |
| 110 * Initializes the TextViews that display tips for handling repeated crashes . | |
| 111 * @param context Context of the resulting Sad Tab view. | |
| 112 * @param sadTabView The parent Sad Tab view that contains the TextViews. | |
| 113 */ | |
| 114 private static void intializeSuggestionsViews(Context context, View sadTabVi ew) { | |
| 115 TextView suggestionsTitle = | |
| 116 (TextView) sadTabView.findViewById(R.id.sad_tab_suggestions_titl e); | |
| 117 suggestionsTitle.setVisibility(View.VISIBLE); | |
| 118 suggestionsTitle.setText(R.string.sad_tab_reload_try); | |
| 119 | |
| 120 SpannableString bullet1 = | |
|
Ted C
2017/05/10 15:59:46
I would pull out a helper function that takes just
Theresa
2017/05/10 18:20:22
Done.
| |
| 121 new SpannableString(context.getString(R.string.sad_tab_reload_cl ose_notabs)); | |
| 122 bullet1.setSpan(new SadTabBulletSpan(context), 0, bullet1.length(), 0); | |
| 123 | |
| 124 SpannableString bullet2 = | |
| 125 new SpannableString(context.getString(R.string.sad_tab_reload_in cognito)); | |
| 126 bullet2.setSpan(new SadTabBulletSpan(context), 0, bullet2.length(), 0); | |
| 127 | |
| 128 SpannableString bullet3 = | |
| 129 new SpannableString(context.getString(R.string.sad_tab_reload_re start_browser)); | |
| 130 bullet3.setSpan(new SadTabBulletSpan(context), 0, bullet3.length(), 0); | |
| 131 | |
| 132 SpannableString bullet4 = | |
| 133 new SpannableString(context.getString(R.string.sad_tab_reload_re start_device)); | |
| 134 bullet4.setSpan(new SadTabBulletSpan(context), 0, bullet4.length(), 0); | |
| 135 | |
| 136 TextView suggestions = (TextView) sadTabView.findViewById(R.id.sad_tab_s uggestions); | |
| 137 suggestions.setVisibility(View.VISIBLE); | |
| 138 suggestions.setText( | |
| 139 TextUtils.concat(bullet1, "\n", bullet2, "\n", bullet3, "\n", bu llet4, "\n")); | |
| 140 } | |
| 141 | |
| 142 /** | |
| 143 * Records enumerated histograms for {@link SadTabEvent}. | |
| 144 * @param sendFeedbackView Whether the event is for the "send feedback" vers ion of the Sad Tab. | |
| 145 * @param event The {@link SadTabEvent} to record. | |
| 146 */ | |
| 147 public static void recordEvent(boolean sendFeedbackView, @SadTabEvent int ev ent) { | |
| 148 if (sendFeedbackView) { | |
| 149 RecordHistogram.recordEnumeratedHistogram( | |
| 150 "Tabs.SadTab.Feedback.Event", event, MAX_SAD_TAB_EVENT); | |
| 151 } else { | |
| 152 RecordHistogram.recordEnumeratedHistogram( | |
| 153 "Tabs.SadTab.Reload.Event", event, MAX_SAD_TAB_EVENT); | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 private static class SadTabBulletSpan extends BulletSpan { | |
| 158 private int mXOffset; | |
| 159 | |
| 160 public SadTabBulletSpan(Context context) { | |
| 161 super(context.getResources().getDimensionPixelSize(R.dimen.sad_tab_g ap)); | |
| 162 mXOffset = context.getResources().getDimensionPixelSize(R.dimen.sad_ tab_leading_offset); | |
| 163 } | |
| 164 | |
| 165 @Override | |
| 166 public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top , int baseline, | |
| 167 int bottom, CharSequence text, int start, int end, boolean first , Layout l) { | |
| 168 // Android cuts off the bullet points. Adjust the x-position so that the bullets aren't | |
|
Ted C
2017/05/10 15:59:46
WAH?! sadness
| |
| 169 // cut off. | |
| 170 super.drawLeadingMargin( | |
| 171 c, p, x + mXOffset, dir, top, baseline, bottom, text, start, end, first, l); | |
| 172 } | |
| 70 } | 173 } |
| 71 } | 174 } |
| OLD | NEW |