Bug 945212 - Encapsulate identity data/security mode behind a type-safe API (r=margaret)
new file mode 100644
--- /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
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -1,19 +1,19 @@
/* -*- 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.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;
import org.json.JSONObject;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
@@ -41,17 +41,17 @@ public class Tab {
private String mBaseDomain;
private String mUserSearch;
private String mTitle;
private Bitmap mFavicon;
private String mFaviconUrl;
private int mFaviconSize;
private boolean mHasFeeds;
private boolean mHasOpenSearch;
- private JSONObject mIdentityData;
+ private SiteIdentity mSiteIdentity;
private boolean mReaderEnabled;
private BitmapDrawable mThumbnail;
private int mHistoryIndex;
private int mHistorySize;
private int mParentId;
private HomePager.Page mAboutHomePage;
private boolean mExternal;
private boolean mBookmark;
@@ -97,17 +97,17 @@ public class Tab {
mParentId = parentId;
mAboutHomePage = HomePager.Page.TOP_SITES;
mTitle = title == null ? "" : title;
mFavicon = null;
mFaviconUrl = null;
mFaviconSize = 0;
mHasFeeds = false;
mHasOpenSearch = false;
- mIdentityData = null;
+ mSiteIdentity = new SiteIdentity();
mReaderEnabled = false;
mEnteringReaderMode = false;
mThumbnail = null;
mHistoryIndex = -1;
mHistorySize = 0;
mBookmark = false;
mReadingListItem = false;
mFaviconLoadId = 0;
@@ -242,27 +242,22 @@ public class Tab {
public boolean hasFeeds() {
return mHasFeeds;
}
public boolean hasOpenSearch() {
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() {
return mReaderEnabled;
}
public boolean isBookmark() {
return mBookmark;
@@ -411,17 +406,17 @@ public class Tab {
mHasFeeds = hasFeeds;
}
public void setHasOpenSearch(boolean hasOpenSearch) {
mHasOpenSearch = hasOpenSearch;
}
public void updateIdentityData(JSONObject identityData) {
- mIdentityData = identityData;
+ mSiteIdentity.update(identityData);
}
public void setReaderEnabled(boolean readerEnabled) {
mReaderEnabled = readerEnabled;
Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.MENU_UPDATED);
}
void updateBookmark() {
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -273,16 +273,17 @@ gbjar.sources += [
'ReaderModeUtils.java',
'ReferrerReceiver.java',
'RemoteTabs.java',
'Restarter.java',
'ScrollAnimator.java',
'ServiceNotificationClient.java',
'SessionParser.java',
'SharedPreferencesHelper.java',
+ 'SiteIdentity.java',
'SmsManager.java',
'sqlite/ByteBufferInputStream.java',
'sqlite/MatrixBlobCursor.java',
'sqlite/SQLiteBridge.java',
'sqlite/SQLiteBridgeException.java',
'SurfaceBits.java',
'Tab.java',
'Tabs.java',
--- a/mobile/android/base/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/toolbar/BrowserToolbar.java
@@ -7,16 +7,18 @@ package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.GeckoApplication;
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;
import org.mozilla.gecko.animation.PropertyAnimator.PropertyAnimationListener;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.menu.MenuPopup;
import org.mozilla.gecko.PrefsHelper;
@@ -423,23 +425,25 @@ public class BrowserToolbar extends Geck
});
Button.OnClickListener faviconListener = new Button.OnClickListener() {
@Override
public void onClick(View view) {
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();
}
};
mFavicon.setOnClickListener(faviconListener);
mSiteSecurity.setOnClickListener(faviconListener);
mStop.setOnClickListener(new Button.OnClickListener() {
@@ -973,21 +977,20 @@ public class BrowserToolbar extends Geck
if (image != null) {
image = Bitmap.createScaledBitmap(image, mFaviconSize, mFaviconSize, false);
mFavicon.setImageBitmap(image);
} else {
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);
}
public void prepareTabsAnimation(PropertyAnimator animator, boolean tabsAreShown) {
if (!tabsAreShown) {
PropertyAnimator buttonsAnimator =
new PropertyAnimator(animator.getDuration(), sButtonsInterpolator);
--- a/mobile/android/base/toolbar/SiteIdentityPopup.java
+++ b/mobile/android/base/toolbar/SiteIdentityPopup.java
@@ -3,16 +3,18 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.toolbar;
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;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.res.Resources;
@@ -26,29 +28,16 @@ import android.widget.TextView;
/**
* SiteIdentityPopup is a singleton class that displays site identity data in
* an arrow panel popup hanging from the lock icon in the browser toolbar.
*/
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";
private Resources mResources;
private LinearLayout mIdentity;
private TextView mHost;
@@ -61,32 +50,16 @@ public class SiteIdentityPopup extends A
SiteIdentityPopup(BrowserApp activity) {
super(activity);
mResources = activity.getResources();
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();
// Make the popup focusable so it doesn't inadvertently trigger click events elsewhere
// which may reshow the popup (see bug 785156)
setFocusable(true);
@@ -94,43 +67,41 @@ public class SiteIdentityPopup extends A
mIdentity = (LinearLayout) inflater.inflate(R.layout.site_identity, null);
mContent.addView(mIdentity);
mHost = (TextView) mIdentity.findViewById(R.id.host);
mOwner = (TextView) mIdentity.findViewById(R.id.owner);
mVerifier = (TextView) mIdentity.findViewById(R.id.verifier);
}
- private void setIdentity(JSONObject identityData) {
- try {
- String host = identityData.getString("host");
- mHost.setText(host);
+ 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 = identityData.getString("owner");
+ String owner = siteIdentity.getOwner();
// Supplemental data is optional.
- String supplemental = identityData.optString("supplemental");
+ final String supplemental = siteIdentity.getSupplemental();
if (!TextUtils.isEmpty(supplemental)) {
owner += "\n" + supplemental;
}
mOwner.setText(owner);
- String verifier = identityData.getString("verifier");
- String encrypted = identityData.getString("encrypted");
+ 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);
-
- } catch (JSONException e) {
- // 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);
}
}
private void addMixedContentNotification(boolean blocked) {
// Remove any exixting mixed content notification.
removeMixedContentNotification();
mMixedContentNotification = new DoorHanger(mActivity, DoorHanger.Theme.DARK);
@@ -164,37 +135,31 @@ public class SiteIdentityPopup extends A
mContent.removeView(mMixedContentNotification);
mMixedContentNotification = null;
}
}
/*
* @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;
}
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);
}
}
@Override
public void dismiss() {
super.dismiss();
removeMixedContentNotification();
}