Bug 857165 - Highlight domain when showing urls. r=mfinkle
☠☠ backed out by 1421ddeb0348 ☠ ☠
authorWes Johnston <wjohnston@mozilla.com>
Fri, 26 Apr 2013 16:17:37 -0700
changeset 141075 84b4d799cc6dadba5455385da7ced60b7056065e
parent 141074 cc161ca434fab1f50c3a766d5ae33080cfbcf3d0
child 141076 ab534b63501a84782d2ee98bd6e66ece9220f593
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs857165
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 857165 - Highlight domain when showing urls. r=mfinkle
mobile/android/base/BrowserToolbar.java
mobile/android/base/Tab.java
mobile/android/base/resources/values/colors.xml
mobile/android/chrome/content/browser.js
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -2,33 +2,38 @@
  * 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.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.gfx.LayerView;
+import org.mozilla.gecko.util.StringUtils;
 import org.mozilla.gecko.util.HardwareUtils;
 
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.UiAsyncTask;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
 import android.os.Build;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.text.style.ForegroundColorSpan;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.ContextMenu;
 import android.view.MenuInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
@@ -106,16 +111,19 @@ public class BrowserToolbar implements T
     private int mFaviconSize;
 
     private PropertyAnimator mVisibilityAnimator;
 
     private static final int TABS_CONTRACTED = 1;
     private static final int TABS_EXPANDED = 2;
 
     private static final int FORWARD_ANIMATION_DURATION = 450;
+    private final ForegroundColorSpan mUrlColor;
+    private final ForegroundColorSpan mDomainColor;
+    private final ForegroundColorSpan mPrivateDomainColor;
 
     private boolean mShowUrl;
 
     public BrowserToolbar(BrowserApp activity) {
         // BrowserToolbar is attached to BrowserApp only.
         mActivity = activity;
 
         sActionItems = new ArrayList<View>();
@@ -131,24 +139,28 @@ public class BrowserToolbar implements T
                 SharedPreferences settings = mActivity.getSharedPreferences(PREFS_NAME, 0);
                 settings.registerOnSharedPreferenceChangeListener(BrowserToolbar.this);
                 mShowUrl = settings.getBoolean(PREFS_SHOW_URL, false);
                 return null;
             }
 
             @Override
             public void onPostExecute(Void v) {
-                if (mShowUrl) {
-                    Tab tab = Tabs.getInstance().getSelectedTab();
-                    if (tab != null) {
-                        setTitle(tab.getURL());
-                    }
+                Tab tab = Tabs.getInstance().getSelectedTab();
+                if (tab != null) {
+                    setTitle(tab.getDisplayTitle());
                 }
             }
         }).execute();
+
+        Resources res = mActivity.getResources();
+        mUrlColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_urltext));
+        mDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext_private));
+        mPrivateDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext));
+
     }
 
     public void from(RelativeLayout layout) {
         if (mLayout != null) {
             // make sure we retain the visibility property on rotation
             layout.setVisibility(mLayout.getVisibility());
         }
 
@@ -419,17 +431,17 @@ public class BrowserToolbar implements T
             mAwesomeBarRightEdge.requestLayout();
     }
 
     @Override
     public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
         switch(msg) {
             case TITLE:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
-                    setTitle(mShowUrl ? tab.getURL() : tab.getDisplayTitle());
+                    setTitle(tab.getDisplayTitle());
                 }
                 break;
             case START:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     updateBackButton(tab.canDoBack());
                     updateForwardButton(tab.canDoForward());
                     Boolean showProgress = (Boolean)data;
                     if (showProgress && tab.getState() == Tab.STATE_LOADING)
@@ -439,17 +451,17 @@ public class BrowserToolbar implements T
                 }
                 break;
             case STOP:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     updateBackButton(tab.canDoBack());
                     updateForwardButton(tab.canDoForward());
                     setProgressVisibility(false);
                     // Reset the title in case we haven't navigated to a new page yet.
-                    setTitle(mShowUrl ? tab.getURL() : tab.getDisplayTitle());
+                    setTitle(tab.getDisplayTitle());
                 }
                 break;
             case RESTORED:
                 updateTabCount(Tabs.getInstance().getDisplayCount());
                 break;
             case SELECTED:
                 mAnimateSiteSecurity = false;
                 // fall through
@@ -960,31 +972,52 @@ public class BrowserToolbar implements T
         visible &= !(url == null || (url.startsWith("about:") && 
                      !url.equals("about:blank")));
 
         if ((mShadow.getVisibility() == View.VISIBLE) != visible) {
             mShadow.setVisibility(visible ? View.VISIBLE : View.GONE);
         }
     }
 
