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.content.Intent; | |
11 import android.graphics.Color; | 10 import android.graphics.Color; |
12 import android.provider.Browser; | 11 import android.graphics.drawable.ColorDrawable; |
13 import android.text.TextUtils; | 12 import android.text.Spannable; |
| 13 import android.text.SpannableStringBuilder; |
| 14 import android.text.style.ForegroundColorSpan; |
| 15 import android.text.style.StyleSpan; |
| 16 import android.view.Gravity; |
14 import android.view.LayoutInflater; | 17 import android.view.LayoutInflater; |
15 import android.view.View; | |
16 import android.view.View.OnClickListener; | |
17 import android.view.ViewGroup; | 18 import android.view.ViewGroup; |
18 import android.view.Window; | 19 import android.view.Window; |
19 import android.widget.Button; | |
20 import android.widget.ImageView; | |
21 import android.widget.LinearLayout; | 20 import android.widget.LinearLayout; |
22 import android.widget.ScrollView; | 21 import android.widget.ScrollView; |
23 import android.widget.TextView; | 22 import android.widget.TextView; |
24 | 23 |
25 import org.chromium.base.ApiCompatibilityUtils; | |
26 import org.chromium.base.CalledByNative; | 24 import org.chromium.base.CalledByNative; |
| 25 import org.chromium.base.CommandLine; |
27 import org.chromium.chrome.R; | 26 import org.chromium.chrome.R; |
28 import org.chromium.content.browser.WebContentsObserverAndroid; | 27 import org.chromium.content.browser.WebContentsObserverAndroid; |
| 28 import org.chromium.content.common.ContentSwitches; |
29 import org.chromium.content_public.browser.WebContents; | 29 import org.chromium.content_public.browser.WebContents; |
30 | 30 |
31 import java.net.URISyntaxException; | |
32 | |
33 /** | 31 /** |
34 * Java side of Android implementation of the website settings UI. | 32 * Java side of Android implementation of the website settings UI. |
35 */ | 33 */ |
36 public class WebsiteSettingsPopup implements OnClickListener { | 34 public class WebsiteSettingsPopup { |
37 private static final String HELP_URL = | |
38 "http://www.google.com/support/chrome/bin/answer.py?answer=95617"; | |
39 private static final int DESCRIPTION_TEXT_SIZE_SP = 12; | |
40 private final Context mContext; | 35 private final Context mContext; |
| 36 private final WebContents mWebContents; |
| 37 |
| 38 // A pointer to the C++ object for this UI. |
| 39 private final long mNativeWebsiteSettingsPopup; |
| 40 |
| 41 // The outer container, filled with the layout from website_settings.xml. |
| 42 private final LinearLayout mContainer; |
| 43 |
| 44 // UI elements in the dialog. |
| 45 private final TextView mUrlTitle; |
| 46 private final TextView mUrlConnectionMessage; |
| 47 |
| 48 // The dialog the container is placed in. |
41 private final Dialog mDialog; | 49 private final Dialog mDialog; |
42 private final LinearLayout mContainer; | |
43 private final WebContents mWebContents; | |
44 private final int mPaddingWide, mPaddingThin; | |
45 private final long mNativeWebsiteSettingsPopup; | |
46 private TextView mCertificateViewer, mMoreInfoLink; | |
47 private ViewGroup mCertificateLayout, mDescriptionLayout; | |
48 private Button mResetCertDecisionsButton; | |
49 private String mLinkUrl; | |
50 | 50 |
| 51 /** |
| 52 * Creates the WebsiteSettingsPopup, but does not display it. Also |
| 53 * initializes the corresponding C++ object and saves a pointer to it. |
| 54 */ |
51 private WebsiteSettingsPopup(Context context, WebContents webContents) { | 55 private WebsiteSettingsPopup(Context context, WebContents webContents) { |
52 mContext = context; | 56 mContext = context; |
53 mWebContents = webContents; | 57 mWebContents = webContents; |
54 | 58 |
55 mContainer = new LinearLayout(mContext); | 59 // Find the container and all it's important subviews. |
56 mContainer.setOrientation(LinearLayout.VERTICAL); | 60 mContainer = (LinearLayout) LayoutInflater.from(mContext).inflate( |
57 mContainer.setBackgroundColor(Color.WHITE); | 61 R.layout.website_settings, null); |
58 mPaddingWide = (int) context.getResources().getDimension( | |
59 R.dimen.certificate_viewer_padding_wide); | |
60 mPaddingThin = (int) context.getResources().getDimension( | |
61 R.dimen.certificate_viewer_padding_thin); | |
62 mContainer.setPadding(mPaddingWide, mPaddingWide + mPaddingThin, mPaddin
gWide, | |
63 mPaddingWide); | |
64 | 62 |
| 63 mUrlTitle = (TextView) mContainer |
| 64 .findViewById(R.id.website_settings_url); |
| 65 mUrlConnectionMessage = (TextView) mContainer |
| 66 .findViewById(R.id.website_settings_permission_message); |
| 67 |
| 68 // Create the dialog. |
65 mDialog = new Dialog(mContext); | 69 mDialog = new Dialog(mContext); |
66 mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); | 70 mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); |
67 mDialog.setCanceledOnTouchOutside(true); | 71 mDialog.setCanceledOnTouchOutside(true); |
| 72 |
| 73 // Place the dialog at the top of the screen, and remove its border. |
| 74 Window window = mDialog.getWindow(); |
| 75 window.setGravity(Gravity.TOP); |
| 76 window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); |
| 77 |
68 // This needs to come after other member initialization. | 78 // This needs to come after other member initialization. |
69 mNativeWebsiteSettingsPopup = nativeInit(this, webContents); | 79 mNativeWebsiteSettingsPopup = nativeInit(this, webContents); |
70 final WebContentsObserverAndroid webContentsObserver = | 80 final WebContentsObserverAndroid webContentsObserver = new WebContentsOb
serverAndroid( |
71 new WebContentsObserverAndroid(mWebContents) { | 81 mWebContents) { |
72 @Override | 82 @Override |
73 public void navigationEntryCommitted() { | 83 public void navigationEntryCommitted() { |
74 // If a navigation is committed (e.g. from in-page redirect), th
e data we're | 84 // If a navigation is committed (e.g. from in-page redirect), th
e data we're |
75 // showing is stale so dismiss the dialog. | 85 // showing is stale so dismiss the dialog. |
76 mDialog.dismiss(); | 86 mDialog.dismiss(); |
77 } | 87 } |
78 }; | 88 }; |
79 mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { | 89 mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { |
80 @Override | 90 @Override |
81 public void onDismiss(DialogInterface dialog) { | 91 public void onDismiss(DialogInterface dialog) { |
82 assert mNativeWebsiteSettingsPopup != 0; | 92 assert mNativeWebsiteSettingsPopup != 0; |
83 webContentsObserver.detachFromWebContents(); | 93 webContentsObserver.detachFromWebContents(); |
84 nativeDestroy(mNativeWebsiteSettingsPopup); | 94 nativeDestroy(mNativeWebsiteSettingsPopup); |
85 } | 95 } |
86 }); | 96 }); |
87 } | 97 } |
88 | 98 |
89 /** | 99 /** |
90 * Adds certificate section, which contains an icon, a headline, a | 100 * Sets the URL in the title to: (scheme)://(domain)(path). Also colors |
91 * description and a label for certificate info link. | 101 * different parts of the URL depending on connectionType. |
| 102 * connectionType should be a valid PageInfoConnectionType. |
92 */ | 103 */ |
93 @CalledByNative | 104 @CalledByNative |
94 private void addCertificateSection(int enumeratedIconId, String headline, St
ring description, | 105 private void setURLTitle(String scheme, String domain, String path, int conn
ectionType) { |
95 String label) { | 106 boolean makeDomainBold = false; |
96 View section = addSection(enumeratedIconId, headline, description); | 107 int schemeColorId = R.color.website_settings_popup_url_scheme_broken; |
97 assert mCertificateLayout == null; | 108 switch (connectionType) { |
98 mCertificateLayout = (ViewGroup) section.findViewById(R.id.website_setti
ngs_text_layout); | 109 case PageInfoConnectionType.CONNECTION_UNKNOWN: |
99 if (label != null && !label.isEmpty()) { | 110 schemeColorId = R.color.website_settings_popup_url_scheme_http; |
100 setCertificateViewer(label); | 111 makeDomainBold = true; |
| 112 break; |
| 113 case PageInfoConnectionType.CONNECTION_ENCRYPTED: |
| 114 schemeColorId = R.color.website_settings_popup_url_scheme_https; |
| 115 break; |
| 116 case PageInfoConnectionType.CONNECTION_MIXED_CONTENT: |
| 117 schemeColorId = R.color.website_settings_popup_url_scheme_mixed; |
| 118 makeDomainBold = true; |
| 119 break; |
| 120 case PageInfoConnectionType.CONNECTION_UNENCRYPTED: |
| 121 schemeColorId = R.color.website_settings_popup_url_scheme_http; |
| 122 makeDomainBold = true; |
| 123 break; |
| 124 case PageInfoConnectionType.CONNECTION_ENCRYPTED_ERROR: |
| 125 schemeColorId = R.color.website_settings_popup_url_scheme_broken
; |
| 126 makeDomainBold = true; |
| 127 break; |
| 128 case PageInfoConnectionType.CONNECTION_INTERNAL_PAGE: |
| 129 schemeColorId = R.color.website_settings_popup_url_scheme_http; |
| 130 break; |
| 131 default: |
| 132 assert false : "Unexpected connection type: " + connectionType; |
101 } | 133 } |
| 134 |
| 135 SpannableStringBuilder sb = new SpannableStringBuilder(scheme + "://" +
domain + path); |
| 136 |
| 137 ForegroundColorSpan schemeColorSpan = new ForegroundColorSpan( |
| 138 mContext.getResources().getColor(schemeColorId)); |
| 139 sb.setSpan(schemeColorSpan, 0, scheme.length(), Spannable.SPAN_INCLUSIVE
_INCLUSIVE); |
| 140 |
| 141 int domainStartIndex = scheme.length() + 3; |
| 142 ForegroundColorSpan domainColorSpan = new ForegroundColorSpan( |
| 143 mContext.getResources().getColor(R.color.website_settings_popup_
url_domain)); |
| 144 sb.setSpan(domainColorSpan, domainStartIndex, domainStartIndex + domain.
length(), |
| 145 Spannable.SPAN_INCLUSIVE_INCLUSIVE); |
| 146 |
| 147 if (makeDomainBold) { |
| 148 StyleSpan boldStyleSpan = new StyleSpan(android.graphics.Typeface.BO
LD); |
| 149 sb.setSpan(boldStyleSpan, domainStartIndex, domainStartIndex + domai
n.length(), |
| 150 Spannable.SPAN_INCLUSIVE_INCLUSIVE); |
| 151 } |
| 152 |
| 153 mUrlTitle.setText(sb); |
102 } | 154 } |
103 | 155 |
104 /** | 156 /** |
105 * Adds Description section, which contains an icon, a headline, and a | 157 * Sets the connection message displayed at the top of the dialog to |
106 * description. Most likely headline for description is empty | 158 * connectionMessage (e.g. "Could not securely connect to this site"). |
107 */ | 159 */ |
108 @CalledByNative | 160 @CalledByNative |
109 private void addDescriptionSection(int enumeratedIconId, String headline, St
ring description) { | 161 private void setConnectionMessage(String connectionMessage) { |
110 View section = addSection(enumeratedIconId, headline, description); | 162 mUrlConnectionMessage.setText(connectionMessage); |
111 assert mDescriptionLayout == null; | |
112 mDescriptionLayout = (ViewGroup) section.findViewById(R.id.website_setti
ngs_text_layout); | |
113 } | |
114 | |
115 private View addSection(int enumeratedIconId, String headline, String descri
ption) { | |
116 View section = LayoutInflater.from(mContext).inflate(R.layout.website_se
ttings, null); | |
117 ImageView i = (ImageView) section.findViewById(R.id.website_settings_ico
n); | |
118 int drawableId = ResourceId.mapToDrawableId(enumeratedIconId); | |
119 i.setImageResource(drawableId); | |
120 | |
121 TextView h = (TextView) section.findViewById(R.id.website_settings_headl
ine); | |
122 h.setText(headline); | |
123 if (TextUtils.isEmpty(headline)) h.setVisibility(View.GONE); | |
124 | |
125 TextView d = (TextView) section.findViewById(R.id.website_settings_descr
iption); | |
126 d.setText(description); | |
127 d.setTextSize(DESCRIPTION_TEXT_SIZE_SP); | |
128 if (TextUtils.isEmpty(description)) d.setVisibility(View.GONE); | |
129 | |
130 mContainer.addView(section); | |
131 return section; | |
132 } | |
133 | |
134 private void setCertificateViewer(String label) { | |
135 assert mCertificateViewer == null; | |
136 mCertificateViewer = new TextView(mContext); | |
137 mCertificateViewer.setText(label); | |
138 mCertificateViewer.setTextColor( | |
139 mContext.getResources().getColor(R.color.website_settings_popup_
text_link)); | |
140 mCertificateViewer.setTextSize(DESCRIPTION_TEXT_SIZE_SP); | |
141 mCertificateViewer.setOnClickListener(this); | |
142 mCertificateViewer.setPadding(0, mPaddingWide, 0, mPaddingWide); | |
143 mCertificateLayout.addView(mCertificateViewer); | |
144 } | |
145 | |
146 @CalledByNative | |
147 private void addResetCertDecisionsButton(String label) { | |
148 assert mNativeWebsiteSettingsPopup != 0; | |
149 assert mResetCertDecisionsButton == null; | |
150 | |
151 mResetCertDecisionsButton = new Button(mContext); | |
152 mResetCertDecisionsButton.setText(label); | |
153 ApiCompatibilityUtils.setBackgroundForView(mResetCertDecisionsButton, | |
154 mContext.getResources().getDrawable( | |
155 R.drawable.website_settings_reset_cert_decisions)); | |
156 mResetCertDecisionsButton.setTextColor( | |
157 mContext.getResources().getColor( | |
158 R.color.website_settings_popup_reset_cert_decisions_button)); | |
159 mResetCertDecisionsButton.setTextSize(DESCRIPTION_TEXT_SIZE_SP); | |
160 mResetCertDecisionsButton.setOnClickListener(this); | |
161 | |
162 LinearLayout container = new LinearLayout(mContext); | |
163 container.setOrientation(LinearLayout.VERTICAL); | |
164 container.addView(mResetCertDecisionsButton); | |
165 container.setPadding(0, 0, 0, mPaddingWide); | |
166 mContainer.addView(container); | |
167 } | |
168 | |
169 @CalledByNative | |
170 private void addMoreInfoLink(String linkText) { | |
171 addUrl(linkText, HELP_URL); | |
172 } | |
173 | |
174 /** Adds a section containing a description and a hyperlink. */ | |
175 private void addUrl(String label, String url) { | |
176 mMoreInfoLink = new TextView(mContext); | |
177 mLinkUrl = url; | |
178 mMoreInfoLink.setText(label); | |
179 mMoreInfoLink.setTextColor( | |
180 mContext.getResources().getColor(R.color.website_settings_popup_
text_link)); | |
181 mMoreInfoLink.setTextSize(DESCRIPTION_TEXT_SIZE_SP); | |
182 mMoreInfoLink.setPadding(0, mPaddingWide + mPaddingThin, 0, mPaddingWide
); | |
183 mMoreInfoLink.setOnClickListener(this); | |
184 mDescriptionLayout.addView(mMoreInfoLink); | |
185 } | 163 } |
186 | 164 |
187 /** Displays the WebsiteSettingsPopup. */ | 165 /** Displays the WebsiteSettingsPopup. */ |
188 @CalledByNative | 166 @CalledByNative |
189 private void showDialog() { | 167 private void showDialog() { |
| 168 // Wrap the dialog in a ScrollView in case the content is too long. |
190 ScrollView scrollView = new ScrollView(mContext); | 169 ScrollView scrollView = new ScrollView(mContext); |
191 scrollView.addView(mContainer); | 170 scrollView.addView(mContainer); |
192 mDialog.addContentView(scrollView, | 171 mDialog.addContentView(scrollView, new LinearLayout.LayoutParams( |
193 new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PA
RENT, | 172 LinearLayout.LayoutParams.MATCH_PARENT, |
194 LinearLayout.LayoutParams.MATCH_PARENT)); | 173 LinearLayout.LayoutParams.MATCH_PARENT)); |
| 174 |
| 175 // Make the dialog fill the width of the screen. This must be called |
| 176 // after addContentView, or it won't fully fill to the edge. |
| 177 Window window = mDialog.getWindow(); |
| 178 window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, |
| 179 ViewGroup.LayoutParams.WRAP_CONTENT); |
| 180 |
195 mDialog.show(); | 181 mDialog.show(); |
196 } | 182 } |
197 | 183 |
198 @Override | 184 /** |
199 public void onClick(View v) { | 185 * Shows a WebsiteSettings dialog for the provided WebContents. The popup |
200 mDialog.dismiss(); | 186 * adds itself to the view hierarchy which owns the reference while it's |
201 if (mResetCertDecisionsButton == v) { | 187 * visible. |
202 nativeResetCertDecisions(mNativeWebsiteSettingsPopup, mWebContents); | 188 * |
203 } else if (mCertificateViewer == v) { | 189 * @param context Context which is used for launching a dialog. |
204 byte[][] certChain = nativeGetCertificateChain(mWebContents); | 190 * @param webContents The WebContents for which to show Website information. |
205 if (certChain == null) { | 191 * This information is retrieved for the visible entry. |
206 // The WebContents may have been destroyed/invalidated. If so, | 192 */ |
207 // ignore this request. | 193 @SuppressWarnings("unused") |
208 return; | 194 public static void show(Context context, WebContents webContents) { |
209 } | 195 if (CommandLine.getInstance().hasSwitch( |
210 CertificateViewer.showCertificateChain(mContext, certChain); | 196 ContentSwitches.ENABLE_NEW_WEBSITE_SETTINGS)) { |
211 } else if (mMoreInfoLink == v) { | 197 new WebsiteSettingsPopup(context, webContents); |
212 try { | 198 } else { |
213 Intent i = Intent.parseUri(mLinkUrl, Intent.URI_INTENT_SCHEME); | 199 WebsiteSettingsPopupLegacy.show(context, webContents); |
214 i.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true); | |
215 i.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName
()); | |
216 mContext.startActivity(i); | |
217 } catch (URISyntaxException ex) { | |
218 // Do nothing intentionally. | |
219 } | |
220 } | 200 } |
221 } | 201 } |
222 | 202 |
223 /** | 203 private static native long nativeInit(WebsiteSettingsPopup popup, |
224 * Shows a WebsiteSettings dialog for the provided WebContents. | 204 WebContents webContents); |
225 * | |
226 * The popup adds itself to the view hierarchy which owns the reference whil
e it's | |
227 * visible. | |
228 * | |
229 * @param context Context which is used for launching a dialog. | |
230 * @param webContents The WebContents for which to show Website information.
This | |
231 * information is retrieved for the visible entry. | |
232 */ | |
233 @SuppressWarnings("unused") | |
234 public static void show(Context context, WebContents webContents) { | |
235 new WebsiteSettingsPopup(context, webContents); | |
236 } | |
237 | 205 |
238 private static native long nativeInit(WebsiteSettingsPopup popup, WebContent
s webContents); | |
239 private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid); | 206 private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid); |
240 private native void nativeResetCertDecisions( | |
241 long nativeWebsiteSettingsPopupAndroid, WebContents webContents); | |
242 private native byte[][] nativeGetCertificateChain(WebContents webContents); | |
243 } | 207 } |
OLD | NEW |