зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1319245 - Track rich telemetry data for Activity Stream r=sebastian
General concept is to populate the "extras" field with a stringified JSON object which contains bunch of additional data which, in aggregate, might give insight into user's actions. A builder is used in order to make constructing the extras json string easier. This builder has a concept of a "global state" which lets us easily include some information with every A-S telemetry ping. Currently this is used to track whether or not user has a firefox account. An instance of a builder is passed around, augmented as more information becomes known, and is materialized into an "extras" string whenever an action occurs and telemetry event needs to be sent. MozReview-Commit-ID: GDmxkWChnnA --HG-- extra : rebase_source : 025d198e16d3a8af8b6e94bd531e916b80f9841a
This commit is contained in:
Родитель
8b13894203
Коммит
2f9475c465
|
@ -8,10 +8,14 @@ package org.mozilla.gecko.activitystream;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.keepsafe.switchboard.SwitchBoard;
|
import com.keepsafe.switchboard.SwitchBoard;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
import org.mozilla.gecko.AppConstants;
|
import org.mozilla.gecko.AppConstants;
|
||||||
import org.mozilla.gecko.Experiments;
|
import org.mozilla.gecko.Experiments;
|
||||||
import org.mozilla.gecko.GeckoSharedPrefs;
|
import org.mozilla.gecko.GeckoSharedPrefs;
|
||||||
|
@ -20,6 +24,7 @@ import org.mozilla.gecko.util.StringUtils;
|
||||||
import org.mozilla.gecko.util.publicsuffix.PublicSuffix;
|
import org.mozilla.gecko.util.publicsuffix.PublicSuffix;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ActivityStream {
|
public class ActivityStream {
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
/* -*- 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.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.mozilla.gecko.R;
|
||||||
|
import org.mozilla.gecko.db.BrowserContract;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Telemetry constants and an 'extras' builder specific to Activity Stream.
|
||||||
|
*/
|
||||||
|
public class ActivityStreamTelemetry {
|
||||||
|
public static class Contract {
|
||||||
|
// Keys
|
||||||
|
public final static String FX_ACCOUNT_PRESENT = "fx_account_present";
|
||||||
|
public final static String ITEM = "item";
|
||||||
|
public final static String SOURCE_TYPE = "source_type";
|
||||||
|
public final static String SOURCE_SUBTYPE = "source_subtype";
|
||||||
|
public final static String ACTION_POSITION = "action_position";
|
||||||
|
public final static String COUNT = "count";
|
||||||
|
|
||||||
|
// Values
|
||||||
|
public final static String TYPE_TOPSITES = "topsites";
|
||||||
|
public final static String TYPE_HIGHLIGHTS = "highlights";
|
||||||
|
public final static String SUBTYPE_PINNED = "pinned";
|
||||||
|
public final static String SUBTYPE_SUGGESTED = "suggested";
|
||||||
|
public final static String SUBTYPE_TOP = "top";
|
||||||
|
public final static String SUBTYPE_VISITED = "visited";
|
||||||
|
public final static String SUBTYPE_BOOKMARKED = "bookmarked";
|
||||||
|
public final static String ITEM_SHARE = "share";
|
||||||
|
public final static String ITEM_ADD_BOOKMARK = "add_bookmark";
|
||||||
|
public final static String ITEM_REMOVE_BOOKMARK = "remove_bookmark";
|
||||||
|
public final static String ITEM_PIN = "pin";
|
||||||
|
public final static String ITEM_UNPIN = "unpin";
|
||||||
|
public final static String ITEM_COPY = "copy";
|
||||||
|
public final static String ITEM_ADD_TO_HOMESCREEN = "homescreen";
|
||||||
|
public final static String ITEM_NEW_TAB = "newtab";
|
||||||
|
public final static String ITEM_PRIVATE_TAB = "privatetab";
|
||||||
|
public final static String ITEM_DISMISS = "dismiss";
|
||||||
|
public final static String ITEM_DELETE_HISTORY = "delete";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class used for composing an 'extras' field. It encapsulates a holder of "global"
|
||||||
|
* key/value pairs which will be present in every 'extras' constructed by this class, and a
|
||||||
|
* static builder which is aware of Activity Stream telemetry needs.
|
||||||
|
*/
|
||||||
|
public final static class Extras {
|
||||||
|
private static final HashMap<String, Object> globals = new HashMap<>();
|
||||||
|
|
||||||
|
public static void setGlobal(String key, Object value) {
|
||||||
|
globals.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows composing a JSON extras blob, which is then "built" into a string representation.
|
||||||
|
*/
|
||||||
|
public final static class Builder {
|
||||||
|
private final JSONObject data;
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
data = new JSONObject(globals);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
|
||||||
|
* Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be
|
||||||
|
* {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
|
||||||
|
* infinities}.
|
||||||
|
* @return this object.
|
||||||
|
*/
|
||||||
|
public Builder set(@NonNull String key, Object value) {
|
||||||
|
try {
|
||||||
|
data.put(key, value);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
throw new IllegalArgumentException("Key can't be null");
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets extras values describing a context menu interaction based on the menu item ID.
|
||||||
|
*
|
||||||
|
* @param itemId ID of a menu item, which is transformed into a corresponding item
|
||||||
|
* key/value pair and passed off to {@link this#set(String, Object)}.
|
||||||
|
* @return this object.
|
||||||
|
*/
|
||||||
|
public Builder fromMenuItemId(int itemId) {
|
||||||
|
switch (itemId) {
|
||||||
|
case R.id.share:
|
||||||
|
this.set(Contract.ITEM, Contract.ITEM_SHARE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R.id.copy_url:
|
||||||
|
this.set(Contract.ITEM, Contract.ITEM_COPY);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R.id.add_homescreen:
|
||||||
|
this.set(Contract.ITEM, Contract.ITEM_ADD_TO_HOMESCREEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R.id.open_new_tab:
|
||||||
|
this.set(Contract.ITEM, Contract.ITEM_NEW_TAB);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R.id.open_new_private_tab:
|
||||||
|
this.set(Contract.ITEM, Contract.ITEM_PRIVATE_TAB);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R.id.dismiss:
|
||||||
|
this.set(Contract.ITEM, Contract.ITEM_DISMISS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R.id.delete:
|
||||||
|
this.set(Contract.ITEM, Contract.ITEM_DELETE_HISTORY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder forHighlightSource(Utils.HighlightSource source) {
|
||||||
|
switch (source) {
|
||||||
|
case VISITED:
|
||||||
|
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_VISITED);
|
||||||
|
break;
|
||||||
|
case BOOKMARKED:
|
||||||
|
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_BOOKMARKED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown highlight source: " + source);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder forTopSiteType(int type) {
|
||||||
|
switch (type) {
|
||||||
|
case BrowserContract.TopSites.TYPE_PINNED:
|
||||||
|
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_PINNED);
|
||||||
|
break;
|
||||||
|
case BrowserContract.TopSites.TYPE_SUGGESTED:
|
||||||
|
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_SUGGESTED);
|
||||||
|
break;
|
||||||
|
case BrowserContract.TopSites.TYPE_TOP:
|
||||||
|
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_TOP);
|
||||||
|
break;
|
||||||
|
// While we also have a "blank" type, it is not used by Activity Stream.
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown top site type: " + type);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String build() {
|
||||||
|
return data.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* -*- 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.database.Cursor;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.db.BrowserContract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various util methods and constants that are shared by different parts of Activity Stream.
|
||||||
|
*/
|
||||||
|
public class Utils {
|
||||||
|
public enum HighlightSource {
|
||||||
|
VISITED,
|
||||||
|
BOOKMARKED
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HighlightSource highlightSource(final Cursor cursor) {
|
||||||
|
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Combined.BOOKMARK_ID))) {
|
||||||
|
return HighlightSource.BOOKMARKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Combined.HISTORY_ID))) {
|
||||||
|
return HighlightSource.VISITED;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Unknown highlight source.");
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,20 +11,17 @@ import android.os.Bundle;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
import android.support.v4.graphics.ColorUtils;
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.DisplayMetrics;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
|
||||||
import org.mozilla.gecko.db.BrowserDB;
|
import org.mozilla.gecko.db.BrowserDB;
|
||||||
|
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||||
import org.mozilla.gecko.home.HomePager;
|
import org.mozilla.gecko.home.HomePager;
|
||||||
import org.mozilla.gecko.home.activitystream.topsites.TopSitesPagerAdapter;
|
import org.mozilla.gecko.home.activitystream.topsites.TopSitesPagerAdapter;
|
||||||
import org.mozilla.gecko.util.ContextUtils;
|
|
||||||
import org.mozilla.gecko.widget.RecyclerViewClickSupport;
|
import org.mozilla.gecko.widget.RecyclerViewClickSupport;
|
||||||
|
|
||||||
public class ActivityStream extends FrameLayout {
|
public class ActivityStream extends FrameLayout {
|
||||||
|
@ -62,6 +59,11 @@ public class ActivityStream extends FrameLayout {
|
||||||
desiredTileWidth = resources.getDimensionPixelSize(R.dimen.activity_stream_desired_tile_width);
|
desiredTileWidth = resources.getDimensionPixelSize(R.dimen.activity_stream_desired_tile_width);
|
||||||
desiredTilesHeight = resources.getDimensionPixelSize(R.dimen.activity_stream_desired_tile_height);
|
desiredTilesHeight = resources.getDimensionPixelSize(R.dimen.activity_stream_desired_tile_height);
|
||||||
tileMargin = resources.getDimensionPixelSize(R.dimen.activity_stream_base_margin);
|
tileMargin = resources.getDimensionPixelSize(R.dimen.activity_stream_base_margin);
|
||||||
|
|
||||||
|
ActivityStreamTelemetry.Extras.setGlobal(
|
||||||
|
ActivityStreamTelemetry.Contract.FX_ACCOUNT_PRESENT,
|
||||||
|
FirefoxAccounts.firefoxAccountsExist(context)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOnUrlOpenListeners(HomePager.OnUrlOpenListener onUrlOpenListener, HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
|
void setOnUrlOpenListeners(HomePager.OnUrlOpenListener onUrlOpenListener, HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
|
||||||
|
|
|
@ -23,7 +23,11 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import org.mozilla.gecko.GeckoSharedPrefs;
|
import org.mozilla.gecko.GeckoSharedPrefs;
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
|
import org.mozilla.gecko.Telemetry;
|
||||||
|
import org.mozilla.gecko.TelemetryContract;
|
||||||
|
import org.mozilla.gecko.activitystream.Utils;
|
||||||
import org.mozilla.gecko.activitystream.ActivityStream.LabelCallback;
|
import org.mozilla.gecko.activitystream.ActivityStream.LabelCallback;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
|
||||||
import org.mozilla.gecko.db.BrowserContract;
|
import org.mozilla.gecko.db.BrowserContract;
|
||||||
import org.mozilla.gecko.home.HomePager;
|
import org.mozilla.gecko.home.HomePager;
|
||||||
import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
|
import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
|
||||||
|
@ -135,17 +139,14 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
|
||||||
public static class HighlightItem extends StreamItem implements IconCallback {
|
public static class HighlightItem extends StreamItem implements IconCallback {
|
||||||
public static final int LAYOUT_ID = R.layout.activity_stream_card_history_item;
|
public static final int LAYOUT_ID = R.layout.activity_stream_card_history_item;
|
||||||
|
|
||||||
enum HighlightSource {
|
|
||||||
VISITED,
|
|
||||||
BOOKMARKED
|
|
||||||
}
|
|
||||||
|
|
||||||
String title;
|
String title;
|
||||||
String url;
|
String url;
|
||||||
|
|
||||||
@Nullable Boolean isPinned;
|
@Nullable Boolean isPinned;
|
||||||
@Nullable Boolean isBookmarked;
|
@Nullable Boolean isBookmarked;
|
||||||
|
|
||||||
|
Utils.HighlightSource source;
|
||||||
|
|
||||||
final FaviconView vIconView;
|
final FaviconView vIconView;
|
||||||
final TextView vLabel;
|
final TextView vLabel;
|
||||||
final TextView vTimeSince;
|
final TextView vTimeSince;
|
||||||
|
@ -180,12 +181,23 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
|
||||||
menuButton.setOnClickListener(new View.OnClickListener() {
|
menuButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
ActivityStreamTelemetry.Extras.Builder extras = ActivityStreamTelemetry.Extras.builder()
|
||||||
|
.set(ActivityStreamTelemetry.Contract.SOURCE_TYPE, ActivityStreamTelemetry.Contract.TYPE_HIGHLIGHTS)
|
||||||
|
.forHighlightSource(source);
|
||||||
|
|
||||||
ActivityStreamContextMenu.show(v.getContext(),
|
ActivityStreamContextMenu.show(v.getContext(),
|
||||||
menuButton,
|
menuButton,
|
||||||
|
extras,
|
||||||
ActivityStreamContextMenu.MenuMode.HIGHLIGHT,
|
ActivityStreamContextMenu.MenuMode.HIGHLIGHT,
|
||||||
title, url, isBookmarked, isPinned,
|
title, url, isBookmarked, isPinned,
|
||||||
onUrlOpenListener, onUrlOpenInBackgroundListener,
|
onUrlOpenListener, onUrlOpenInBackgroundListener,
|
||||||
vIconView.getWidth(), vIconView.getHeight());
|
vIconView.getWidth(), vIconView.getHeight());
|
||||||
|
|
||||||
|
Telemetry.sendUIEvent(
|
||||||
|
TelemetryContract.Event.SHOW,
|
||||||
|
TelemetryContract.Method.CONTEXT_MENU,
|
||||||
|
extras.build()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -193,12 +205,12 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bind(Cursor cursor, int tilesWidth, int tilesHeight) {
|
public void bind(Cursor cursor, int tilesWidth, int tilesHeight) {
|
||||||
|
|
||||||
final long time = cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Highlights.DATE));
|
final long time = cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Highlights.DATE));
|
||||||
final String ago = DateUtils.getRelativeTimeSpanString(time, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, 0).toString();
|
final String ago = DateUtils.getRelativeTimeSpanString(time, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, 0).toString();
|
||||||
|
|
||||||
title = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.History.TITLE));
|
title = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.History.TITLE));
|
||||||
url = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
|
url = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
|
||||||
|
source = Utils.highlightSource(cursor);
|
||||||
|
|
||||||
vLabel.setText(title);
|
vLabel.setText(title);
|
||||||
vTimeSince.setText(ago);
|
vTimeSince.setText(ago);
|
||||||
|
@ -208,9 +220,7 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
|
||||||
layoutParams.height = tilesHeight;
|
layoutParams.height = tilesHeight;
|
||||||
vIconView.setLayoutParams(layoutParams);
|
vIconView.setLayoutParams(layoutParams);
|
||||||
|
|
||||||
final HighlightSource source = highlightSource(cursor);
|
updateStateForSource(source);
|
||||||
|
|
||||||
updateStateForSource(source, cursor);
|
|
||||||
updateUiForSource(source);
|
updateUiForSource(source);
|
||||||
updatePage(url);
|
updatePage(url);
|
||||||
|
|
||||||
|
@ -225,7 +235,7 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
|
||||||
.execute(this);
|
.execute(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStateForSource(HighlightSource source, Cursor cursor) {
|
private void updateStateForSource(Utils.HighlightSource source) {
|
||||||
// We can only be certain of bookmark state if an item is a bookmark item.
|
// We can only be certain of bookmark state if an item is a bookmark item.
|
||||||
// Otherwise, due to the underlying highlights query, we have to look up states when
|
// Otherwise, due to the underlying highlights query, we have to look up states when
|
||||||
// menus are displayed.
|
// menus are displayed.
|
||||||
|
@ -243,7 +253,7 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUiForSource(HighlightSource source) {
|
private void updateUiForSource(Utils.HighlightSource source) {
|
||||||
switch (source) {
|
switch (source) {
|
||||||
case BOOKMARKED:
|
case BOOKMARKED:
|
||||||
vSourceView.setText(R.string.activity_stream_highlight_label_bookmarked);
|
vSourceView.setText(R.string.activity_stream_highlight_label_bookmarked);
|
||||||
|
@ -279,16 +289,4 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
|
||||||
vIconView.updateImage(response);
|
vIconView.updateImage(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HighlightItem.HighlightSource highlightSource(final Cursor cursor) {
|
|
||||||
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Combined.BOOKMARK_ID))) {
|
|
||||||
return HighlightItem.HighlightSource.BOOKMARKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Combined.HISTORY_ID))) {
|
|
||||||
return HighlightItem.HighlightSource.VISITED;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Unknown highlight source.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.mozilla.gecko.Telemetry;
|
import org.mozilla.gecko.Telemetry;
|
||||||
import org.mozilla.gecko.TelemetryContract;
|
import org.mozilla.gecko.TelemetryContract;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
|
||||||
|
import org.mozilla.gecko.activitystream.Utils;
|
||||||
import org.mozilla.gecko.db.BrowserContract;
|
import org.mozilla.gecko.db.BrowserContract;
|
||||||
import org.mozilla.gecko.home.HomePager;
|
import org.mozilla.gecko.home.HomePager;
|
||||||
import org.mozilla.gecko.home.activitystream.StreamItem.HighlightItem;
|
import org.mozilla.gecko.home.activitystream.StreamItem.HighlightItem;
|
||||||
|
@ -113,15 +115,25 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> impl
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
highlightsCursor.moveToPosition(
|
int actualPosition = translatePositionToCursor(position);
|
||||||
translatePositionToCursor(position));
|
highlightsCursor.moveToPosition(actualPosition);
|
||||||
|
|
||||||
final String url = highlightsCursor.getString(
|
final String url = highlightsCursor.getString(
|
||||||
highlightsCursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
|
highlightsCursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
|
||||||
|
|
||||||
onUrlOpenListener.onUrlOpen(url, EnumSet.of(HomePager.OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
|
onUrlOpenListener.onUrlOpen(url, EnumSet.of(HomePager.OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
|
||||||
|
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM, "as_highlights");
|
ActivityStreamTelemetry.Extras.Builder extras = ActivityStreamTelemetry.Extras.builder()
|
||||||
|
.forHighlightSource(Utils.highlightSource(highlightsCursor))
|
||||||
|
.set(ActivityStreamTelemetry.Contract.SOURCE_TYPE, ActivityStreamTelemetry.Contract.TYPE_HIGHLIGHTS)
|
||||||
|
.set(ActivityStreamTelemetry.Contract.ACTION_POSITION, actualPosition)
|
||||||
|
.set(ActivityStreamTelemetry.Contract.COUNT, highlightsCursor.getCount());
|
||||||
|
|
||||||
|
Telemetry.sendUIEvent(
|
||||||
|
TelemetryContract.Event.LOAD_URL,
|
||||||
|
TelemetryContract.Method.LIST_ITEM,
|
||||||
|
extras.build()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.mozilla.gecko.IntentHelper;
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
import org.mozilla.gecko.Telemetry;
|
import org.mozilla.gecko.Telemetry;
|
||||||
import org.mozilla.gecko.TelemetryContract;
|
import org.mozilla.gecko.TelemetryContract;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
|
||||||
import org.mozilla.gecko.annotation.RobocopTarget;
|
import org.mozilla.gecko.annotation.RobocopTarget;
|
||||||
import org.mozilla.gecko.db.BrowserDB;
|
import org.mozilla.gecko.db.BrowserDB;
|
||||||
import org.mozilla.gecko.home.HomePager;
|
import org.mozilla.gecko.home.HomePager;
|
||||||
|
@ -43,6 +44,8 @@ public abstract class ActivityStreamContextMenu
|
||||||
final String title;
|
final String title;
|
||||||
final String url;
|
final String url;
|
||||||
|
|
||||||
|
private final ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder;
|
||||||
|
|
||||||
// We might not know bookmarked/pinned states, so we allow for null values.
|
// We might not know bookmarked/pinned states, so we allow for null values.
|
||||||
private @Nullable Boolean isBookmarked;
|
private @Nullable Boolean isBookmarked;
|
||||||
private @Nullable Boolean isPinned;
|
private @Nullable Boolean isPinned;
|
||||||
|
@ -60,12 +63,14 @@ public abstract class ActivityStreamContextMenu
|
||||||
final MenuMode mode;
|
final MenuMode mode;
|
||||||
|
|
||||||
/* package-private */ ActivityStreamContextMenu(final Context context,
|
/* package-private */ ActivityStreamContextMenu(final Context context,
|
||||||
|
final ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
|
||||||
final MenuMode mode,
|
final MenuMode mode,
|
||||||
final String title, @NonNull final String url,
|
final String title, @NonNull final String url,
|
||||||
@Nullable final Boolean isBookmarked, @Nullable final Boolean isPinned,
|
@Nullable final Boolean isBookmarked, @Nullable final Boolean isPinned,
|
||||||
HomePager.OnUrlOpenListener onUrlOpenListener,
|
HomePager.OnUrlOpenListener onUrlOpenListener,
|
||||||
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
|
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.telemetryExtraBuilder = telemetryExtraBuilder;
|
||||||
|
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
|
||||||
|
@ -156,13 +161,12 @@ public abstract class ActivityStreamContextMenu
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground() {
|
protected Void doInBackground() {
|
||||||
final Cursor cursor = BrowserDB.from(context).getHistoryForURL(context.getContentResolver(), url);
|
final Cursor cursor = BrowserDB.from(context).getHistoryForURL(context.getContentResolver(), url);
|
||||||
try {
|
if (cursor == null) {
|
||||||
if (cursor != null &&
|
|
||||||
cursor.getCount() == 1) {
|
|
||||||
hasHistory = true;
|
|
||||||
} else {
|
|
||||||
hasHistory = false;
|
hasHistory = false;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
hasHistory = cursor.getCount() == 1;
|
||||||
} finally {
|
} finally {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
|
@ -181,27 +185,32 @@ public abstract class ActivityStreamContextMenu
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onNavigationItemSelected(MenuItem item) {
|
public boolean onNavigationItemSelected(MenuItem item) {
|
||||||
|
final int menuItemId = item.getItemId();
|
||||||
|
|
||||||
|
// Sets extra telemetry which doesn't require additional state information.
|
||||||
|
// Pin and bookmark items are handled separately below, since they do require state
|
||||||
|
// information to handle correctly.
|
||||||
|
telemetryExtraBuilder.fromMenuItemId(menuItemId);
|
||||||
|
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.share:
|
case R.id.share:
|
||||||
|
// NB: Generic menu item action event will be sent at the end of this function.
|
||||||
|
// We have a seemingly duplicate telemetry event here because we want to emit
|
||||||
|
// a concrete event in case it is used by other queries to estimate feature usage.
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST, "as_contextmenu");
|
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST, "as_contextmenu");
|
||||||
|
|
||||||
IntentHelper.openUriExternal(url, "text/plain", "", "", Intent.ACTION_SEND, title, false);
|
IntentHelper.openUriExternal(url, "text/plain", "", "", Intent.ACTION_SEND, title, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.bookmark:
|
case R.id.bookmark:
|
||||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
final BrowserDB db = BrowserDB.from(context);
|
|
||||||
|
|
||||||
final TelemetryContract.Event telemetryEvent;
|
final TelemetryContract.Event telemetryEvent;
|
||||||
final String telemetryExtra;
|
final String telemetryExtra;
|
||||||
if (isBookmarked) {
|
|
||||||
db.removeBookmarksWithURL(context.getContentResolver(), url);
|
|
||||||
|
|
||||||
SavedReaderViewHelper rch = SavedReaderViewHelper.getSavedReaderViewHelper(context);
|
SavedReaderViewHelper rch = SavedReaderViewHelper.getSavedReaderViewHelper(context);
|
||||||
final boolean isReaderViewPage = rch.isURLCached(url);
|
final boolean isReaderViewPage = rch.isURLCached(url);
|
||||||
|
|
||||||
|
// While isBookmarked is nullable, behaviour of postInit - disabling 'bookmark' item
|
||||||
|
// until we know value of isBookmarked - guarantees that it will be set when we get here.
|
||||||
|
if (isBookmarked) {
|
||||||
telemetryEvent = TelemetryContract.Event.UNSAVE;
|
telemetryEvent = TelemetryContract.Event.UNSAVE;
|
||||||
|
|
||||||
if (isReaderViewPage) {
|
if (isReaderViewPage) {
|
||||||
|
@ -209,21 +218,43 @@ public abstract class ActivityStreamContextMenu
|
||||||
} else {
|
} else {
|
||||||
telemetryExtra = "as_bookmark";
|
telemetryExtra = "as_bookmark";
|
||||||
}
|
}
|
||||||
|
telemetryExtraBuilder.set(ActivityStreamTelemetry.Contract.ITEM, ActivityStreamTelemetry.Contract.ITEM_REMOVE_BOOKMARK);
|
||||||
|
} else {
|
||||||
|
telemetryEvent = TelemetryContract.Event.SAVE;
|
||||||
|
telemetryExtra = "as_bookmark";
|
||||||
|
telemetryExtraBuilder.set(ActivityStreamTelemetry.Contract.ITEM, ActivityStreamTelemetry.Contract.ITEM_ADD_BOOKMARK);
|
||||||
|
}
|
||||||
|
// NB: Generic menu item action event will be sent at the end of this function.
|
||||||
|
// We have a seemingly duplicate telemetry event here because we want to emit
|
||||||
|
// a concrete event in case it is used by other queries to estimate feature usage.
|
||||||
|
Telemetry.sendUIEvent(telemetryEvent, TelemetryContract.Method.CONTEXT_MENU, telemetryExtra);
|
||||||
|
|
||||||
|
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final BrowserDB db = BrowserDB.from(context);
|
||||||
|
|
||||||
|
if (isBookmarked) {
|
||||||
|
db.removeBookmarksWithURL(context.getContentResolver(), url);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// We only store raw URLs in history (and bookmarks), hence we won't ever show about:reader
|
// We only store raw URLs in history (and bookmarks), hence we won't ever show about:reader
|
||||||
// URLs in AS topsites or highlights. Therefore we don't need to do any special about:reader handling here.
|
// URLs in AS topsites or highlights. Therefore we don't need to do any special about:reader handling here.
|
||||||
db.addBookmark(context.getContentResolver(), title, url);
|
db.addBookmark(context.getContentResolver(), title, url);
|
||||||
|
|
||||||
telemetryEvent = TelemetryContract.Event.SAVE;
|
|
||||||
telemetryExtra = "as_bookmark";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Telemetry.sendUIEvent(telemetryEvent, TelemetryContract.Method.CONTEXT_MENU, telemetryExtra);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.pin:
|
case R.id.pin:
|
||||||
|
// While isPinned is nullable, behaviour of postInit - disabling 'pin' item
|
||||||
|
// until we know value of isPinned - guarantees that it will be set when we get here.
|
||||||
|
if (isPinned) {
|
||||||
|
telemetryExtraBuilder.set(ActivityStreamTelemetry.Contract.ITEM, ActivityStreamTelemetry.Contract.ITEM_UNPIN);
|
||||||
|
} else {
|
||||||
|
telemetryExtraBuilder.set(ActivityStreamTelemetry.Contract.ITEM, ActivityStreamTelemetry.Contract.ITEM_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -236,6 +267,7 @@ public abstract class ActivityStreamContextMenu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
case R.id.copy_url:
|
case R.id.copy_url:
|
||||||
Clipboard.setText(url);
|
Clipboard.setText(url);
|
||||||
|
@ -243,20 +275,14 @@ public abstract class ActivityStreamContextMenu
|
||||||
|
|
||||||
case R.id.add_homescreen:
|
case R.id.add_homescreen:
|
||||||
GeckoAppShell.createShortcut(title, url);
|
GeckoAppShell.createShortcut(title, url);
|
||||||
|
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.CONTEXT_MENU, "as_add_to_launcher");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.open_new_tab:
|
case R.id.open_new_tab:
|
||||||
onUrlOpenInBackgroundListener.onUrlOpenInBackground(url, EnumSet.noneOf(HomePager.OnUrlOpenInBackgroundListener.Flags.class));
|
onUrlOpenInBackgroundListener.onUrlOpenInBackground(url, EnumSet.noneOf(HomePager.OnUrlOpenInBackgroundListener.Flags.class));
|
||||||
|
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.CONTEXT_MENU, "as_new_tab");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.open_new_private_tab:
|
case R.id.open_new_private_tab:
|
||||||
onUrlOpenInBackgroundListener.onUrlOpenInBackground(url, EnumSet.of(HomePager.OnUrlOpenInBackgroundListener.Flags.PRIVATE));
|
onUrlOpenInBackgroundListener.onUrlOpenInBackground(url, EnumSet.of(HomePager.OnUrlOpenInBackgroundListener.Flags.PRIVATE));
|
||||||
|
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.CONTEXT_MENU, "as_private_tab");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.dismiss:
|
case R.id.dismiss:
|
||||||
|
@ -285,6 +311,12 @@ public abstract class ActivityStreamContextMenu
|
||||||
throw new IllegalArgumentException("Menu item with ID=" + item.getItemId() + " not handled");
|
throw new IllegalArgumentException("Menu item with ID=" + item.getItemId() + " not handled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Telemetry.sendUIEvent(
|
||||||
|
TelemetryContract.Event.ACTION,
|
||||||
|
TelemetryContract.Method.CONTEXT_MENU,
|
||||||
|
telemetryExtraBuilder.build()
|
||||||
|
);
|
||||||
|
|
||||||
dismiss();
|
dismiss();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -292,7 +324,7 @@ public abstract class ActivityStreamContextMenu
|
||||||
|
|
||||||
@RobocopTarget
|
@RobocopTarget
|
||||||
public static ActivityStreamContextMenu show(Context context,
|
public static ActivityStreamContextMenu show(Context context,
|
||||||
View anchor,
|
View anchor, ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
|
||||||
final MenuMode menuMode,
|
final MenuMode menuMode,
|
||||||
final String title, @NonNull final String url,
|
final String title, @NonNull final String url,
|
||||||
@Nullable final Boolean isBookmarked, @Nullable final Boolean isPinned,
|
@Nullable final Boolean isBookmarked, @Nullable final Boolean isPinned,
|
||||||
|
@ -303,14 +335,14 @@ public abstract class ActivityStreamContextMenu
|
||||||
|
|
||||||
if (!HardwareUtils.isTablet()) {
|
if (!HardwareUtils.isTablet()) {
|
||||||
menu = new BottomSheetContextMenu(context,
|
menu = new BottomSheetContextMenu(context,
|
||||||
menuMode,
|
telemetryExtraBuilder, menuMode,
|
||||||
title, url, isBookmarked, isPinned,
|
title, url, isBookmarked, isPinned,
|
||||||
onUrlOpenListener, onUrlOpenInBackgroundListener,
|
onUrlOpenListener, onUrlOpenInBackgroundListener,
|
||||||
tilesWidth, tilesHeight);
|
tilesWidth, tilesHeight);
|
||||||
} else {
|
} else {
|
||||||
menu = new PopupContextMenu(context,
|
menu = new PopupContextMenu(context,
|
||||||
anchor,
|
anchor,
|
||||||
menuMode,
|
telemetryExtraBuilder, menuMode,
|
||||||
title, url, isBookmarked, isPinned,
|
title, url, isBookmarked, isPinned,
|
||||||
onUrlOpenListener, onUrlOpenInBackgroundListener);
|
onUrlOpenListener, onUrlOpenInBackgroundListener);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ package org.mozilla.gecko.home.activitystream.menu;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.BottomSheetBehavior;
|
|
||||||
import android.support.design.widget.BottomSheetDialog;
|
import android.support.design.widget.BottomSheetDialog;
|
||||||
import android.support.design.widget.NavigationView;
|
import android.support.design.widget.NavigationView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -18,6 +17,7 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
import org.mozilla.gecko.activitystream.ActivityStream;
|
import org.mozilla.gecko.activitystream.ActivityStream;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
|
||||||
import org.mozilla.gecko.home.HomePager;
|
import org.mozilla.gecko.home.HomePager;
|
||||||
import org.mozilla.gecko.icons.IconCallback;
|
import org.mozilla.gecko.icons.IconCallback;
|
||||||
import org.mozilla.gecko.icons.IconResponse;
|
import org.mozilla.gecko.icons.IconResponse;
|
||||||
|
@ -35,6 +35,7 @@ import static org.mozilla.gecko.activitystream.ActivityStream.extractLabel;
|
||||||
private final NavigationView navigationView;
|
private final NavigationView navigationView;
|
||||||
|
|
||||||
public BottomSheetContextMenu(final Context context,
|
public BottomSheetContextMenu(final Context context,
|
||||||
|
final ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
|
||||||
final MenuMode mode,
|
final MenuMode mode,
|
||||||
final String title, @NonNull final String url,
|
final String title, @NonNull final String url,
|
||||||
@Nullable final Boolean isBookmarked, @Nullable final Boolean isPinned,
|
@Nullable final Boolean isBookmarked, @Nullable final Boolean isPinned,
|
||||||
|
@ -43,6 +44,7 @@ import static org.mozilla.gecko.activitystream.ActivityStream.extractLabel;
|
||||||
final int tilesWidth, final int tilesHeight) {
|
final int tilesWidth, final int tilesHeight) {
|
||||||
|
|
||||||
super(context,
|
super(context,
|
||||||
|
telemetryExtraBuilder,
|
||||||
mode,
|
mode,
|
||||||
title,
|
title,
|
||||||
url,
|
url,
|
||||||
|
|
|
@ -16,6 +16,8 @@ import android.view.View;
|
||||||
import android.widget.PopupWindow;
|
import android.widget.PopupWindow;
|
||||||
|
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStream;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
|
||||||
import org.mozilla.gecko.home.HomePager;
|
import org.mozilla.gecko.home.HomePager;
|
||||||
|
|
||||||
/* package-private */ class PopupContextMenu
|
/* package-private */ class PopupContextMenu
|
||||||
|
@ -28,6 +30,7 @@ import org.mozilla.gecko.home.HomePager;
|
||||||
|
|
||||||
public PopupContextMenu(final Context context,
|
public PopupContextMenu(final Context context,
|
||||||
View anchor,
|
View anchor,
|
||||||
|
final ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
|
||||||
final MenuMode mode,
|
final MenuMode mode,
|
||||||
final String title,
|
final String title,
|
||||||
@NonNull final String url,
|
@NonNull final String url,
|
||||||
|
@ -36,6 +39,7 @@ import org.mozilla.gecko.home.HomePager;
|
||||||
HomePager.OnUrlOpenListener onUrlOpenListener,
|
HomePager.OnUrlOpenListener onUrlOpenListener,
|
||||||
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
|
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
|
||||||
super(context,
|
super(context,
|
||||||
|
telemetryExtraBuilder,
|
||||||
mode,
|
mode,
|
||||||
title,
|
title,
|
||||||
url,
|
url,
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.mozilla.gecko.R;
|
||||||
import org.mozilla.gecko.Telemetry;
|
import org.mozilla.gecko.Telemetry;
|
||||||
import org.mozilla.gecko.TelemetryContract;
|
import org.mozilla.gecko.TelemetryContract;
|
||||||
import org.mozilla.gecko.activitystream.ActivityStream;
|
import org.mozilla.gecko.activitystream.ActivityStream;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
|
||||||
import org.mozilla.gecko.db.BrowserContract;
|
import org.mozilla.gecko.db.BrowserContract;
|
||||||
import org.mozilla.gecko.home.HomePager;
|
import org.mozilla.gecko.home.HomePager;
|
||||||
import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
|
import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
|
||||||
|
@ -103,13 +104,22 @@ class TopSitesCard extends RecyclerView.ViewHolder
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View clickedView) {
|
public void onClick(View clickedView) {
|
||||||
|
ActivityStreamTelemetry.Extras.Builder extras = ActivityStreamTelemetry.Extras.builder()
|
||||||
|
.set(ActivityStreamTelemetry.Contract.SOURCE_TYPE, ActivityStreamTelemetry.Contract.TYPE_TOPSITES)
|
||||||
|
.forTopSiteType(type);
|
||||||
|
|
||||||
if (clickedView == itemView) {
|
if (clickedView == itemView) {
|
||||||
onUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(HomePager.OnUrlOpenListener.Flags.class));
|
onUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(HomePager.OnUrlOpenListener.Flags.class));
|
||||||
|
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM, "as_top_sites");
|
Telemetry.sendUIEvent(
|
||||||
|
TelemetryContract.Event.LOAD_URL,
|
||||||
|
TelemetryContract.Method.LIST_ITEM,
|
||||||
|
extras.build()
|
||||||
|
);
|
||||||
} else if (clickedView == menuButton) {
|
} else if (clickedView == menuButton) {
|
||||||
ActivityStreamContextMenu.show(clickedView.getContext(),
|
ActivityStreamContextMenu.show(clickedView.getContext(),
|
||||||
menuButton,
|
menuButton,
|
||||||
|
extras,
|
||||||
ActivityStreamContextMenu.MenuMode.TOPSITE,
|
ActivityStreamContextMenu.MenuMode.TOPSITE,
|
||||||
title.getText().toString(), url,
|
title.getText().toString(), url,
|
||||||
|
|
||||||
|
@ -118,11 +128,15 @@ class TopSitesCard extends RecyclerView.ViewHolder
|
||||||
onUrlOpenListener, onUrlOpenInBackgroundListener,
|
onUrlOpenListener, onUrlOpenInBackgroundListener,
|
||||||
faviconView.getWidth(), faviconView.getHeight());
|
faviconView.getWidth(), faviconView.getHeight());
|
||||||
|
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.CONTEXT_MENU, "as_top_sites");
|
Telemetry.sendUIEvent(
|
||||||
|
TelemetryContract.Event.SHOW,
|
||||||
|
TelemetryContract.Method.CONTEXT_MENU,
|
||||||
|
extras.build()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isPinned(int type) {
|
private boolean isPinned(int type) {
|
||||||
return type == BrowserContract.TopSites.TYPE_PINNED;
|
return type == BrowserContract.TopSites.TYPE_PINNED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,6 +334,8 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||||
'ActionModeCompatView.java',
|
'ActionModeCompatView.java',
|
||||||
'ActivityHandlerHelper.java',
|
'ActivityHandlerHelper.java',
|
||||||
'activitystream/ActivityStream.java',
|
'activitystream/ActivityStream.java',
|
||||||
|
'activitystream/ActivityStreamTelemetry.java',
|
||||||
|
'activitystream/Utils.java',
|
||||||
'adjust/AdjustBrowserAppDelegate.java',
|
'adjust/AdjustBrowserAppDelegate.java',
|
||||||
'animation/AnimationUtils.java',
|
'animation/AnimationUtils.java',
|
||||||
'animation/HeightChangeAnimation.java',
|
'animation/HeightChangeAnimation.java',
|
||||||
|
|
|
@ -10,6 +10,8 @@ import android.view.View;
|
||||||
import com.robotium.solo.Condition;
|
import com.robotium.solo.Condition;
|
||||||
|
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStream;
|
||||||
|
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
|
||||||
import org.mozilla.gecko.db.BrowserDB;
|
import org.mozilla.gecko.db.BrowserDB;
|
||||||
import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
|
import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
|
||||||
|
|
||||||
|
@ -61,7 +63,8 @@ public class testActivityStreamContextMenu extends BaseTest {
|
||||||
private void testMenuForUrl(final String url, final Boolean isBookmarkedKnownState, final boolean isBookmarked, final Boolean isPinnedKnownState, final boolean isPinned, final boolean isVisited) {
|
private void testMenuForUrl(final String url, final Boolean isBookmarkedKnownState, final boolean isBookmarked, final Boolean isPinnedKnownState, final boolean isPinned, final boolean isVisited) {
|
||||||
final View anchor = new View(getActivity());
|
final View anchor = new View(getActivity());
|
||||||
|
|
||||||
final ActivityStreamContextMenu menu = ActivityStreamContextMenu.show(getActivity(), anchor, ActivityStreamContextMenu.MenuMode.HIGHLIGHT, "foobar", url, isBookmarkedKnownState, isPinnedKnownState, null, null, 100, 100);
|
final ActivityStreamContextMenu menu = ActivityStreamContextMenu.show(
|
||||||
|
getActivity(), anchor, ActivityStreamTelemetry.Extras.builder(), ActivityStreamContextMenu.MenuMode.HIGHLIGHT, "foobar", url, isBookmarkedKnownState, isPinnedKnownState, null, null, 100, 100);
|
||||||
|
|
||||||
final int expectedBookmarkString;
|
final int expectedBookmarkString;
|
||||||
if (isBookmarked) {
|
if (isBookmarked) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче