Bug 1299201 - Introduce ActivityStream.extractLabel() to extravt a label from a URL. r?grisha draft
authorSebastian Kaspari <s.kaspari@gmail.com>
Tue, 11 Oct 2016 13:47:45 +0200
changeset 424153 19a00c8e267d3d672c0f335135316fc8eb93e872
parent 424152 3e87f101df6bf14a9925ae1cfb0da295214f8c88
child 424337 4b0878a53d199ff1247fc6f54f40bf8b8ec706ed
child 424775 f93946908908871b1c917158f9ecb8529d457ab4
push id32081
push users.kaspari@gmail.com
push dateWed, 12 Oct 2016 08:40:21 +0000
reviewersgrisha
bugs1299201
milestone52.0a1
Bug 1299201 - Introduce ActivityStream.extractLabel() to extravt a label from a URL. r?grisha MozReview-Commit-ID: 8IM7qppwmJ6
mobile/android/base/java/org/mozilla/gecko/activitystream/ActivityStream.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/activitystream/TestActivityStream.java
--- a/mobile/android/base/java/org/mozilla/gecko/activitystream/ActivityStream.java
+++ b/mobile/android/base/java/org/mozilla/gecko/activitystream/ActivityStream.java
@@ -1,31 +1,105 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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.activitystream;
 
 import android.content.Context;