-    private void setTitle(CharSequence title) {
+    private void setTitle(String title) {
         Tab tab = Tabs.getInstance().getSelectedTab();
+        CharSequence displayTitle = title;
 
         // Keep the title unchanged if the tab is entering reader mode
         if (tab != null && tab.isEnteringReaderMode())
             return;
 
         // Setting a null title will ensure we just see the "Enter Search or Address"
         // placeholder text. Because "about:home" and "about:privatebrowsing" don't
         // have titles, their display titles will always match their URLs.
         if (tab != null && ("about:home".equals(title) ||
-                            "about:privatebrowsing".equals(title)))
-            title = null;
+                            "about:privatebrowsing".equals(title))) {
+            displayTitle = null;
+        }
+
+        if (mShowUrl && displayTitle != null) {
+            title = StringUtils.stripScheme(tab.getURL());
+            title = StringUtils.stripCommonSubdomains(title);
+            displayTitle = title;
 
-        mTitle.setText(title);
+            // highlight the domain name if we find one
+            String baseDomain = tab.getBaseDomain();
+            if (!TextUtils.isEmpty(baseDomain)) {
+                SpannableStringBuilder builder = new SpannableStringBuilder(title);
+                int index = title.indexOf(baseDomain);
+                if (index > -1) {
+                    builder.setSpan(mUrlColor, 0, title.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+                    builder.setSpan(tab.isPrivate() ? mPrivateDomainColor : mDomainColor, index, index+baseDomain.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+
+                    displayTitle = builder;
+                }
+            }
+        }
+
+        mTitle.setText(displayTitle);
         mLayout.setContentDescription(title != null ? title : mTitle.getHint());
     }
 
     private void setFavicon(Bitmap image) {
         if (Tabs.getInstance().getSelectedTab().getState() == Tab.STATE_LOADING)
             return;
 
         if (image != null) {
@@ -1159,37 +1192,38 @@ public class BrowserToolbar implements T
     public void hide() {
         mLayout.setVisibility(View.GONE);
     }
 
     public void refresh() {
         Tab tab = Tabs.getInstance().getSelectedTab();
         if (tab != null) {
             String url = tab.getURL();
-            setTitle(mShowUrl ? tab.getURL() : tab.getDisplayTitle());
+            setTitle(tab.getDisplayTitle());
             setFavicon(tab.getFavicon());
             setProgressVisibility(tab.getState() == Tab.STATE_LOADING);
             setSecurityMode(tab.getSecurityMode());
             setReaderMode(tab.getReaderEnabled());
             setShadowVisibility(true);
             updateTabCount(Tabs.getInstance().getDisplayCount());
             updateBackButton(tab.canDoBack());
             updateForwardButton(tab.canDoForward());
 
-            mAddressBarBg.setPrivateMode(tab.isPrivate());
-            mLayout.setPrivateMode(tab.isPrivate());
-            mTabs.setPrivateMode(tab.isPrivate());
-            mTitle.setPrivateMode(tab.isPrivate());
-            mMenu.setPrivateMode(tab.isPrivate());
+            final boolean isPrivate = tab.isPrivate();
+            mAddressBarBg.setPrivateMode(isPrivate);
+            mLayout.setPrivateMode(isPrivate);
+            mTabs.setPrivateMode(isPrivate);
+            mTitle.setPrivateMode(isPrivate);
+            mMenu.setPrivateMode(isPrivate);
 
             if (mBack instanceof BackButton)
-                ((BackButton) mBack).setPrivateMode(tab.isPrivate());
+                ((BackButton) mBack).setPrivateMode(isPrivate);
 
             if (mForward instanceof ForwardButton)
-                ((ForwardButton) mForward).setPrivateMode(tab.isPrivate());
+                ((ForwardButton) mForward).setPrivateMode(isPrivate);
         }
     }
 
     public void onDestroy() {
         Tabs.unregisterOnTabsChangedListener(this);
     }
 
     public boolean openOptionsMenu() {
@@ -1213,13 +1247,13 @@ public class BrowserToolbar implements T
         return true;
     }
 
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
         if (key.equals(PREFS_SHOW_URL)) {
             mShowUrl = sharedPreferences.getBoolean(key, false);
             Tab tab = Tabs.getInstance().getSelectedTab();
             if (tab != null) {
-                setTitle(mShowUrl ? tab.getURL() : tab.getDisplayTitle());
+                setTitle(tab.getDisplayTitle());
             }
         }
     }
 }
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -31,16 +31,17 @@ import java.util.regex.Pattern;
 
 public class Tab {
     private static final String LOGTAG = "GeckoTab";
 
     private static Pattern sColorPattern;
     private final int mId;
     private long mLastUsed;
     private String mUrl;
+    private String mBaseDomain;
     private String mUserSearch;
     private String mTitle;
     private Bitmap mFavicon;
     private String mFaviconUrl;
     private int mFaviconSize;
     private boolean mFeedsEnabled;
     private JSONObject mIdentityData;
     private boolean mReaderEnabled;
@@ -72,16 +73,17 @@ public class Tab {
     public static final int STATE_SUCCESS = 2;
     public static final int STATE_ERROR = 3;
 
     public Tab(Context context, int id, String url, boolean external, int parentId, String title) {
         mContext = context;
         mId = id;
         mLastUsed = 0;
         mUrl = url;
+        mBaseDomain = "";
         mUserSearch = "";
         mExternal = external;
         mParentId = parentId;
         mTitle = title == null ? "" : title;
         mFavicon = null;
         mFaviconUrl = null;
         mFaviconSize = 0;
         mFeedsEnabled = false;
@@ -149,16 +151,20 @@ public class Tab {
     public String getDisplayTitle() {
         if (mTitle != null && mTitle.length() > 0) {
             return mTitle;
         }
 
         return mUrl;
     }
 
+    public String getBaseDomain() {
+        return mBaseDomain;
+    }
+
     public Bitmap getFavicon() {
         return mFavicon;
     }
 
     public Drawable getThumbnail() {
         return mThumbnail;
     }
 
@@ -561,16 +567,17 @@ public class Tab {
 
     void handleLocationChange(JSONObject message) throws JSONException {
         final String uri = message.getString("uri");
         mEnteringReaderMode = ReaderModeUtils.isEnteringReaderMode(mUrl, uri);
         updateURL(uri);
         updateUserSearch(message.getString("userSearch"));
 
         setDocumentURI(message.getString("documentURI"));
+        mBaseDomain = message.optString("baseDomain");
         if (message.getBoolean("sameDocument")) {
             // We can get a location change event for the same document with an anchor tag
             // Notify listeners so that buttons like back or forward will update themselves
             Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.LOCATION_CHANGE, uri);
             return;
         }
 
         setContentType(message.getString("contentType"));
--- a/mobile/android/base/resources/values/colors.xml
+++ b/mobile/android/base/resources/values/colors.xml
@@ -78,10 +78,14 @@
   <color name="abouthome_topsite_pin">#55000000</color>
   <color name="dialogtitle_textcolor">#ffffff</color>
 
   <color name="textbox_background">#FFF</color>
   <color name="textbox_background_disabled">#DDD</color>
   <color name="textbox_stroke">#000</color>
   <color name="textbox_stroke_disabled">#666</color>
 
+  <color name="url_bar_urltext">#A6A6A6</color>
+  <color name="url_bar_domaintext">#000</color>
+  <color name="url_bar_domaintext_private">#FFF</color>
+
 </resources>
 
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3382,23 +3382,40 @@ Tab.prototype = {
                        ((this.browser.lastURI != null) && fixedURI.equals(this.browser.lastURI) && !fixedURI.equals(aLocationURI));
     this.browser.lastURI = fixedURI;
 
     // Reset state of click-to-play plugin notifications.
     clearTimeout(this.pluginDoorhangerTimeout);
     this.pluginDoorhangerTimeout = null;
     this.shouldShowPluginDoorhanger = true;
     this.clickToPlayPluginsActivated = false;
+    // Borrowed from desktop Firefox: http://mxr.mozilla.org/mozilla-central/source/browser/base/content/urlbarBindings.xml#174
+    let matchedURL = documentURI.match(/^((?:[a-z]+:\/\/)?(?:[^\/]+@)?)(.+?)(?::\d+)?(?:\/|$)/);
+    let baseDomain = "";
+    if (matchedURL) {
+      var domain = "";
+      [, , domain] = matchedURL;
+
+      try {
+        baseDomain = Services.eTLD.getBaseDomainFromHost(domain);
+        if (!domain.endsWith(baseDomain)) {
+          // getBaseDomainFromHost converts its resultant to ACE.
+          let IDNService = Cc["@mozilla.org/network/idn-service;1"].getService(Ci.nsIIDNService);
+          baseDomain = IDNService.convertACEtoUTF8(baseDomain);
+        }
+      } catch (e) {}
+    }
 
     let message = {
       type: "Content:LocationChange",
       tabID: this.id,
       uri: fixedURI.spec,
       userSearch: this.userSearch || "",
       documentURI: documentURI,
+      baseDomain: baseDomain,
       contentType: (contentType ? contentType : ""),
       sameDocument: sameDocument
     };
 
     sendMessageToJava(message);
 
     // The search term is only valid for this location change event, so reset it here.
     this.userSearch = "";