blob: b92add9cd0e048e7b59fb1ab89f33979d0da7340 [file] [log] [blame]
Michael Kolb8233fac2010-10-26 16:08:53 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Bijan Amirzada41242f22014-03-21 12:12:18 -070017package com.android.browser;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080018
Michael Kolb8233fac2010-10-26 16:08:53 -070019import android.app.AlertDialog;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.content.res.Configuration;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080023import android.content.res.Resources;
Michael Kolb8233fac2010-10-26 16:08:53 -070024import android.net.http.SslCertificate;
25import android.net.http.SslError;
Michael Kolb8233fac2010-10-26 16:08:53 -070026import android.view.LayoutInflater;
27import android.view.View;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080028import org.codeaurora.swe.HttpAuthHandler;
29import org.codeaurora.swe.SslErrorHandler;
Kulanthaivel Palanichamyf36e1db2015-04-08 16:11:06 -070030import org.codeaurora.swe.WebRefiner;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080031import org.codeaurora.swe.WebView;
32
Bijan Amirzada58383e72014-04-01 14:45:22 -070033import com.android.browser.reflect.ReflectHelper;
Bijan Amirzada41242f22014-03-21 12:12:18 -070034import com.android.browser.R;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080035
Michael Kolb8233fac2010-10-26 16:08:53 -070036import android.widget.LinearLayout;
37import android.widget.TextView;
38
Michael Kolb8233fac2010-10-26 16:08:53 -070039/**
40 * Displays page info
41 *
42 */
43public class PageDialogsHandler {
44
45 private Context mContext;
46 private Controller mController;
47 private boolean mPageInfoFromShowSSLCertificateOnError;
Huahui Wuae0c0412011-06-28 10:17:05 -070048 private String mUrlCertificateOnError;
Michael Kolb8233fac2010-10-26 16:08:53 -070049 private Tab mPageInfoView;
50 private AlertDialog mPageInfoDialog;
51
52 // as SSLCertificateOnError has different style for landscape / portrait,
53 // we have to re-open it when configuration changed
54 private AlertDialog mSSLCertificateOnErrorDialog;
55 private WebView mSSLCertificateOnErrorView;
56 private SslErrorHandler mSSLCertificateOnErrorHandler;
57 private SslError mSSLCertificateOnErrorError;
58
59 // as SSLCertificate has different style for landscape / portrait, we
60 // have to re-open it when configuration changed
61 private AlertDialog mSSLCertificateDialog;
62 private Tab mSSLCertificateView;
63 private HttpAuthenticationDialog mHttpAuthenticationDialog;
64
65 public PageDialogsHandler(Context context, Controller controller) {
66 mContext = context;
67 mController = controller;
68 }
69
70 public void onConfigurationChanged(Configuration config) {
71 if (mPageInfoDialog != null) {
72 mPageInfoDialog.dismiss();
Huahui Wuae0c0412011-06-28 10:17:05 -070073 showPageInfo(mPageInfoView,
74 mPageInfoFromShowSSLCertificateOnError,
75 mUrlCertificateOnError);
Michael Kolb8233fac2010-10-26 16:08:53 -070076 }
77 if (mSSLCertificateDialog != null) {
78 mSSLCertificateDialog.dismiss();
79 showSSLCertificate(mSSLCertificateView);
80 }
81 if (mSSLCertificateOnErrorDialog != null) {
82 mSSLCertificateOnErrorDialog.dismiss();
Huahui Wuae0c0412011-06-28 10:17:05 -070083 showSSLCertificateOnError(mSSLCertificateOnErrorView,
84 mSSLCertificateOnErrorHandler,
85 mSSLCertificateOnErrorError);
Michael Kolb8233fac2010-10-26 16:08:53 -070086 }
87 if (mHttpAuthenticationDialog != null) {
88 mHttpAuthenticationDialog.reshow();
89 }
90 }
91
92 /**
93 * Displays an http-authentication dialog.
94 */
95 void showHttpAuthentication(final Tab tab, final HttpAuthHandler handler, String host, String realm) {
96 mHttpAuthenticationDialog = new HttpAuthenticationDialog(mContext, host, realm);
97 mHttpAuthenticationDialog.setOkListener(new HttpAuthenticationDialog.OkListener() {
98 public void onOk(String host, String realm, String username, String password) {
99 setHttpAuthUsernamePassword(host, realm, username, password);
100 handler.proceed(username, password);
101 mHttpAuthenticationDialog = null;
102 }
103 });
104 mHttpAuthenticationDialog.setCancelListener(new HttpAuthenticationDialog.CancelListener() {
105 public void onCancel() {
106 handler.cancel();
Steve Block2466eff2011-10-03 15:33:09 +0100107 mController.onUpdatedSecurityState(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700108 mHttpAuthenticationDialog = null;
109 }
110 });
111 mHttpAuthenticationDialog.show();
112 }
113
114 /**
115 * Set HTTP authentication password.
116 *
117 * @param host The host for the password
118 * @param realm The realm for the password
119 * @param username The username for the password. If it is null, it means
120 * password can't be saved.
121 * @param password The password
122 */
123 public void setHttpAuthUsernamePassword(String host, String realm,
124 String username,
125 String password) {
126 WebView w = mController.getCurrentTopWebView();
Panos Thomase5a847f2015-01-07 10:15:41 -0800127 if (w != null && BrowserSettings.getInstance().rememberPasswords()) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700128 w.setHttpAuthUsernamePassword(host, realm, username, password);
129 }
130 }
131
132 /**
133 * Displays a page-info dialog.
134 * @param tab The tab to show info about
135 * @param fromShowSSLCertificateOnError The flag that indicates whether
136 * this dialog was opened from the SSL-certificate-on-error dialog or
137 * not. This is important, since we need to know whether to return to
138 * the parent dialog or simply dismiss.
Huahui Wuae0c0412011-06-28 10:17:05 -0700139 * @param urlCertificateOnError The URL that invokes SSLCertificateError.
140 * Null when fromShowSSLCertificateOnError is false.
Michael Kolb8233fac2010-10-26 16:08:53 -0700141 */
142 void showPageInfo(final Tab tab,
Huahui Wuae0c0412011-06-28 10:17:05 -0700143 final boolean fromShowSSLCertificateOnError,
144 final String urlCertificateOnError) {
Michael Kolbd5cb4fa2012-04-18 08:29:16 -0700145 if (tab == null) return;
Michael Kolb8233fac2010-10-26 16:08:53 -0700146 final LayoutInflater factory = LayoutInflater.from(mContext);
147
148 final View pageInfoView = factory.inflate(R.layout.page_info, null);
149
150 final WebView view = tab.getWebView();
151
Huahui Wuae0c0412011-06-28 10:17:05 -0700152 String url = fromShowSSLCertificateOnError ? urlCertificateOnError : tab.getUrl();
John Reck30c714c2010-12-16 17:30:34 -0800153 String title = tab.getTitle();
Michael Kolb8233fac2010-10-26 16:08:53 -0700154
155 if (url == null) {
156 url = "";
157 }
158 if (title == null) {
159 title = "";
160 }
161
162 ((TextView) pageInfoView.findViewById(R.id.address)).setText(url);
163 ((TextView) pageInfoView.findViewById(R.id.title)).setText(title);
164
Kulanthaivel Palanichamyf36e1db2015-04-08 16:11:06 -0700165 if (WebRefiner.isInitialized() && view != null) {
166 (pageInfoView.findViewById(R.id.web_refiner_info)).setVisibility(View.VISIBLE);
167 int count = WebRefiner.getInstance().getBlockedURLCount(view);
168 String msg = String.valueOf(count) + " requests blocked on this page";
169 ((TextView) pageInfoView.findViewById(R.id.web_refiner_blocked_status)).setText(msg);
170 } else {
171 (pageInfoView.findViewById(R.id.web_refiner_info)).setVisibility(View.INVISIBLE);
172 }
173
Michael Kolb8233fac2010-10-26 16:08:53 -0700174 mPageInfoView = tab;
175 mPageInfoFromShowSSLCertificateOnError = fromShowSSLCertificateOnError;
Huahui Wuae0c0412011-06-28 10:17:05 -0700176 mUrlCertificateOnError = urlCertificateOnError;
Michael Kolb8233fac2010-10-26 16:08:53 -0700177
178 AlertDialog.Builder alertDialogBuilder =
179 new AlertDialog.Builder(mContext)
180 .setTitle(R.string.page_info)
181 .setIcon(android.R.drawable.ic_dialog_info)
182 .setView(pageInfoView)
183 .setPositiveButton(
184 R.string.ok,
185 new DialogInterface.OnClickListener() {
186 public void onClick(DialogInterface dialog,
187 int whichButton) {
188 mPageInfoDialog = null;
189 mPageInfoView = null;
190
191 // if we came here from the SSL error dialog
192 if (fromShowSSLCertificateOnError) {
193 // go back to the SSL error dialog
194 showSSLCertificateOnError(
195 mSSLCertificateOnErrorView,
196 mSSLCertificateOnErrorHandler,
197 mSSLCertificateOnErrorError);
198 }
199 }
200 })
201 .setOnCancelListener(
202 new DialogInterface.OnCancelListener() {
203 public void onCancel(DialogInterface dialog) {
204 mPageInfoDialog = null;
205 mPageInfoView = null;
206
207 // if we came here from the SSL error dialog
208 if (fromShowSSLCertificateOnError) {
209 // go back to the SSL error dialog
210 showSSLCertificateOnError(
211 mSSLCertificateOnErrorView,
212 mSSLCertificateOnErrorHandler,
213 mSSLCertificateOnErrorError);
214 }
215 }
216 });
217
218 // if we have a main top-level page SSL certificate set or a certificate
219 // error
220 if (fromShowSSLCertificateOnError ||
221 (view != null && view.getCertificate() != null)) {
222 // add a 'View Certificate' button
223 alertDialogBuilder.setNeutralButton(
224 R.string.view_certificate,
225 new DialogInterface.OnClickListener() {
226 public void onClick(DialogInterface dialog,
227 int whichButton) {
228 mPageInfoDialog = null;
229 mPageInfoView = null;
230
231 // if we came here from the SSL error dialog
232 if (fromShowSSLCertificateOnError) {
233 // go back to the SSL error dialog
234 showSSLCertificateOnError(
235 mSSLCertificateOnErrorView,
236 mSSLCertificateOnErrorHandler,
237 mSSLCertificateOnErrorError);
238 } else {
239 // otherwise, display the top-most certificate from
240 // the chain
Steve Blockcbc67a02011-10-05 17:56:19 +0100241 showSSLCertificate(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700242 }
243 }
244 });
245 }
246
247 mPageInfoDialog = alertDialogBuilder.show();
248 }
249
250 /**
251 * Displays the main top-level page SSL certificate dialog
252 * (accessible from the Page-Info dialog).
253 * @param tab The tab to show certificate for.
254 */
255 private void showSSLCertificate(final Tab tab) {
Brian Carlstrom873034c2011-06-26 21:06:43 -0700256
257 SslCertificate cert = tab.getWebView().getCertificate();
258 if (cert == null) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700259 return;
260 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700261
262 mSSLCertificateView = tab;
Steve Block08a6f0c2011-10-06 12:12:53 +0100263 mSSLCertificateDialog = createSslCertificateDialog(cert, tab.getSslCertificateError())
Michael Kolb8233fac2010-10-26 16:08:53 -0700264 .setPositiveButton(R.string.ok,
265 new DialogInterface.OnClickListener() {
266 public void onClick(DialogInterface dialog,
267 int whichButton) {
268 mSSLCertificateDialog = null;
269 mSSLCertificateView = null;
270
Huahui Wuae0c0412011-06-28 10:17:05 -0700271 showPageInfo(tab, false, null);
Michael Kolb8233fac2010-10-26 16:08:53 -0700272 }
273 })
274 .setOnCancelListener(
275 new DialogInterface.OnCancelListener() {
276 public void onCancel(DialogInterface dialog) {
277 mSSLCertificateDialog = null;
278 mSSLCertificateView = null;
279
Huahui Wuae0c0412011-06-28 10:17:05 -0700280 showPageInfo(tab, false, null);
Michael Kolb8233fac2010-10-26 16:08:53 -0700281 }
282 })
283 .show();
284 }
285
286 /**
287 * Displays the SSL error certificate dialog.
288 * @param view The target web-view.
289 * @param handler The SSL error handler responsible for cancelling the
290 * connection that resulted in an SSL error or proceeding per user request.
291 * @param error The SSL error object.
292 */
293 void showSSLCertificateOnError(
294 final WebView view, final SslErrorHandler handler,
295 final SslError error) {
296
Brian Carlstrom873034c2011-06-26 21:06:43 -0700297 SslCertificate cert = error.getCertificate();
298 if (cert == null) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700299 return;
300 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700301
302 mSSLCertificateOnErrorHandler = handler;
303 mSSLCertificateOnErrorView = view;
304 mSSLCertificateOnErrorError = error;
Steve Blockcbc67a02011-10-05 17:56:19 +0100305 mSSLCertificateOnErrorDialog = createSslCertificateDialog(cert, error)
Michael Kolb8233fac2010-10-26 16:08:53 -0700306 .setPositiveButton(R.string.ok,
307 new DialogInterface.OnClickListener() {
308 public void onClick(DialogInterface dialog,
309 int whichButton) {
310 mSSLCertificateOnErrorDialog = null;
311 mSSLCertificateOnErrorView = null;
312 mSSLCertificateOnErrorHandler = null;
313 mSSLCertificateOnErrorError = null;
314
Jonathan Dixone1d6dfc2012-12-17 13:39:17 -0800315 ((BrowserWebView) view).getWebViewClient().
Jonathan Dixon4d2fcab2012-02-24 00:13:06 +0000316 onReceivedSslError(view, handler, error);
Michael Kolb8233fac2010-10-26 16:08:53 -0700317 }
318 })
319 .setNeutralButton(R.string.page_info_view,
320 new DialogInterface.OnClickListener() {
321 public void onClick(DialogInterface dialog,
322 int whichButton) {
323 mSSLCertificateOnErrorDialog = null;
324
325 // do not clear the dialog state: we will
326 // need to show the dialog again once the
327 // user is done exploring the page-info details
328
329 showPageInfo(mController.getTabControl()
330 .getTabFromView(view),
Huahui Wuae0c0412011-06-28 10:17:05 -0700331 true,
332 error.getUrl());
Michael Kolb8233fac2010-10-26 16:08:53 -0700333 }
334 })
335 .setOnCancelListener(
336 new DialogInterface.OnCancelListener() {
337 public void onCancel(DialogInterface dialog) {
338 mSSLCertificateOnErrorDialog = null;
339 mSSLCertificateOnErrorView = null;
340 mSSLCertificateOnErrorHandler = null;
341 mSSLCertificateOnErrorError = null;
342
Jonathan Dixone1d6dfc2012-12-17 13:39:17 -0800343 ((BrowserWebView) view).getWebViewClient().
Jonathan Dixon4d2fcab2012-02-24 00:13:06 +0000344 onReceivedSslError(view, handler, error);
Michael Kolb8233fac2010-10-26 16:08:53 -0700345 }
346 })
347 .show();
348 }
Steve Blockcbc67a02011-10-05 17:56:19 +0100349
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800350 private static View inflateCertificateView(SslCertificate certificate, Context ctx) {
Bijan Amirzada58383e72014-04-01 14:45:22 -0700351 Object[] params = {ctx};
352 Class[] type = new Class[] {Context.class};
353 return (View)ReflectHelper.invokeMethod(certificate, "inflateCertificateView",type, params);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800354 }
355
Steve Blockcbc67a02011-10-05 17:56:19 +0100356 /*
357 * Creates an AlertDialog to display the given certificate. If error is
358 * null, text is added to state that the certificae is valid and the icon
359 * is set accordingly. If error is non-null, it must relate to the supplied
360 * certificate. In this case, error is used to add text describing the
361 * problems with the certificate and a different icon is used.
362 */
363 private AlertDialog.Builder createSslCertificateDialog(SslCertificate certificate,
364 SslError error) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800365 View certificateView = inflateCertificateView(certificate, mContext);
366 Resources res = Resources.getSystem();
Tarun Nainaniac724562014-11-03 17:40:38 -0800367 // load 'android.R.placeholder' via introspection, since it's not a public resource ID
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800368 int placeholder_id = res.getIdentifier("placeholder", "id", "android");
Steve Blockcbc67a02011-10-05 17:56:19 +0100369 final LinearLayout placeholder =
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800370 (LinearLayout)certificateView.findViewById(placeholder_id);
Steve Blockcbc67a02011-10-05 17:56:19 +0100371
372 LayoutInflater factory = LayoutInflater.from(mContext);
373 int iconId;
374
375 if (error == null) {
376 iconId = R.drawable.ic_dialog_browser_certificate_secure;
377 LinearLayout table = (LinearLayout)factory.inflate(R.layout.ssl_success, placeholder);
378 TextView successString = (TextView)table.findViewById(R.id.success);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800379 successString.setText(R.string.ssl_certificate_is_valid);
Steve Blockcbc67a02011-10-05 17:56:19 +0100380 } else {
381 iconId = R.drawable.ic_dialog_browser_certificate_partially_secure;
382 if (error.hasError(SslError.SSL_UNTRUSTED)) {
383 addError(factory, placeholder, R.string.ssl_untrusted);
384 }
385 if (error.hasError(SslError.SSL_IDMISMATCH)) {
386 addError(factory, placeholder, R.string.ssl_mismatch);
387 }
388 if (error.hasError(SslError.SSL_EXPIRED)) {
389 addError(factory, placeholder, R.string.ssl_expired);
390 }
391 if (error.hasError(SslError.SSL_NOTYETVALID)) {
392 addError(factory, placeholder, R.string.ssl_not_yet_valid);
393 }
394 if (error.hasError(SslError.SSL_DATE_INVALID)) {
395 addError(factory, placeholder, R.string.ssl_date_invalid);
396 }
397 if (error.hasError(SslError.SSL_INVALID)) {
398 addError(factory, placeholder, R.string.ssl_invalid);
399 }
400 // The SslError should always have at least one type of error and we
401 // should explicitly handle every type of error it supports. We
402 // therefore expect the condition below to never be hit. We use it
403 // as as safety net in case a new error type is added to SslError
404 // without the logic above being updated accordingly.
405 if (placeholder.getChildCount() == 0) {
406 addError(factory, placeholder, R.string.ssl_unknown);
407 }
408 }
409
410 return new AlertDialog.Builder(mContext)
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800411 .setTitle(R.string.ssl_certificate)
Steve Blockcbc67a02011-10-05 17:56:19 +0100412 .setIcon(iconId)
413 .setView(certificateView);
414 }
415
416 private void addError(LayoutInflater inflater, LinearLayout parent, int error) {
417 TextView textView = (TextView) inflater.inflate(R.layout.ssl_warning,
418 parent, false);
419 textView.setText(error);
420 parent.addView(textView);
421 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700422}