mobile/android/base/TabsAccessor.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 package org.mozilla.gecko;
michael@0 6
michael@0 7 import org.mozilla.gecko.db.BrowserContract;
michael@0 8 import org.mozilla.gecko.util.ThreadUtils;
michael@0 9 import org.mozilla.gecko.util.UiAsyncTask;
michael@0 10
michael@0 11 import org.json.JSONArray;
michael@0 12 import org.json.JSONException;
michael@0 13
michael@0 14 import android.content.ContentResolver;
michael@0 15 import android.content.ContentValues;
michael@0 16 import android.content.Context;
michael@0 17 import android.database.Cursor;
michael@0 18 import android.net.Uri;
michael@0 19 import android.util.Log;
michael@0 20
michael@0 21 import java.util.ArrayList;
michael@0 22 import java.util.Collections;
michael@0 23 import java.util.List;
michael@0 24
michael@0 25 public final class TabsAccessor {
michael@0 26 private static final String LOGTAG = "GeckoTabsAccessor";
michael@0 27
michael@0 28 private static final String[] CLIENTS_AVAILABILITY_PROJECTION = new String[] {
michael@0 29 BrowserContract.Clients.GUID
michael@0 30 };
michael@0 31
michael@0 32 private static final String[] TABS_PROJECTION_COLUMNS = new String[] {
michael@0 33 BrowserContract.Tabs.TITLE,
michael@0 34 BrowserContract.Tabs.URL,
michael@0 35 BrowserContract.Clients.GUID,
michael@0 36 BrowserContract.Clients.NAME
michael@0 37 };
michael@0 38
michael@0 39 // Projection column numbers
michael@0 40 public static enum TABS_COLUMN {
michael@0 41 TITLE,
michael@0 42 URL,
michael@0 43 GUID,
michael@0 44 NAME
michael@0 45 };
michael@0 46
michael@0 47 private static final String CLIENTS_SELECTION = BrowserContract.Clients.GUID + " IS NOT NULL";
michael@0 48 private static final String TABS_SELECTION = BrowserContract.Tabs.CLIENT_GUID + " IS NOT NULL";
michael@0 49
michael@0 50 private static final String LOCAL_CLIENT_SELECTION = BrowserContract.Clients.GUID + " IS NULL";
michael@0 51 private static final String LOCAL_TABS_SELECTION = BrowserContract.Tabs.CLIENT_GUID + " IS NULL";
michael@0 52
michael@0 53 public static class RemoteTab {
michael@0 54 public String title;
michael@0 55 public String url;
michael@0 56 public String guid;
michael@0 57 public String name;
michael@0 58 }
michael@0 59
michael@0 60 public interface OnQueryTabsCompleteListener {
michael@0 61 public void onQueryTabsComplete(List<RemoteTab> tabs);
michael@0 62 }
michael@0 63
michael@0 64 // This method returns all tabs from all remote clients,
michael@0 65 // ordered by most recent client first, most recent tab first
michael@0 66 public static void getTabs(final Context context, final OnQueryTabsCompleteListener listener) {
michael@0 67 getTabs(context, 0, listener);
michael@0 68 }
michael@0 69
michael@0 70 // This method returns limited number of tabs from all remote clients,
michael@0 71 // ordered by most recent client first, most recent tab first
michael@0 72 public static void getTabs(final Context context, final int limit, final OnQueryTabsCompleteListener listener) {
michael@0 73 // If there is no listener, no point in doing work.
michael@0 74 if (listener == null)
michael@0 75 return;
michael@0 76
michael@0 77 (new UiAsyncTask<Void, Void, List<RemoteTab>>(ThreadUtils.getBackgroundHandler()) {
michael@0 78 @Override
michael@0 79 protected List<RemoteTab> doInBackground(Void... unused) {
michael@0 80 Uri uri = BrowserContract.Tabs.CONTENT_URI;
michael@0 81
michael@0 82 if (limit > 0) {
michael@0 83 uri = uri.buildUpon()
michael@0 84 .appendQueryParameter(BrowserContract.PARAM_LIMIT, String.valueOf(limit))
michael@0 85 .build();
michael@0 86 }
michael@0 87
michael@0 88 Cursor cursor = context.getContentResolver().query(uri,
michael@0 89 TABS_PROJECTION_COLUMNS,
michael@0 90 TABS_SELECTION,
michael@0 91 null,
michael@0 92 null);
michael@0 93
michael@0 94 if (cursor == null)
michael@0 95 return null;
michael@0 96
michael@0 97 RemoteTab tab;
michael@0 98 final ArrayList<RemoteTab> tabs = new ArrayList<RemoteTab> ();
michael@0 99 try {
michael@0 100 while (cursor.moveToNext()) {
michael@0 101 tab = new RemoteTab();
michael@0 102 tab.title = cursor.getString(TABS_COLUMN.TITLE.ordinal());
michael@0 103 tab.url = cursor.getString(TABS_COLUMN.URL.ordinal());
michael@0 104 tab.guid = cursor.getString(TABS_COLUMN.GUID.ordinal());
michael@0 105 tab.name = cursor.getString(TABS_COLUMN.NAME.ordinal());
michael@0 106
michael@0 107 tabs.add(tab);
michael@0 108 }
michael@0 109 } finally {
michael@0 110 cursor.close();
michael@0 111 }
michael@0 112
michael@0 113 return Collections.unmodifiableList(tabs);
michael@0 114 }
michael@0 115
michael@0 116 @Override
michael@0 117 protected void onPostExecute(List<RemoteTab> tabs) {
michael@0 118 listener.onQueryTabsComplete(tabs);
michael@0 119 }
michael@0 120 }).execute();
michael@0 121 }
michael@0 122
michael@0 123 // Updates the modified time of the local client with the current time.
michael@0 124 private static void updateLocalClient(final ContentResolver cr) {
michael@0 125 ContentValues values = new ContentValues();
michael@0 126 values.put(BrowserContract.Clients.LAST_MODIFIED, System.currentTimeMillis());
michael@0 127 cr.update(BrowserContract.Clients.CONTENT_URI, values, LOCAL_CLIENT_SELECTION, null);
michael@0 128 }
michael@0 129
michael@0 130 // Deletes all local tabs.
michael@0 131 private static void deleteLocalTabs(final ContentResolver cr) {
michael@0 132 cr.delete(BrowserContract.Tabs.CONTENT_URI, LOCAL_TABS_SELECTION, null);
michael@0 133 }
michael@0 134
michael@0 135 /**
michael@0 136 * Tabs are positioned in the DB in the same order that they appear in the tabs param.
michael@0 137 * - URL should never empty or null. Skip this tab if there's no URL.
michael@0 138 * - TITLE should always a string, either a page title or empty.
michael@0 139 * - LAST_USED should always be numeric.
michael@0 140 * - FAVICON should be a URL or null.
michael@0 141 * - HISTORY should be serialized JSON array of URLs.
michael@0 142 * - POSITION should always be numeric.
michael@0 143 * - CLIENT_GUID should always be null to represent the local client.
michael@0 144 */
michael@0 145 private static void insertLocalTabs(final ContentResolver cr, final Iterable<Tab> tabs) {
michael@0 146 // Reuse this for serializing individual history URLs as JSON.
michael@0 147 JSONArray history = new JSONArray();
michael@0 148 ArrayList<ContentValues> valuesToInsert = new ArrayList<ContentValues>();
michael@0 149
michael@0 150 int position = 0;
michael@0 151 for (Tab tab : tabs) {
michael@0 152 // Skip this tab if it has a null URL or is in private browsing mode
michael@0 153 String url = tab.getURL();
michael@0 154 if (url == null || tab.isPrivate())
michael@0 155 continue;
michael@0 156
michael@0 157 ContentValues values = new ContentValues();
michael@0 158 values.put(BrowserContract.Tabs.URL, url);
michael@0 159 values.put(BrowserContract.Tabs.TITLE, tab.getTitle());
michael@0 160 values.put(BrowserContract.Tabs.LAST_USED, tab.getLastUsed());
michael@0 161
michael@0 162 String favicon = tab.getFaviconURL();
michael@0 163 if (favicon != null)
michael@0 164 values.put(BrowserContract.Tabs.FAVICON, favicon);
michael@0 165 else
michael@0 166 values.putNull(BrowserContract.Tabs.FAVICON);
michael@0 167
michael@0 168 // We don't have access to session history in Java, so for now, we'll
michael@0 169 // just use a JSONArray that holds most recent history item.
michael@0 170 try {
michael@0 171 history.put(0, tab.getURL());
michael@0 172 values.put(BrowserContract.Tabs.HISTORY, history.toString());
michael@0 173 } catch (JSONException e) {
michael@0 174 Log.w(LOGTAG, "JSONException adding URL to tab history array.", e);
michael@0 175 }
michael@0 176
michael@0 177 values.put(BrowserContract.Tabs.POSITION, position++);
michael@0 178
michael@0 179 // A null client guid corresponds to the local client.
michael@0 180 values.putNull(BrowserContract.Tabs.CLIENT_GUID);
michael@0 181
michael@0 182 valuesToInsert.add(values);
michael@0 183 }
michael@0 184
michael@0 185 ContentValues[] valuesToInsertArray = valuesToInsert.toArray(new ContentValues[valuesToInsert.size()]);
michael@0 186 cr.bulkInsert(BrowserContract.Tabs.CONTENT_URI, valuesToInsertArray);
michael@0 187 }
michael@0 188
michael@0 189 // Deletes all local tabs and replaces them with a new list of tabs.
michael@0 190 public static synchronized void persistLocalTabs(final ContentResolver cr, final Iterable<Tab> tabs) {
michael@0 191 deleteLocalTabs(cr);
michael@0 192 insertLocalTabs(cr, tabs);
michael@0 193 updateLocalClient(cr);
michael@0 194 }
michael@0 195 }

mercurial