diff --git a/mobile/android/base/TabsAccessor.java b/mobile/android/base/TabsAccessor.java
index 6cd6a9a93cab..f9629f067c4e 100644
--- a/mobile/android/base/TabsAccessor.java
+++ b/mobile/android/base/TabsAccessor.java
@@ -7,7 +7,6 @@ package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
-
import org.json.JSONArray;
import org.json.JSONException;
@@ -34,7 +33,8 @@ public final class TabsAccessor {
BrowserContract.Tabs.TITLE,
BrowserContract.Tabs.URL,
BrowserContract.Clients.GUID,
- BrowserContract.Clients.NAME
+ BrowserContract.Clients.NAME,
+ BrowserContract.Clients.LAST_MODIFIED,
};
// Projection column numbers
@@ -42,7 +42,8 @@ public final class TabsAccessor {
TITLE,
URL,
GUID,
- NAME
+ NAME,
+ LAST_MODIFIED,
};
private static final String CLIENTS_SELECTION = BrowserContract.Clients.GUID + " IS NOT NULL";
@@ -57,6 +58,11 @@ public final class TabsAccessor {
public String url;
public String guid;
public String name;
+ /**
+ * This is the last time the remote client uploaded a tabs record; that
+ * is, it is not per tab, but per remote client.
+ */
+ public long lastModified;
}
public interface OnQueryTabsCompleteListener {
@@ -105,7 +111,8 @@ public final class TabsAccessor {
tab.url = cursor.getString(TABS_COLUMN.URL.ordinal());
tab.guid = cursor.getString(TABS_COLUMN.GUID.ordinal());
tab.name = cursor.getString(TABS_COLUMN.NAME.ordinal());
-
+ tab.lastModified = cursor.getLong(TABS_COLUMN.LAST_MODIFIED.ordinal());
+
tabs.add(tab);
}
} finally {
diff --git a/mobile/android/base/TelemetryContract.java b/mobile/android/base/TelemetryContract.java
index bd7d3ae7fe1e..a4488c8ce93a 100644
--- a/mobile/android/base/TelemetryContract.java
+++ b/mobile/android/base/TelemetryContract.java
@@ -49,6 +49,10 @@ public interface TelemetryContract {
// Generic action, usually for tracking menu and toolbar actions.
public static final String ACTION = "action.1";
+
+ // Launching (opening) an external application
+ // Note: Only used in JavaScript for now, but here for completeness.
+ public static final String LAUNCH = "launch.1";
}
/**
@@ -82,6 +86,10 @@ public interface TelemetryContract {
// Action triggered from a suggestion provided to the user.
public static final String SUGGESTION = "suggestion";
+
+ // Action triggered from a pageaction in the URLBar.
+ // Note: Only used in JavaScript for now, but here for completeness.
+ public static final String PAGEACTION = "pageaction";
}
/**
@@ -101,10 +109,10 @@ public interface TelemetryContract {
public static final String READER = "reader.1";
// URL bar focused.
- public static final String URLBAR_FOCUSED = "urlbar.1:";
+ public static final String URLBAR_FOCUSED = "urlbar.1";
// Awesomescreen frecency search is active.
- public static final String FRECENCY = "frecency.1:";
+ public static final String FRECENCY = "frecency.1";
}
/**
diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd
index 90a170eb81be..8e4a9d2cdffb 100644
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -434,3 +434,11 @@ just addresses the organization to follow, e.g. "This site is run by " -->
They are never shown to users -->
+
+
+
diff --git a/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_child.xml b/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_child.xml
index 2715cc2a10b3..ff0ec06934d8 100644
--- a/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_child.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_child.xml
@@ -4,24 +4,24 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
diff --git a/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_group.xml b/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_group.xml
index 887bd903c2a7..54b08d0fc295 100644
--- a/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_group.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/remote_tabs_group.xml
@@ -3,16 +3,28 @@
- 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/. -->
-
+
+
+
+
+
+
+
diff --git a/mobile/android/base/resources/layout/remote_tabs_child.xml b/mobile/android/base/resources/layout/remote_tabs_child.xml
index 23fe57bc9247..32f79a8e53ab 100644
--- a/mobile/android/base/resources/layout/remote_tabs_child.xml
+++ b/mobile/android/base/resources/layout/remote_tabs_child.xml
@@ -4,25 +4,25 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+ android:textSize="18sp" />
+ android:maxLength="1024"
+ android:textSize="14sp" />
diff --git a/mobile/android/base/resources/layout/remote_tabs_group.xml b/mobile/android/base/resources/layout/remote_tabs_group.xml
index 7f776651458f..3a4f134acd13 100644
--- a/mobile/android/base/resources/layout/remote_tabs_group.xml
+++ b/mobile/android/base/resources/layout/remote_tabs_group.xml
@@ -3,14 +3,27 @@
- 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/. -->
-
+
+
+
+
+
+
+
diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in
index d19a990d8ab9..d54e375cb778 100644
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -404,4 +404,5 @@
&ellipsis;
+ &remote_tabs_last_synced;
diff --git a/mobile/android/base/tabspanel/RemoteTabsList.java b/mobile/android/base/tabspanel/RemoteTabsList.java
index 669e83af8487..6f95bdbac7c8 100644
--- a/mobile/android/base/tabspanel/RemoteTabsList.java
+++ b/mobile/android/base/tabspanel/RemoteTabsList.java
@@ -4,14 +4,6 @@
package org.mozilla.gecko.tabspanel;
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ExpandableListView;
-import android.widget.SimpleExpandableListAdapter;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -22,6 +14,14 @@ import org.mozilla.gecko.TabsAccessor;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
+import android.content.Context;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ExpandableListView;
+import android.widget.SimpleExpandableListAdapter;
+
/**
* The actual list of synced tabs. This serves as the only child view of {@link RemoteTabsContainer}
* so it can be refreshed using a swipe-to-refresh gesture.
@@ -30,9 +30,9 @@ class RemoteTabsList extends ExpandableListView
implements ExpandableListView.OnGroupClickListener,
ExpandableListView.OnChildClickListener,
TabsAccessor.OnQueryTabsCompleteListener {
- private static final String[] CLIENT_KEY = new String[] { "name" };
+ private static final String[] CLIENT_KEY = new String[] { "name", "last_synced" };
private static final String[] TAB_KEY = new String[] { "title", "url" };
- private static final int[] CLIENT_RESOURCE = new int[] { R.id.client };
+ private static final int[] CLIENT_RESOURCE = new int[] { R.id.client, R.id.last_synced };
private static final int[] TAB_RESOURCE = new int[] { R.id.tab, R.id.url };
private final Context context;
@@ -92,10 +92,13 @@ class RemoteTabsList extends ExpandableListView
HashMap client;
HashMap tab;
+ final long now = System.currentTimeMillis();
+
for (TabsAccessor.RemoteTab remoteTab : remoteTabs) {
if (oldGuid == null || !TextUtils.equals(oldGuid, remoteTab.guid)) {
client = new HashMap ();
client.put("name", remoteTab.name);
+ client.put("last_synced", getLastSyncedString(now, remoteTab.lastModified));
clients.add(client);
tabsForClient = new ArrayList >();
@@ -124,4 +127,16 @@ class RemoteTabsList extends ExpandableListView
expandGroup(i);
}
}
+
+ /**
+ * Return a relative "Last synced" time span for the given tab record.
+ *
+ * @param now local time.
+ * @param time to format string for.
+ * @return string describing time span
+ */
+ protected String getLastSyncedString(long now, long time) {
+ CharSequence relativeTimeSpanString = DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
+ return getResources().getString(R.string.remote_tabs_last_synced, relativeTimeSpanString);
+ }
}
diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js
index 9edd5d04500a..f2bc233d41d7 100644
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -8101,6 +8101,10 @@ var ExternalApps = {
icon: "drawable://icon_openinapp",
clickCallback: () => {
+ // Create a relative timestamp for telemetry
+ let uptime = Date.now() - Services.startup.getStartupInfo().linkerInitialized;
+ UITelemetry.addEvent("launch.1", "pageaction", uptime, "helper");
+
if (apps.length > 1) {
// Use the HelperApps prompt here to filter out any Http handlers
HelperApps.prompt(apps, {
diff --git a/mobile/android/installer/Makefile.in b/mobile/android/installer/Makefile.in
index 763680a9158b..96dceab183f2 100644
--- a/mobile/android/installer/Makefile.in
+++ b/mobile/android/installer/Makefile.in
@@ -46,15 +46,22 @@ DEFINES += -DENABLE_MARIONETTE=1
endif
ifdef MOZ_PKG_MANIFEST_P
-$(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) $(GLOBAL_DEPS)
+# When MOZ_CHROME_MULTILOCALE is defined, we write multilocale.json like:
+# {"locales": ["en-US", "de", "ar", ...]}
+
+$(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) $(GLOBAL_DEPS) FORCE
$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $< -o $@)
ifdef MOZ_CHROME_MULTILOCALE
printf '\n[multilocale]\n' >> $@
+ printf '@BINPATH@/res/multilocale.json\n' >> $@
for LOCALE in en-US $(MOZ_CHROME_MULTILOCALE) ;\
do \
printf '$(BINPATH)/chrome/'"$$LOCALE"'$(JAREXT)\n' >> $@; \
printf '$(BINPATH)/chrome/'"$$LOCALE"'.manifest\n' >> $@; \
done
+ COMMA=,
+ echo '{"locales": [$(foreach l,$(MOZ_CHROME_MULTILOCALE),"$(l)"$(COMMA)) "en-US"]}' \
+ > $(FINAL_TARGET)/res/multilocale.json
endif
GARBAGE += $(MOZ_PKG_MANIFEST)