blob: c902f65d86ad4cceb3ba3f291d477990cd759eea [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;
42 private Tab mPageInfoView;
43 private AlertDialog mPageInfoDialog;
44
45 // as SSLCertificateOnError has different style for landscape / portrait,
46 // we have to re-open it when configuration changed
47 private AlertDialog mSSLCertificateOnErrorDialog;
48 private WebView mSSLCertificateOnErrorView;
49 private SslErrorHandler mSSLCertificateOnErrorHandler;
50 private SslError mSSLCertificateOnErrorError;
51
52 // as SSLCertificate has different style for landscape / portrait, we
53 // have to re-open it when configuration changed
54 private AlertDialog mSSLCertificateDialog;
55 private Tab mSSLCertificateView;
56 private HttpAuthenticationDialog mHttpAuthenticationDialog;
57
58 public PageDialogsHandler(Context context, Controller controller) {
59 mContext = context;
60 mController = controller;
61 }
62
63 public void onConfigurationChanged(Configuration config) {
64 if (mPageInfoDialog != null) {
65 mPageInfoDialog.dismiss();
66 showPageInfo(mPageInfoView, mPageInfoFromShowSSLCertificateOnError);
67 }
68 if (mSSLCertificateDialog != null) {
69 mSSLCertificateDialog.dismiss();
70 showSSLCertificate(mSSLCertificateView);
71 }
72 if (mSSLCertificateOnErrorDialog != null) {
73 mSSLCertificateOnErrorDialog.dismiss();
74 showSSLCertificateOnError(mSSLCertificateOnErrorView, mSSLCertificateOnErrorHandler,
75 mSSLCertificateOnErrorError);
76 }
77 if (mHttpAuthenticationDialog != null) {
78 mHttpAuthenticationDialog.reshow();
79 }
80 }
81
82 /**
83 * Displays an http-authentication dialog.
84 */
85 void showHttpAuthentication(final Tab tab, final HttpAuthHandler handler, String host, String realm) {
86 mHttpAuthenticationDialog = new HttpAuthenticationDialog(mContext, host, realm);
87 mHttpAuthenticationDialog.setOkListener(new HttpAuthenticationDialog.OkListener() {
88 public void onOk(String host, String realm, String username, String password) {
89 setHttpAuthUsernamePassword(host, realm, username, password);
90 handler.proceed(username, password);
91 mHttpAuthenticationDialog = null;
92 }
93 });
94 mHttpAuthenticationDialog.setCancelListener(new HttpAuthenticationDialog.CancelListener() {
95 public void onCancel() {
96 handler.cancel();
John Reck30c714c2010-12-16 17:30:34 -080097 mController.onUpdatedLockIcon(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -070098 mHttpAuthenticationDialog = null;
99 }
100 });
101 mHttpAuthenticationDialog.show();
102 }
103
104 /**
105 * Set HTTP authentication password.
106 *
107 * @param host The host for the password
108 * @param realm The realm for the password
109 * @param username The username for the password. If it is null, it means
110 * password can't be saved.
111 * @param password The password
112 */
113 public void setHttpAuthUsernamePassword(String host, String realm,
114 String username,
115 String password) {
116 WebView w = mController.getCurrentTopWebView();
117 if (w != null) {
118 w.setHttpAuthUsernamePassword(host, realm, username, password);
119 }
120 }
121
122 /**
123 * Displays a page-info dialog.
124 * @param tab The tab to show info about
125 * @param fromShowSSLCertificateOnError The flag that indicates whether
126 * this dialog was opened from the SSL-certificate-on-error dialog or
127 * not. This is important, since we need to know whether to return to
128 * the parent dialog or simply dismiss.
129 */
130 void showPageInfo(final Tab tab,
131 final boolean fromShowSSLCertificateOnError) {
132 final LayoutInflater factory = LayoutInflater.from(mContext);
133
134 final View pageInfoView = factory.inflate(R.layout.page_info, null);
135
136 final WebView view = tab.getWebView();
137
John Reck30c714c2010-12-16 17:30:34 -0800138 String url = tab.getUrl();
139 String title = tab.getTitle();
Michael Kolb8233fac2010-10-26 16:08:53 -0700140
141 if (url == null) {
142 url = "";
143 }
144 if (title == null) {
145 title = "";
146 }
147
148 ((TextView) pageInfoView.findViewById(R.id.address)).setText(url);
149 ((TextView) pageInfoView.findViewById(R.id.title)).setText(title);
150
151 mPageInfoView = tab;
152 mPageInfoFromShowSSLCertificateOnError = fromShowSSLCertificateOnError;
153
154 AlertDialog.Builder alertDialogBuilder =
155 new AlertDialog.Builder(mContext)
156 .setTitle(R.string.page_info)
157 .setIcon(android.R.drawable.ic_dialog_info)
158 .setView(pageInfoView)
159 .setPositiveButton(
160 R.string.ok,
161 new DialogInterface.OnClickListener() {
162 public void onClick(DialogInterface dialog,
163 int whichButton) {
164 mPageInfoDialog = null;
165 mPageInfoView = null;
166
167 // if we came here from the SSL error dialog
168 if (fromShowSSLCertificateOnError) {
169 // go back to the SSL error dialog
170 showSSLCertificateOnError(
171 mSSLCertificateOnErrorView,
172 mSSLCertificateOnErrorHandler,
173 mSSLCertificateOnErrorError);
174 }
175 }
176 })
177 .setOnCancelListener(
178 new DialogInterface.OnCancelListener() {
179 public void onCancel(DialogInterface dialog) {
180 mPageInfoDialog = null;
181 mPageInfoView = null;
182
183 // if we came here from the SSL error dialog
184 if (fromShowSSLCertificateOnError) {
185 // go back to the SSL error dialog
186 showSSLCertificateOnError(
187 mSSLCertificateOnErrorView,
188 mSSLCertificateOnErrorHandler,
189 mSSLCertificateOnErrorError);
190 }
191 }
192 });
193
194 // if we have a main top-level page SSL certificate set or a certificate
195 // error
196 if (fromShowSSLCertificateOnError ||
197 (view != null && view.getCertificate() != null)) {
198 // add a 'View Certificate' button
199 alertDialogBuilder.setNeutralButton(
200 R.string.view_certificate,
201 new DialogInterface.OnClickListener() {
202 public void onClick(DialogInterface dialog,
203 int whichButton) {
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 } else {
215 // otherwise, display the top-most certificate from
216 // the chain
217 if (view.getCertificate() != null) {
218 showSSLCertificate(tab);
219 }
220 }
221 }
222 });
223 }
224
225 mPageInfoDialog = alertDialogBuilder.show();
226 }
227
228 /**
229 * Displays the main top-level page SSL certificate dialog
230 * (accessible from the Page-Info dialog).
231 * @param tab The tab to show certificate for.
232 */
233 private void showSSLCertificate(final Tab tab) {
Brian Carlstrom873034c2011-06-26 21:06:43 -0700234
235 SslCertificate cert = tab.getWebView().getCertificate();
236 if (cert == null) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700237 return;
238 }
Brian Carlstrom873034c2011-06-26 21:06:43 -0700239 final View certificateView = cert.inflateCertificateView(mContext);
Michael Kolb8233fac2010-10-26 16:08:53 -0700240
241 LayoutInflater factory = LayoutInflater.from(mContext);
242
243 final LinearLayout placeholder =
244 (LinearLayout)certificateView.findViewById(R.id.placeholder);
245
246 LinearLayout ll = (LinearLayout) factory.inflate(
247 R.layout.ssl_success, placeholder);
248 ((TextView)ll.findViewById(R.id.success))
Brian Carlstrom873034c2011-06-26 21:06:43 -0700249 .setText(com.android.internal.R.string.ssl_certificate_is_valid);
Michael Kolb8233fac2010-10-26 16:08:53 -0700250
251 mSSLCertificateView = tab;
252 mSSLCertificateDialog =
253 new AlertDialog.Builder(mContext)
Brian Carlstrom873034c2011-06-26 21:06:43 -0700254 .setTitle(com.android.internal.R.string.ssl_certificate).setIcon(
Michael Kolb8233fac2010-10-26 16:08:53 -0700255 R.drawable.ic_dialog_browser_certificate_secure)
256 .setView(certificateView)
257 .setPositiveButton(R.string.ok,
258 new DialogInterface.OnClickListener() {
259 public void onClick(DialogInterface dialog,
260 int whichButton) {
261 mSSLCertificateDialog = null;
262 mSSLCertificateView = null;
263
264 showPageInfo(tab, false);
265 }
266 })
267 .setOnCancelListener(
268 new DialogInterface.OnCancelListener() {
269 public void onCancel(DialogInterface dialog) {
270 mSSLCertificateDialog = null;
271 mSSLCertificateView = null;
272
273 showPageInfo(tab, false);
274 }
275 })
276 .show();
277 }
278
279 /**
280 * Displays the SSL error certificate dialog.
281 * @param view The target web-view.
282 * @param handler The SSL error handler responsible for cancelling the
283 * connection that resulted in an SSL error or proceeding per user request.
284 * @param error The SSL error object.
285 */
286 void showSSLCertificateOnError(
287 final WebView view, final SslErrorHandler handler,
288 final SslError error) {
289
Brian Carlstrom873034c2011-06-26 21:06:43 -0700290 SslCertificate cert = error.getCertificate();
291 if (cert == null) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700292 return;
293 }
Brian Carlstrom873034c2011-06-26 21:06:43 -0700294 final View certificateView = cert.inflateCertificateView(mContext);
Michael Kolb8233fac2010-10-26 16:08:53 -0700295
296 LayoutInflater factory = LayoutInflater.from(mContext);
297
298 final LinearLayout placeholder =
299 (LinearLayout)certificateView.findViewById(R.id.placeholder);
300
301 if (error.hasError(SslError.SSL_UNTRUSTED)) {
302 LinearLayout ll = (LinearLayout)factory
303 .inflate(R.layout.ssl_warning, placeholder);
304 ((TextView)ll.findViewById(R.id.warning))
305 .setText(R.string.ssl_untrusted);
306 }
307
308 if (error.hasError(SslError.SSL_IDMISMATCH)) {
309 LinearLayout ll = (LinearLayout)factory
310 .inflate(R.layout.ssl_warning, placeholder);
311 ((TextView)ll.findViewById(R.id.warning))
312 .setText(R.string.ssl_mismatch);
313 }
314
315 if (error.hasError(SslError.SSL_EXPIRED)) {
316 LinearLayout ll = (LinearLayout)factory
317 .inflate(R.layout.ssl_warning, placeholder);
318 ((TextView)ll.findViewById(R.id.warning))
319 .setText(R.string.ssl_expired);
320 }
321
322 if (error.hasError(SslError.SSL_NOTYETVALID)) {
323 LinearLayout ll = (LinearLayout)factory
324 .inflate(R.layout.ssl_warning, placeholder);
325 ((TextView)ll.findViewById(R.id.warning))
326 .setText(R.string.ssl_not_yet_valid);
327 }
328
329 mSSLCertificateOnErrorHandler = handler;
330 mSSLCertificateOnErrorView = view;
331 mSSLCertificateOnErrorError = error;
332 mSSLCertificateOnErrorDialog =
333 new AlertDialog.Builder(mContext)
Brian Carlstrom873034c2011-06-26 21:06:43 -0700334 .setTitle(com.android.internal.R.string.ssl_certificate).setIcon(
Michael Kolb8233fac2010-10-26 16:08:53 -0700335 R.drawable.ic_dialog_browser_certificate_partially_secure)
336 .setView(certificateView)
337 .setPositiveButton(R.string.ok,
338 new DialogInterface.OnClickListener() {
339 public void onClick(DialogInterface dialog,
340 int whichButton) {
341 mSSLCertificateOnErrorDialog = null;
342 mSSLCertificateOnErrorView = null;
343 mSSLCertificateOnErrorHandler = null;
344 mSSLCertificateOnErrorError = null;
345
346 view.getWebViewClient().onReceivedSslError(
347 view, handler, error);
348 }
349 })
350 .setNeutralButton(R.string.page_info_view,
351 new DialogInterface.OnClickListener() {
352 public void onClick(DialogInterface dialog,
353 int whichButton) {
354 mSSLCertificateOnErrorDialog = null;
355
356 // do not clear the dialog state: we will
357 // need to show the dialog again once the
358 // user is done exploring the page-info details
359
360 showPageInfo(mController.getTabControl()
361 .getTabFromView(view),
362 true);
363 }
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}