PageDialogsHandler.java revision 0cda68a870051d9346ff70448c93dcde541ca173
1/* 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; 25import 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 33/** 34 * Displays page info 35 * 36 */ 37public class PageDialogsHandler { 38 39 private Context mContext; 40 private Controller mController; 41 private boolean mPageInfoFromShowSSLCertificateOnError; 42 private String mUrlCertificateOnError; 43 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(); 67 showPageInfo(mPageInfoView, 68 mPageInfoFromShowSSLCertificateOnError, 69 mUrlCertificateOnError); 70 } 71 if (mSSLCertificateDialog != null) { 72 mSSLCertificateDialog.dismiss(); 73 showSSLCertificate(mSSLCertificateView); 74 } 75 if (mSSLCertificateOnErrorDialog != null) { 76 mSSLCertificateOnErrorDialog.dismiss(); 77 showSSLCertificateOnError(mSSLCertificateOnErrorView, 78 mSSLCertificateOnErrorHandler, 79 mSSLCertificateOnErrorError); 80 } 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(); 101 mController.onUpdatedLockIcon(tab); 102 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. 133 * @param urlCertificateOnError The URL that invokes SSLCertificateError. 134 * Null when fromShowSSLCertificateOnError is false. 135 */ 136 void showPageInfo(final Tab tab, 137 final boolean fromShowSSLCertificateOnError, 138 final String urlCertificateOnError) { 139 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 145 String url = fromShowSSLCertificateOnError ? urlCertificateOnError : tab.getUrl(); 146 String title = tab.getTitle(); 147 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; 160 mUrlCertificateOnError = urlCertificateOnError; 161 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) { 242 243 SslCertificate cert = tab.getWebView().getCertificate(); 244 if (cert == null) { 245 return; 246 } 247 final View certificateView = cert.inflateCertificateView(mContext); 248 249 LayoutInflater factory = LayoutInflater.from(mContext); 250 251 final LinearLayout placeholder = 252 (LinearLayout)certificateView.findViewById(com.android.internal.R.id.placeholder); 253 254 LinearLayout ll = (LinearLayout) factory.inflate( 255 R.layout.ssl_success, placeholder); 256 ((TextView)ll.findViewById(R.id.success)) 257 .setText(com.android.internal.R.string.ssl_certificate_is_valid); 258 259 mSSLCertificateView = tab; 260 mSSLCertificateDialog = 261 new AlertDialog.Builder(mContext) 262 .setTitle(com.android.internal.R.string.ssl_certificate).setIcon( 263 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 272 showPageInfo(tab, false, null); 273 } 274 }) 275 .setOnCancelListener( 276 new DialogInterface.OnCancelListener() { 277 public void onCancel(DialogInterface dialog) { 278 mSSLCertificateDialog = null; 279 mSSLCertificateView = null; 280 281 showPageInfo(tab, false, null); 282 } 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 298 SslCertificate cert = error.getCertificate(); 299 if (cert == null) { 300 return; 301 } 302 final View certificateView = cert.inflateCertificateView(mContext); 303 304 LayoutInflater factory = LayoutInflater.from(mContext); 305 306 final LinearLayout placeholder = 307 (LinearLayout)certificateView.findViewById(com.android.internal.R.id.placeholder); 308 309 if (error.hasError(SslError.SSL_UNTRUSTED)) { 310 LinearLayout ll = (LinearLayout)factory 311 .inflate(R.layout.ssl_warning, placeholder); 312 ((TextView)ll.findViewById(R.id.warning)) 313 .setText(R.string.ssl_untrusted); 314 } 315 316 if (error.hasError(SslError.SSL_IDMISMATCH)) { 317 LinearLayout ll = (LinearLayout)factory 318 .inflate(R.layout.ssl_warning, placeholder); 319 ((TextView)ll.findViewById(R.id.warning)) 320 .setText(R.string.ssl_mismatch); 321 } 322 323 if (error.hasError(SslError.SSL_EXPIRED)) { 324 LinearLayout ll = (LinearLayout)factory 325 .inflate(R.layout.ssl_warning, placeholder); 326 ((TextView)ll.findViewById(R.id.warning)) 327 .setText(R.string.ssl_expired); 328 } 329 330 if (error.hasError(SslError.SSL_NOTYETVALID)) { 331 LinearLayout ll = (LinearLayout)factory 332 .inflate(R.layout.ssl_warning, placeholder); 333 ((TextView)ll.findViewById(R.id.warning)) 334 .setText(R.string.ssl_not_yet_valid); 335 } 336 337 mSSLCertificateOnErrorHandler = handler; 338 mSSLCertificateOnErrorView = view; 339 mSSLCertificateOnErrorError = error; 340 mSSLCertificateOnErrorDialog = 341 new AlertDialog.Builder(mContext) 342 .setTitle(com.android.internal.R.string.ssl_certificate).setIcon( 343 R.drawable.ic_dialog_browser_certificate_partially_secure) 344 .setView(certificateView) 345 .setPositiveButton(R.string.ok, 346 new DialogInterface.OnClickListener() { 347 public void onClick(DialogInterface dialog, 348 int whichButton) { 349 mSSLCertificateOnErrorDialog = null; 350 mSSLCertificateOnErrorView = null; 351 mSSLCertificateOnErrorHandler = null; 352 mSSLCertificateOnErrorError = null; 353 354 view.getWebViewClient().onReceivedSslError( 355 view, handler, error); 356 } 357 }) 358 .setNeutralButton(R.string.page_info_view, 359 new DialogInterface.OnClickListener() { 360 public void onClick(DialogInterface dialog, 361 int whichButton) { 362 mSSLCertificateOnErrorDialog = null; 363 364 // do not clear the dialog state: we will 365 // need to show the dialog again once the 366 // user is done exploring the page-info details 367 368 showPageInfo(mController.getTabControl() 369 .getTabFromView(view), 370 true, 371 error.getUrl()); 372 } 373 }) 374 .setOnCancelListener( 375 new DialogInterface.OnCancelListener() { 376 public void onCancel(DialogInterface dialog) { 377 mSSLCertificateOnErrorDialog = null; 378 mSSLCertificateOnErrorView = null; 379 mSSLCertificateOnErrorHandler = null; 380 mSSLCertificateOnErrorError = null; 381 382 view.getWebViewClient().onReceivedSslError( 383 view, handler, error); 384 } 385 }) 386 .show(); 387 } 388} 389