1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/toolbar/SiteIdentityPopup.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,198 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.toolbar; 1.9 + 1.10 +import org.mozilla.gecko.BrowserApp; 1.11 +import org.mozilla.gecko.R; 1.12 +import org.mozilla.gecko.GeckoAppShell; 1.13 +import org.mozilla.gecko.GeckoEvent; 1.14 +import org.mozilla.gecko.SiteIdentity; 1.15 +import org.mozilla.gecko.SiteIdentity.SecurityMode; 1.16 +import org.mozilla.gecko.widget.ArrowPopup; 1.17 +import org.mozilla.gecko.widget.DoorHanger; 1.18 +import org.mozilla.gecko.widget.DoorHanger.OnButtonClickListener; 1.19 + 1.20 +import org.json.JSONException; 1.21 +import org.json.JSONObject; 1.22 + 1.23 +import android.content.res.Resources; 1.24 +import android.text.TextUtils; 1.25 +import android.util.Log; 1.26 +import android.view.LayoutInflater; 1.27 +import android.view.View; 1.28 +import android.widget.ImageView; 1.29 +import android.widget.LinearLayout; 1.30 +import android.widget.TextView; 1.31 + 1.32 +/** 1.33 + * SiteIdentityPopup is a singleton class that displays site identity data in 1.34 + * an arrow panel popup hanging from the lock icon in the browser toolbar. 1.35 + */ 1.36 +public class SiteIdentityPopup extends ArrowPopup { 1.37 + private static final String LOGTAG = "GeckoSiteIdentityPopup"; 1.38 + 1.39 + // FIXME: Update this URL for mobile. See bug 885923. 1.40 + private static final String MIXED_CONTENT_SUPPORT_URL = 1.41 + "https://support.mozilla.org/kb/how-does-content-isnt-secure-affect-my-safety"; 1.42 + 1.43 + private SiteIdentity mSiteIdentity; 1.44 + 1.45 + private Resources mResources; 1.46 + 1.47 + private LinearLayout mIdentity; 1.48 + private TextView mHost; 1.49 + private TextView mOwner; 1.50 + private TextView mVerifier; 1.51 + 1.52 + private DoorHanger mMixedContentNotification; 1.53 + 1.54 + private final OnButtonClickListener mButtonClickListener; 1.55 + 1.56 + SiteIdentityPopup(BrowserApp activity) { 1.57 + super(activity); 1.58 + 1.59 + mResources = activity.getResources(); 1.60 + mButtonClickListener = new PopupButtonListener(); 1.61 + } 1.62 + 1.63 + @Override 1.64 + protected void init() { 1.65 + super.init(); 1.66 + 1.67 + // Make the popup focusable so it doesn't inadvertently trigger click events elsewhere 1.68 + // which may reshow the popup (see bug 785156) 1.69 + setFocusable(true); 1.70 + 1.71 + LayoutInflater inflater = LayoutInflater.from(mActivity); 1.72 + mIdentity = (LinearLayout) inflater.inflate(R.layout.site_identity, null); 1.73 + mContent.addView(mIdentity); 1.74 + 1.75 + mHost = (TextView) mIdentity.findViewById(R.id.host); 1.76 + mOwner = (TextView) mIdentity.findViewById(R.id.owner); 1.77 + mVerifier = (TextView) mIdentity.findViewById(R.id.verifier); 1.78 + } 1.79 + 1.80 + private void updateUi() { 1.81 + if (!mInflated) { 1.82 + init(); 1.83 + } 1.84 + 1.85 + if (mSiteIdentity.getSecurityMode() == SecurityMode.MIXED_CONTENT_LOADED || 1.86 + mSiteIdentity.getSecurityMode() == SecurityMode.MIXED_CONTENT_BLOCKED) { 1.87 + // Hide the identity data if there isn't valid site identity data. 1.88 + // Set some top padding on the popup content to create a of light blue 1.89 + // between the popup arrow and the mixed content notification. 1.90 + mContent.setPadding(0, (int) mResources.getDimension(R.dimen.identity_padding_top), 0, 0); 1.91 + mIdentity.setVisibility(View.GONE); 1.92 + } else { 1.93 + mHost.setText(mSiteIdentity.getHost()); 1.94 + 1.95 + String owner = mSiteIdentity.getOwner(); 1.96 + 1.97 + // Supplemental data is optional. 1.98 + final String supplemental = mSiteIdentity.getSupplemental(); 1.99 + if (!TextUtils.isEmpty(supplemental)) { 1.100 + owner += "\n" + supplemental; 1.101 + } 1.102 + mOwner.setText(owner); 1.103 + 1.104 + final String verifier = mSiteIdentity.getVerifier(); 1.105 + final String encrypted = mSiteIdentity.getEncrypted(); 1.106 + mVerifier.setText(verifier + "\n" + encrypted); 1.107 + 1.108 + mContent.setPadding(0, 0, 0, 0); 1.109 + mIdentity.setVisibility(View.VISIBLE); 1.110 + } 1.111 + } 1.112 + 1.113 + private void addMixedContentNotification(boolean blocked) { 1.114 + // Remove any exixting mixed content notification. 1.115 + removeMixedContentNotification(); 1.116 + mMixedContentNotification = new DoorHanger(mActivity, DoorHanger.Theme.DARK); 1.117 + 1.118 + String message; 1.119 + if (blocked) { 1.120 + message = mActivity.getString(R.string.blocked_mixed_content_message_top) + "\n\n" + 1.121 + mActivity.getString(R.string.blocked_mixed_content_message_bottom); 1.122 + } else { 1.123 + message = mActivity.getString(R.string.loaded_mixed_content_message); 1.124 + } 1.125 + mMixedContentNotification.setMessage(message); 1.126 + mMixedContentNotification.addLink(mActivity.getString(R.string.learn_more), MIXED_CONTENT_SUPPORT_URL, "\n\n"); 1.127 + 1.128 + if (blocked) { 1.129 + mMixedContentNotification.setIcon(R.drawable.shield_doorhanger); 1.130 + mMixedContentNotification.addButton(mActivity.getString(R.string.disable_protection), 1.131 + "disable", mButtonClickListener); 1.132 + mMixedContentNotification.addButton(mActivity.getString(R.string.keep_blocking), 1.133 + "keepBlocking", mButtonClickListener); 1.134 + } else { 1.135 + mMixedContentNotification.setIcon(R.drawable.warning_doorhanger); 1.136 + mMixedContentNotification.addButton(mActivity.getString(R.string.enable_protection), 1.137 + "enable", mButtonClickListener); 1.138 + } 1.139 + 1.140 + mContent.addView(mMixedContentNotification); 1.141 + } 1.142 + 1.143 + private void removeMixedContentNotification() { 1.144 + if (mMixedContentNotification != null) { 1.145 + mContent.removeView(mMixedContentNotification); 1.146 + mMixedContentNotification = null; 1.147 + } 1.148 + } 1.149 + 1.150 + /* 1.151 + * @param identityData A JSONObject that holds the current tab's identity data. 1.152 + */ 1.153 + void setSiteIdentity(SiteIdentity siteIdentity) { 1.154 + mSiteIdentity = siteIdentity; 1.155 + } 1.156 + 1.157 + @Override 1.158 + public void show() { 1.159 + if (mSiteIdentity == null) { 1.160 + Log.e(LOGTAG, "Can't show site identity popup for undefined state"); 1.161 + return; 1.162 + } 1.163 + 1.164 + final SecurityMode mode = mSiteIdentity.getSecurityMode(); 1.165 + if (mode == SecurityMode.UNKNOWN) { 1.166 + Log.e(LOGTAG, "Can't show site identity popup in non-identified state"); 1.167 + return; 1.168 + } 1.169 + 1.170 + updateUi(); 1.171 + 1.172 + if (mode == SecurityMode.MIXED_CONTENT_LOADED || 1.173 + mode == SecurityMode.MIXED_CONTENT_BLOCKED) { 1.174 + addMixedContentNotification(mode == SecurityMode.MIXED_CONTENT_BLOCKED); 1.175 + } 1.176 + 1.177 + super.show(); 1.178 + } 1.179 + 1.180 + @Override 1.181 + public void dismiss() { 1.182 + super.dismiss(); 1.183 + removeMixedContentNotification(); 1.184 + } 1.185 + 1.186 + private class PopupButtonListener implements OnButtonClickListener { 1.187 + @Override 1.188 + public void onButtonClick(DoorHanger dh, String tag) { 1.189 + try { 1.190 + JSONObject data = new JSONObject(); 1.191 + data.put("allowMixedContent", tag.equals("disable")); 1.192 + GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Reload", data.toString()); 1.193 + GeckoAppShell.sendEventToGecko(e); 1.194 + } catch (JSONException e) { 1.195 + Log.e(LOGTAG, "Exception creating message to enable/disable mixed content blocking", e); 1.196 + } 1.197 + 1.198 + dismiss(); 1.199 + } 1.200 + } 1.201 +}