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; | 5 package org.chromium.chrome.browser; |
6 | 6 |
7 import android.app.Dialog; | 7 import android.app.Dialog; |
8 import android.content.Context; | 8 import android.content.Context; |
9 import android.content.DialogInterface; | 9 import android.content.DialogInterface; |
10 import android.graphics.Color; | 10 import android.graphics.Color; |
11 import android.graphics.drawable.ColorDrawable; | 11 import android.graphics.drawable.ColorDrawable; |
12 import android.net.Uri; | |
13 import android.text.Layout; | 12 import android.text.Layout; |
14 import android.text.Spannable; | 13 import android.text.Spannable; |
15 import android.text.SpannableStringBuilder; | 14 import android.text.SpannableStringBuilder; |
16 import android.text.style.ForegroundColorSpan; | 15 import android.text.style.ForegroundColorSpan; |
17 import android.text.style.StyleSpan; | 16 import android.text.style.StyleSpan; |
18 import android.util.AttributeSet; | 17 import android.util.AttributeSet; |
19 import android.view.Gravity; | 18 import android.view.Gravity; |
20 import android.view.LayoutInflater; | 19 import android.view.LayoutInflater; |
21 import android.view.View; | 20 import android.view.View; |
22 import android.view.View.OnClickListener; | 21 import android.view.View.OnClickListener; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
68 this.type = type; | 67 this.type = type; |
69 this.value = value; | 68 this.value = value; |
70 } | 69 } |
71 | 70 |
72 @Override | 71 @Override |
73 public String toString() { | 72 public String toString() { |
74 return name; | 73 return name; |
75 } | 74 } |
76 } | 75 } |
77 | 76 |
77 /** | |
78 * A TextView which truncates and displays a URL such that the origin is alw ays visible. | |
79 * The URL can be expanded by clicking on the it. | |
80 */ | |
78 public static class ElidedUrlTextView extends TextView { | 81 public static class ElidedUrlTextView extends TextView { |
79 // The number of lines to display when the URL is truncated. This number | 82 // The number of lines to display when the URL is truncated. This number |
80 // should still allow the origin to be displayed. NULL before | 83 // should still allow the origin to be displayed. NULL before |
81 // setUrlAfterLayout() is called. | 84 // setUrlAfterLayout() is called. |
82 private Integer mTruncatedUrlLinesToDisplay; | 85 private Integer mTruncatedUrlLinesToDisplay; |
83 | 86 |
87 // The number of lines to display when the URL is expanded. This should be enough to display | |
88 // at most two lines of the fragment if there is one in the URL. | |
89 private Integer mFullLinesToDisplay; | |
90 | |
84 // If true, the text view will show the truncated text. If false, it | 91 // If true, the text view will show the truncated text. If false, it |
85 // will show the full, expanded text. | 92 // will show the full, expanded text. |
86 private boolean mIsShowingTruncatedText = true; | 93 private boolean mIsShowingTruncatedText = true; |
87 | 94 |
88 // The profile to use when getting the end index for the origin. | 95 // The profile to use when getting the end index for the origin. |
89 private Profile mProfile = null; | 96 private Profile mProfile = null; |
90 | 97 |
91 // The maximum number of lines currently shown in the view | 98 // The maximum number of lines currently shown in the view |
92 private int mCurrentMaxLines = Integer.MAX_VALUE; | 99 private int mCurrentMaxLines = Integer.MAX_VALUE; |
93 | 100 |
94 /** Constructor for inflating from XML. */ | 101 /** Constructor for inflating from XML. */ |
95 public ElidedUrlTextView(Context context, AttributeSet attrs) { | 102 public ElidedUrlTextView(Context context, AttributeSet attrs) { |
96 super(context, attrs); | 103 super(context, attrs); |
97 } | 104 } |
98 | 105 |
99 @Override | 106 @Override |
100 public void setMaxLines(int maxlines) { | 107 public void setMaxLines(int maxlines) { |
101 super.setMaxLines(maxlines); | 108 super.setMaxLines(maxlines); |
102 mCurrentMaxLines = maxlines; | 109 mCurrentMaxLines = maxlines; |
103 } | 110 } |
104 | 111 |
112 /** | |
113 * Find the number of lines of text which must be shown in order to disp lay the character at | |
114 * a given index. | |
115 */ | |
116 private int getLineForIndex(int index) { | |
117 Layout layout = getLayout(); | |
118 int endLine = 0; | |
119 while (endLine < layout.getLineCount() && layout.getLineEnd(endLine) < index) { | |
120 endLine++; | |
121 } | |
122 // Since endLine is an index, add 1 to get the number of lines. | |
123 return endLine + 1; | |
124 } | |
125 | |
105 @Override | 126 @Override |
106 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | 127 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
107 setMaxLines(Integer.MAX_VALUE); | 128 setMaxLines(Integer.MAX_VALUE); |
108 super.onMeasure(widthMeasureSpec, heightMeasureSpec); | 129 super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
109 assert mProfile != null : "setProfile() must be called before layout ."; | 130 assert mProfile != null : "setProfile() must be called before layout ."; |
131 String urlText = getText().toString(); | |
110 | 132 |
111 // Lay out the URL in a StaticLayout that is the same size as our fi nal | 133 // Lay out the URL in a StaticLayout that is the same size as our fi nal |
112 // container. | 134 // container. |
113 Layout layout = getLayout(); | 135 int originEndIndex = OmniboxUrlEmphasizer.getOriginEndIndex(urlText, mProfile); |
114 int originEndIndex = | |
115 OmniboxUrlEmphasizer.getOriginEndIndex(getText().toString(), mProfile); | |
116 | 136 |
117 // Find the range of lines containing the origin. | 137 // Find the range of lines containing the origin. |
118 int originEndLineIndex = 0; | 138 int originEndLine = getLineForIndex(originEndIndex); |
119 while (originEndLineIndex < layout.getLineCount() | |
120 && layout.getLineEnd(originEndLineIndex) < originEndIndex) { | |
121 originEndLineIndex++; | |
122 } | |
123 | 139 |
124 // Display an extra line so we don't accidentally hide the origin wi th | 140 // Display an extra line so we don't accidentally hide the origin wi th |
125 // ellipses | 141 // ellipses |
126 int lastLineIndexToDisplay = originEndLineIndex + 1; | 142 mTruncatedUrlLinesToDisplay = originEndLine + 1; |
127 | 143 |
128 // Since lastLineToDisplay is an index, add 1 to get the maximum num ber | 144 // Find the line where the fragment starts. Since # is a reserved ch aracter, it is safe |
129 // of lines. This will always be at least 2 lines (when the origin i s | 145 // to just search for the first # to appear in the url. |
130 // fully contained on line 0). | 146 int fragmentStartIndex = urlText.indexOf('#'); |
131 mTruncatedUrlLinesToDisplay = lastLineIndexToDisplay + 1; | 147 // Do not truncate a fragment in URLs which have no fragment or no o rigin (according to |
148 // OmniboxUrlEmphasizer). | |
149 if (fragmentStartIndex == -1 || fragmentStartIndex < originEndIndex) { | |
150 fragmentStartIndex = urlText.length(); | |
juhonurm
2015/04/15 06:07:57
Now the original issue is ignored in non-HTTP(S) U
tsergeant
2015/04/15 07:13:54
Done.
| |
151 } | |
152 | |
153 mFullLinesToDisplay = getLineForIndex(fragmentStartIndex) + 1; | |
132 | 154 |
133 if (updateMaxLines()) super.onMeasure(widthMeasureSpec, heightMeasur eSpec); | 155 if (updateMaxLines()) super.onMeasure(widthMeasureSpec, heightMeasur eSpec); |
134 } | 156 } |
135 | 157 |
136 /** | 158 /** |
137 * Sets the profile to use when calculating the end index of the origin. | 159 * Sets the profile to use when calculating the end index of the origin. |
138 * Must be called before layout. | 160 * Must be called before layout. |
139 * | 161 * |
140 * @param profile The profile to use when coloring the URL. | 162 * @param profile The profile to use when coloring the URL. |
141 */ | 163 */ |
142 public void setProfile(Profile profile) { | 164 public void setProfile(Profile profile) { |
143 mProfile = profile; | 165 mProfile = profile; |
144 } | 166 } |
145 | 167 |
146 /** | 168 /** |
147 * Toggles truncating/expanding the URL text. If the URL text is not | 169 * Toggles truncating/expanding the URL text. If the URL text is not |
148 * truncated, has no effect. | 170 * truncated, has no effect. |
149 */ | 171 */ |
150 public void toggleTruncation() { | 172 public void toggleTruncation() { |
151 mIsShowingTruncatedText = !mIsShowingTruncatedText; | 173 mIsShowingTruncatedText = !mIsShowingTruncatedText; |
152 updateMaxLines(); | 174 updateMaxLines(); |
153 } | 175 } |
154 | 176 |
155 private boolean updateMaxLines() { | 177 private boolean updateMaxLines() { |
156 int maxLines = Integer.MAX_VALUE; | 178 int maxLines = mFullLinesToDisplay; |
157 if (mIsShowingTruncatedText) maxLines = mTruncatedUrlLinesToDisplay; | 179 if (mIsShowingTruncatedText) maxLines = mTruncatedUrlLinesToDisplay; |
158 if (maxLines != mCurrentMaxLines) { | 180 if (maxLines != mCurrentMaxLines) { |
159 setMaxLines(maxLines); | 181 setMaxLines(maxLines); |
160 return true; | 182 return true; |
161 } | 183 } |
162 return false; | 184 return false; |
163 } | 185 } |
164 } | 186 } |
165 | 187 |
166 private static final int MAX_TABLET_DIALOG_WIDTH_DP = 400; | 188 private static final int MAX_TABLET_DIALOG_WIDTH_DP = 400; |
167 | 189 |
168 private static final char FIRST_UNICODE_WHITESPACE = '\u2000'; | |
169 private static final char FINAL_UNICODE_WHITESPACE = '\u200F'; | |
170 private static final char UNICODE_NBSP = '\u00A0'; | |
171 | |
172 private final Context mContext; | 190 private final Context mContext; |
173 private final Profile mProfile; | 191 private final Profile mProfile; |
174 private final WebContents mWebContents; | 192 private final WebContents mWebContents; |
175 | 193 |
176 // A pointer to the C++ object for this UI. | 194 // A pointer to the C++ object for this UI. |
177 private final long mNativeWebsiteSettingsPopup; | 195 private final long mNativeWebsiteSettingsPopup; |
178 | 196 |
179 // The outer container, filled with the layout from website_settings.xml. | 197 // The outer container, filled with the layout from website_settings.xml. |
180 private final LinearLayout mContainer; | 198 private final LinearLayout mContainer; |
181 | 199 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
291 try { | 309 try { |
292 mParsedUrl = new URI(mFullUrl); | 310 mParsedUrl = new URI(mFullUrl); |
293 mIsInternalPage = UrlUtilities.isInternalScheme(mParsedUrl); | 311 mIsInternalPage = UrlUtilities.isInternalScheme(mParsedUrl); |
294 } catch (URISyntaxException e) { | 312 } catch (URISyntaxException e) { |
295 mParsedUrl = null; | 313 mParsedUrl = null; |
296 mIsInternalPage = false; | 314 mIsInternalPage = false; |
297 } | 315 } |
298 mSecurityLevel = ToolbarModel.getSecurityLevelForWebContents(mWebContent s); | 316 mSecurityLevel = ToolbarModel.getSecurityLevelForWebContents(mWebContent s); |
299 mDeprecatedSHA1Present = ToolbarModel.isDeprecatedSHA1Present(mWebConten ts); | 317 mDeprecatedSHA1Present = ToolbarModel.isDeprecatedSHA1Present(mWebConten ts); |
300 | 318 |
301 String displayUrl = prepareUrlForDisplay(mFullUrl); | 319 SpannableStringBuilder urlBuilder = new SpannableStringBuilder(mFullUrl) ; |
302 SpannableStringBuilder urlBuilder = new SpannableStringBuilder(displayUr l); | |
303 OmniboxUrlEmphasizer.emphasizeUrl(urlBuilder, mContext.getResources(), m Profile, | 320 OmniboxUrlEmphasizer.emphasizeUrl(urlBuilder, mContext.getResources(), m Profile, |
304 mSecurityLevel, mIsInternalPage, true); | 321 mSecurityLevel, mIsInternalPage, true); |
305 mUrlTitle.setText(urlBuilder); | 322 mUrlTitle.setText(urlBuilder); |
306 | 323 |
307 // Set the URL connection message now, and the URL after layout (so it | 324 // Set the URL connection message now, and the URL after layout (so it |
308 // can calculate its ideal height). | 325 // can calculate its ideal height). |
309 mUrlConnectionMessage.setText(getUrlConnectionMessage()); | 326 mUrlConnectionMessage.setText(getUrlConnectionMessage()); |
310 } | 327 } |
311 | 328 |
312 /** | 329 /** |
313 * Percent-encodes suspicious Unicode whitespace characters in a URL so that it can be safely | |
314 * displayed. | |
315 */ | |
316 public static String prepareUrlForDisplay(String urlStr) { | |
317 StringBuilder urlBuilder = new StringBuilder(); | |
318 for (int i = 0; i < urlStr.length(); i++) { | |
319 char c = urlStr.charAt(i); | |
320 if ((c >= FIRST_UNICODE_WHITESPACE | |
321 && c <= FINAL_UNICODE_WHITESPACE) | |
322 || c == ' ' | |
323 || c == UNICODE_NBSP) { | |
324 urlBuilder.append(Uri.encode(Character.toString(c))); | |
325 } else { | |
326 urlBuilder.append(c); | |
327 } | |
328 } | |
329 return urlBuilder.toString(); | |
330 } | |
331 | |
332 /** | |
333 * Sets the visibility of the lower area of the dialog (containing the permi ssions and 'Site | 330 * Sets the visibility of the lower area of the dialog (containing the permi ssions and 'Site |
334 * Settings' button). | 331 * Settings' button). |
335 * | 332 * |
336 * @param isVisible Whether to show or hide the dialog area. | 333 * @param isVisible Whether to show or hide the dialog area. |
337 */ | 334 */ |
338 private void setVisibilityOfLowerDialogArea(boolean isVisible) { | 335 private void setVisibilityOfLowerDialogArea(boolean isVisible) { |
339 mHorizontalSeparator.setVisibility(isVisible ? View.VISIBLE : View.GONE) ; | 336 mHorizontalSeparator.setVisibility(isVisible ? View.VISIBLE : View.GONE) ; |
340 mLowerDialogArea.setVisibility(isVisible ? View.VISIBLE : View.GONE); | 337 mLowerDialogArea.setVisibility(isVisible ? View.VISIBLE : View.GONE); |
341 } | 338 } |
342 | 339 |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
569 new WebsiteSettingsPopup(context, profile, webContents); | 566 new WebsiteSettingsPopup(context, profile, webContents); |
570 } | 567 } |
571 | 568 |
572 private static native long nativeInit(WebsiteSettingsPopup popup, WebContent s webContents); | 569 private static native long nativeInit(WebsiteSettingsPopup popup, WebContent s webContents); |
573 | 570 |
574 private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid); | 571 private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid); |
575 | 572 |
576 private native void nativeOnPermissionSettingChanged(long nativeWebsiteSetti ngsPopupAndroid, | 573 private native void nativeOnPermissionSettingChanged(long nativeWebsiteSetti ngsPopupAndroid, |
577 int type, int setting); | 574 int type, int setting); |
578 } | 575 } |
OLD | NEW |