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