blob: e027e80a0651f50c97f490a54e126afcf05035a7 [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;
30import org.codeaurora.swe.WebView;
31
Bijan Amirzada58383e72014-04-01 14:45:22 -070032import com.android.browser.reflect.ReflectHelper;
Bijan Amirzada41242f22014-03-21 12:12:18 -070033import com.android.browser.R;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080034
Michael Kolb8233fac2010-10-26 16:08:53 -070035import android.widget.LinearLayout;
36import android.widget.TextView;
37
Michael Kolb8233fac2010-10-26 16:08:53 -070038/**
39 * Displays page info
40 *
41 */
42public class PageDialogsHandler {
43
44 private Context mContext;
45 private Controller mController;
46 private boolean mPageInfoFromShowSSLCertificateOnError;
Huahui Wuae0c0412011-06-28 10:17:05 -070047 private String mUrlCertificateOnError;
Michael Kolb8233fac2010-10-26 16:08:53 -070048 private Tab mPageInfoView;
49 private AlertDialog mPageInfoDialog;
50
51 // as SSLCertificateOnError has different style for landscape / portrait,
52 // we have to re-open it when configuration changed
53 private AlertDialog mSSLCertificateOnErrorDialog;
54 private WebView mSSLCertificateOnErrorView;
55 private SslErrorHandler mSSLCertificateOnErrorHandler;
56 private SslError mSSLCertificateOnErrorError;
57
58 // as SSLCertificate has different style for landscape / portrait, we
59 // have to re-open it when configuration changed
60 private AlertDialog mSSLCertificateDialog;
61 private Tab mSSLCertificateView;
62 private HttpAuthenticationDialog mHttpAuthenticationDialog;
63
64 public PageDialogsHandler(Context context, Controller controller) {
65 mContext = context;
66 mController = controller;
67 }
68
69 public void onConfigurationChanged(Configuration config) {
70 if (mPageInfoDialog != null) {
71 mPageInfoDialog.dismiss();
Huahui Wuae0c0412011-06-28 10:17:05 -070072 showPageInfo(mPageInfoView,
73 mPageInfoFromShowSSLCertificateOnError,
74 mUrlCertificateOnError);
Michael Kolb8233fac2010-10-26 16:08:53 -070075 }
76 if (mSSLCertificateDialog != null) {
77 mSSLCertificateDialog.dismiss();
78 showSSLCertificate(mSSLCertificateView);
79 }
80 if (mSSLCertificateOnErrorDialog != null) {
81 mSSLCertificateOnErrorDialog.dismiss();
Huahui Wuae0c0412011-06-28 10:17:05 -070082 showSSLCertificateOnError(mSSLCertificateOnErrorView,
83 mSSLCertificateOnErrorHandler,
84 mSSLCertificateOnErrorError);
Michael Kolb8233fac2010-10-26 16:08:53 -070085 }
86 if (mHttpAuthenticationDialog != null) {
87 mHttpAuthenticationDialog.reshow();
88 }
89 }
90
91 /**
92 * Displays an http-authentication dialog.
93 */
94 void showHttpAuthentication(final Tab tab, final HttpAuthHandler handler, String host, String realm) {
95 mHttpAuthenticationDialog = new HttpAuthenticationDialog(mContext, host, realm);
96 mHttpAuthenticationDialog.setOkListener(new HttpAuthenticationDialog.OkListener() {
97 public void onOk(String host, String realm, String username, String password) {
98 setHttpAuthUsernamePassword(host, realm, username, password);
99 handler.proceed(username, password);
100 mHttpAuthenticationDialog = null;
101 }
102 });
103 mHttpAuthenticationDialog.setCancelListener(new HttpAuthenticationDialog.CancelListener() {
104 public void onCancel() {
105 handler.cancel();
Steve Block2466eff2011-10-03 15:33:09 +0100106 mController.onUpdatedSecurityState(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700107 mHttpAuthenticationDialog = null;
108 }
109 });
110 mHttpAuthenticationDialog.show();
111 }
112
113 /**
114 * Set HTTP authentication password.
115 *
116 * @param host The host for the password
117 * @param realm The realm for the password
118 * @param username The username for the password. If it is null, it means
119 * password can't be saved.
120 * @param password The password
121 */
122 public void setHttpAuthUsernamePassword(String host, String realm,
123 String username,
124 String password) {
125 WebView w = mController.getCurrentTopWebView();
Panos Thomase5a847f2015-01-07 10:15:41 -0800126 if (w != null && BrowserSettings.getInstance().rememberPasswords()) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700127 w.setHttpAuthUsernamePassword(host, realm, username, password);
128 }
129 }
130
131 /**
132 * Displays a page-info dialog.
133 * @param tab The tab to show info about
134 * @param fromShowSSLCertificateOnError The flag that indicates whether
135 * this dialog was opened from the SSL-certificate-on-error dialog or
136 * not. This is important, since we need to know whether to return to
137 * the parent dialog or simply dismiss.
Huahui Wuae0c0412011-06-28 10:17:05 -0700138 * @param urlCertificateOnError The URL that invokes SSLCertificateError.
139 * Null when fromShowSSLCertificateOnError is false.
Michael Kolb8233fac2010-10-26 16:08:53 -0700140 */
141 void showPageInfo(final Tab tab,
Huahui Wuae0c0412011-06-28 10:17:05 -0700142 final boolean fromShowSSLCertificateOnError,
143 final String urlCertificateOnError) {
Michael Kolbd5cb4fa2012-04-18 08:29:16 -0700144 if (tab == null) return;
Michael Kolb8233fac2010-10-26 16:08:53 -0700145 final LayoutInflater factory = LayoutInflater.from(mContext);
146
147 final View pageInfoView = factory.inflate(R.layout.page_info, null);
148
149 final WebView view = tab.getWebView();
150
Huahui Wuae0c0412011-06-28 10:17:05 -0700151 String url = fromShowSSLCertificateOnError ? urlCertificateOnError : tab.getUrl();
John Reck30c714c2010-12-16 17:30:34 -0800152 String title = tab.getTitle();
Michael Kolb8233fac2010-10-26 16:08:53 -0700153
154 if (url == null) {
155 url = "";
156 }
157 if (title == null) {
158 title = "";
159 }
160
161 ((TextView) pageInfoView.findViewById(R.id.address)).setText(url);
162 ((TextView) pageInfoView.findViewById(R.id.title)).setText(title);
163
164 mPageInfoView = tab;
165 mPageInfoFromShowSSLCertificateOnError = fromShowSSLCertificateOnError;
Huahui Wuae0c0412011-06-28 10:17:05 -0700166 mUrlCertificateOnError = urlCertificateOnError;
Michael Kolb8233fac2010-10-26 16:08:53 -0700167
168 AlertDialog.Builder alertDialogBuilder =
169 new AlertDialog.Builder(mContext)
170 .setTitle(R.string.page_info)
171 .setIcon(android.R.drawable.ic_dialog_info)
172 .setView(pageInfoView)
173 .setPositiveButton(
174 R.string.ok,
175 new DialogInterface.OnClickListener() {
176 public void onClick(DialogInterface dialog,
177 int whichButton) {
178 mPageInfoDialog = null;
179 mPageInfoView = null;
180
181 // if we came here from the SSL error dialog
182 if (fromShowSSLCertificateOnError) {
183 // go back to the SSL error dialog
184 showSSLCertificateOnError(
185 mSSLCertificateOnErrorView,
186 mSSLCertificateOnErrorHandler,
187 mSSLCertificateOnErrorError);
188 }
189 }
190 })
191 .setOnCancelListener(
192 new DialogInterface.OnCancelListener() {
193 public void onCancel(DialogInterface dialog) {
194 mPageInfoDialog = null;
195 mPageInfoView = null;
196
197 // if we came here from the SSL error dialog
198 if (fromShowSSLCertificateOnError) {
199 // go back to the SSL error dialog
200 showSSLCertificateOnError(
201 mSSLCertificateOnErrorView,
202 mSSLCertificateOnErrorHandler,
203 mSSLCertificateOnErrorError);
204 }
205 }
206 });
207
208 // if we have a main top-level page SSL certificate set or a certificate
209 // error
210 if (fromShowSSLCertificateOnError ||
211 (view != null && view.getCertificate() != null)) {
212 // add a 'View Certificate' button
213 alertDialogBuilder.setNeutralButton(
214 R.string.view_certificate,
215 new DialogInterface.OnClickListener() {
216 public void onClick(DialogInterface dialog,
217 int whichButton) {
218 mPageInfoDialog = null;
219 mPageInfoView = null;
220
221 // if we came here from the SSL error dialog
222 if (fromShowSSLCertificateOnError) {
223 // go back to the SSL error dialog
224 showSSLCertificateOnError(
225 mSSLCertificateOnErrorView,
226 mSSLCertificateOnErrorHandler,
227 mSSLCertificateOnErrorError);
228 } else {
229 // otherwise, display the top-most certificate from
230 // the chain
Steve Blockcbc67a02011-10-05 17:56:19 +0100231 showSSLCertificate(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700232 }
233 }
234 });
235 }
236
237 mPageInfoDialog = alertDialogBuilder.show();
238 }
239
240 /**
241 * Displays the main top-level page SSL certificate dialog
242 * (accessible from the Page-Info dialog).
243 * @param tab The tab to show certificate for.
244 */
245 private void showSSLCertificate(final Tab tab) {
Brian Carlstrom873034c2011-06-26 21:06:43 -0700246
247 SslCertificate cert = tab.getWebView().getCertificate();
248 if (cert == null) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700249 return;
250 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700251
252 mSSLCertificateView = tab;
Steve Block08a6f0c2011-10-06 12:12:53 +0100253 mSSLCertificateDialog = createSslCertificateDialog(cert, tab.getSslCertificateError())
Michael Kolb8233fac2010-10-26 16:08:53 -0700254 .setPositiveButton(R.string.ok,
255 new DialogInterface.OnClickListener() {
256 public void onClick(DialogInterface dialog,
257 int whichButton) {
258 mSSLCertificateDialog = null;
259 mSSLCertificateView = null;
260
Huahui Wuae0c0412011-06-28 10:17:05 -0700261 showPageInfo(tab, false, null);
Michael Kolb8233fac2010-10-26 16:08:53 -0700262 }
263 })
264 .setOnCancelListener(
265 new DialogInterface.OnCancelListener() {
266 public void onCancel(DialogInterface dialog) {
267 mSSLCertificateDialog = null;
268 mSSLCertificateView = null;
269
Huahui Wuae0c0412011-06-28 10:17:05 -0700270 showPageInfo(tab, false, null);
Michael Kolb8233fac2010-10-26 16:08:53 -0700271 }
272 })
273 .show();
274 }
275
276 /**
277 * Displays the SSL error certificate dialog.
278 * @param view The target web-view.
279 * @param handler The SSL error handler responsible for cancelling the
280 * connection that resulted in an SSL error or proceeding per user request.
281 * @param error The SSL error object.
282 */
283 void showSSLCertificateOnError(
284 final WebView view, final SslErrorHandler handler,
285 final SslError error) {
286
Brian Carlstrom873034c2011-06-26 21:06:43 -0700287 SslCertificate cert = error.getCertificate();
288 if (cert == null) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700289 return;
290 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700291
292 mSSLCertificateOnErrorHandler = handler;
293 mSSLCertificateOnErrorView = view;
294 mSSLCertificateOnErrorError = error;
Steve Blockcbc67a02011-10-05 17:56:19 +0100295 mSSLCertificateOnErrorDialog = createSslCertificateDialog(cert, error)
Michael Kolb8233fac2010-10-26 16:08:53 -0700296 .setPositiveButton(R.string.ok,
297 new DialogInterface.OnClickListener() {
298 public void onClick(DialogInterface dialog,
299 int whichButton) {
300 mSSLCertificateOnErrorDialog = null;
301 mSSLCertificateOnErrorView = null;
302 mSSLCertificateOnErrorHandler = null;
303 mSSLCertificateOnErrorError = null;
304
Jonathan Dixone1d6dfc2012-12-17 13:39:17 -0800305 ((BrowserWebView) view).getWebViewClient().
Jonathan Dixon4d2fcab2012-02-24 00:13:06 +0000306 onReceivedSslError(view, handler, error);
Michael Kolb8233fac2010-10-26 16:08:53 -0700307 }
308 })
309 .setNeutralButton(R.string.page_info_view,
310 new DialogInterface.OnClickListener() {
311 public void onClick(DialogInterface dialog,
312 int whichButton) {
313 mSSLCertificateOnErrorDialog = null;
314
315 // do not clear the dialog state: we will
316 // need to show the dialog again once the
317 // user is done exploring the page-info details
318
319 showPageInfo(mController.getTabControl()
320 .getTabFromView(view),
Huahui Wuae0c0412011-06-28 10:17:05 -0700321 true,
322 error.getUrl());
Michael Kolb8233fac2010-10-26 16:08:53 -0700323 }
324 })
325 .setOnCancelListener(
326 new DialogInterface.OnCancelListener() {
327 public void onCancel(DialogInterface dialog) {
328 mSSLCertificateOnErrorDialog = null;
329 mSSLCertificateOnErrorView = null;
330 mSSLCertificateOnErrorHandler = null;
331 mSSLCertificateOnErrorError = null;
332
Jonathan Dixone1d6dfc2012-12-17 13:39:17 -0800333 ((BrowserWebView) view).getWebViewClient().
Jonathan Dixon4d2fcab2012-02-24 00:13:06 +0000334 onReceivedSslError(view, handler, error);
Michael Kolb8233fac2010-10-26 16:08:53 -0700335 }
336 })
337 .show();
338 }
Steve Blockcbc67a02011-10-05 17:56:19 +0100339
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800340 private static View inflateCertificateView(SslCertificate certificate, Context ctx) {
Bijan Amirzada58383e72014-04-01 14:45:22 -0700341 Object[] params = {ctx};
342 Class[] type = new Class[] {Context.class};
343 return (View)ReflectHelper.invokeMethod(certificate, "inflateCertificateView",type, params);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800344 }
345
Steve Blockcbc67a02011-10-05 17:56:19 +0100346 /*
347 * Creates an AlertDialog to display the given certificate. If error is
348 * null, text is added to state that the certificae is valid and the icon
349 * is set accordingly. If error is non-null, it must relate to the supplied
350 * certificate. In this case, error is used to add text describing the
351 * problems with the certificate and a different icon is used.
352 */
353 private AlertDialog.Builder createSslCertificateDialog(SslCertificate certificate,
354 SslError error) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800355 View certificateView = inflateCertificateView(certificate, mContext);
356 Resources res = Resources.getSystem();
Tarun Nainaniac724562014-11-03 17:40:38 -0800357 // load 'android.R.placeholder' via introspection, since it's not a public resource ID
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800358 int placeholder_id = res.getIdentifier("placeholder", "id", "android");
Steve Blockcbc67a02011-10-05 17:56:19 +0100359 final LinearLayout placeholder =
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800360 (LinearLayout)certificateView.findViewById(placeholder_id);
Steve Blockcbc67a02011-10-05 17:56:19 +0100361
362 LayoutInflater factory = LayoutInflater.from(mContext);
363 int iconId;
364
365 if (error == null) {
366 iconId = R.drawable.ic_dialog_browser_certificate_secure;
367 LinearLayout table = (LinearLayout)factory.inflate(R.layout.ssl_success, placeholder);
368 TextView successString = (TextView)table.findViewById(R.id.success);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800369 successString.setText(R.string.ssl_certificate_is_valid);
Steve Blockcbc67a02011-10-05 17:56:19 +0100370 } else {
371 iconId = R.drawable.ic_dialog_browser_certificate_partially_secure;
372 if (error.hasError(SslError.SSL_UNTRUSTED)) {
373 addError(factory, placeholder, R.string.ssl_untrusted);
374 }
375 if (error.hasError(SslError.SSL_IDMISMATCH)) {
376 addError(factory, placeholder, R.string.ssl_mismatch);
377 }
378 if (error.hasError(SslError.SSL_EXPIRED)) {
379 addError(factory, placeholder, R.string.ssl_expired);
380 }
381 if (error.hasError(SslError.SSL_NOTYETVALID)) {
382 addError(factory, placeholder, R.string.ssl_not_yet_valid);
383 }
384 if (error.hasError(SslError.SSL_DATE_INVALID)) {
385 addError(factory, placeholder, R.string.ssl_date_invalid);
386 }
387 if (error.hasError(SslError.SSL_INVALID)) {
388 addError(factory, placeholder, R.string.ssl_invalid);
389 }
390 // The SslError should always have at least one type of error and we
391 // should explicitly handle every type of error it supports. We
392 // therefore expect the condition below to never be hit. We use it
393 // as as safety net in case a new error type is added to SslError
394 // without the logic above being updated accordingly.
395 if (placeholder.getChildCount() == 0) {
396 addError(factory, placeholder, R.string.ssl_unknown);
397 }
398 }
399
400 return new AlertDialog.Builder(mContext)
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800401 .setTitle(R.string.ssl_certificate)
Steve Blockcbc67a02011-10-05 17:56:19 +0100402 .setIcon(iconId)
403 .setView(certificateView);
404 }
405
406 private void addError(LayoutInflater inflater, LinearLayout parent, int error) {
407 TextView textView = (TextView) inflater.inflate(R.layout.ssl_warning,
408 parent, false);
409 textView.setText(error);
410 parent.addView(textView);
411 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700412}