summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryfriedman@chromium.org <yfriedman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-26 04:20:08 +0000
committeryfriedman@chromium.org <yfriedman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-26 04:20:08 +0000
commit152ca7e5280d1aaee5f38181a97c2c9fc0d09105 (patch)
tree8c570c6373df79c675e951212c75c3c2b0875777
parentef747cffdfb4d48eafb35cf38980890e1012a7d5 (diff)
downloadchromium_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.xml30
-rw-r--r--chrome/android/java/res/values/dimens.xml3
-rw-r--r--chrome/android/java/res/values/strings.xml4
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/CertificateViewer.java212
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java153
-rw-r--r--chrome/browser/android/chrome_jni_registrar.cc6
-rw-r--r--chrome/browser/ui/android/certificate_viewer_android.cc59
-rw-r--r--chrome/browser/ui/android/website_settings_popup_android.cc185
-rw-r--r--chrome/browser/ui/android/website_settings_popup_android.h55
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/chrome_browser_ui.gypi2
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',