From fc210fdac82cc6d374488fac31c6202a6e7c7dfa Mon Sep 17 00:00:00 2001 From: Lucas Rocha Date: Thu, 12 Dec 2013 00:28:15 +0000 Subject: [PATCH] Bug 945212 - Encapsulate identity data/security mode behind a type-safe API (r=margaret) --- mobile/android/base/SiteIdentity.java | 110 ++++++++++++++++++ mobile/android/base/Tab.java | 21 ++-- mobile/android/base/moz.build | 1 + .../android/base/toolbar/BrowserToolbar.java | 19 +-- .../base/toolbar/SiteIdentityPopup.java | 93 +++++---------- 5 files changed, 159 insertions(+), 85 deletions(-) create mode 100644 mobile/android/base/SiteIdentity.java diff --git a/mobile/android/base/SiteIdentity.java b/mobile/android/base/SiteIdentity.java new file mode 100644 index 000000000000..7e76314513c9 --- /dev/null +++ b/mobile/android/base/SiteIdentity.java @@ -0,0 +1,110 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import org.json.JSONObject; + +import android.text.TextUtils; + +public class SiteIdentity { + private SecurityMode mSecurityMode; + private String mHost; + private String mOwner; + private String mSupplemental; + private String mVerifier; + private String mEncrypted; + + // The order of the items here correspond to image + // levels in site_security_level.xml + public enum SecurityMode { + UNKNOWN("unknown"), + VERIFIED("verified"), + IDENTIFIED("identified"), + MIXED_CONTENT_BLOCKED("mixed_content_blocked"), + MIXED_CONTENT_LOADED("mixed_content_loaded"); + + private final String mId; + + private SecurityMode(String id) { + mId = id; + } + + public static SecurityMode fromString(String id) { + if (id == null) { + throw new IllegalArgumentException("Can't convert null String to SiteIdentity"); + } + + for (SecurityMode mode : SecurityMode.values()) { + if (TextUtils.equals(mode.mId, id.toLowerCase())) { + return mode; + } + } + + throw new IllegalArgumentException("Could not convert String id to SiteIdentity"); + } + + @Override + public String toString() { + return mId; + } + } + + public SiteIdentity() { + reset(SecurityMode.UNKNOWN); + } + + private void reset(SecurityMode securityMode) { + mSecurityMode = securityMode; + mHost = null; + mOwner = null; + mSupplemental = null; + mVerifier = null; + mEncrypted = null; + } + + void update(JSONObject identityData) { + try { + mSecurityMode = SecurityMode.fromString(identityData.getString("mode")); + } catch (Exception e) { + reset(SecurityMode.UNKNOWN); + return; + } + + try { + mHost = identityData.getString("host"); + mOwner = identityData.getString("owner"); + mSupplemental = identityData.optString("supplemental", null); + mVerifier = identityData.getString("verifier"); + mEncrypted = identityData.getString("encrypted"); + } catch (Exception e) { + reset(mSecurityMode); + } + } + + public SecurityMode getSecurityMode() { + return mSecurityMode; + } + + public String getHost() { + return mHost; + } + + public String getOwner() { + return mOwner; + } + + public String getSupplemental() { + return mSupplemental; + } + + public String getVerifier() { + return mVerifier; + } + + public String getEncrypted() { + return mEncrypted; + } +} \ No newline at end of file diff --git a/mobile/android/base/Tab.java b/mobile/android/base/Tab.java index 4dd16320e3c8..09171f428372 100644 --- a/mobile/android/base/Tab.java +++ b/mobile/android/base/Tab.java @@ -5,10 +5,10 @@ package org.mozilla.gecko; +import org.mozilla.gecko.SiteIdentity.SecurityMode; import org.mozilla.gecko.db.BrowserDB; import org.mozilla.gecko.gfx.Layer; import org.mozilla.gecko.home.HomePager; -import org.mozilla.gecko.toolbar.SiteIdentityPopup; import org.mozilla.gecko.util.ThreadUtils; import org.json.JSONException; @@ -46,7 +46,7 @@ public class Tab { private int mFaviconSize; private boolean mHasFeeds; private boolean mHasOpenSearch; - private JSONObject mIdentityData; + private SiteIdentity mSiteIdentity; private boolean mReaderEnabled; private BitmapDrawable mThumbnail; private int mHistoryIndex; @@ -102,7 +102,7 @@ public class Tab { mFaviconSize = 0; mHasFeeds = false; mHasOpenSearch = false; - mIdentityData = null; + mSiteIdentity = new SiteIdentity(); mReaderEnabled = false; mEnteringReaderMode = false; mThumbnail = null; @@ -247,17 +247,12 @@ public class Tab { return mHasOpenSearch; } - public String getSecurityMode() { - try { - return mIdentityData.getString("mode"); - } catch (Exception e) { - // If mIdentityData is null, or we get a JSONException - return SiteIdentityPopup.UNKNOWN; - } + public SecurityMode getSecurityMode() { + return mSiteIdentity.getSecurityMode(); } - public JSONObject getIdentityData() { - return mIdentityData; + public SiteIdentity getSiteIdentity() { + return mSiteIdentity; } public boolean getReaderEnabled() { @@ -416,7 +411,7 @@ public class Tab { } public void updateIdentityData(JSONObject identityData) { - mIdentityData = identityData; + mSiteIdentity.update(identityData); } public void setReaderEnabled(boolean readerEnabled) { diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 9b54ccbae4ca..2eaf5ce6262a 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -278,6 +278,7 @@ gbjar.sources += [ 'ServiceNotificationClient.java', 'SessionParser.java', 'SharedPreferencesHelper.java', + 'SiteIdentity.java', 'SmsManager.java', 'sqlite/ByteBufferInputStream.java', 'sqlite/MatrixBlobCursor.java', diff --git a/mobile/android/base/toolbar/BrowserToolbar.java b/mobile/android/base/toolbar/BrowserToolbar.java index 4aa890fbcff6..dc8fc6c405dd 100644 --- a/mobile/android/base/toolbar/BrowserToolbar.java +++ b/mobile/android/base/toolbar/BrowserToolbar.java @@ -12,6 +12,8 @@ import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoProfile; import org.mozilla.gecko.LightweightTheme; import org.mozilla.gecko.R; +import org.mozilla.gecko.SiteIdentity; +import org.mozilla.gecko.SiteIdentity.SecurityMode; import org.mozilla.gecko.Tab; import org.mozilla.gecko.Tabs; import org.mozilla.gecko.animation.PropertyAnimator; @@ -428,13 +430,15 @@ public class BrowserToolbar extends GeckoRelativeLayout if (mSiteSecurity.getVisibility() != View.VISIBLE) return; - JSONObject identityData = Tabs.getInstance().getSelectedTab().getIdentityData(); - if (identityData == null) { + final Tab tab = Tabs.getInstance().getSelectedTab(); + + final SiteIdentity siteIdentity = tab.getSiteIdentity(); + if (siteIdentity.getSecurityMode() == SecurityMode.UNKNOWN) { Log.e(LOGTAG, "Selected tab has no identity data"); return; } - mSiteIdentityPopup.updateIdentity(identityData); + mSiteIdentityPopup.updateIdentity(siteIdentity); mSiteIdentityPopup.show(); } }; @@ -978,11 +982,10 @@ public class BrowserToolbar extends GeckoRelativeLayout mFavicon.setImageDrawable(null); } } - - private void setSecurityMode(String mode) { - int imageLevel = SiteIdentityPopup.getSecurityImageLevel(mode); - mSiteSecurity.setImageLevel(imageLevel); - mShowSiteSecurity = (imageLevel != SiteIdentityPopup.LEVEL_UKNOWN); + + private void setSecurityMode(SecurityMode mode) { + mSiteSecurity.setImageLevel(mode.ordinal()); + mShowSiteSecurity = (mode != SecurityMode.UNKNOWN); setPageActionVisibility(mStop.getVisibility() == View.VISIBLE); } diff --git a/mobile/android/base/toolbar/SiteIdentityPopup.java b/mobile/android/base/toolbar/SiteIdentityPopup.java index 5d7ef73497e9..e8999f31e926 100644 --- a/mobile/android/base/toolbar/SiteIdentityPopup.java +++ b/mobile/android/base/toolbar/SiteIdentityPopup.java @@ -8,6 +8,8 @@ import org.mozilla.gecko.BrowserApp; import org.mozilla.gecko.R; import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoEvent; +import org.mozilla.gecko.SiteIdentity; +import org.mozilla.gecko.SiteIdentity.SecurityMode; import org.mozilla.gecko.widget.ArrowPopup; import org.mozilla.gecko.widget.DoorHanger; import org.mozilla.gecko.widget.DoorHanger.OnButtonClickListener; @@ -31,19 +33,6 @@ import android.widget.TextView; public class SiteIdentityPopup extends ArrowPopup { private static final String LOGTAG = "GeckoSiteIdentityPopup"; - public static final String UNKNOWN = "unknown"; - public static final String VERIFIED = "verified"; - public static final String IDENTIFIED = "identified"; - public static final String MIXED_CONTENT_BLOCKED = "mixed_content_blocked"; - public static final String MIXED_CONTENT_LOADED = "mixed_content_loaded"; - - // Security states corresponding to image levels in site_security_level.xml - static final int LEVEL_UKNOWN = 0; - static final int LEVEL_IDENTIFIED = 1; - static final int LEVEL_VERIFIED = 2; - static final int LEVEL_MIXED_CONTENT_BLOCKED = 3; - static final int LEVEL_MIXED_CONTENT_LOADED = 4; - // FIXME: Update this URL for mobile. See bug 885923. private static final String MIXED_CONTENT_SUPPORT_URL = "https://support.mozilla.org/kb/how-does-content-isnt-secure-affect-my-safety"; @@ -66,22 +55,6 @@ public class SiteIdentityPopup extends ArrowPopup { mButtonClickListener = new PopupButtonListener(); } - static int getSecurityImageLevel(String mode) { - if (IDENTIFIED.equals(mode)) { - return LEVEL_IDENTIFIED; - } - if (VERIFIED.equals(mode)) { - return LEVEL_VERIFIED; - } - if (MIXED_CONTENT_BLOCKED.equals(mode)) { - return LEVEL_MIXED_CONTENT_BLOCKED; - } - if (MIXED_CONTENT_LOADED.equals(mode)) { - return LEVEL_MIXED_CONTENT_LOADED; - } - return LEVEL_UKNOWN; - } - @Override protected void init() { super.init(); @@ -99,33 +72,31 @@ public class SiteIdentityPopup extends ArrowPopup { mVerifier = (TextView) mIdentity.findViewById(R.id.verifier); } - private void setIdentity(JSONObject identityData) { - try { - String host = identityData.getString("host"); - mHost.setText(host); - - String owner = identityData.getString("owner"); - - // Supplemental data is optional. - String supplemental = identityData.optString("supplemental"); - if (!TextUtils.isEmpty(supplemental)) { - owner += "\n" + supplemental; - } - mOwner.setText(owner); - - String verifier = identityData.getString("verifier"); - String encrypted = identityData.getString("encrypted"); - mVerifier.setText(verifier + "\n" + encrypted); - - mContent.setPadding(0, 0, 0, 0); - mIdentity.setVisibility(View.VISIBLE); - - } catch (JSONException e) { + private void setIdentity(SiteIdentity siteIdentity) { + if (siteIdentity.getSecurityMode() == SecurityMode.MIXED_CONTENT_LOADED) { // Hide the identity data if there isn't valid site identity data. // Set some top padding on the popup content to create a of light blue // between the popup arrow and the mixed content notification. mContent.setPadding(0, (int) mResources.getDimension(R.dimen.identity_padding_top), 0, 0); mIdentity.setVisibility(View.GONE); + } else { + mHost.setText(siteIdentity.getHost()); + + String owner = siteIdentity.getOwner(); + + // Supplemental data is optional. + final String supplemental = siteIdentity.getSupplemental(); + if (!TextUtils.isEmpty(supplemental)) { + owner += "\n" + supplemental; + } + mOwner.setText(owner); + + final String verifier = siteIdentity.getVerifier(); + final String encrypted = siteIdentity.getEncrypted(); + mVerifier.setText(verifier + "\n" + encrypted); + + mContent.setPadding(0, 0, 0, 0); + mIdentity.setVisibility(View.VISIBLE); } } @@ -169,16 +140,9 @@ public class SiteIdentityPopup extends ArrowPopup { /* * @param identityData A JSONObject that holds the current tab's identity data. */ - void updateIdentity(JSONObject identityData) { - String mode; - try { - mode = identityData.getString("mode"); - } catch (JSONException e) { - Log.e(LOGTAG, "Exception trying to get identity mode", e); - return; - } - - if (UNKNOWN.equals(mode)) { + void updateIdentity(SiteIdentity siteIdentity) { + final SecurityMode mode = siteIdentity.getSecurityMode(); + if (mode == SecurityMode.UNKNOWN) { Log.e(LOGTAG, "Can't show site identity popup in non-identified state"); return; } @@ -186,10 +150,11 @@ public class SiteIdentityPopup extends ArrowPopup { if (!mInflated) init(); - setIdentity(identityData); + setIdentity(siteIdentity); - if (MIXED_CONTENT_BLOCKED.equals(mode) || MIXED_CONTENT_LOADED.equals(mode)) { - addMixedContentNotification(MIXED_CONTENT_BLOCKED.equals(mode)); + if (mode == SecurityMode.MIXED_CONTENT_LOADED || + mode == SecurityMode.MIXED_CONTENT_BLOCKED) { + addMixedContentNotification(mode == SecurityMode.MIXED_CONTENT_BLOCKED); } }