1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.chrome.browser; 6 7import android.app.Dialog; 8import android.content.Context; 9import android.content.DialogInterface; 10import android.content.Intent; 11import android.graphics.Color; 12import android.provider.Browser; 13import android.text.TextUtils; 14import android.view.LayoutInflater; 15import android.view.View; 16import android.view.View.OnClickListener; 17import android.view.ViewGroup; 18import android.view.Window; 19import android.widget.ImageView; 20import android.widget.LinearLayout; 21import android.widget.ScrollView; 22import android.widget.TextView; 23 24import org.chromium.base.CalledByNative; 25import org.chromium.chrome.R; 26import org.chromium.content.browser.WebContentsObserverAndroid; 27import org.chromium.content_public.browser.WebContents; 28 29import java.net.URISyntaxException; 30 31/** 32 * Java side of Android implementation of the website settings UI. 33 */ 34public class WebsiteSettingsPopup implements OnClickListener { 35 private static final String HELP_URL = 36 "http://www.google.com/support/chrome/bin/answer.py?answer=95617"; 37 private static final int DESCRIPTION_TEXT_SIZE_SP = 12; 38 private final Context mContext; 39 private final Dialog mDialog; 40 private final LinearLayout mContainer; 41 private final WebContents mWebContents; 42 private final int mPaddingWide, mPaddingThin; 43 private TextView mCertificateViewer, mMoreInfoLink; 44 private ViewGroup mCertificateLayout, mDescriptionLayout; 45 private String mLinkUrl; 46 47 private WebsiteSettingsPopup(Context context, WebContents webContents) { 48 mContext = context; 49 mWebContents = webContents; 50 51 mContainer = new LinearLayout(mContext); 52 mContainer.setOrientation(LinearLayout.VERTICAL); 53 mContainer.setBackgroundColor(Color.WHITE); 54 mPaddingWide = (int) context.getResources().getDimension( 55 R.dimen.certificate_viewer_padding_wide); 56 mPaddingThin = (int) context.getResources().getDimension( 57 R.dimen.certificate_viewer_padding_thin); 58 mContainer.setPadding(mPaddingWide, mPaddingWide + mPaddingThin, mPaddingWide, 59 mPaddingWide); 60 61 mDialog = new Dialog(mContext); 62 mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 63 mDialog.setCanceledOnTouchOutside(true); 64 // This needs to come after other member initialization. 65 final long nativeWebsiteSettingsPopup = nativeInit(this, webContents); 66 final WebContentsObserverAndroid webContentsObserver = 67 new WebContentsObserverAndroid(mWebContents) { 68 @Override 69 public void navigationEntryCommitted() { 70 // If a navigation is committed (e.g. from in-page redirect), the data we're 71 // showing is stale so dismiss the dialog. 72 mDialog.dismiss(); 73 } 74 }; 75 mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { 76 @Override 77 public void onDismiss(DialogInterface dialog) { 78 assert nativeWebsiteSettingsPopup != 0; 79 webContentsObserver.detachFromWebContents(); 80 nativeDestroy(nativeWebsiteSettingsPopup); 81 } 82 }); 83 } 84 85 /** 86 * Adds certificate section, which contains an icon, a headline, a 87 * description and a label for certificate info link. 88 */ 89 @CalledByNative 90 private void addCertificateSection(int enumeratedIconId, String headline, String description, 91 String label) { 92 View section = addSection(enumeratedIconId, headline, description); 93 assert mCertificateLayout == null; 94 mCertificateLayout = (ViewGroup) section.findViewById(R.id.website_settings_text_layout); 95 if (label != null && !label.isEmpty()) { 96 setCertificateViewer(label); 97 } 98 } 99 100 /** 101 * Adds Description section, which contains an icon, a headline, and a 102 * description. Most likely headline for description is empty 103 */ 104 @CalledByNative 105 private void addDescriptionSection(int enumeratedIconId, String headline, String description) { 106 View section = addSection(enumeratedIconId, headline, description); 107 assert mDescriptionLayout == null; 108 mDescriptionLayout = (ViewGroup) section.findViewById(R.id.website_settings_text_layout); 109 } 110 111 private View addSection(int enumeratedIconId, String headline, String description) { 112 View section = LayoutInflater.from(mContext).inflate(R.layout.website_settings, null); 113 ImageView i = (ImageView) section.findViewById(R.id.website_settings_icon); 114 int drawableId = ResourceId.mapToDrawableId(enumeratedIconId); 115 i.setImageResource(drawableId); 116 117 TextView h = (TextView) section.findViewById(R.id.website_settings_headline); 118 h.setText(headline); 119 if (TextUtils.isEmpty(headline)) h.setVisibility(View.GONE); 120 121 TextView d = (TextView) section.findViewById(R.id.website_settings_description); 122 d.setText(description); 123 d.setTextSize(DESCRIPTION_TEXT_SIZE_SP); 124 if (TextUtils.isEmpty(description)) d.setVisibility(View.GONE); 125 126 mContainer.addView(section); 127 return section; 128 } 129 130 private void setCertificateViewer(String label) { 131 assert mCertificateViewer == null; 132 mCertificateViewer = new TextView(mContext); 133 mCertificateViewer.setText(label); 134 mCertificateViewer.setTextColor( 135 mContext.getResources().getColor(R.color.website_settings_popup_text_link)); 136 mCertificateViewer.setTextSize(DESCRIPTION_TEXT_SIZE_SP); 137 mCertificateViewer.setOnClickListener(this); 138 mCertificateViewer.setPadding(0, mPaddingWide, 0, mPaddingWide); 139 mCertificateLayout.addView(mCertificateViewer); 140 } 141 142 @CalledByNative 143 private void addMoreInfoLink(String linkText) { 144 addUrl(linkText, HELP_URL); 145 } 146 147 /** Adds a section containing a description and a hyperlink. */ 148 private void addUrl(String label, String url) { 149 mMoreInfoLink = new TextView(mContext); 150 mLinkUrl = url; 151 mMoreInfoLink.setText(label); 152 mMoreInfoLink.setTextColor( 153 mContext.getResources().getColor(R.color.website_settings_popup_text_link)); 154 mMoreInfoLink.setTextSize(DESCRIPTION_TEXT_SIZE_SP); 155 mMoreInfoLink.setPadding(0, mPaddingWide + mPaddingThin, 0, mPaddingWide); 156 mMoreInfoLink.setOnClickListener(this); 157 mDescriptionLayout.addView(mMoreInfoLink); 158 } 159 160 /** Displays the WebsiteSettingsPopup. */ 161 @CalledByNative 162 private void showDialog() { 163 ScrollView scrollView = new ScrollView(mContext); 164 scrollView.addView(mContainer); 165 mDialog.addContentView(scrollView, 166 new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 167 LinearLayout.LayoutParams.MATCH_PARENT)); 168 mDialog.show(); 169 } 170 171 @Override 172 public void onClick(View v) { 173 mDialog.dismiss(); 174 if (mCertificateViewer == v) { 175 byte[][] certChain = nativeGetCertificateChain(mWebContents); 176 if (certChain == null) { 177 // The WebContents may have been destroyed/invalidated. If so, 178 // ignore this request. 179 return; 180 } 181 CertificateViewer.showCertificateChain(mContext, certChain); 182 } else if (mMoreInfoLink == v) { 183 try { 184 Intent i = Intent.parseUri(mLinkUrl, Intent.URI_INTENT_SCHEME); 185 i.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true); 186 i.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName()); 187 mContext.startActivity(i); 188 } catch (URISyntaxException ex) {} 189 } 190 } 191 192 /** 193 * Shows a WebsiteSettings dialog for the provided WebContents. 194 * 195 * The popup adds itself to the view hierarchy which owns the reference while it's 196 * visible. 197 * 198 * @param context Context which is used for launching a dialog. 199 * @param webContents The WebContents for which to show Website information. This 200 * information is retrieved for the visible entry. 201 */ 202 @SuppressWarnings("unused") 203 public static void show(Context context, WebContents webContents) { 204 new WebsiteSettingsPopup(context, webContents); 205 } 206 207 private static native long nativeInit(WebsiteSettingsPopup popup, WebContents webContents); 208 private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid); 209 private native byte[][] nativeGetCertificateChain(WebContents webContents); 210}