diff options
author | yfriedman@chromium.org <yfriedman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-26 04:20:08 +0000 |
---|---|---|
committer | yfriedman@chromium.org <yfriedman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-26 04:20:08 +0000 |
commit | 152ca7e5280d1aaee5f38181a97c2c9fc0d09105 (patch) | |
tree | 8c570c6373df79c675e951212c75c3c2b0875777 | |
parent | ef747cffdfb4d48eafb35cf38980890e1012a7d5 (diff) | |
download | chromium_src-152ca7e5280d1aaee5f38181a97c2c9fc0d09105.zip chromium_src-152ca7e5280d1aaee5f38181a97c2c9fc0d09105.tar.gz chromium_src-152ca7e5280d1aaee5f38181a97c2c9fc0d09105.tar.bz2 |
Android implementation of WebsiteSettingsUi
BUG=172013
Review URL: https://chromiumcodereview.appspot.com/12045081
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@179027 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/android/java/res/layout/website_settings.xml | 30 | ||||
-rw-r--r-- | chrome/android/java/res/values/dimens.xml | 3 | ||||
-rw-r--r-- | chrome/android/java/res/values/strings.xml | 4 | ||||
-rw-r--r-- | chrome/android/java/src/org/chromium/chrome/browser/CertificateViewer.java | 212 | ||||
-rw-r--r-- | chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java | 153 | ||||
-rw-r--r-- | chrome/browser/android/chrome_jni_registrar.cc | 6 | ||||
-rw-r--r-- | chrome/browser/ui/android/certificate_viewer_android.cc | 59 | ||||
-rw-r--r-- | chrome/browser/ui/android/website_settings_popup_android.cc | 185 | ||||
-rw-r--r-- | chrome/browser/ui/android/website_settings_popup_android.h | 55 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 4 | ||||
-rw-r--r-- | chrome/chrome_browser_ui.gypi | 2 |
11 files changed, 712 insertions, 1 deletions
diff --git a/chrome/android/java/res/layout/website_settings.xml b/chrome/android/java/res/layout/website_settings.xml new file mode 100644 index 0000000..a1d645d --- /dev/null +++ b/chrome/android/java/res/layout/website_settings.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (c) 2013 The Chromium Authors. All rights reserved. + + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingTop="@dimen/certificate_viewer_padding" + android:paddingBottom="@dimen/certificate_viewer_padding"> + <ImageView android:id="@+id/website_settings_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="@dimen/certificate_viewer_padding"/> + <LinearLayout android:orientation="vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="@dimen/certificate_viewer_padding" + android:paddingRight="@dimen/certificate_viewer_padding"> + <TextView android:id="@+id/website_settings_headline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textStyle="bold"/> + <TextView android:id="@+id/website_settings_description" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + </LinearLayout> +</LinearLayout> diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 328b8f3..901d446 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml @@ -16,4 +16,7 @@ <dimen name="favicon_fold_corner_radii">1dp</dimen> <dimen name="favicon_fold_border">1px</dimen> <dimen name="favicon_fold_shadow">2dp</dimen> + + <!-- Certificate Viewer Dimensions --> + <dimen name="certificate_viewer_padding">20dp</dimen> </resources> diff --git a/chrome/android/java/res/values/strings.xml b/chrome/android/java/res/values/strings.xml index 0dae284..10cbb3a 100644 --- a/chrome/android/java/res/values/strings.xml +++ b/chrome/android/java/res/values/strings.xml @@ -34,4 +34,8 @@ <string name="suppress_js_modal_dialogs">Prevent this page from creating additional dialogs</string> <!-- Content description for the input javascript modal dialog prompt. [CHAR-LIMIT=32] --> <string name="accessibility_js_modal_dialog_prompt">Prompt</string> + + <!-- Certificate Viewer --> + <!-- Dialog box title for viewing security certificates. [CHAR-LIMIT=32] --> + <string name="certtitle">Certificate Viewer</string> </resources> diff --git a/chrome/android/java/src/org/chromium/chrome/browser/CertificateViewer.java b/chrome/android/java/src/org/chromium/chrome/browser/CertificateViewer.java new file mode 100644 index 0000000..009952c --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/CertificateViewer.java @@ -0,0 +1,212 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Typeface; +import android.net.http.SslCertificate; +import android.text.format.DateFormat; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ArrayAdapter; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.Spinner; +import android.widget.TextView; + +import org.chromium.chrome.R; + +import java.io.ByteArrayInputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; + +/** + * UI component for displaying certificate information. + */ +class CertificateViewer implements OnItemSelectedListener { + private static final String X_509 = "X.509"; + private final Context mContext; + private final ArrayList<LinearLayout> mViews; + private final ArrayList<String> mTitles; + private final int mPadding; + private CertificateFactory mCertificateFactory; + + /** + * Show a dialog with the provided certificate information. + * + * @param context The context this view should display in. + * @param derData DER-encoded data representing a X509 certificate chain. + */ + public static void showCertificateChain(Context context, byte[][] derData) { + CertificateViewer viewer = new CertificateViewer(context); + viewer.showCertificateChain(derData); + } + + private CertificateViewer(Context context) { + mContext = context; + mViews = new ArrayList<LinearLayout>(); + mTitles = new ArrayList<String>(); + mPadding = (int) context.getResources().getDimension( + R.dimen.certificate_viewer_padding) / 2; + } + + // Show information about an array of DER-encoded data representing a X509 certificate chain. + // A spinner will be displayed allowing the user to select which certificate to display. + private void showCertificateChain(byte[][] derData) { + for (int i = 0; i < derData.length; i++) { + addCertificate(derData[i]); + } + ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(mContext, + android.R.layout.simple_spinner_item, + mTitles); + arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + Spinner spinner = new Spinner(mContext); + spinner.setAdapter(arrayAdapter); + spinner.setOnItemSelectedListener(this); + + LinearLayout container = new LinearLayout(mContext); + container.setOrientation(LinearLayout.VERTICAL); + container.addView(spinner); + + for (int i = 0; i < mViews.size(); ++i) { + LinearLayout certificateView = mViews.get(i); + if (i != 0) { + certificateView.setVisibility(LinearLayout.GONE); + } + container.addView(certificateView); + } + + showDialogForView(container); + } + + // Displays a dialog with scrolling for the given view. + private void showDialogForView(View view) { + Dialog dialog = new Dialog(mContext); + dialog.setTitle(R.string.certtitle); + ScrollView scrollView = new ScrollView(mContext); + scrollView.addView(view); + dialog.addContentView(scrollView, + new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT)); + dialog.show(); + } + + private void addCertificate(byte[] derData) { + try { + if (mCertificateFactory == null) { + mCertificateFactory = CertificateFactory.getInstance(X_509); + } + Certificate cert = mCertificateFactory.generateCertificate( + new ByteArrayInputStream(derData)); + addCertificateDetails(cert); + } catch (CertificateException e) { + Log.e("CertViewer", "Error parsing certificate" + e.toString()); + } + } + + private void addCertificateDetails(Certificate cert) { + LinearLayout certificateView = new LinearLayout(mContext); + mViews.add(certificateView); + certificateView.setOrientation(LinearLayout.VERTICAL); + + X509Certificate x509 = (X509Certificate) cert; + SslCertificate sslCert = new SslCertificate(x509); + + mTitles.add(sslCert.getIssuedTo().getCName()); + + addSectionTitle(certificateView, nativeGetIssuedToText()); + addItem(certificateView, nativeGetCertInfoCommonNameText(), + sslCert.getIssuedTo().getCName()); + addItem(certificateView, nativeGetCertInfoOrganizationText(), + sslCert.getIssuedTo().getOName()); + addItem(certificateView, nativeGetCertInfoOrganizationUnitText(), + sslCert.getIssuedTo().getUName()); + addItem(certificateView, nativeGetCertInfoSerialNumberText(), + formatSerial(x509.getSerialNumber().toByteArray())); + + addSectionTitle(certificateView, nativeGetCertIssuedByText()); + addItem(certificateView, nativeGetCertInfoCommonNameText(), + sslCert.getIssuedBy().getCName()); + addItem(certificateView, nativeGetCertInfoOrganizationText(), + sslCert.getIssuedBy().getOName()); + addItem(certificateView, nativeGetCertInfoOrganizationUnitText(), + sslCert.getIssuedBy().getUName()); + + addSectionTitle(certificateView, nativeGetCertValidity()); + java.text.DateFormat dateFormat = DateFormat.getDateFormat(mContext); + addItem(certificateView, nativeGetCertIssuedOnText(), + dateFormat.format(sslCert.getValidNotBeforeDate())); + addItem(certificateView, nativeGetCertExpiresOnText(), + dateFormat.format(sslCert.getValidNotAfterDate())); + } + + private void addSectionTitle(LinearLayout certificateView, String label) { + TextView title = addLabel(certificateView, label); + title.setAllCaps(true); + } + + private void addItem(LinearLayout certificateView, String label, String value) { + if (value.isEmpty()) return; + + addLabel(certificateView, label); + addValue(certificateView, value); + } + + private TextView addLabel(LinearLayout certificateView, String label) { + TextView t = new TextView(mContext); + t.setPadding(mPadding, mPadding / 2, mPadding, 0); + t.setText(label); + t.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); + certificateView.addView(t); + return t; + } + + private void addValue(LinearLayout certificateView, String value) { + TextView t = new TextView(mContext); + t.setText(value); + t.setPadding(mPadding, 0, mPadding, mPadding / 2); + certificateView.addView(t); + } + + private static String formatSerial(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < bytes.length; i++) { + sb.append(String.format("%02X", bytes[i])); + if (i != bytes.length - 1) { + sb.append(':'); + } + } + return sb.toString(); + } + + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + for (int i = 0; i < mViews.size(); ++i) { + mViews.get(i).setVisibility( + i == position ? LinearLayout.VISIBLE : LinearLayout.GONE); + } + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + } + + private static native String nativeGetIssuedToText(); + private static native String nativeGetCertInfoCommonNameText(); + private static native String nativeGetCertInfoOrganizationText(); + private static native String nativeGetCertInfoSerialNumberText(); + private static native String nativeGetCertInfoOrganizationUnitText(); + private static native String nativeGetCertIssuedByText(); + private static native String nativeGetCertValidity(); + private static native String nativeGetCertIssuedOnText(); + private static native String nativeGetCertExpiresOnText(); +} diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java new file mode 100644 index 0000000..9405964 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java @@ -0,0 +1,153 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.provider.Browser; +import android.text.Html; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup.LayoutParams; +import android.view.Window; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import org.chromium.base.CalledByNative; +import org.chromium.chrome.R; +import org.chromium.content.browser.ContentViewCore; + +import java.net.URISyntaxException; + +/** + * Java side of Android implementation of the website settings UI. + */ +class WebsiteSettingsPopup implements OnClickListener { + private static final String HELP_URL = + "http://www.google.com/support/chrome/bin/answer.py?answer=95617"; + private final Context mContext; + private final Dialog mDialog; + private final LinearLayout mContainer; + private final ContentViewCore mContentViewCore; + private final int mPadding; + private TextView mCertificateViewer, mMoreInfoLink; + private String mLinkUrl; + + private WebsiteSettingsPopup(Context context, ContentViewCore contentViewCore, + final int nativeWebsiteSettingsPopup) { + mContext = context; + mDialog = new Dialog(mContext); + mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + mDialog.setCanceledOnTouchOutside(true); + mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialogInterface) { + assert nativeWebsiteSettingsPopup != 0; + nativeDestroy(nativeWebsiteSettingsPopup); + } + }); + mContainer = new LinearLayout(mContext); + mContainer.setOrientation(LinearLayout.VERTICAL); + mContentViewCore = contentViewCore; + mPadding = (int) context.getResources().getDimension(R.dimen.certificate_viewer_padding); + mContainer.setPadding(mPadding, 0, mPadding, 0); + } + + /** Adds a section, which contains an icon, a headline, and a description. */ + @CalledByNative + private void addSection(Bitmap icon, String headline, String description) { + View section = LayoutInflater.from(mContext).inflate(R.layout.website_settings, null); + ImageView i = (ImageView) section.findViewById(R.id.website_settings_icon); + i.setImageBitmap(icon); + TextView h = (TextView) section.findViewById(R.id.website_settings_headline); + h.setText(headline); + if (TextUtils.isEmpty(headline)) h.setVisibility(View.GONE); + + TextView d = (TextView) section.findViewById(R.id.website_settings_description); + d.setText(description); + if (TextUtils.isEmpty(description)) d.setVisibility(View.GONE); + + mContainer.addView(section); + } + + /** Adds a horizontal dividing line to separate sections. */ + @CalledByNative + private void addDivider() { + View divider = new View(mContext); + final int dividerHeight = (int) (2 * mContext.getResources().getDisplayMetrics().density); + divider.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, dividerHeight)); + divider.setBackgroundColor(Color.GRAY); + mContainer.addView(divider); + } + + @CalledByNative + private void setCertificateViewer(String label) { + assert mCertificateViewer == null; + mCertificateViewer = new TextView(mContext); + mCertificateViewer.setText(Html.fromHtml("<a href='#'>" + label + "</a>")); + mCertificateViewer.setOnClickListener(this); + mCertificateViewer.setPadding(0, 0, 0, mPadding); + mContainer.addView(mCertificateViewer); + } + + @CalledByNative + private void addMoreInfoLink(String linkText) { + addUrl(linkText, HELP_URL); + } + + /** Adds a section containing a description and a hyperlink. */ + private void addUrl(String label, String url) { + mMoreInfoLink = new TextView(mContext); + mLinkUrl = url; + mMoreInfoLink.setText(Html.fromHtml("<a href='#'>" + label + "</a>")); + mMoreInfoLink.setPadding(0, mPadding, 0, mPadding); + mMoreInfoLink.setOnClickListener(this); + mContainer.addView(mMoreInfoLink); + } + + /** Displays the WebsiteSettingsPopup. */ + @CalledByNative + private void show() { + ScrollView scrollView = new ScrollView(mContext); + scrollView.addView(mContainer); + mDialog.addContentView(scrollView, + new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT)); + mDialog.show(); + } + + @Override + public void onClick(View v) { + mDialog.dismiss(); + if (mCertificateViewer == v) { + byte[][] certChain = nativeGetCertificateChain(mContentViewCore); + CertificateViewer.showCertificateChain(mContext, certChain); + } else if (mMoreInfoLink == v) { + try { + Intent i = Intent.parseUri(mLinkUrl, Intent.URI_INTENT_SCHEME); + i.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true); + i.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName()); + mContext.startActivity(i); + } catch (URISyntaxException ex) {} + } + } + + @CalledByNative + private static WebsiteSettingsPopup create(Context context, ContentViewCore contentViewCore, + int nativeWebsiteSettingsPopup) { + return new WebsiteSettingsPopup(context, contentViewCore, nativeWebsiteSettingsPopup); + } + + private native void nativeDestroy(int nativeWebsiteSettingsPopupAndroid); + private native byte[][] nativeGetCertificateChain(ContentViewCore contentViewCore); +}
\ No newline at end of file diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index 2fca549..cb737ee 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc @@ -18,9 +18,12 @@ #include "chrome/browser/ui/android/chrome_http_auth_handler.h" #include "chrome/browser/ui/android/javascript_app_modal_dialog_android.h" #include "chrome/browser/ui/android/navigation_popup.h" +#include "chrome/browser/ui/android/website_settings_popup_android.h" #include "components/navigation_interception/component_jni_registrar.h" #include "components/web_contents_delegate_android/component_jni_registrar.h" +bool RegisterCertificateViewer(JNIEnv* env); + namespace chrome { namespace android { @@ -33,6 +36,7 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = { { "ApplicationLifetime", browser::RegisterApplicationLifetimeAndroid}, { "AutofillPopup", AutofillPopupViewAndroid::RegisterAutofillPopupViewAndroid}, + { "CertificateViewer", RegisterCertificateViewer}, { "ChromeBrowserProvider", ChromeBrowserProvider::RegisterChromeBrowserProvider }, { "ChromeHttpAuthHandler", @@ -47,6 +51,8 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = { { "NavigationPopup", NavigationPopup::RegisterNavigationPopup }, { "ProcessUtils", RegisterProcessUtils }, { "SqliteCursor", SQLiteCursor::RegisterSqliteCursor }, + { "WebsiteSettingsPopupAndroid", + WebsiteSettingsPopupAndroid::RegisterWebsiteSettingsPopupAndroid }, }; bool RegisterJni(JNIEnv* env) { diff --git a/chrome/browser/ui/android/certificate_viewer_android.cc b/chrome/browser/ui/android/certificate_viewer_android.cc index 6dcfee4..e594e9d 100644 --- a/chrome/browser/ui/android/certificate_viewer_android.cc +++ b/chrome/browser/ui/android/certificate_viewer_android.cc @@ -4,8 +4,15 @@ #include "chrome/browser/certificate_viewer.h" +#include "base/android/jni_string.h" #include "base/logging.h" +#include "grit/generated_resources.h" +#include "jni/CertificateViewer_jni.h" #include "net/base/x509_certificate.h" +#include "ui/base/l10n/l10n_util.h" + +using base::android::ConvertUTF8ToJavaString; +using base::android::ScopedJavaLocalRef; void ShowCertificateViewer(content::WebContents* web_contents, gfx::NativeWindow parent, @@ -13,3 +20,55 @@ void ShowCertificateViewer(content::WebContents* web_contents, // TODO(yfriedman, bulach): Hook this up to Java ui code: crbug.com/114822 NOTIMPLEMENTED(); } + +static jstring GetIssuedToText(JNIEnv* env, jclass) { + return ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8(IDS_CERT_INFO_SUBJECT_GROUP)).Release(); +} + +static jstring GetCertInfoCommonNameText(JNIEnv* env, jclass) { + return ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8(IDS_CERT_INFO_COMMON_NAME_LABEL)).Release(); +} + +static jstring GetCertInfoOrganizationText(JNIEnv* env, jclass) { + return ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8( + IDS_CERT_INFO_ORGANIZATION_LABEL)).Release(); +} + +static jstring GetCertInfoSerialNumberText(JNIEnv* env, jclass) { + return ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8( + IDS_CERT_INFO_SERIAL_NUMBER_LABEL)).Release(); +} + +static jstring GetCertInfoOrganizationUnitText(JNIEnv* env, jclass) { + return ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8( + IDS_CERT_INFO_ORGANIZATIONAL_UNIT_LABEL)).Release(); +} + +static jstring GetCertIssuedByText(JNIEnv* env, jclass) { + return ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8(IDS_CERT_INFO_ISSUER_GROUP)).Release(); +} + +static jstring GetCertValidity(JNIEnv* env, jclass) { + return ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8(IDS_CERT_INFO_VALIDITY_GROUP)).Release(); +} + +static jstring GetCertIssuedOnText(JNIEnv* env, jclass) { + return ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8(IDS_CERT_INFO_ISSUED_ON_LABEL)).Release(); +} + +static jstring GetCertExpiresOnText(JNIEnv* env, jclass) { + return ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8(IDS_CERT_INFO_EXPIRES_ON_LABEL)).Release(); +} + +bool RegisterCertificateViewer(JNIEnv* env) { + return RegisterNativesImpl(env); +} diff --git a/chrome/browser/ui/android/website_settings_popup_android.cc b/chrome/browser/ui/android/website_settings_popup_android.cc new file mode 100644 index 0000000..aa07ad1 --- /dev/null +++ b/chrome/browser/ui/android/website_settings_popup_android.cc @@ -0,0 +1,185 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/android/website_settings_popup_android.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "chrome/browser/api/infobars/infobar_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/website_settings/website_settings.h" +#include "content/public/browser/android/content_view_core.h" +#include "content/public/browser/cert_store.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/ssl_status.h" +#include "grit/generated_resources.h" +#include "jni/WebsiteSettingsPopup_jni.h" +#include "net/base/x509_certificate.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/android/java_bitmap.h" + +using base::android::CheckException; +using base::android::ConvertUTF8ToJavaString; +using base::android::ConvertUTF16ToJavaString; +using base::android::GetClass; +using base::android::ScopedJavaLocalRef; +using content::CertStore; +using content::WebContents; +using gfx::ConvertToJavaBitmap; + +static jobjectArray GetCertificateChain(JNIEnv* env, + jobject obj, + jobject view) { + content::WebContents* contents = + content::ContentViewCore::GetNativeContentViewCore(env, view)-> + GetWebContents(); + int cert_id = contents->GetController().GetActiveEntry()->GetSSL().cert_id; + scoped_refptr<net::X509Certificate> cert; + bool ok = CertStore::GetInstance()->RetrieveCert(cert_id, &cert); + CHECK(ok); + + std::vector<std::string> cert_chain; + net::X509Certificate::OSCertHandles cert_handles = + cert->GetIntermediateCertificates(); + // Make sure the peer's own cert is the first in the chain, if it's not + // already there. + if (cert_handles.empty() || cert_handles[0] != cert->os_cert_handle()) + cert_handles.insert(cert_handles.begin(), cert->os_cert_handle()); + + cert_chain.reserve(cert_handles.size()); + for (net::X509Certificate::OSCertHandles::const_iterator it = + cert_handles.begin(); + it != cert_handles.end(); + ++it) { + std::string cert_bytes; + net::X509Certificate::GetDEREncoded(*it, &cert_bytes); + cert_chain.push_back(cert_bytes); + } + + // OK to release, JNI binding. + return base::android::ToJavaArrayOfByteArray(env, cert_chain).Release(); +} + +// static +void WebsiteSettingsPopupAndroid::Show(JNIEnv* env, + jobject context, + jobject java_content_view, + WebContents* web_contents) { + new WebsiteSettingsPopupAndroid(env, context, java_content_view, + web_contents); +} + +WebsiteSettingsPopupAndroid::WebsiteSettingsPopupAndroid( + JNIEnv* env, + jobject context, + jobject java_content_view, + WebContents* web_contents) { + if (web_contents->GetController().GetActiveEntry() == NULL) + return; + + popup_jobject_.Reset( + Java_WebsiteSettingsPopup_create(env, context, java_content_view, + reinterpret_cast<jint>(this))); + + presenter_.reset(new WebsiteSettings( + this, + Profile::FromBrowserContext(web_contents->GetBrowserContext()), + TabSpecificContentSettings::FromWebContents(web_contents), + InfoBarService::FromWebContents(web_contents), + web_contents->GetURL(), + web_contents->GetController().GetActiveEntry()->GetSSL(), + content::CertStore::GetInstance())); +} + +WebsiteSettingsPopupAndroid::~WebsiteSettingsPopupAndroid() {} + +void WebsiteSettingsPopupAndroid::Destroy(JNIEnv* env, jobject obj) { + delete this; +} + +void WebsiteSettingsPopupAndroid::SetIdentityInfo( + const IdentityInfo& identity_info) { + JNIEnv* env = base::android::AttachCurrentThread(); + + { + const gfx::Image& icon_image = WebsiteSettingsUI::GetIdentityIcon( + identity_info.identity_status); + // Creates a java version of the bitmap and makes a copy of the pixels + ScopedJavaLocalRef<jobject> icon = ConvertToJavaBitmap( + icon_image.ToSkBitmap()); + + // The headline and the certificate dialog link of the site's identity + // section is only displayed if the site's identity was verified. If the + // site's identity was verified, then the headline contains the organization + // name from the provided certificate. If the organization name is not + // available than the hostname of the site is used instead. + std::string headline; + if (identity_info.cert_id) { + headline = identity_info.site_identity; + } + + ScopedJavaLocalRef<jstring> description = ConvertUTF8ToJavaString( + env, identity_info.identity_status_description); + Java_WebsiteSettingsPopup_addSection(env, popup_jobject_.obj(), icon.obj(), + ConvertUTF8ToJavaString(env, headline).obj(), description.obj()); + + string16 certificate_label = + l10n_util::GetStringUTF16(IDS_PAGEINFO_CERT_INFO_BUTTON); + if (!certificate_label.empty()) { + Java_WebsiteSettingsPopup_setCertificateViewer(env, popup_jobject_.obj(), + ConvertUTF16ToJavaString(env, certificate_label).obj()); + } + + Java_WebsiteSettingsPopup_addDivider(env, popup_jobject_.obj()); + } + + { + const gfx::Image& icon_image = WebsiteSettingsUI::GetConnectionIcon( + identity_info.connection_status); + ScopedJavaLocalRef<jobject> icon = ConvertToJavaBitmap( + icon_image.ToSkBitmap()); + + ScopedJavaLocalRef<jstring> description = ConvertUTF8ToJavaString( + env, identity_info.connection_status_description); + Java_WebsiteSettingsPopup_addSection(env, popup_jobject_.obj(), icon.obj(), + NULL, description.obj()); + + Java_WebsiteSettingsPopup_addDivider(env, popup_jobject_.obj()); + } + + Java_WebsiteSettingsPopup_addMoreInfoLink(env, popup_jobject_.obj(), + ConvertUTF8ToJavaString( + env, l10n_util::GetStringUTF8(IDS_PAGE_INFO_HELP_CENTER_LINK)).obj()); + Java_WebsiteSettingsPopup_show(env, popup_jobject_.obj()); +} + +void WebsiteSettingsPopupAndroid::SetCookieInfo( + const CookieInfoList& cookie_info_list) { + NOTIMPLEMENTED(); +} + +void WebsiteSettingsPopupAndroid::SetPermissionInfo( + const PermissionInfoList& permission_info_list) { + NOTIMPLEMENTED(); +} + +void WebsiteSettingsPopupAndroid::SetSelectedTab( + WebsiteSettingsUI::TabId tab_id) { + // There's no tab UI on Android - only connection info is shown. + NOTIMPLEMENTED(); +} + +void WebsiteSettingsPopupAndroid::SetFirstVisit( + const string16& first_visit) { + NOTIMPLEMENTED(); +} + +// static +bool WebsiteSettingsPopupAndroid::RegisterWebsiteSettingsPopupAndroid( + JNIEnv* env) { + return RegisterNativesImpl(env); +} diff --git a/chrome/browser/ui/android/website_settings_popup_android.h b/chrome/browser/ui/android/website_settings_popup_android.h new file mode 100644 index 0000000..2edbe626 --- /dev/null +++ b/chrome/browser/ui/android/website_settings_popup_android.h @@ -0,0 +1,55 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ANDROID_WEBSITE_SETTINGS_POPUP_ANDROID_H_ +#define CHROME_BROWSER_UI_ANDROID_WEBSITE_SETTINGS_POPUP_ANDROID_H_ + +#include <jni.h> + +#include "base/android/scoped_java_ref.h" +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/website_settings/website_settings_ui.h" + +namespace content { +class WebContents; +} + +// Androidimplementation of the website settings UI. +class WebsiteSettingsPopupAndroid : public WebsiteSettingsUI { + public: + static void Show(JNIEnv* env, + jobject context, + jobject java_content_view, + content::WebContents* web_contents); + + virtual ~WebsiteSettingsPopupAndroid(); + void Destroy(JNIEnv* env, jobject obj); + + // WebsiteSettingsUI implementations. + virtual void SetCookieInfo(const CookieInfoList& cookie_info_list) OVERRIDE; + virtual void SetPermissionInfo( + const PermissionInfoList& permission_info_list) OVERRIDE; + virtual void SetIdentityInfo(const IdentityInfo& identity_info) OVERRIDE; + virtual void SetFirstVisit(const string16& first_visit) OVERRIDE; + virtual void SetSelectedTab(WebsiteSettingsUI::TabId tab_id) OVERRIDE; + + static bool RegisterWebsiteSettingsPopupAndroid(JNIEnv* env); + + private: + WebsiteSettingsPopupAndroid(JNIEnv* env, + jobject context, + jobject java_content_view, + content::WebContents* web_contents); + + // The presenter that controlls the Website Settings UI. + scoped_ptr<WebsiteSettings> presenter_; + + // The java prompt implementation. + base::android::ScopedJavaGlobalRef<jobject> popup_jobject_; + + DISALLOW_COPY_AND_ASSIGN(WebsiteSettingsPopupAndroid); +}; + +#endif // CHROME_BROWSER_UI_ANDROID_WEBSITE_SETTINGS_POPUP_ANDROID_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 7ebc615..661292c 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -3089,17 +3089,19 @@ 'sources': [ 'android/java/src/org/chromium/chrome/browser/ApplicationLifetime.java', 'android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupGlue.java', + 'android/java/src/org/chromium/chrome/browser/CertificateViewer.java', 'android/java/src/org/chromium/chrome/browser/ChromeBrowserProvider.java', 'android/java/src/org/chromium/chrome/browser/ChromeHttpAuthHandler.java', 'android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java', 'android/java/src/org/chromium/chrome/browser/ContentViewUtil.java', + 'android/java/src/org/chromium/chrome/browser/database/SQLiteCursor.java', 'android/java/src/org/chromium/chrome/browser/DevToolsServer.java', 'android/java/src/org/chromium/chrome/browser/IntentHelper.java', 'android/java/src/org/chromium/chrome/browser/JavascriptAppModalDialog.java', 'android/java/src/org/chromium/chrome/browser/NavigationPopup.java', 'android/java/src/org/chromium/chrome/browser/ProcessUtils.java', 'android/java/src/org/chromium/chrome/browser/TabBase.java', - 'android/java/src/org/chromium/chrome/browser/database/SQLiteCursor.java', + 'android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java', ], 'variables': { 'jni_gen_dir': 'chrome', diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 1f22e91..b8eb918 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -95,6 +95,8 @@ 'browser/ui/android/tab_model/tab_model_list.cc', 'browser/ui/android/tab_model/tab_model_list.h', 'browser/ui/android/tab_restore_service_delegate_android.cc', + 'browser/ui/android/website_settings_popup_android.cc', + 'browser/ui/android/website_settings_popup_android.h', 'browser/ui/android/window_android_helper.cc', 'browser/ui/android/window_android_helper.h', 'browser/ui/app_list/app_list_controller_delegate.cc', |