mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 22:25:30 +00:00
Bug 836450 - Add default bookmark support for distributions. r=mfinkle,wesj
This commit is contained in:
parent
e2aa595942
commit
1a271a3897
@ -12,19 +12,26 @@ package org.mozilla.gecko;
|
||||
import org.mozilla.gecko.util.GeckoBackgroundThread;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public final class Distribution {
|
||||
private static final String LOGTAG = "GeckoDistribution";
|
||||
|
||||
@ -35,13 +42,13 @@ public final class Distribution {
|
||||
/**
|
||||
* Initializes distribution if it hasn't already been initalized.
|
||||
*/
|
||||
public static void init(final Activity activity) {
|
||||
public static void init(final Context context) {
|
||||
// Read/write preferences and files on the background thread.
|
||||
GeckoBackgroundThread.getHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
// Bail if we've already initialized the distribution.
|
||||
SharedPreferences settings = activity.getPreferences(Activity.MODE_PRIVATE);
|
||||
String keyName = activity.getPackageName() + ".distribution_state";
|
||||
SharedPreferences settings = context.getSharedPreferences(GeckoApp.PREFS_NAME, Activity.MODE_PRIVATE);
|
||||
String keyName = context.getPackageName() + ".distribution_state";
|
||||
int state = settings.getInt(keyName, STATE_UNKNOWN);
|
||||
if (state == STATE_NONE)
|
||||
return;
|
||||
@ -54,7 +61,7 @@ public final class Distribution {
|
||||
|
||||
boolean distributionSet = false;
|
||||
try {
|
||||
distributionSet = copyFiles(activity);
|
||||
distributionSet = copyFiles(context);
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "Error copying distribution files", e);
|
||||
}
|
||||
@ -73,8 +80,8 @@ public final class Distribution {
|
||||
* Copies the /distribution folder out of the APK and into the app's data directory.
|
||||
* Returns true if distribution files were found and copied.
|
||||
*/
|
||||
private static boolean copyFiles(Activity activity) throws IOException {
|
||||
File applicationPackage = new File(activity.getPackageResourcePath());
|
||||
private static boolean copyFiles(Context context) throws IOException {
|
||||
File applicationPackage = new File(context.getPackageResourcePath());
|
||||
ZipFile zip = new ZipFile(applicationPackage);
|
||||
|
||||
boolean distributionSet = false;
|
||||
@ -88,7 +95,7 @@ public final class Distribution {
|
||||
|
||||
distributionSet = true;
|
||||
|
||||
File dataDir = new File(activity.getApplicationInfo().dataDir);
|
||||
File dataDir = new File(context.getApplicationInfo().dataDir);
|
||||
File outFile = new File(dataDir, name);
|
||||
|
||||
File dir = outFile.getParentFile();
|
||||
@ -111,4 +118,62 @@ public final class Distribution {
|
||||
|
||||
return distributionSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parsed contents of bookmarks.json.
|
||||
* This method should only be called from a background thread.
|
||||
*/
|
||||
public static JSONArray getBookmarks(Context context) {
|
||||
SharedPreferences settings = context.getSharedPreferences(GeckoApp.PREFS_NAME, Activity.MODE_PRIVATE);
|
||||
String keyName = context.getPackageName() + ".distribution_state";
|
||||
int state = settings.getInt(keyName, STATE_UNKNOWN);
|
||||
if (state == STATE_NONE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ZipFile zip = null;
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
if (state == STATE_UNKNOWN) {
|
||||
// If the distribution hasn't been set yet, get bookmarks.json out of the APK
|
||||
File applicationPackage = new File(context.getPackageResourcePath());
|
||||
zip = new ZipFile(applicationPackage);
|
||||
ZipEntry zipEntry = zip.getEntry("distribution/bookmarks.json");
|
||||
if (zipEntry == null) {
|
||||
return null;
|
||||
}
|
||||
inputStream = zip.getInputStream(zipEntry);
|
||||
} else {
|
||||
// Otherwise, get bookmarks.json out of the data directory
|
||||
File dataDir = new File(context.getApplicationInfo().dataDir);
|
||||
File file = new File(dataDir, "distribution/bookmarks.json");
|
||||
inputStream = new FileInputStream(file);
|
||||
}
|
||||
|
||||
// Convert input stream to JSONArray
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String s;
|
||||
while ((s = reader.readLine()) != null) {
|
||||
stringBuilder.append(s);
|
||||
}
|
||||
return new JSONArray(stringBuilder.toString());
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "Error getting bookmarks", e);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Error parsing bookmarks.json", e);
|
||||
} finally {
|
||||
try {
|
||||
if (zip != null) {
|
||||
zip.close();
|
||||
}
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "Error closing streams", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -8,20 +8,19 @@ package @ANDROID_PACKAGE_NAME@.db;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.Class;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.Distribution;
|
||||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
||||
@ -38,6 +37,7 @@ import org.mozilla.gecko.db.BrowserContract.URLColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.DBUtils;
|
||||
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
import org.mozilla.gecko.ProfileMigrator;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.util.GeckoBackgroundThread;
|
||||
@ -49,8 +49,8 @@ import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.ContentProviderResult;
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.OperationApplicationException;
|
||||
import android.content.Context;
|
||||
import android.content.OperationApplicationException;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
@ -67,6 +67,10 @@ import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class BrowserProvider extends ContentProvider {
|
||||
private static final String LOGTAG = "GeckoBrowserProvider";
|
||||
private Context mContext;
|
||||
@ -973,28 +977,77 @@ public class BrowserProvider extends ContentProvider {
|
||||
|
||||
createOrUpdateAllSpecialFolders(db);
|
||||
|
||||
createDefaultBookmarks(db, "^bookmarkdefaults_title_");
|
||||
// Create distribution bookmarks before our own default bookmarks
|
||||
int pos = createDistributionBookmarks(db);
|
||||
createDefaultBookmarks(db, pos);
|
||||
}
|
||||
|
||||
private void createDefaultBookmarks(SQLiteDatabase db, String pattern) {
|
||||
Class<?> stringsClass = R.string.class;
|
||||
private String getLocalizedProperty(JSONObject bookmark, String property, Locale locale) throws JSONException {
|
||||
// Try the full locale
|
||||
String fullLocale = property + "." + locale.toString();
|
||||
if (bookmark.has(fullLocale)) {
|
||||
return bookmark.getString(fullLocale);
|
||||
}
|
||||
// Try without a variant
|
||||
if (!TextUtils.isEmpty(locale.getVariant())) {
|
||||
String noVariant = fullLocale.substring(0, fullLocale.lastIndexOf("_"));
|
||||
if (bookmark.has(noVariant)) {
|
||||
return bookmark.getString(noVariant);
|
||||
}
|
||||
}
|
||||
// Try just the language
|
||||
String lang = property + "." + locale.getLanguage();
|
||||
if (bookmark.has(lang)) {
|
||||
return bookmark.getString(lang);
|
||||
}
|
||||
// Default to the non-localized property name
|
||||
return bookmark.getString(property);
|
||||
}
|
||||
|
||||
Field[] fields = stringsClass.getFields();
|
||||
Pattern p = Pattern.compile(pattern);
|
||||
|
||||
ContentValues bookmarksValues = new ContentValues();
|
||||
bookmarksValues.put(Bookmarks.PARENT, guidToID(db, Bookmarks.MOBILE_FOLDER_GUID));
|
||||
long now = System.currentTimeMillis();
|
||||
bookmarksValues.put(Bookmarks.DATE_CREATED, now);
|
||||
bookmarksValues.put(Bookmarks.DATE_MODIFIED, now);
|
||||
// Returns the number of bookmarks inserted in the db
|
||||
private int createDistributionBookmarks(SQLiteDatabase db) {
|
||||
JSONArray bookmarks = Distribution.getBookmarks(mContext);
|
||||
if (bookmarks == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Locale locale = Locale.getDefault();
|
||||
int pos = 0;
|
||||
for (int i = 0; i < bookmarks.length(); i++) {
|
||||
try {
|
||||
JSONObject bookmark = bookmarks.getJSONObject(i);
|
||||
|
||||
String title = getLocalizedProperty(bookmark, "title", locale);
|
||||
String url = getLocalizedProperty(bookmark, "url", locale);
|
||||
|
||||
// Look for an optional icon data URI
|
||||
Bitmap icon = null;
|
||||
if (bookmark.has("icon")) {
|
||||
String iconData = bookmark.getString("icon");
|
||||
icon = BitmapUtils.getBitmapFromDataURI(iconData);
|
||||
}
|
||||
|
||||
createBookmark(db, title, url, pos, icon);
|
||||
pos++;
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Error creating distribution bookmark", e);
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Inserts default bookmarks, starting at a specified position
|
||||
private void createDefaultBookmarks(SQLiteDatabase db, int pos) {
|
||||
Class<?> stringsClass = R.string.class;
|
||||
Field[] fields = stringsClass.getFields();
|
||||
Pattern p = Pattern.compile("^bookmarkdefaults_title_");
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
String name = fields[i].getName();
|
||||
Matcher m = p.matcher(name);
|
||||
if (!m.find())
|
||||
if (!m.find()) {
|
||||
continue;
|
||||
|
||||
}
|
||||
try {
|
||||
int titleid = fields[i].getInt(null);
|
||||
String title = mContext.getString(titleid);
|
||||
@ -1003,13 +1056,11 @@ public class BrowserProvider extends ContentProvider {
|
||||
int urlId = urlField.getInt(null);
|
||||
String url = mContext.getString(urlId);
|
||||
|
||||
bookmarksValues.put(Bookmarks.TITLE, title);
|
||||
bookmarksValues.put(Bookmarks.URL, url);
|
||||
bookmarksValues.put(Bookmarks.GUID, Utils.generateGuid());
|
||||
bookmarksValues.put(Bookmarks.POSITION, pos);
|
||||
db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.TITLE, bookmarksValues);
|
||||
|
||||
setDefaultFavicon(db, name, url);
|
||||
Bitmap icon = getDefaultFaviconFromPath(name);
|
||||
if (icon == null) {
|
||||
icon = getDefaultFaviconFromDrawable(name);
|
||||
}
|
||||
createBookmark(db, title, url, pos, icon);
|
||||
pos++;
|
||||
} catch (java.lang.IllegalAccessException ex) {
|
||||
Log.e(LOGTAG, "Can't create bookmark " + name, ex);
|
||||
@ -1019,27 +1070,42 @@ public class BrowserProvider extends ContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultFavicon(SQLiteDatabase db, String name, String url) {
|
||||
ByteArrayOutputStream stream = getDefaultFaviconFromPath(db, name, url);
|
||||
if (stream == null) {
|
||||
stream = getDefaultFaviconFromDrawable(db, name, url);
|
||||
}
|
||||
if (stream != null) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Favicons.DATA, stream.toByteArray());
|
||||
values.put(Favicons.PAGE_URL, url);
|
||||
insertFavicon(db, values);
|
||||
private void createBookmark(SQLiteDatabase db, String title, String url, int pos, Bitmap icon) {
|
||||
ContentValues bookmarkValues = new ContentValues();
|
||||
bookmarkValues.put(Bookmarks.PARENT, guidToID(db, Bookmarks.MOBILE_FOLDER_GUID));
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
bookmarkValues.put(Bookmarks.DATE_CREATED, now);
|
||||
bookmarkValues.put(Bookmarks.DATE_MODIFIED, now);
|
||||
|
||||
bookmarkValues.put(Bookmarks.TITLE, title);
|
||||
bookmarkValues.put(Bookmarks.URL, url);
|
||||
bookmarkValues.put(Bookmarks.GUID, Utils.generateGuid());
|
||||
bookmarkValues.put(Bookmarks.POSITION, pos);
|
||||
db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.TITLE, bookmarkValues);
|
||||
|
||||
// Return early if there's no icon to set
|
||||
if (icon == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
icon.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||
|
||||
ContentValues iconValues = new ContentValues();
|
||||
iconValues.put(Favicons.DATA, stream.toByteArray());
|
||||
iconValues.put(Favicons.PAGE_URL, url);
|
||||
insertFavicon(db, iconValues);
|
||||
}
|
||||
|
||||
private ByteArrayOutputStream getDefaultFaviconFromPath(SQLiteDatabase db, String name, String url) {
|
||||
ByteArrayOutputStream stream = null;
|
||||
private Bitmap getDefaultFaviconFromPath(String name) {
|
||||
Class<?> stringClass = R.string.class;
|
||||
try {
|
||||
// Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_*
|
||||
Field faviconField = stringClass.getField(name.replace("_title_", "_favicon_"));
|
||||
if (faviconField == null)
|
||||
return null;
|
||||
if (faviconField == null) {
|
||||
return null;
|
||||
}
|
||||
int faviconId = faviconField.getInt(null);
|
||||
String path = mContext.getString(faviconId);
|
||||
|
||||
@ -1048,44 +1114,33 @@ public class BrowserProvider extends ContentProvider {
|
||||
BitmapDrawable bitmapDrawable = GeckoJarReader.getBitmapDrawable(mContext.getResources(),
|
||||
"jar:jar:" + apkFile.toURI() + "!/omni.ja!/" + path);
|
||||
if (bitmapDrawable == null) {
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
Bitmap bitmap = bitmapDrawable.getBitmap();
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
stream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||
return bitmapDrawable.getBitmap();
|
||||
} catch (java.lang.IllegalAccessException ex) {
|
||||
Log.e(LOGTAG, "[Path] Can't create favicon " + name, ex);
|
||||
} catch (java.lang.NoSuchFieldException ex) {
|
||||
// if there is no such field, create the bookmark without a favicon
|
||||
Log.d(LOGTAG, "[Path] Can't create favicon " + name);
|
||||
Log.e(LOGTAG, "[Path] Can't create favicon " + name, ex);
|
||||
}
|
||||
return stream;
|
||||
return null;
|
||||
}
|
||||
|
||||
private ByteArrayOutputStream getDefaultFaviconFromDrawable(SQLiteDatabase db, String name, String url) {
|
||||
private Bitmap getDefaultFaviconFromDrawable(String name) {
|
||||
Class<?> drawablesClass = R.drawable.class;
|
||||
ByteArrayOutputStream stream = null;
|
||||
try {
|
||||
// Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_*
|
||||
Field faviconField = drawablesClass.getField(name.replace("_title_", "_favicon_"));
|
||||
if (faviconField == null)
|
||||
return null;
|
||||
|
||||
if (faviconField == null) {
|
||||
return null;
|
||||
}
|
||||
int faviconId = faviconField.getInt(null);
|
||||
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), faviconId);
|
||||
stream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||
return BitmapFactory.decodeResource(mContext.getResources(), faviconId);
|
||||
} catch (java.lang.IllegalAccessException ex) {
|
||||
Log.e(LOGTAG, "[Drawable] Can't create favicon " + name, ex);
|
||||
} catch (java.lang.NoSuchFieldException ex) {
|
||||
// if there is no such field, create the bookmark without a favicon
|
||||
Log.d(LOGTAG, "[Drawable] Can't create favicon " + name);
|
||||
Log.e(LOGTAG, "[Drawable] Can't create favicon " + name, ex);
|
||||
}
|
||||
|
||||
return stream;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void createOrUpdateAllSpecialFolders(SQLiteDatabase db) {
|
||||
|
Loading…
Reference in New Issue
Block a user