michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.toolbar; michael@0: michael@0: import org.mozilla.gecko.BrowserApp; michael@0: import org.mozilla.gecko.R; michael@0: import org.mozilla.gecko.GeckoAppShell; michael@0: import org.mozilla.gecko.GeckoEvent; michael@0: import org.mozilla.gecko.SiteIdentity; michael@0: import org.mozilla.gecko.SiteIdentity.SecurityMode; michael@0: import org.mozilla.gecko.widget.ArrowPopup; michael@0: import org.mozilla.gecko.widget.DoorHanger; michael@0: import org.mozilla.gecko.widget.DoorHanger.OnButtonClickListener; michael@0: michael@0: import org.json.JSONException; michael@0: import org.json.JSONObject; michael@0: michael@0: import android.content.res.Resources; michael@0: import android.text.TextUtils; michael@0: import android.util.Log; michael@0: import android.view.LayoutInflater; michael@0: import android.view.View; michael@0: import android.widget.ImageView; michael@0: import android.widget.LinearLayout; michael@0: import android.widget.TextView; michael@0: michael@0: /** michael@0: * SiteIdentityPopup is a singleton class that displays site identity data in michael@0: * an arrow panel popup hanging from the lock icon in the browser toolbar. michael@0: */ michael@0: public class SiteIdentityPopup extends ArrowPopup { michael@0: private static final String LOGTAG = "GeckoSiteIdentityPopup"; michael@0: michael@0: // FIXME: Update this URL for mobile. See bug 885923. michael@0: private static final String MIXED_CONTENT_SUPPORT_URL = michael@0: "https://support.mozilla.org/kb/how-does-content-isnt-secure-affect-my-safety"; michael@0: michael@0: private SiteIdentity mSiteIdentity; michael@0: michael@0: private Resources mResources; michael@0: michael@0: private LinearLayout mIdentity; michael@0: private TextView mHost; michael@0: private TextView mOwner; michael@0: private TextView mVerifier; michael@0: michael@0: private DoorHanger mMixedContentNotification; michael@0: michael@0: private final OnButtonClickListener mButtonClickListener; michael@0: michael@0: SiteIdentityPopup(BrowserApp activity) { michael@0: super(activity); michael@0: michael@0: mResources = activity.getResources(); michael@0: mButtonClickListener = new PopupButtonListener(); michael@0: } michael@0: michael@0: @Override michael@0: protected void init() { michael@0: super.init(); michael@0: michael@0: // Make the popup focusable so it doesn't inadvertently trigger click events elsewhere michael@0: // which may reshow the popup (see bug 785156) michael@0: setFocusable(true); michael@0: michael@0: LayoutInflater inflater = LayoutInflater.from(mActivity); michael@0: mIdentity = (LinearLayout) inflater.inflate(R.layout.site_identity, null); michael@0: mContent.addView(mIdentity); michael@0: michael@0: mHost = (TextView) mIdentity.findViewById(R.id.host); michael@0: mOwner = (TextView) mIdentity.findViewById(R.id.owner); michael@0: mVerifier = (TextView) mIdentity.findViewById(R.id.verifier); michael@0: } michael@0: michael@0: private void updateUi() { michael@0: if (!mInflated) { michael@0: init(); michael@0: } michael@0: michael@0: if (mSiteIdentity.getSecurityMode() == SecurityMode.MIXED_CONTENT_LOADED || michael@0: mSiteIdentity.getSecurityMode() == SecurityMode.MIXED_CONTENT_BLOCKED) { michael@0: // Hide the identity data if there isn't valid site identity data. michael@0: // Set some top padding on the popup content to create a of light blue michael@0: // between the popup arrow and the mixed content notification. michael@0: mContent.setPadding(0, (int) mResources.getDimension(R.dimen.identity_padding_top), 0, 0); michael@0: mIdentity.setVisibility(View.GONE); michael@0: } else { michael@0: mHost.setText(mSiteIdentity.getHost()); michael@0: michael@0: String owner = mSiteIdentity.getOwner(); michael@0: michael@0: // Supplemental data is optional. michael@0: final String supplemental = mSiteIdentity.getSupplemental(); michael@0: if (!TextUtils.isEmpty(supplemental)) { michael@0: owner += "\n" + supplemental; michael@0: } michael@0: mOwner.setText(owner); michael@0: michael@0: final String verifier = mSiteIdentity.getVerifier(); michael@0: final String encrypted = mSiteIdentity.getEncrypted(); michael@0: mVerifier.setText(verifier + "\n" + encrypted); michael@0: michael@0: mContent.setPadding(0, 0, 0, 0); michael@0: mIdentity.setVisibility(View.VISIBLE); michael@0: } michael@0: } michael@0: michael@0: private void addMixedContentNotification(boolean blocked) { michael@0: // Remove any exixting mixed content notification. michael@0: removeMixedContentNotification(); michael@0: mMixedContentNotification = new DoorHanger(mActivity, DoorHanger.Theme.DARK); michael@0: michael@0: String message; michael@0: if (blocked) { michael@0: message = mActivity.getString(R.string.blocked_mixed_content_message_top) + "\n\n" + michael@0: mActivity.getString(R.string.blocked_mixed_content_message_bottom); michael@0: } else { michael@0: message = mActivity.getString(R.string.loaded_mixed_content_message); michael@0: } michael@0: mMixedContentNotification.setMessage(message); michael@0: mMixedContentNotification.addLink(mActivity.getString(R.string.learn_more), MIXED_CONTENT_SUPPORT_URL, "\n\n"); michael@0: michael@0: if (blocked) { michael@0: mMixedContentNotification.setIcon(R.drawable.shield_doorhanger); michael@0: mMixedContentNotification.addButton(mActivity.getString(R.string.disable_protection), michael@0: "disable", mButtonClickListener); michael@0: mMixedContentNotification.addButton(mActivity.getString(R.string.keep_blocking), michael@0: "keepBlocking", mButtonClickListener); michael@0: } else { michael@0: mMixedContentNotification.setIcon(R.drawable.warning_doorhanger); michael@0: mMixedContentNotification.addButton(mActivity.getString(R.string.enable_protection), michael@0: "enable", mButtonClickListener); michael@0: } michael@0: michael@0: mContent.addView(mMixedContentNotification); michael@0: } michael@0: michael@0: private void removeMixedContentNotification() { michael@0: if (mMixedContentNotification != null) { michael@0: mContent.removeView(mMixedContentNotification); michael@0: mMixedContentNotification = null; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * @param identityData A JSONObject that holds the current tab's identity data. michael@0: */ michael@0: void setSiteIdentity(SiteIdentity siteIdentity) { michael@0: mSiteIdentity = siteIdentity; michael@0: } michael@0: michael@0: @Override michael@0: public void show() { michael@0: if (mSiteIdentity == null) { michael@0: Log.e(LOGTAG, "Can't show site identity popup for undefined state"); michael@0: return; michael@0: } michael@0: michael@0: final SecurityMode mode = mSiteIdentity.getSecurityMode(); michael@0: if (mode == SecurityMode.UNKNOWN) { michael@0: Log.e(LOGTAG, "Can't show site identity popup in non-identified state"); michael@0: return; michael@0: } michael@0: michael@0: updateUi(); michael@0: michael@0: if (mode == SecurityMode.MIXED_CONTENT_LOADED || michael@0: mode == SecurityMode.MIXED_CONTENT_BLOCKED) { michael@0: addMixedContentNotification(mode == SecurityMode.MIXED_CONTENT_BLOCKED); michael@0: } michael@0: michael@0: super.show(); michael@0: } michael@0: michael@0: @Override michael@0: public void dismiss() { michael@0: super.dismiss(); michael@0: removeMixedContentNotification(); michael@0: } michael@0: michael@0: private class PopupButtonListener implements OnButtonClickListener { michael@0: @Override michael@0: public void onButtonClick(DoorHanger dh, String tag) { michael@0: try { michael@0: JSONObject data = new JSONObject(); michael@0: data.put("allowMixedContent", tag.equals("disable")); michael@0: GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Reload", data.toString()); michael@0: GeckoAppShell.sendEventToGecko(e); michael@0: } catch (JSONException e) { michael@0: Log.e(LOGTAG, "Exception creating message to enable/disable mixed content blocking", e); michael@0: } michael@0: michael@0: dismiss(); michael@0: } michael@0: } michael@0: }