blob: 3f64758f339b92e3860f4569bab1fa6f42072c5c [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
17package com.android.browser;
18
19import android.app.AlertDialog;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.content.res.Configuration;
23import android.net.http.SslCertificate;
24import android.net.http.SslError;
Michael Kolb8233fac2010-10-26 16:08:53 -070025import android.view.LayoutInflater;
26import android.view.View;
27import android.webkit.HttpAuthHandler;
28import android.webkit.SslErrorHandler;
29import android.webkit.WebView;
30import android.widget.LinearLayout;
31import android.widget.TextView;
32
Michael Kolb8233fac2010-10-26 16:08:53 -070033/**
34 * Displays page info
35 *
36 */
37public class PageDialogsHandler {
38
39 private Context mContext;
40 private Controller mController;
41 private boolean mPageInfoFromShowSSLCertificateOnError;
Huahui Wuae0c0412011-06-28 10:17:05 -070042 private String mUrlCertificateOnError;
Michael Kolb8233fac2010-10-26 16:08:53 -070043 private Tab mPageInfoView;
44 private AlertDialog mPageInfoDialog;
45
46 // as SSLCertificateOnError has different style for landscape / portrait,
47 // we have to re-open it when configuration changed
48 private AlertDialog mSSLCertificateOnErrorDialog;
49 private WebView mSSLCertificateOnErrorView;
50 private SslErrorHandler mSSLCertificateOnErrorHandler;
51 private SslError mSSLCertificateOnErrorError;
52
53 // as SSLCertificate has different style for landscape / portrait, we
54 // have to re-open it when configuration changed
55 private AlertDialog mSSLCertificateDialog;
56 private Tab mSSLCertificateView;
57 private HttpAuthenticationDialog mHttpAuthenticationDialog;
58
59 public PageDialogsHandler(Context context, Controller controller) {
60 mContext = context;
61 mController = controller;
62 }
63
64 public void onConfigurationChanged(Configuration config) {
65 if (mPageInfoDialog != null) {
66 mPageInfoDialog.dismiss();
Huahui Wuae0c0412011-06-28 10:17:05 -070067 showPageInfo(mPageInfoView,
68 mPageInfoFromShowSSLCertificateOnError,
69 mUrlCertificateOnError);
Michael Kolb8233fac2010-10-26 16:08:53 -070070 }
71 if (mSSLCertificateDialog != null) {
72 mSSLCertificateDialog.dismiss();
73 showSSLCertificate(mSSLCertificateView);
74 }
75 if (mSSLCertificateOnErrorDialog != null) {
76 mSSLCertificateOnErrorDialog.dismiss();
Huahui Wuae0c0412011-06-28 10:17:05 -070077 showSSLCertificateOnError(mSSLCertificateOnErrorView,
78 mSSLCertificateOnErrorHandler,
79 mSSLCertificateOnErrorError);
Michael Kolb8233fac2010-10-26 16:08:53 -070080 }
81 if (mHttpAuthenticationDialog != null) {
82 mHttpAuthenticationDialog.reshow();
83 }
84 }
85
86 /**
87 * Displays an http-authentication dialog.
88 */
89 void showHttpAuthentication(final Tab tab, final HttpAuthHandler handler, String host, String realm) {
90 mHttpAuthenticationDialog = new HttpAuthenticationDialog(mContext, host, realm);
91 mHttpAuthenticationDialog.setOkListener(new HttpAuthenticationDialog.OkListener() {
92 public void onOk(String host, String realm, String username, String password) {
93 setHttpAuthUsernamePassword(host, realm, username, password);
94 handler.proceed(username, password);
95 mHttpAuthenticationDialog = null;
96 }
97 });
98 mHttpAuthenticationDialog.setCancelListener(new HttpAuthenticationDialog.CancelListener() {
99 public void onCancel() {
100 handler.cancel();
John Reck30c714c2010-12-16 17:30:34 -0800101 mController.onUpdatedLockIcon(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700102 mHttpAuthenticationDialog = null;
103 }
104 });
105 mHttpAuthenticationDialog.show();
106 }
107
108 /**
109 * Set HTTP authentication password.
110 *
111 * @param host The host for the password
112 * @param realm The realm for the password
113 * @param username The username for the password. If it is null, it means
114 * password can't be saved.
115 * @param password The password
116 */
117 public void setHttpAuthUsernamePassword(String host, String realm,
118 String username,
119 String password) {
120 WebView w = mController.getCurrentTopWebView();
121 if (w != null) {
122 w.setHttpAuthUsernamePassword(host, realm, username, password);
123 }
124 }
125
126 /**
127 * Displays a page-info dialog.
128 * @param tab The tab to show info about
129 * @param fromShowSSLCertificateOnError The flag that indicates whether
130 * this dialog was opened from the SSL-certificate-on-error dialog or
131 * not. This is important, since we need to know whether to return to
132 * the parent dialog or simply dismiss.
Huahui Wuae0c0412011-06-28 10:17:05 -0700133 * @param urlCertificateOnError The URL that invokes SSLCertificateError.
134 * Null when fromShowSSLCertificateOnError is false.
Michael Kolb8233fac2010-10-26 16:08:53 -0700135 */
136 void showPageInfo(final Tab tab,
Huahui Wuae0c0412011-06-28 10:17:05 -0700137 final boolean fromShowSSLCertificateOnError,
138 final String urlCertificateOnError) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700139 final LayoutInflater factory = LayoutInflater.from(mContext);
140
141 final View pageInfoView = factory.inflate(R.layout.page_info, null);
142
143 final WebView view = tab.getWebView();
144
Huahui Wuae0c0412011-06-28 10:17:05 -0700145 String url = fromShowSSLCertificateOnError ? urlCertificateOnError : tab.getUrl();
John Reck30c714c2010-12-16 17:30:34 -0800146 String title = tab.getTitle();
Michael Kolb8233fac2010-10-26 16:08:53 -0700147
148 if (url == null) {
149 url = "";
150 }
151 if (title == null) {
152 title = "";
153 }
154
155 ((TextView) pageInfoView.findViewById(R.id.address)).setText(url);
156 ((TextView) pageInfoView.findViewById(R.id.title)).setText(title);
157
158 mPageInfoView = tab;
159 mPageInfoFromShowSSLCertificateOnError = fromShowSSLCertificateOnError;
Huahui Wuae0c0412011-06-28 10:17:05 -0700160 mUrlCertificateOnError = urlCertificateOnError;
Michael Kolb8233fac2010-10-26 16:08:53 -0700161
162 AlertDialog.Builder alertDialogBuilder =
163 new AlertDialog.Builder(mContext)
164 .setTitle(R.string.page_info)
165 .setIcon(android.R.drawable.ic_dialog_info)
166 .setView(pageInfoView)
167 .setPositiveButton(
168 R.string.ok,
169 new DialogInterface.OnClickListener() {
170 public void onClick(DialogInterface dialog,
171 int whichButton) {
172 mPageInfoDialog = null;
173 mPageInfoView = null;
174
175 // if we came here from the SSL error dialog
176 if (fromShowSSLCertificateOnError) {
177 // go back to the SSL error dialog
178 showSSLCertificateOnError(
179 mSSLCertificateOnErrorView,
180 mSSLCertificateOnErrorHandler,
181 mSSLCertificateOnErrorError);
182 }
183 }
184 })
185 .setOnCancelListener(
186 new DialogInterface.OnCancelListener() {
187 public void onCancel(DialogInterface dialog) {
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
202 // if we have a main top-level page SSL certificate set or a certificate
203 // error
204 if (fromShowSSLCertificateOnError ||
205 (view != null && view.getCertificate() != null)) {
206 // add a 'View Certificate' button
207 alertDialogBuilder.setNeutralButton(
208 R.string.view_certificate,
209 new DialogInterface.OnClickListener() {
210 public void onClick(DialogInterface dialog,
211 int whichButton) {
212 mPageInfoDialog = null;
213 mPageInfoView = null;
214
215 // if we came here from the SSL error dialog
216 if (fromShowSSLCertificateOnError) {
217 // go back to the SSL error dialog
218 showSSLCertificateOnError(
219 mSSLCertificateOnErrorView,
220 mSSLCertificateOnErrorHandler,
221 mSSLCertificateOnErrorError);
222 } else {
223 // otherwise, display the top-most certificate from
224 // the chain
225 if (view.getCertificate() != null) {
226 showSSLCertificate(tab);
227 }
228 }
229 }
230 });
231 }
232
233 mPageInfoDialog = alertDialogBuilder.show();
234 }
235
236 /**
237 * Displays the main top-level page SSL certificate dialog
238 * (accessible from the Page-Info dialog).
239 * @param tab The tab to show certificate for.
240 */
241 private void showSSLCertificate(final Tab tab) {
Brian Carlstrom873034c2011-06-26 21:06:43 -0700242
243 SslCertificate cert = tab.getWebView().getCertificate();
244 if (cert == null) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700245 return;
246 }
Brian Carlstrom873034c2011-06-26 21:06:43 -0700247 final View certificateView = cert.inflateCertificateView(mContext);
Michael Kolb8233fac2010-10-26 16:08:53 -0700248
249 LayoutInflater factory = LayoutInflater.from(mContext);
250
251 final LinearLayout placeholder =
Brian Carlstrom0cda68a2011-07-06 13:56:29 -0700252 (LinearLayout)certificateView.findViewById(com.android.internal.R.id.placeholder);
Michael Kolb8233fac2010-10-26 16:08:53 -0700253
254 LinearLayout ll = (LinearLayout) factory.inflate(
255 R.layout.ssl_success, placeholder);
256 ((TextView)ll.findViewById(R.id.success))
Brian Carlstrom873034c2011-06-26 21:06:43 -0700257 .setText(com.android.internal.R.string.ssl_certificate_is_valid);
Michael Kolb8233fac2010-10-26 16:08:53 -0700258
259 mSSLCertificateView = tab;
260 mSSLCertificateDialog =
261 new AlertDialog.Builder(mContext)
Brian Carlstrom873034c2011-06-26 21:06:43 -0700262 .setTitle(com.android.internal.R.string.ssl_certificate).setIcon(
Michael Kolb8233fac2010-10-26 16:08:53 -0700263 R.drawable.ic_dialog_browser_certificate_secure)
264 .setView(certificateView)
265 .setPositiveButton(R.string.ok,
266 new DialogInterface.OnClickListener() {
267 public void onClick(DialogInterface dialog,
268 int whichButton) {
269 mSSLCertificateDialog = null;
270 mSSLCertificateView = null;
271
Huahui Wuae0c0412011-06-28 10:17:05 -0700272 showPageInfo(tab, false, null);
Michael Kolb8233fac2010-10-26 16:08:53 -0700273 }
274 })
275 .setOnCancelListener(
276 new DialogInterface.OnCancelListener() {
277 public void onCancel(DialogInterface dialog) {
278 mSSLCertificateDialog = null;
279 mSSLCertificateView = null;
280
Huahui Wuae0c0412011-06-28 10:17:05 -0700281 showPageInfo(tab, false, null);
Michael Kolb8233fac2010-10-26 16:08:53 -0700282 }
283 })
284 .show();
285 }
286
287 /**
288 * Displays the SSL error certificate dialog.
289 * @param view The target web-view.
290 * @param handler The SSL error handler responsible for cancelling the
291 * connection that resulted in an SSL error or proceeding per user request.
292 * @param error The SSL error object.
293 */
294 void showSSLCertificateOnError(
295 final WebView view, final SslErrorHandler handler,
296 final SslError error) {
297
Brian Carlstrom873034c2011-06-26 21:06:43 -0700298 SslCertificate cert = error.getCertificate();
299 if (cert == null) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700300 return;
301 }
Brian Carlstrom873034c2011-06-26 21:06:43 -0700302 final View certificateView = cert.inflateCertificateView(mContext);
Michael Kolb8233fac2010-10-26 16:08:53 -0700303
304 LayoutInflater factory = LayoutInflater.from(mContext);
305
306 final LinearLayout placeholder =
Brian Carlstrom0cda68a2011-07-06 13:56:29 -0700307 (LinearLayout)certificateView.findViewById(com.android.internal.R.id.placeholder);
Michael Kolb8233fac2010-10-26 16:08:53 -0700308
Kristian Monsen9eb0e892011-07-13 20:22:37 +0100309 LinearLayout ll = (LinearLayout)factory.inflate(R.layout.ssl_warning, placeholder);
310 TextView textView = (TextView)ll.findViewById(R.id.warning);
311
Michael Kolb8233fac2010-10-26 16:08:53 -0700312 if (error.hasError(SslError.SSL_UNTRUSTED)) {
Kristian Monsen9eb0e892011-07-13 20:22:37 +0100313 textView.setText(R.string.ssl_untrusted);
314 } else if (error.hasError(SslError.SSL_IDMISMATCH)) {
315 textView.setText(R.string.ssl_mismatch);
316 } else if (error.hasError(SslError.SSL_EXPIRED)) {
317 textView.setText(R.string.ssl_expired);
318 } else if (error.hasError(SslError.SSL_NOTYETVALID)) {
319 textView.setText(R.string.ssl_not_yet_valid);
320 } else if (error.hasError(SslError.SSL_DATE_INVALID)) {
321 textView.setText(R.string.ssl_date_invalid);
322 } else if (error.hasError(SslError.SSL_INVALID)) {
323 textView.setText(R.string.ssl_invalid);
324 } else {
325 textView.setText(R.string.ssl_unknown);
Michael Kolb8233fac2010-10-26 16:08:53 -0700326 }
327
328 mSSLCertificateOnErrorHandler = handler;
329 mSSLCertificateOnErrorView = view;
330 mSSLCertificateOnErrorError = error;
331 mSSLCertificateOnErrorDialog =
332 new AlertDialog.Builder(mContext)
Brian Carlstrom873034c2011-06-26 21:06:43 -0700333 .setTitle(com.android.internal.R.string.ssl_certificate).setIcon(
Michael Kolb8233fac2010-10-26 16:08:53 -0700334 R.drawable.ic_dialog_browser_certificate_partially_secure)
335 .setView(certificateView)
336 .setPositiveButton(R.string.ok,
337 new DialogInterface.OnClickListener() {
338 public void onClick(DialogInterface dialog,
339 int whichButton) {
340 mSSLCertificateOnErrorDialog = null;
341 mSSLCertificateOnErrorView = null;
342 mSSLCertificateOnErrorHandler = null;
343 mSSLCertificateOnErrorError = null;
344
345 view.getWebViewClient().onReceivedSslError(
346 view, handler, error);
347 }
348 })
349 .setNeutralButton(R.string.page_info_view,
350 new DialogInterface.OnClickListener() {
351 public void onClick(DialogInterface dialog,
352 int whichButton) {
353 mSSLCertificateOnErrorDialog = null;
354
355 // do not clear the dialog state: we will
356 // need to show the dialog again once the
357 // user is done exploring the page-info details
358
359 showPageInfo(mController.getTabControl()
360 .getTabFromView(view),
Huahui Wuae0c0412011-06-28 10:17:05 -0700361 true,
362 error.getUrl());
Michael Kolb8233fac2010-10-26 16:08:53 -0700363 }
364 })
365 .setOnCancelListener(
366 new DialogInterface.OnCancelListener() {
367 public void onCancel(DialogInterface dialog) {
368 mSSLCertificateOnErrorDialog = null;
369 mSSLCertificateOnErrorView = null;
370 mSSLCertificateOnErrorHandler = null;
371 mSSLCertificateOnErrorError = null;
372
373 view.getWebViewClient().onReceivedSslError(
374 view, handler, error);
375 }
376 })
377 .show();
378 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700379}