Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Reader] Improve analytics tracking for subscribed sites and followed tags #20388

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ public enum DeletablePrefKey implements PrefKey {

READER_ANALYTICS_COUNT_TAGS_TIMESTAMP,

READER_ANALYTICS_COUNT_SITES_TIMESTAMP,

// currently active tab on the main Reader screen when the user is in Reader
READER_ACTIVE_TAB,

Expand Down Expand Up @@ -1172,6 +1174,14 @@ public static void setReaderAnalyticsCountTagsTimestamp(long timestamp) {
setLong(DeletablePrefKey.READER_ANALYTICS_COUNT_TAGS_TIMESTAMP, timestamp);
}

public static long getReaderAnalyticsCountSitesTimestamp() {
return getLong(DeletablePrefKey.READER_ANALYTICS_COUNT_SITES_TIMESTAMP, -1);
}

public static void setReaderAnalyticsCountSitesTimestamp(long timestamp) {
setLong(DeletablePrefKey.READER_ANALYTICS_COUNT_SITES_TIMESTAMP, timestamp);
}

public static long getReaderCssUpdatedTimestamp() {
return getLong(DeletablePrefKey.READER_CSS_UPDATED_TIMESTAMP, 0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class AppPrefsWrapper @Inject constructor() {
get() = AppPrefs.getReaderTagsUpdatedTimestamp()
set(timestamp) = AppPrefs.setReaderTagsUpdatedTimestamp(timestamp)

var readerAnalyticsCountTagsTimestamp: Long
get() = AppPrefs.getReaderAnalyticsCountTagsTimestamp()
set(timestamp) = AppPrefs.setReaderAnalyticsCountTagsTimestamp(timestamp)

var readerCssUpdatedTimestamp: Long
get() = AppPrefs.getReaderCssUpdatedTimestamp()
set(timestamp) = AppPrefs.setReaderCssUpdatedTimestamp(timestamp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,18 @@ private ReaderEvents() {
public static class FollowedTagsFetched {
private final boolean mDidSucceed;
private final boolean mDidChange;
private final int mTotalTags;

public FollowedTagsFetched(boolean didSucceed) {
public FollowedTagsFetched(boolean didSucceed, int tagsFollowed) {
mDidSucceed = didSucceed;
mDidChange = true;
mTotalTags = tagsFollowed;
}

public FollowedTagsFetched(boolean didSucceed, boolean didChange) {
public FollowedTagsFetched(boolean didSucceed, int tagsFollowed, boolean didChange) {
mDidSucceed = didSucceed;
mDidChange = didChange;
mTotalTags = tagsFollowed;
}

public boolean didSucceed() {
Expand All @@ -47,6 +50,9 @@ public boolean didSucceed() {
public boolean didChange() {
return mDidChange;
}
public int getTotalTags() {
return mTotalTags;
}
}

public static class TagAdded {
Expand All @@ -61,13 +67,19 @@ public String getTagName() {
}
}

public static class FollowedBlogsChanged {
public static class FollowedBlogsFetched {
private final int mTotalSubscriptions;
private final boolean mDidChange;

public boolean didChange() {
return mDidChange;
}
public int getTotalSubscriptions() {
return mTotalSubscriptions;
}
public FollowedBlogsChanged(int totalSubscriptions) {
public FollowedBlogsFetched(int totalSubscriptions, boolean didChange) {
mTotalSubscriptions = totalSubscriptions;
mDidChange = didChange;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import org.wordpress.android.ui.mysite.jetpackbadge.JetpackPoweredBottomSheetFragment;
import org.wordpress.android.ui.pages.SnackbarMessageHolder;
import org.wordpress.android.ui.prefs.AppPrefs;
import org.wordpress.android.ui.reader.ReaderEvents.FollowedBlogsFetched;
import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched;
import org.wordpress.android.ui.reader.ReaderEvents.TagAdded;
import org.wordpress.android.ui.reader.ReaderTypes.ReaderPostListType;
Expand Down Expand Up @@ -118,7 +119,6 @@
import org.wordpress.android.ui.reader.subfilter.SubfilterListItem.SiteAll;
import org.wordpress.android.ui.reader.tracker.ReaderTracker;
import org.wordpress.android.ui.reader.usecases.ReaderSiteFollowUseCase.FollowSiteState.FollowStatusChanged;
import org.wordpress.android.ui.reader.utils.DateProvider;
import org.wordpress.android.ui.reader.utils.ReaderUtils;
import org.wordpress.android.ui.reader.viewmodels.ReaderModeInfo;
import org.wordpress.android.ui.reader.viewmodels.ReaderPostListViewModel;
Expand Down Expand Up @@ -949,28 +949,18 @@ public void onEventMainThread(FollowedTagsFetched event) {
updateCurrentTag();
}
}

// Check last time we've bumped tags followed analytics for this user,
// and bumping again if > 1 hrs
long tagsUpdatedTimestamp = AppPrefs.getReaderAnalyticsCountTagsTimestamp();
long now = new DateProvider().getCurrentDate().getTime();
if (now - tagsUpdatedTimestamp > 1000 * 60 * 60) { // 1 hr
ReaderTracker.trackFollowedTagsCount(ReaderTagTable.getFollowedTags().size());
AppPrefs.setReaderAnalyticsCountTagsTimestamp(now);
}
}

@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(ReaderEvents.FollowedBlogsChanged event) {
public void onEventMainThread(FollowedBlogsFetched event) {
// refresh posts if user is viewing "Followed Sites"
if (getPostListType() == ReaderPostListType.TAG_FOLLOWED
if (event.didChange()
&& getPostListType() == ReaderPostListType.TAG_FOLLOWED
&& hasCurrentTag()
&& (getCurrentTag().isFollowedSites() || getCurrentTag().isDefaultInMemoryTag())) {
refreshPosts();
}

ReaderTracker.trackSubscribedSitesCount(event.getTotalSubscriptions());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.wordpress.android.ui.LocaleAwareActivity;
import org.wordpress.android.ui.RequestCodes;
import org.wordpress.android.ui.prefs.AppPrefs;
import org.wordpress.android.ui.reader.ReaderEvents.FollowedBlogsFetched;
import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched;
import org.wordpress.android.ui.reader.actions.ReaderActions;
import org.wordpress.android.ui.reader.actions.ReaderBlogActions;
Expand Down Expand Up @@ -211,9 +212,11 @@ public void onEventMainThread(FollowedTagsFetched event) {

@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(ReaderEvents.FollowedBlogsChanged event) {
AppLog.d(AppLog.T.READER, "reader subs > followed blogs changed");
getPageAdapter().refreshBlogFragments(ReaderBlogType.FOLLOWED);
public void onEventMainThread(FollowedBlogsFetched event) {
if (event.didChange()) {
AppLog.d(AppLog.T.READER, "reader subs > followed blogs changed");
getPageAdapter().refreshBlogFragments(ReaderBlogType.FOLLOWED);
}
}

private void performUpdate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static boolean deleteTag(final ReaderTag tag,
private static boolean deleteTagsLocallyOnly(ActionListener actionListener, ReaderTag tag) {
ReaderTagTable.deleteTag(tag);
ReaderActions.callActionListener(actionListener, true);
EventBus.getDefault().post(new FollowedTagsFetched(true));
EventBus.getDefault().post(new FollowedTagsFetched(true, ReaderTagTable.getFollowedTags().size()));

return true;
}
Expand Down Expand Up @@ -130,7 +130,7 @@ public static boolean addTags(@NonNull final List<ReaderTag> tags,
private static boolean saveTagsLocallyOnly(ActionListener actionListener, ReaderTagList newTags) {
ReaderTagTable.addOrUpdateTags(newTags);
ReaderActions.callActionListener(actionListener, true);
EventBus.getDefault().post(new FollowedTagsFetched(true));
EventBus.getDefault().post(new FollowedTagsFetched(true, ReaderTagTable.getFollowedTags().size()));

return true;
}
Expand All @@ -147,7 +147,7 @@ private static boolean saveTagsLocallyAndRemotely(ActionListener actionListener,
if (actionListener != null) {
ReaderActions.callActionListener(actionListener, true);
}
EventBus.getDefault().post(new FollowedTagsFetched(true));
EventBus.getDefault().post(new FollowedTagsFetched(true, ReaderTagTable.getFollowedTags().size()));
};

RestRequest.ErrorListener errorListener = volleyError -> {
Expand All @@ -159,7 +159,7 @@ private static boolean saveTagsLocallyAndRemotely(ActionListener actionListener,
if (actionListener != null) {
ReaderActions.callActionListener(actionListener, true);
}
EventBus.getDefault().post(new FollowedTagsFetched(true));
EventBus.getDefault().post(new FollowedTagsFetched(true, ReaderTagTable.getFollowedTags().size()));
return;
}

Expand All @@ -171,7 +171,7 @@ private static boolean saveTagsLocallyAndRemotely(ActionListener actionListener,
if (actionListener != null) {
ReaderActions.callActionListener(actionListener, false);
}
EventBus.getDefault().post(new FollowedTagsFetched(false));
EventBus.getDefault().post(new FollowedTagsFetched(false, ReaderTagTable.getFollowedTags().size()));
};

ReaderTagTable.addOrUpdateTags(newTags);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import org.wordpress.android.models.ReaderTagType;
import org.wordpress.android.ui.prefs.AppPrefs;
import org.wordpress.android.ui.reader.ReaderConstants;
import org.wordpress.android.ui.reader.ReaderEvents;
import org.wordpress.android.ui.reader.ReaderEvents.FollowedBlogsFetched;
import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched;
import org.wordpress.android.ui.reader.ReaderEvents.InterestTagsFetchEnded;
import org.wordpress.android.ui.reader.services.ServiceCompletionListener;
Expand Down Expand Up @@ -193,7 +193,9 @@ public void run() {
// broadcast the fact that there are changes
didChangeFollowedTags = true;
}
EventBus.getDefault().post(new FollowedTagsFetched(true, didChangeFollowedTags));
EventBus.getDefault().post(new FollowedTagsFetched(true,
ReaderTagTable.getFollowedTags().size(),
didChangeFollowedTags));
AppPrefs.setReaderTagsUpdatedTimestamp(new Date().getTime());

taskCompleted(UpdateTask.TAGS);
Expand Down Expand Up @@ -327,6 +329,9 @@ public void run() {
// but it's better to keep it separate since we aim to remove this check as soon as possible.
removeDuplicateBlogs(serverBlogs);

boolean sitesSubscribedChanged = false;
final int totalSites = jsonObject == null ? 0 : jsonObject.optInt("total_subscriptions", 0);

if (!localBlogs.isSameList(serverBlogs)) {
// always update the list of followed blogs if there are *any* changes between
// server and local (including subscription count, description, etc.)
Expand All @@ -335,13 +340,12 @@ public void run() {
// changed if the server list doesn't have the same blogs as the local list
// (ie: a blog has been followed/unfollowed since local was last updated)
if (!localBlogs.hasSameBlogs(serverBlogs)) {
final int totalSites = jsonObject == null ? 0 : jsonObject.optInt("total_subscriptions", 0);
ReaderPostTable.updateFollowedStatus();
AppLog.i(AppLog.T.READER, "reader blogs service > followed blogs changed");
EventBus.getDefault().post(new ReaderEvents.FollowedBlogsChanged(totalSites));
sitesSubscribedChanged = true;
}
}

EventBus.getDefault().post(new FollowedBlogsFetched(totalSites, sitesSubscribedChanged));
taskCompleted(UpdateTask.FOLLOWED_BLOGS);
}
}.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,9 +400,11 @@ class SubFilterViewModel @Inject constructor(

@Suppress("unused", "UNUSED_PARAMETER")
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(event: ReaderEvents.FollowedBlogsChanged) {
AppLog.d(T.READER, "Subfilter bottom sheet > followed blogs changed")
loadSubFilters()
fun onEventMainThread(event: ReaderEvents.FollowedBlogsFetched) {
if(event.didChange()) {
AppLog.d(T.READER, "Subfilter bottom sheet > followed blogs changed")
loadSubFilters()
}
}

override fun onCleared() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,21 @@ class ReaderTracker @Inject constructor(
}
}

private fun trackFollowedCount(type: String, numberOfItems: Int) {
val props: MutableMap<String, String> = HashMap()
props["type"] = type
props["count"] = numberOfItems.toString()
AnalyticsTracker.track(Stat.READER_FOLLOWING_FETCHED, props)
}

fun trackFollowedTagsCount(numberOfItems: Int) {
trackFollowedCount("tags", numberOfItems)
}

fun trackSubscribedSitesCount(numberOfItems: Int) {
trackFollowedCount("sites", numberOfItems)
}

/* HELPER */

@JvmOverloads
Expand Down Expand Up @@ -466,23 +481,6 @@ class ReaderTracker @Inject constructor(
AnalyticsTracker.track(stat, properties)
}

private fun trackFollowedCount(type: String, numberOfItems: Int) {
val props: MutableMap<String, String> = HashMap()
props["type"] = type
props["count"] = numberOfItems.toString()
AnalyticsTracker.track(Stat.READER_FOLLOWING_FETCHED, props)
}

@JvmStatic
fun trackFollowedTagsCount(numberOfItems: Int) {
trackFollowedCount("tags", numberOfItems)
}

@JvmStatic
fun trackSubscribedSitesCount(numberOfItems: Int) {
trackFollowedCount("sites", numberOfItems)
}

fun isUserProfileSource(source: String): Boolean {
return (source == SOURCE_READER_LIKE_LIST_USER_PROFILE ||
source == SOURCE_NOTIF_LIKE_LIST_USER_PROFILE ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil
import org.wordpress.android.ui.jetpackoverlay.JetpackOverlayConnectedFeature.READER
import org.wordpress.android.ui.mysite.SelectedSiteRepository
import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartRepository
import org.wordpress.android.ui.prefs.AppPrefs
import org.wordpress.android.ui.prefs.AppPrefsWrapper
import org.wordpress.android.ui.quickstart.QuickStartEvent
import org.wordpress.android.ui.reader.ReaderEvents
Expand Down Expand Up @@ -60,6 +61,7 @@ import kotlin.coroutines.CoroutineContext

const val UPDATE_TAGS_THRESHOLD = 1000 * 60 * 60 // 1 hr
const val TRACK_TAB_CHANGED_THROTTLE = 100L
const val ONE_HOUR_MILLIS = 1000 * 60 * 60

@Suppress("ForbiddenComment")
class ReaderViewModel @Inject constructor(
Expand Down Expand Up @@ -220,6 +222,29 @@ class ReaderViewModel @Inject constructor(
@Subscribe(threadMode = MAIN)
fun onTagsUpdated(event: ReaderEvents.FollowedTagsFetched) {
loadTabs()
// Determine if analytics should be bumped either due to tags changed or time elapsed since last bump
val now = DateProvider().getCurrentDate().time
val shouldBumpAnalytics = event.didChange()
|| ( now - appPrefsWrapper.readerAnalyticsCountTagsTimestamp > ONE_HOUR_MILLIS)

if (shouldBumpAnalytics) {
readerTracker.trackFollowedTagsCount(event.totalTags)
appPrefsWrapper.readerAnalyticsCountTagsTimestamp = now
}
}

@Suppress("unused", "UNUSED_PARAMETER")
@Subscribe(threadMode = MAIN)
fun onSubscribedSitesUpdated(event: ReaderEvents.FollowedBlogsFetched) {
// Determine if analytics should be bumped either due to sites changed or time elapsed since last bump
val now = DateProvider().getCurrentDate().time
val shouldBumpAnalytics = event.didChange()
|| (now - AppPrefs.getReaderAnalyticsCountSitesTimestamp() > ONE_HOUR_MILLIS)

if (shouldBumpAnalytics) {
readerTracker.trackSubscribedSitesCount(event.totalSubscriptions)
AppPrefs.setReaderAnalyticsCountSitesTimestamp(now)
}
}

fun onScreenInForeground() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class FetchFollowedTagsUseCaseTest : BaseUnitTest() {
fun `Success returned when FollowedTagsFetched event is posted with success`() = test {
// Given
whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true)
val event = FollowedTagsFetched(true)
val event = FollowedTagsFetched(true, 10)
whenever(readerUpdateServiceStarterWrapper.startService(contextProvider.getContext(), EnumSet.of(TAGS)))
.then { useCase.onFollowedTagsFetched(event) }

Expand All @@ -79,7 +79,7 @@ class FetchFollowedTagsUseCaseTest : BaseUnitTest() {
fun `RemoteRequestFailure returned when FollowedTagsFetched event is posted with failure`() = test {
// Given
whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true)
val event = FollowedTagsFetched(false)
val event = FollowedTagsFetched(false, 10)
whenever(readerUpdateServiceStarterWrapper.startService(contextProvider.getContext(), EnumSet.of(TAGS)))
.then { useCase.onFollowedTagsFetched(event) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@ class ReaderDiscoverDataProviderTest : BaseUnitTest() {
// Act
dataProvider.onFollowedTagsFetched(
FollowedTagsFetched(
true
true,
10
)
)
// Assert
Expand Down
Loading