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 if (fragmentStartIndex == -1) fragmentStartIndex = urlText.length(); |
| 148 |
| 149 int fragmentStartLine = getLineForIndex(fragmentStartIndex); |
| 150 mFullLinesToDisplay = fragmentStartLine + 1; |
| 151 |
| 152 // If there is no origin (according to OmniboxUrlEmphasizer), make s
ure the fragment is |
| 153 // still hidden correctly. |
| 154 if (mFullLinesToDisplay < mTruncatedUrlLinesToDisplay) { |
| 155 mTruncatedUrlLinesToDisplay = mFullLinesToDisplay; |
| 156 } |
132 | 157 |
133 if (updateMaxLines()) super.onMeasure(widthMeasureSpec, heightMeasur
eSpec); | 158 if (updateMaxLines()) super.onMeasure(widthMeasureSpec, heightMeasur
eSpec); |
134 } | 159 } |
135 | 160 |
136 /** | 161 /** |
137 * Sets the profile to use when calculating the end index of the origin. | 162 * Sets the profile to use when calculating the end index of the origin. |
138 * Must be called before layout. | 163 * Must be called before layout. |
139 * | 164 * |
140 * @param profile The profile to use when coloring the URL. | 165 * @param profile The profile to use when coloring the URL. |
141 */ | 166 */ |
142 public void setProfile(Profile profile) { | 167 public void setProfile(Profile profile) { |
143 mProfile = profile; | 168 mProfile = profile; |
144 } | 169 } |
145 | 170 |
146 /** | 171 /** |
147 * Toggles truncating/expanding the URL text. If the URL text is not | 172 * Toggles truncating/expanding the URL text. If the URL text is not |
148 * truncated, has no effect. | 173 * truncated, has no effect. |
149 */ | 174 */ |
150 public void toggleTruncation() { | 175 public void toggleTruncation() { |
151 mIsShowingTruncatedText = !mIsShowingTruncatedText; | 176 mIsShowingTruncatedText = !mIsShowingTruncatedText; |
152 updateMaxLines(); | 177 updateMaxLines(); |
153 } | 178 } |
154 | 179 |
155 private boolean updateMaxLines() { | 180 private boolean updateMaxLines() { |
156 int maxLines = Integer.MAX_VALUE; | 181 int maxLines = mFullLinesToDisplay; |
157 if (mIsShowingTruncatedText) maxLines = mTruncatedUrlLinesToDisplay; | 182 if (mIsShowingTruncatedText) maxLines = mTruncatedUrlLinesToDisplay; |
158 if (maxLines != mCurrentMaxLines) { | 183 if (maxLines != mCurrentMaxLines) { |
159 setMaxLines(maxLines); | 184 setMaxLines(maxLines); |
160 return true; | 185 return true; |
161 } | 186 } |
162 return false; | 187 return false; |
163 } | 188 } |
164 } | 189 } |
165 | 190 |
166 private static final int MAX_TABLET_DIALOG_WIDTH_DP = 400; | 191 private static final int MAX_TABLET_DIALOG_WIDTH_DP = 400; |
167 | 192 |
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; | 193 private final Context mContext; |
173 private final Profile mProfile; | 194 private final Profile mProfile; |
174 private final WebContents mWebContents; | 195 private final WebContents mWebContents; |
175 | 196 |
176 // A pointer to the C++ object for this UI. | 197 // A pointer to the C++ object for this UI. |
177 private final long mNativeWebsiteSettingsPopup; | 198 private final long mNativeWebsiteSettingsPopup; |
178 | 199 |
179 // The outer container, filled with the layout from website_settings.xml. | 200 // The outer container, filled with the layout from website_settings.xml. |
180 private final LinearLayout mContainer; | 201 private final LinearLayout mContainer; |
181 | 202 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 try { | 312 try { |
292 mParsedUrl = new URI(mFullUrl); | 313 mParsedUrl = new URI(mFullUrl); |
293 mIsInternalPage = UrlUtilities.isInternalScheme(mParsedUrl); | 314 mIsInternalPage = UrlUtilities.isInternalScheme(mParsedUrl); |
294 } catch (URISyntaxException e) { | 315 } catch (URISyntaxException e) { |
295 mParsedUrl = null; | 316 mParsedUrl = null; |
296 mIsInternalPage = false; | 317 mIsInternalPage = false; |
297 } | 318 } |
298 mSecurityLevel = ToolbarModel.getSecurityLevelForWebContents(mWebContent
s); | 319 mSecurityLevel = ToolbarModel.getSecurityLevelForWebContents(mWebContent
s); |
299 mDeprecatedSHA1Present = ToolbarModel.isDeprecatedSHA1Present(mWebConten
ts); | 320 mDeprecatedSHA1Present = ToolbarModel.isDeprecatedSHA1Present(mWebConten
ts); |
300 | 321 |
301 String displayUrl = prepareUrlForDisplay(mFullUrl); | 322 SpannableStringBuilder urlBuilder = new SpannableStringBuilder(mFullUrl)
; |
302 SpannableStringBuilder urlBuilder = new SpannableStringBuilder(displayUr
l); | |
303 OmniboxUrlEmphasizer.emphasizeUrl(urlBuilder, mContext.getResources(), m
Profile, | 323 OmniboxUrlEmphasizer.emphasizeUrl(urlBuilder, mContext.getResources(), m
Profile, |
304 mSecurityLevel, mIsInternalPage, true); | 324 mSecurityLevel, mIsInternalPage, true); |
305 mUrlTitle.setText(urlBuilder); | 325 mUrlTitle.setText(urlBuilder); |
306 | 326 |
307 // Set the URL connection message now, and the URL after layout (so it | 327 // Set the URL connection message now, and the URL after layout (so it |
308 // can calculate its ideal height). | 328 // can calculate its ideal height). |
309 mUrlConnectionMessage.setText(getUrlConnectionMessage()); | 329 mUrlConnectionMessage.setText(getUrlConnectionMessage()); |
310 } | 330 } |
311 | 331 |
312 /** | 332 /** |
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 | 333 * Sets the visibility of the lower area of the dialog (containing the permi
ssions and 'Site |
334 * Settings' button). | 334 * Settings' button). |
335 * | 335 * |
336 * @param isVisible Whether to show or hide the dialog area. | 336 * @param isVisible Whether to show or hide the dialog area. |
337 */ | 337 */ |
338 private void setVisibilityOfLowerDialogArea(boolean isVisible) { | 338 private void setVisibilityOfLowerDialogArea(boolean isVisible) { |
339 mHorizontalSeparator.setVisibility(isVisible ? View.VISIBLE : View.GONE)
; | 339 mHorizontalSeparator.setVisibility(isVisible ? View.VISIBLE : View.GONE)
; |
340 mLowerDialogArea.setVisibility(isVisible ? View.VISIBLE : View.GONE); | 340 mLowerDialogArea.setVisibility(isVisible ? View.VISIBLE : View.GONE); |
341 } | 341 } |
342 | 342 |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 new WebsiteSettingsPopup(context, profile, webContents); | 569 new WebsiteSettingsPopup(context, profile, webContents); |
570 } | 570 } |
571 | 571 |
572 private static native long nativeInit(WebsiteSettingsPopup popup, WebContent
s webContents); | 572 private static native long nativeInit(WebsiteSettingsPopup popup, WebContent
s webContents); |
573 | 573 |
574 private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid); | 574 private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid); |
575 | 575 |
576 private native void nativeOnPermissionSettingChanged(long nativeWebsiteSetti
ngsPopupAndroid, | 576 private native void nativeOnPermissionSettingChanged(long nativeWebsiteSetti
ngsPopupAndroid, |
577 int type, int setting); | 577 int type, int setting); |
578 } | 578 } |
OLD | NEW |