Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
1497dad
Use a Timer, and a TimerTask, to correctly track application `backgro…
daniloercoli Apr 29, 2016
1d9c4e0
First pass at reader search service
nbradbury May 13, 2016
24a4bf5
Submit search query on suggestion click
nbradbury May 13, 2016
5813aed
Empty view for no results now works
nbradbury May 13, 2016
f9a5b4b
Added "Searching..." message while search is active
nbradbury May 13, 2016
ca18d72
Search results are now stored in main post table
nbradbury May 13, 2016
aa4b578
Updated getTagForSearchQuery
nbradbury May 13, 2016
41477b5
Added ReaderPostListType.SEARCH_RESULTS
nbradbury May 13, 2016
39f2a1f
Search results are now correctly displayed when search finishes
nbradbury May 13, 2016
89190a4
Clear existing results before performing search
nbradbury May 13, 2016
b366ecc
Return max 10 results
nbradbury May 13, 2016
b543159
Set the autocomplete search threshold to 1
nbradbury May 13, 2016
60a7fb2
Move setThreshold() to initial setup
nbradbury May 13, 2016
dcbfb3e
Show boxes & pages anim when searching
nbradbury May 13, 2016
87840c5
Retain search activity title upon rotation
nbradbury May 13, 2016
9e5aaf5
No longer removing previous search results
nbradbury May 13, 2016
c358566
Use custom layout for search suggestions
nbradbury May 14, 2016
3f687aa
Apply max suggestions
nbradbury May 14, 2016
fef6b5c
Clean up getQueryStrings
nbradbury May 14, 2016
f5696bd
First pass at infinite scroll for search
nbradbury May 14, 2016
fd35877
Second pass at infinite scroll for search
nbradbury May 15, 2016
1dfe743
Third pass at infinite scroll for search
nbradbury May 15, 2016
bd3551f
Parse score from search results to determine sort order
nbradbury May 15, 2016
4367231
Updated comment about timestamps
nbradbury May 15, 2016
7d529c4
Change post timestamp to REAL (double)
nbradbury May 15, 2016
132fe18
First pass at showing search results in main reader (no separate acti…
nbradbury May 15, 2016
db99f1e
2nd pass at showing search results in main reader
nbradbury May 15, 2016
7112499
3rd pass at showing search results in main reader
nbradbury May 15, 2016
5e7d397
Fixed search message for landscape
nbradbury May 15, 2016
32f883e
Fixed device rotation issues, now re-using empty view for search message
nbradbury May 15, 2016
1363d6f
Simplified post adapter to use the current tag when searching
nbradbury May 15, 2016
007ae27
No longer clearing cached searches again
nbradbury May 15, 2016
0f1b346
Make sure toolbar showing search keyword is showing when returning to…
nbradbury May 15, 2016
d4cd5d0
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
nbradbury May 15, 2016
72987f1
Use a CursorAdapter rather than a SimpleCursorAdapter for search sugg…
nbradbury May 15, 2016
5136967
Enable deleting search suggestions
nbradbury May 15, 2016
4032f4c
Renamed suggestion table and dropped counter
nbradbury May 15, 2016
769acfb
Increment db version counter
nbradbury May 15, 2016
ca4c263
Rewrote `setEmptyTitleAndDescription` to better handle search
nbradbury May 15, 2016
d0912a9
Added `showEmptyView()` and `hideEmptyView()`
nbradbury May 16, 2016
11eb8b8
Removed `newInstanceForSearch`
nbradbury May 16, 2016
0808f6e
Show search message even in landscape
nbradbury May 16, 2016
946eed1
Clear query when searchView is collapsed
nbradbury May 16, 2016
ca9d45e
Added some comments that describe how we're detecting the "onBackgrou…
daniloercoli May 16, 2016
c973d68
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
nbradbury May 16, 2016
ffdf77a
Purge all searches when reader db is purged at startup
nbradbury May 16, 2016
52549d3
Merge pull request #4036 from wordpress-mobile/issue/4033-manage-back…
maxme May 17, 2016
dfca3da
Merge branch 'develop' of https://github.com/wordpress-mobile/WordPre…
nbradbury May 17, 2016
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
4 changes: 4 additions & 0 deletions WordPress/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,10 @@
android:name=".ui.reader.services.ReaderPostService"
android:exported="false"
android:label="Reader Post Service" />
<service
android:name=".ui.reader.services.ReaderSearchService"
android:exported="false"
android:label="Reader Search Service" />
<service
android:name=".ui.reader.services.ReaderCommentService"
android:exported="false"
Expand Down
84 changes: 60 additions & 24 deletions WordPress/src/main/java/org/wordpress/android/WordPress.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import de.greenrobot.event.EventBus;
import io.fabric.sdk.android.Fabric;
Expand Down Expand Up @@ -718,8 +720,11 @@ private class ApplicationLifecycleMonitor implements Application.ActivityLifecyc
private final int DEFAULT_TIMEOUT = 2 * 60; // 2 minutes
private Date mLastPingDate;
private Date mApplicationOpenedDate;
boolean mIsInBackground = true;
boolean mFirstActivityResumed = true;
private Timer mActivityTransitionTimer;
private TimerTask mActivityTransitionTimerTask;
private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
boolean mIsInBackground = true;

@Override
public void onConfigurationChanged(final Configuration newConfig) {
Expand All @@ -733,25 +738,6 @@ public void onLowMemory() {

@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// We're in the Background
mIsInBackground = true;
String lastActivityString = AppPrefs.getLastActivityStr();
ActivityId lastActivity = ActivityId.getActivityIdFromName(lastActivityString);
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("last_visible_screen", lastActivity.toString());
if (mApplicationOpenedDate != null) {
Date now = new Date();
properties.put("time_in_app", DateTimeUtils.secondsBetween(now, mApplicationOpenedDate));
mApplicationOpenedDate = null;
}
AnalyticsTracker.track(AnalyticsTracker.Stat.APPLICATION_CLOSED, properties);
AnalyticsTracker.endSession(false);
onAppGoesToBackground();
} else {
mIsInBackground = false;
}

boolean evictBitmaps = false;
switch (level) {
case TRIM_MEMORY_COMPLETE:
Expand Down Expand Up @@ -796,17 +782,64 @@ private void updatePushNotificationTokenIfNotLimited() {
}
}

public void onAppGoesToBackground() {
AppLog.i(T.UTILS, "App goes to background");
ConnectionChangeReceiver.setEnabled(WordPress.this, false);
/**
* The two methods below (startActivityTransitionTimer and stopActivityTransitionTimer)
* are used to track when the app goes to background.
*
* Our implementation uses `onActivityPaused` and `onActivityResumed` of ApplicationLifecycleMonitor
* to start and stop the timer that detects when the app goes to background.
*
* So when the user is simply navigating between the activities, the onActivityPaused() calls `startActivityTransitionTimer`
* and starts the timer, but almost immediately the new activity being entered, the ApplicationLifecycleMonitor cancels the timer
* in its onActivityResumed method, that in order calls `stopActivityTransitionTimer`.
* And so mIsInBackground would be false.
*
* In the case the app is sent to background, the TimerTask is instead executed, and the code that handles all the background logic is run.
*/
private void startActivityTransitionTimer() {
this.mActivityTransitionTimer = new Timer();
this.mActivityTransitionTimerTask = new TimerTask() {
public void run() {
AppLog.i(T.UTILS, "App goes to background");
// We're in the Background
mIsInBackground = true;
String lastActivityString = AppPrefs.getLastActivityStr();
ActivityId lastActivity = ActivityId.getActivityIdFromName(lastActivityString);
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("last_visible_screen", lastActivity.toString());
if (mApplicationOpenedDate != null) {
Date now = new Date();
properties.put("time_in_app", DateTimeUtils.secondsBetween(now, mApplicationOpenedDate));
mApplicationOpenedDate = null;
}
AnalyticsTracker.track(AnalyticsTracker.Stat.APPLICATION_CLOSED, properties);
AnalyticsTracker.endSession(false);
ConnectionChangeReceiver.setEnabled(WordPress.this, false);
}
};

this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask,
MAX_ACTIVITY_TRANSITION_TIME_MS);
}

private void stopActivityTransitionTimer() {
if (this.mActivityTransitionTimerTask != null) {
this.mActivityTransitionTimerTask.cancel();
}

if (this.mActivityTransitionTimer != null) {
this.mActivityTransitionTimer.cancel();
}

mIsInBackground = false;
}

/**
* This method is called when:
* 1. the app starts (but it's not opened by a service or a broadcast receiver, i.e. an activity is resumed)
* 2. the app was in background and is now foreground
*/
public void onAppComesFromBackground() {
private void onAppComesFromBackground() {
AppLog.i(T.UTILS, "App comes from background");
ConnectionChangeReceiver.setEnabled(WordPress.this, true);
AnalyticsUtils.refreshMetadata();
Expand All @@ -832,6 +865,8 @@ public void onActivityResumed(Activity activity) {
// was in background before
onAppComesFromBackground();
}
stopActivityTransitionTimer();

mIsInBackground = false;
if (mFirstActivityResumed) {
deferredInit(activity);
Expand All @@ -850,6 +885,7 @@ public void onActivityDestroyed(Activity arg0) {
@Override
public void onActivityPaused(Activity arg0) {
mLastPingDate = new Date();
startActivityTransitionTimer();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*/
public class ReaderDatabase extends SQLiteOpenHelper {
protected static final String DB_NAME = "wpreader.db";
private static final int DB_VERSION = 116;
private static final int DB_VERSION = 118;

/*
* version history
Expand Down Expand Up @@ -68,6 +68,8 @@ public class ReaderDatabase extends SQLiteOpenHelper {
* 114 - renamed tag_name to tag_slug in tag tables
* 115 - added ReaderSearchTable
* 116 - added tag_display_name to tag tables
* 117 - changed tbl_posts.timestamp from INTEGER to REAL
* 118 - renamed tbl_search_history to tbl_search_suggestions
*/

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ protected static void createTables(SQLiteDatabase db) {
+ " featured_image TEXT,"
+ " featured_video TEXT,"
+ " post_avatar TEXT,"
+ " timestamp INTEGER DEFAULT 0,"
+ " timestamp REAL DEFAULT 0,"
+ " published TEXT,"
+ " num_replies INTEGER DEFAULT 0,"
+ " num_likes INTEGER DEFAULT 0,"
Expand Down Expand Up @@ -180,6 +180,9 @@ protected static int purge(SQLiteDatabase db) {
numDeleted += purgePostsForTag(db, tag);
}

// delete search results
numDeleted += purgeSearchResults(db);

// delete posts in tbl_posts that no longer exist in tbl_post_tags
numDeleted += db.delete("tbl_posts", "pseudo_id NOT IN (SELECT DISTINCT pseudo_id FROM tbl_post_tags)", null);

Expand Down Expand Up @@ -211,6 +214,14 @@ private static int purgePostsForTag(SQLiteDatabase db, ReaderTag tag) {
return numDeleted;
}

/*
* purge all posts that were retained from previous searches
*/
private static int purgeSearchResults(SQLiteDatabase db) {
String[] args = {Integer.toString(ReaderTagType.SEARCH.toInt())};
return db.delete("tbl_post_tags", "tag_type=?", args);
}

public static int getNumPostsInBlog(long blogId) {
if (blogId == 0) {
return 0;
Expand Down Expand Up @@ -624,7 +635,7 @@ public static void addOrUpdatePosts(final ReaderTag tag, ReaderPostList posts) {
stmtPosts.bindString(16, post.getFeaturedImage());
stmtPosts.bindString(17, post.getFeaturedVideo());
stmtPosts.bindString(18, post.getPostAvatar());
stmtPosts.bindLong (19, post.timestamp);
stmtPosts.bindDouble(19, post.timestamp);
stmtPosts.bindString(20, post.getPublished());
stmtPosts.bindLong (21, post.numReplies);
stmtPosts.bindLong (22, post.numLikes);
Expand Down Expand Up @@ -839,7 +850,7 @@ private static ReaderPost getPostFromCursor(Cursor c) {
post.setShortUrl(c.getString(c.getColumnIndex("short_url")));
post.setPostAvatar(c.getString(c.getColumnIndex("post_avatar")));

post.timestamp = c.getLong(c.getColumnIndex("timestamp"));
post.timestamp = c.getDouble(c.getColumnIndex("timestamp"));
post.setPublished(c.getString(c.getColumnIndex("published")));

post.numReplies = c.getInt(c.getColumnIndex("num_replies"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,73 +9,71 @@
import org.wordpress.android.util.DateTimeUtils;
import org.wordpress.android.util.SqlUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
* user's reader search history
* search suggestion table - populated by user's reader search history
*/
public class ReaderSearchTable {

public static final String COL_QUERY = "query_string";

protected static void createTables(SQLiteDatabase db) {
db.execSQL("CREATE TABLE tbl_search_history ("
+ " query_string TEXT NOT NULL COLLATE NOCASE PRIMARY KEY,"
+ " date_used TEXT,"
+ " counter INTEGER DEFAULT 1)");
db.execSQL("CREATE TABLE tbl_search_suggestions ("
+ " _id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ " query_string TEXT NOT NULL COLLATE NOCASE,"
+ " date_used TEXT)");
db.execSQL("CREATE UNIQUE INDEX idx_search_suggestions_query ON tbl_search_suggestions(query_string)");
}

protected static void dropTables(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS tbl_search_history");
db.execSQL("DROP TABLE IF EXISTS tbl_search_suggestions");
}

/*
* adds the passed query string, updating the usage counter and date
* adds the passed query string, updating the usage date
*/
public static void addOrUpdateQueryString(@NonNull String query) {
String date = DateTimeUtils.javaDateToIso8601(new Date());
int counter = getCounterForQueryString(query) + 1;

SQLiteStatement stmt = ReaderDatabase.getWritableDb().compileStatement(
"INSERT OR REPLACE INTO tbl_search_history (query_string, date_used, counter) VALUES (?1,?2,?3)");
"INSERT OR REPLACE INTO tbl_search_suggestions (query_string, date_used) VALUES (?1,?2)");
try {
stmt.bindString(1, query);
stmt.bindString(2, date);
stmt.bindLong (3, counter);
stmt.execute();
} finally {
SqlUtils.closeStatement(stmt);
}
}

private static int getCounterForQueryString(@NonNull String query) {
String[] args = {query};
return SqlUtils.intForQuery(ReaderDatabase.getReadableDb(),
"SELECT counter FROM tbl_search_history WHERE query_string=?", args);
public static void deleteQueryString(@NonNull String query) {
String[] args = new String[]{query};
ReaderDatabase.getWritableDb().delete("tbl_search_suggestions", "query_string=?", args);
}

public static List<String> getQueryStrings() {
return getQueryStrings(null);
}
public static List<String> getQueryStrings(String filter) {
List<String> queries = new ArrayList<>();
Cursor cursor;
/**
* Returns a cursor containing query strings previously typed by the user
* @param filter - filters the list using LIKE syntax (pass null for no filter)
* @param max - limit the list to this many items (pass zero for no limit)
*/
public static Cursor getQueryStringCursor(String filter, int max) {
String sql;
String[] args;
if (TextUtils.isEmpty(filter)) {
cursor = ReaderDatabase.getReadableDb().rawQuery(
"SELECT query_string FROM tbl_search_history ORDER BY date_used DESC", null);
sql = "SELECT * FROM tbl_search_suggestions";
args = null;
} else {
String likeFilter = filter + "%";
cursor = ReaderDatabase.getReadableDb().rawQuery(
"SELECT query_string FROM tbl_search_history WHERE query_string LIKE ? ORDER BY date_used DESC", new String[]{likeFilter});
sql = "SELECT * FROM tbl_search_suggestions WHERE query_string LIKE ?";
args = new String[]{filter + "%"};
}

try {
while (cursor.moveToNext()) {
queries.add(cursor.getString(0));
}
return queries;
} finally {
SqlUtils.closeCursor(cursor);
sql += " ORDER BY date_used DESC";

if (max > 0) {
sql += " LIMIT " + max;
}

return ReaderDatabase.getReadableDb().rawQuery(sql, args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class ReaderPost {
private String primaryTag; // most popular tag on this post based on usage in blog
private String secondaryTag; // second most popular tag on this post based on usage in blog

public long timestamp; // used for sorting
public double timestamp; // used for sorting
private String published;

private String url;
Expand Down Expand Up @@ -116,14 +116,19 @@ public static ReaderPost fromJson(JSONObject json) {
post.blogName = JSONUtils.getStringDecoded(json, "site_name");
post.published = JSONUtils.getString(json, "date");

// the date a post was liked is only returned by the read/liked/ endpoint - if this exists,
// set it as the timestamp so posts are sorted by the date they were liked rather than the
// date they were published (the timestamp is used to sort posts when querying)
String likeDate = JSONUtils.getString(json, "date_liked");
if (!TextUtils.isEmpty(likeDate)) {
post.timestamp = DateTimeUtils.iso8601ToTimestamp(likeDate);
// a post's timestamp determines its sort order
if (json.has("score")) {
// search results include a "score" that should be used for sorting
post.timestamp = json.optDouble("score");
} else {
post.timestamp = DateTimeUtils.iso8601ToTimestamp(post.published);
// liked posts should be sorted by the date they were liked, otherwise sort by the
// published date
String likeDate = JSONUtils.getString(json, "date_liked");
if (!TextUtils.isEmpty(likeDate)) {
post.timestamp = DateTimeUtils.iso8601ToTimestamp(likeDate);
} else {
post.timestamp = DateTimeUtils.iso8601ToTimestamp(post.published);
}
}

// if the post is untitled, make up a title from the excerpt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public static boolean isSameTag(ReaderTag tag1, ReaderTag tag2) {
public boolean isPostsILike() {
return tagType == ReaderTagType.DEFAULT && getEndpoint().endsWith("/read/liked");
}

public boolean isFollowedSites() {
return tagType == ReaderTagType.DEFAULT && getEndpoint().endsWith("/read/following");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ public enum ReaderTagType {
FOLLOWED,
DEFAULT,
RECOMMENDED,
CUSTOM_LIST;
CUSTOM_LIST,
SEARCH;

private static final int INT_DEFAULT = 0;
private static final int INT_FOLLOWED = 1;
private static final int INT_RECOMMENDED = 2;
private static final int INT_CUSTOM_LIST = 3;
private static final int INT_SEARCH = 4;

public static ReaderTagType fromInt(int value) {
switch (value) {
Expand All @@ -19,6 +21,8 @@ public static ReaderTagType fromInt(int value) {
return FOLLOWED;
case INT_CUSTOM_LIST:
return CUSTOM_LIST;
case INT_SEARCH:
return SEARCH;
default :
return DEFAULT;
}
Expand All @@ -32,6 +36,8 @@ public int toInt() {
return INT_RECOMMENDED;
case CUSTOM_LIST:
return INT_CUSTOM_LIST;
case SEARCH:
return INT_SEARCH;
default :
return INT_DEFAULT;
}
Expand Down
Loading