Bug 1080232 - Multiplexing count.(with reviews) r=mcomella
MozReview-Commit-ID: CklXYsVgENI
--- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserContract.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserContract.java
@@ -309,16 +309,18 @@ public class BrowserContract {
private Combined() {}
public static final String VIEW_NAME = "combined";
public static final String VIEW_WITH_FAVICONS = "combined_with_favicons";
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "combined");
+ public static final Uri COUNTS_URI = Uri.withAppendedPath(AUTHORITY_URI, "counts");
+
public static final String BOOKMARK_ID = "bookmark_id";
public static final String HISTORY_ID = "history_id";
public static final String REMOTE_VISITS_COUNT = "remoteVisitCount";
public static final String REMOTE_DATE_LAST_VISITED = "remoteDateLastVisited";
public static final String LOCAL_VISITS_COUNT = "localVisitCount";
public static final String LOCAL_DATE_LAST_VISITED = "localDateLastVisited";
--- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserDB.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserDB.java
@@ -52,16 +52,18 @@ public abstract class BrowserDB {
/**
* Invalidate cached data.
*/
public abstract void invalidate();
public abstract int getCount(ContentResolver cr, String database);
+ public abstract Cursor getAllCounts(ContentResolver cr);
+
/**
* @return a cursor representing the contents of the DB filtered according to the arguments.
* Can return <code>null</code>. <code>CursorLoader</code> will handle this correctly.
*/
public abstract Cursor filter(ContentResolver cr, CharSequence constraint,
int limit, EnumSet<BrowserDB.FilterFlags> flags);
/**
--- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserProvider.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserProvider.java
@@ -133,16 +133,18 @@ public class BrowserProvider extends Sha
static final int VISITS = 1100;
static final int METADATA = 1200;
static final int HIGHLIGHTS = 1300;
static final int ACTIVITY_STREAM_BLOCKLIST = 1400;
+ static final int COUNTS = 1500;
+
static final String DEFAULT_BOOKMARKS_SORT_ORDER = Bookmarks.TYPE
+ " ASC, " + Bookmarks.POSITION + " ASC, " + Bookmarks._ID
+ " ASC";
static final String DEFAULT_HISTORY_SORT_ORDER = History.DATE_LAST_VISITED + " DESC";
static final String DEFAULT_VISITS_SORT_ORDER = Visits.DATE_VISITED + " DESC";
static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
@@ -191,16 +193,18 @@ public class BrowserProvider extends Sha
map.put(Bookmarks.IS_DELETED, Bookmarks.IS_DELETED);
BOOKMARKS_PROJECTION_MAP = Collections.unmodifiableMap(map);
// History
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history", HISTORY);
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history/#", HISTORY_ID);
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history/old", HISTORY_OLD);
+ URI_MATCHER.addURI(BrowserContract.AUTHORITY, "counts", COUNTS);
+
map = new HashMap<String, String>();
map.put(History._ID, History._ID);
map.put(History.TITLE, History.TITLE);
map.put(History.URL, History.URL);
map.put(History.FAVICON, History.FAVICON);
map.put(History.FAVICON_ID, History.FAVICON_ID);
map.put(History.FAVICON_URL, History.FAVICON_URL);
map.put(History.VISITS, History.VISITS);
@@ -1262,18 +1266,41 @@ public class BrowserProvider extends Sha
// we handle that separately, i.e. before retrieving a readable connection.
if (match == TOPSITES) {
if (uri.getBooleanQueryParameter(BrowserContract.PARAM_TOPSITES_DISABLE_PINNED, false)) {
return getPlainTopSites(uri);
} else {
return getTopSites(uri);
}
}
-
SQLiteDatabase db = getReadableDatabase(uri);
+ if (match == COUNTS) {
+ String history_table;
+ String bookmark_table;
+ final boolean isFavIconsInProjection = hasFaviconsInProjection(projection);
+ if (isFavIconsInProjection) {
+ history_table = VIEW_HISTORY_WITH_FAVICONS;
+ } else {
+ history_table = TABLE_HISTORY;
+ }
+ if (isFavIconsInProjection) {
+ bookmark_table = VIEW_BOOKMARKS_WITH_FAVICONS;
+ } else if (selection != null && selection.contains(Bookmarks.ANNOTATION_KEY)) {
+ bookmark_table = VIEW_BOOKMARKS_WITH_ANNOTATIONS;
+ } else {
+ bookmark_table = TABLE_BOOKMARKS;
+ }
+ final String query = "SELECT " +
+ "(SELECT COUNT(" + History._ID + ") FROM " + history_table +
+ " WHERE " + History.VISITS + " > 0) AS history, " +
+ "(SELECT COUNT(" + Bookmarks._ID + ") FROM " + bookmark_table +
+ " WHERE " + Bookmarks.TYPE + " = " + Bookmarks.TYPE_BOOKMARK +
+ ") AS bookmarks;";
+ return db.rawQuery(query, null);
+ }
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String limit = uri.getQueryParameter(BrowserContract.PARAM_LIMIT);
String groupBy = null;
switch (match) {
case BOOKMARKS_FOLDER_ID:
case BOOKMARKS_ID:
--- a/mobile/android/base/java/org/mozilla/gecko/db/LocalBrowserDB.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/LocalBrowserDB.java
@@ -115,16 +115,17 @@ public class LocalBrowserDB extends Brow
private final Uri mCombinedUriWithProfile;
private final Uri mUpdateHistoryUriWithProfile;
private final Uri mFaviconsUriWithProfile;
private final Uri mThumbnailsUriWithProfile;
private final Uri mTopSitesUriWithProfile;
private final Uri mHighlightsUriWithProfile;
private final Uri mSearchHistoryUri;
private final Uri mActivityStreamBlockedUriWithProfile;
+ private final Uri mAllCountsUriWithProfile;
private LocalSearches searches;
private LocalTabsAccessor tabsAccessor;
private LocalURLMetadata urlMetadata;
private LocalUrlAnnotations urlAnnotations;
private static final String[] DEFAULT_BOOKMARK_COLUMNS =
new String[] { Bookmarks._ID,
@@ -143,16 +144,17 @@ public class LocalBrowserDB extends Brow
mHistoryUriWithProfile = DBUtils.appendProfile(profile, History.CONTENT_URI);
mHistoryExpireUriWithProfile = DBUtils.appendProfile(profile, History.CONTENT_OLD_URI);
mCombinedUriWithProfile = DBUtils.appendProfile(profile, Combined.CONTENT_URI);
mFaviconsUriWithProfile = DBUtils.appendProfile(profile, Favicons.CONTENT_URI);
mTopSitesUriWithProfile = DBUtils.appendProfile(profile, TopSites.CONTENT_URI);
mHighlightsUriWithProfile = DBUtils.appendProfile(profile, Highlights.CONTENT_URI);
mThumbnailsUriWithProfile = DBUtils.appendProfile(profile, Thumbnails.CONTENT_URI);
mActivityStreamBlockedUriWithProfile = DBUtils.appendProfile(profile, ActivityStreamBlocklist.CONTENT_URI);
+ mAllCountsUriWithProfile = DBUtils.appendProfile(profile, Combined.COUNTS_URI);
mSearchHistoryUri = BrowserContract.SearchHistory.CONTENT_URI;
mUpdateHistoryUriWithProfile =
mHistoryUriWithProfile.buildUpon()
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true")
.appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true")
.build();
@@ -630,16 +632,20 @@ public class LocalBrowserDB extends Brow
cursor.close();
}
}
debug("Got count " + count + " for " + database);
return count;
}
+ public Cursor getAllCounts(ContentResolver cr) {
+ return cr.query(mAllCountsUriWithProfile, null, null, null, null);
+ }
+
@Override
@RobocopTarget
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit,
EnumSet<FilterFlags> flags) {
String selection = "";
String[] selectionArgs = null;
if (flags.contains(FilterFlags.EXCLUDE_PINNED_SITES)) {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/db/StubBrowserDB.java
@@ -0,0 +1,391 @@
+/* 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.db;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.json.JSONObject;
+import org.mozilla.gecko.annotation.RobocopTarget;
+import org.mozilla.gecko.distribution.Distribution;
+import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
+import org.mozilla.gecko.Tab;
+import org.mozilla.gecko.feeds.subscriptions.FeedSubscription;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.graphics.drawable.BitmapDrawable;
+
+class StubSearches implements Searches {
+ public StubSearches() {
+ }
+
+ public void insert(ContentResolver cr, String query) {
+ }
+}
+
+class StubURLMetadata implements URLMetadata {
+ public StubURLMetadata() {
+ }
+
+ public Map<String, Object> fromJSON(JSONObject obj) {
+ return new HashMap<String, Object>();
+ }
+
+ public Map<String, Map<String, Object>> getForURLs(final ContentResolver cr,
+ final Collection<String> urls,
+ final List<String> columns) {
+ return new HashMap<String, Map<String, Object>>();
+ }
+
+ public void save(final ContentResolver cr, final Map<String, Object> data) {
+ }
+}
+
+class StubTabsAccessor implements TabsAccessor {
+ public StubTabsAccessor() {
+ }
+
+ @Override
+ public List<RemoteClient> getClientsWithoutTabsByRecencyFromCursor(Cursor cursor) {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public List<RemoteClient> getClientsFromCursor(final Cursor cursor) {
+ return new ArrayList<RemoteClient>();
+ }
+
+ @Override
+ public Cursor getRemoteClientsByRecencyCursor(Context context) {
+ return null;
+ }
+
+ public Cursor getRemoteTabsCursor(Context context) {
+ return null;
+ }
+
+ public Cursor getRemoteTabsCursor(Context context, int limit) {
+ return null;
+ }
+
+ public void getTabs(final Context context, final OnQueryTabsCompleteListener listener) {
+ listener.onQueryTabsComplete(new ArrayList<RemoteClient>());
+ }
+ public void getTabs(final Context context, final int limit, final OnQueryTabsCompleteListener listener) {
+ listener.onQueryTabsComplete(new ArrayList<RemoteClient>());
+ }
+
+ public synchronized void persistLocalTabs(final ContentResolver cr, final Iterable<Tab> tabs) { }
+}
+
+class StubUrlAnnotations implements UrlAnnotations {
+ @Override
+ public void insertAnnotation(ContentResolver cr, String url, String key, String value) {}
+
+ @Override
+ public Cursor getScreenshots(ContentResolver cr) { return null; }
+
+ @Override
+ public void insertScreenshot(ContentResolver cr, String pageUrl, final String screenshotLocation) {}
+
+ @Override
+ public Cursor getFeedSubscriptions(ContentResolver cr) { return null; }
+
+ @Override
+ public Cursor getWebsitesWithFeedUrl(ContentResolver cr) { return null; }
+
+ @Override
+ public void deleteFeedUrl(ContentResolver cr, String websiteUrl) {}
+
+ @Override
+ public boolean hasWebsiteForFeedUrl(ContentResolver cr, String feedUrl) { return false; }
+
+ @Override
+ public void deleteFeedSubscription(ContentResolver cr, FeedSubscription subscription) {}
+
+ @Override
+ public void updateFeedSubscription(ContentResolver cr, FeedSubscription subscription) {}
+
+ @Override
+ public boolean hasFeedSubscription(ContentResolver cr, String feedUrl) { return false; }
+
+ @Override
+ public void insertFeedSubscription(ContentResolver cr, FeedSubscription subscription) {}
+
+ @Override
+ public boolean hasFeedUrlForWebsite(ContentResolver cr, String websiteUrl) { return false; }
+
+ @Override
+ public void insertFeedUrl(ContentResolver cr, String originUrl, String feedUrl) {}
+
+ @Override
+ public void insertReaderViewUrl(ContentResolver cr, String pageURL) {}
+
+ @Override
+ public void deleteReaderViewUrl(ContentResolver cr, String pageURL) {}
+
+ @Override
+ public boolean hasAcceptedOrDeclinedHomeScreenShortcut(ContentResolver cr, String url) { return false; }
+
+ @Override
+ public void insertHomeScreenShortcut(ContentResolver cr, String url, boolean hasCreatedShortCut) {}
+
+ @Override
+ public int getAnnotationCount(ContentResolver cr, BrowserContract.UrlAnnotations.Key key) {
+ return 0;
+ }
+}
+
+/*
+ * This base implementation just stubs all methods. For the
+ * real implementations, see LocalBrowserDB.java.
+ */
+public class StubBrowserDB implements BrowserDB {
+ private final StubSearches searches = new StubSearches();
+ private final StubTabsAccessor tabsAccessor = new StubTabsAccessor();
+ private final StubURLMetadata urlMetadata = new StubURLMetadata();
+ private final StubUrlAnnotations urlAnnotations = new StubUrlAnnotations();
+ private SuggestedSites suggestedSites = null;
+
+ @Override
+ public Searches getSearches() {
+ return searches;
+ }
+
+ @Override
+ public TabsAccessor getTabsAccessor() {
+ return tabsAccessor;
+ }
+
+ @Override
+ public URLMetadata getURLMetadata() {
+ return urlMetadata;
+ }
+
+ @Override
+ public UrlAnnotations getUrlAnnotations() {
+ return urlAnnotations;
+ }
+
+ protected static final Integer FAVICON_ID_NOT_FOUND = Integer.MIN_VALUE;
+
+ public StubBrowserDB(String profile) {
+ }
+
+ public void invalidate() { }
+
+ public int addDefaultBookmarks(Context context, ContentResolver cr, final int offset) {
+ return 0;
+ }
+
+ public int addDistributionBookmarks(ContentResolver cr, Distribution distribution, int offset) {
+ return 0;
+ }
+
+ public int getCount(ContentResolver cr, String database) {
+ return 0;
+ }
+
+ @Override
+ public Cursor getAllCounts(ContentResolver cr) {
+ return null;
+ }
+
+ @RobocopTarget
+ public Cursor filter(ContentResolver cr, CharSequence constraint, int limit,
+ EnumSet<BrowserDB.FilterFlags> flags) {
+ return null;
+ }
+
+ public void updateVisitedHistory(ContentResolver cr, String uri) {
+ }
+
+ public void updateHistoryTitle(ContentResolver cr, String uri, String title) {
+ }
+
+ @RobocopTarget
+ public Cursor getAllVisitedHistory(ContentResolver cr) {
+ return null;
+ }
+
+ public Cursor getRecentHistory(ContentResolver cr, int limit) {
+ return null;
+ }
+
+ @Override
+ public Cursor getHistoryForURL(ContentResolver cr, String uri) {
+ return null;
+ }
+
+ @Override
+ public Cursor getRecentHistoryBetweenTime(ContentResolver cr, int limit, long time, long end) {
+ return null;
+ }
+
+ @Override
+ public long getPrePathLastVisitedTimeMilliseconds(ContentResolver cr, String prePath) { return 0; }
+
+ public void expireHistory(ContentResolver cr, BrowserContract.ExpirePriority priority) {
+ }
+
+ @RobocopTarget
+ public void removeHistoryEntry(ContentResolver cr, String url) {
+ }
+
+ public void clearHistory(ContentResolver cr, boolean clearSearchHistory) {
+ }
+
+ @RobocopTarget
+ public Cursor getBookmarksInFolder(ContentResolver cr, long folderId) {
+ return null;
+ }
+
+ public int getBookmarkCountForFolder(ContentResolver cr, long folderId) { return 0; }
+
+ @RobocopTarget
+ public boolean isBookmark(ContentResolver cr, String uri) {
+ return false;
+ }
+
+ public String getUrlForKeyword(ContentResolver cr, String keyword) {
+ return null;
+ }
+
+ protected void bumpParents(ContentResolver cr, String param, String value) {
+ }
+
+ @RobocopTarget
+ public boolean addBookmark(ContentResolver cr, String title, String uri) {
+ return false;
+ }
+
+ @RobocopTarget
+ public void removeBookmarksWithURL(ContentResolver cr, String uri) {
+ }
+
+ public void registerBookmarkObserver(ContentResolver cr, ContentObserver observer) {
+ }
+
+ @RobocopTarget
+ public void updateBookmark(ContentResolver cr, int id, String uri, String title, String keyword) {
+ }
+
+ public LoadFaviconResult getFaviconForUrl(ContentResolver cr, String faviconURL) {
+ return null;
+ }
+
+ public String getFaviconURLFromPageURL(ContentResolver cr, String uri) {
+ return null;
+ }
+
+ public void updateFaviconForUrl(ContentResolver cr, String pageUri,
+ byte[] encodedFavicon, String faviconUri) {
+ }
+
+ public boolean hideSuggestedSite(String url) {
+ return false;
+ }
+
+ public void updateThumbnailForUrl(ContentResolver cr, String uri,
+ BitmapDrawable thumbnail) {
+ }
+
+ @RobocopTarget
+ public byte[] getThumbnailForUrl(ContentResolver cr, String uri) {
+ return null;
+ }
+
+ public Cursor getThumbnailsForUrls(ContentResolver cr, List<String> urls) {
+ return null;
+ }
+
+ @RobocopTarget
+ public void removeThumbnails(ContentResolver cr) {
+ }
+
+ public void updateHistoryInBatch(ContentResolver cr,
+ Collection<ContentProviderOperation> operations,
+ String url, String title,
+ long date, int visits) {
+ }
+
+ public void updateBookmarkInBatch(ContentResolver cr,
+ Collection<ContentProviderOperation> operations,
+ String url, String title, String guid,
+ long parent, long added,
+ long modified, long position,
+ String keyword, int type) {
+ }
+
+ public void updateFaviconInBatch(ContentResolver cr,
+ Collection<ContentProviderOperation> operations,
+ String url, String faviconUrl,
+ String faviconGuid, byte[] data) {
+ }
+
+ public void pinSite(ContentResolver cr, String url, String title, int position) {
+ }
+
+ public void unpinSite(ContentResolver cr, int position) {
+ }
+
+ @RobocopTarget
+ public Cursor getBookmarkForUrl(ContentResolver cr, String url) {
+ return null;
+ }
+
+ @Override
+ public Cursor getBookmarksForPartialUrl(ContentResolver cr, String partialUrl) {
+ return null;
+ }
+
+ @Override
+ public boolean hasBookmarkWithGuid(ContentResolver cr, String guid) {
+ return false;
+ }
+
+ public void setSuggestedSites(SuggestedSites suggestedSites) {
+ this.suggestedSites = suggestedSites;
+ }
+
+ public SuggestedSites getSuggestedSites() {
+ return suggestedSites;
+ }
+
+ public boolean hasSuggestedImageUrl(String url) {
+ return false;
+ }
+
+ public String getSuggestedImageUrlForUrl(String url) {
+ return null;
+ }
+
+ public int getSuggestedBackgroundColorForUrl(String url) {
+ return 0;
+ }
+
+ public Cursor getTopSites(ContentResolver cr, int suggestedRangeLimit, int limit) {
+ return null;
+ }
+
+ public static Factory getFactory() {
+ return new Factory() {
+ @Override
+ public BrowserDB get(String profileName, File profileDir) {
+ return new StubBrowserDB(profileName);
+ }
+ };
+ }
+}