+import android.net.Uri;
+import android.text.TextUtils;
 
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.preferences.GeckoPreferences;
+import org.mozilla.gecko.util.StringUtils;
+import org.mozilla.gecko.util.publicsuffix.PublicSuffix;
+
+import java.util.Arrays;
+import java.util.List;
 
 public class ActivityStream {
+    /**
+     * List of undesired prefixes for labels based on a URL.
+     *
+     * This list is by no means complete and is based on those sources:
+     * - https://gist.github.com/nchapman/36502ad115e8825d522a66549971a3f0
+     * - https://github.com/mozilla/activity-stream/issues/1311
+     */
+    private static final List<String> UNDESIRED_LABEL_PREFIXES = Arrays.asList(
+            "index.",
+            "home."
+    );
+
+    /**
+     * Undesired labels for labels based on a URL.
+     *
+     * This list is by no means complete and is based on those sources:
+     * - https://gist.github.com/nchapman/36502ad115e8825d522a66549971a3f0
+     * - https://github.com/mozilla/activity-stream/issues/1311
+     */
+    private static final List<String> UNDESIRED_LABELS = Arrays.asList(
+            "render",
+            "login",
+            "edit"
+    );
+
     public static boolean isEnabled(Context context) {
         if (!AppConstants.MOZ_ANDROID_ACTIVITY_STREAM) {
             return false;
         }
 
         return GeckoSharedPrefs.forApp(context)
                 .getBoolean(GeckoPreferences.PREFS_ACTIVITY_STREAM, false);
     }
 
     /**
      * Query whether we want to display Activity Stream as a Home Panel (within the HomePager),
      * or as a HomePager replacement.
      */
     public static boolean isHomePanel() {
         return true;
     }
+
+    /**
+     * Extract a label from a URL to use in Activity Stream.
+     *
+     * This method implements the proposal from this desktop AS issue:
+     * https://github.com/mozilla/activity-stream/issues/1311
+     */
+    public static String extractLabel(String url) {
+        if (TextUtils.isEmpty(url)) {
+            return "";
+        }
+
+        final Uri uri = Uri.parse(url);
+
+        // Use last path segment if suitable
+        final String segment = uri.getLastPathSegment();
+        if (!TextUtils.isEmpty(segment)
+                && !UNDESIRED_LABELS.contains(segment)
+                && !segment.matches("^[0-9]+$")) {
+
+            boolean hasUndesiredPrefix = false;
+            for (int i = 0; i < UNDESIRED_LABEL_PREFIXES.size(); i++) {
+                if (segment.startsWith(UNDESIRED_LABEL_PREFIXES.get(i))) {
+                    hasUndesiredPrefix = true;
+                    break;
+                }
+            }
+
+            if (!hasUndesiredPrefix) {
+                return segment;
+            }
+        }
+
+        // If no usable path segment was found then use the host without public suffix and common subdomains
+        final String host = uri.getHost();
+        if (TextUtils.isEmpty(host)) {
+            return url;
+        }
+
+        return StringUtils.stripCommonSubdomains(
+                PublicSuffix.stripPublicSuffix(host));
+    }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/activitystream/TestActivityStream.java
@@ -0,0 +1,95 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+package org.mozilla.gecko.activitystream;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mozilla.gecko.background.testhelpers.TestRunner;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(TestRunner.class)
+public class TestActivityStream {
+    /**
+     * Unit tests for ActivityStream.extractLabel().
+     *
+     * Most test cases are based on this list:
+     * https://gist.github.com/nchapman/36502ad115e8825d522a66549971a3f0
+     */
+    @Test
+    public void testExtractLabel() {
+        // Empty values
+
+        assertEquals("", ActivityStream.extractLabel(""));
+        assertEquals("", ActivityStream.extractLabel(null));
+
+        // Without path
+
+        assertEquals("news.ycombinator",
+                ActivityStream.extractLabel("https://news.ycombinator.com/"));
+
+        assertEquals("sql.telemetry.mozilla",
+                ActivityStream.extractLabel("https://sql.telemetry.mozilla.org/"));
+
+        assertEquals("sso.mozilla",
+                ActivityStream.extractLabel("http://sso.mozilla.com/"));
+
+        assertEquals("youtube",
+                ActivityStream.extractLabel("http://youtube.com/"));
+
+        assertEquals("images.google",
+                ActivityStream.extractLabel("http://images.google.com/"));
+
+        assertEquals("smile.amazon",
+                ActivityStream.extractLabel("http://smile.amazon.com/"));
+
+        assertEquals("localhost",
+                ActivityStream.extractLabel("http://localhost:5000/"));
+
+        assertEquals("independent",
+                ActivityStream.extractLabel("http://www.independent.co.uk/"));
+
+        // With path
+
+        assertEquals("firefox",
+                ActivityStream.extractLabel("https://addons.mozilla.org/en-US/firefox/"));
+
+        assertEquals("activity-stream",
+                ActivityStream.extractLabel("https://trello.com/b/KX3hV8XS/activity-stream"));
+
+        assertEquals("activity-stream",
+                ActivityStream.extractLabel("https://github.com/mozilla/activity-stream"));
+
+        assertEquals("sidekiq",
+                ActivityStream.extractLabel("https://dispatch-news.herokuapp.com/sidekiq"));
+
+        assertEquals("nchapman",
+                ActivityStream.extractLabel("https://github.com/nchapman/"));
+
+        // Unusable paths
+
+        assertEquals("phonebook.mozilla", // instead of "login"
+                ActivityStream.extractLabel("https://phonebook.mozilla.org/mellon/login?ReturnTo=https%3A%2F%2Fphonebook.mozilla.org%2F&IdP=http%3A%2F%2Fwww.okta.com"));
+
+        assertEquals("ipay.adp", // instead of "index.jsf"
+                ActivityStream.extractLabel("https://ipay.adp.com/iPay/index.jsf"));
+
+        assertEquals("calendar.google", // instead of "render"
+                ActivityStream.extractLabel("https://calendar.google.com/calendar/render?pli=1#main_7"));
+
+        assertEquals("myworkday", // instead of "home.htmld"
+                ActivityStream.extractLabel("https://www.myworkday.com/vhr_mozilla/d/home.htmld"));
+
+        assertEquals("mail.google", // instead of "1"
+                ActivityStream.extractLabel("https://mail.google.com/mail/u/1/#inbox"));
+
+        assertEquals("docs.google", // instead of "edit"
+                ActivityStream.extractLabel("https://docs.google.com/presentation/d/11cyrcwhKTmBdEBIZ3szLO0-_Imrx2CGV2B9_LZHDrds/edit#slide=id.g15d41bb0f3_0_82"));
+
+        // Special cases
+
+        assertEquals("irccloud.mozilla",
+                ActivityStream.extractLabel("https://irccloud.mozilla.com/#!/ircs://irc1.dmz.scl3.mozilla.com:6697/%23universal-search"));
+    }
+}