Merge "hide launcher restore behind a flag." into jb-ub-now-kermit
diff --git a/WallpaperPicker/res/values/config.xml b/WallpaperPicker/res/values/config.xml
index 1b24190..71580b5 100644
--- a/WallpaperPicker/res/values/config.xml
+++ b/WallpaperPicker/res/values/config.xml
@@ -15,4 +15,7 @@
 -->
 <resources>
     <bool name="allow_rotation">false</bool>
+    <!-- Specifies whether to expand the cropped area on both sides (rather
+         than just to one side) -->
+    <bool name="center_crop">false</bool>
 </resources>
diff --git a/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java b/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java
index 58add70..44bfdf1 100644
--- a/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java
+++ b/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java
@@ -85,6 +85,9 @@
     }
 
     public SavedWallpaperImages(Activity context) {
+        // We used to store the saved images in the cache directory, but that meant they'd get
+        // deleted sometimes-- move them to the data directory
+        ImageDb.moveFromCacheDirectoryIfNecessary(context);
         mDb = new ImageDb(context);
         mContext = context;
         mLayoutInflater = context.getLayoutInflater();
@@ -215,11 +218,20 @@
         Context mContext;
 
         public ImageDb(Context context) {
-            super(context, new File(context.getCacheDir(), DB_NAME).getPath(), null, DB_VERSION);
+            super(context, context.getDatabasePath(DB_NAME).getPath(), null, DB_VERSION);
             // Store the context for later use
             mContext = context;
         }
 
+        public static void moveFromCacheDirectoryIfNecessary(Context context) {
+            // We used to store the saved images in the cache directory, but that meant they'd get
+            // deleted sometimes-- move them to the data directory
+            File oldSavedImagesFile = new File(context.getCacheDir(), ImageDb.DB_NAME);
+            File savedImagesFile = context.getDatabasePath(ImageDb.DB_NAME);
+            if (oldSavedImagesFile.exists()) {
+                oldSavedImagesFile.renameTo(savedImagesFile);
+            }
+        }
         @Override
         public void onCreate(SQLiteDatabase database) {
             database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
index b3ef073..ee7b819 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
@@ -330,10 +330,10 @@
 
     protected void cropImageAndSetWallpaper(Uri uri,
             OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
+        boolean centerCrop = getResources().getBoolean(R.bool.center_crop);
         // Get the crop
         boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
 
-
         Display d = getWindowManager().getDefaultDisplay();
 
         Point displaySize = new Point();
@@ -358,15 +358,25 @@
         // ADJUST CROP WIDTH
         // Extend the crop all the way to the right, for parallax
         // (or all the way to the left, in RTL)
-        float extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left;
+        float extraSpace;
+        if (centerCrop) {
+            extraSpace = 2f * Math.min(rotatedInSize[0] - cropRect.right, cropRect.left);
+        } else {
+            extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left;
+        }
         // Cap the amount of extra width
         float maxExtraSpace = defaultWallpaperSize.x / cropScale - cropRect.width();
         extraSpace = Math.min(extraSpace, maxExtraSpace);
 
-        if (ltr) {
-            cropRect.right += extraSpace;
+        if (centerCrop) {
+            cropRect.left -= extraSpace / 2f;
+            cropRect.right += extraSpace / 2f;
         } else {
-            cropRect.left -= extraSpace;
+            if (ltr) {
+                cropRect.right += extraSpace;
+            } else {
+                cropRect.left -= extraSpace;
+            }
         }
 
         // ADJUST CROP HEIGHT
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b25b4bb..66bd36f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -218,7 +218,7 @@
     <string name="first_run_cling_create_screens_hint">Create more screens for apps and folders</string>
     <!-- The title text for the migration cling [CHAR_LIMIT=30] -->
     <string name="migration_cling_title">Copy your app icons</string>
-    <!-- The description of what migration does [CHAR_LIMIT=60] -->
+    <!-- The description of what migration does [CHAR_LIMIT=70] -->
     <string name="migration_cling_description">Import icons and folders from your old Home screens?</string>
     <!-- The description of the button to migrate apps from another launcher [CHAR_LIMIT=30] -->
     <string name="migration_cling_copy_apps">COPY ICONS</string>
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 5e41fca..156befb 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -84,7 +84,7 @@
         mIsScreenLarge = isScreenLarge(sContext.getResources());
         mScreenDensity = sContext.getResources().getDisplayMetrics().density;
 
-        mWidgetPreviewCacheDb = new WidgetPreviewLoader.CacheDb(sContext);
+        recreateWidgetPreviewDb();
         mIconCache = new IconCache(sContext);
 
         mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class));
@@ -115,6 +115,13 @@
         resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,
                 mFavoritesObserver);
     }
+    
+    public void recreateWidgetPreviewDb() {
+        if (mWidgetPreviewCacheDb != null) {
+            mWidgetPreviewCacheDb.close();
+        }
+        mWidgetPreviewCacheDb = new WidgetPreviewLoader.CacheDb(sContext);
+    }
 
     /**
      * Call from Application.onTerminate(), which is not guaranteed to ever be called.
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 7e1ad6d..3db0b51 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -10,6 +10,7 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDiskIOException;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
@@ -164,6 +165,12 @@
             editor.commit();
         }
     }
+    
+    public void recreateDb() {
+        LauncherAppState app = LauncherAppState.getInstance();
+        app.recreateWidgetPreviewDb();
+        mDb = app.getWidgetPreviewCacheDb();
+    }
 
     public void setPreviewSize(int previewWidth, int previewHeight,
             PagedViewCellLayout widgetSpacingLayout) {
@@ -347,13 +354,20 @@
         preview.compress(Bitmap.CompressFormat.PNG, 100, stream);
         values.put(CacheDb.COLUMN_PREVIEW_BITMAP, stream.toByteArray());
         values.put(CacheDb.COLUMN_SIZE, mSize);
-        db.insert(CacheDb.TABLE_NAME, null, values);
+        try {
+            db.insert(CacheDb.TABLE_NAME, null, values);
+        } catch (SQLiteDiskIOException e) {
+            recreateDb();
+        }
     }
 
     private void clearDb() {
         SQLiteDatabase db = mDb.getWritableDatabase();
         // Delete everything
-        db.delete(CacheDb.TABLE_NAME, null, null);
+        try {
+            db.delete(CacheDb.TABLE_NAME, null, null);
+        } catch (SQLiteDiskIOException e) {
+        }
     }
 
     public static void removePackageFromDb(final CacheDb cacheDb, final String packageName) {
@@ -363,13 +377,17 @@
         new AsyncTask<Void, Void, Void>() {
             public Void doInBackground(Void ... args) {
                 SQLiteDatabase db = cacheDb.getWritableDatabase();
-                db.delete(CacheDb.TABLE_NAME,
-                        CacheDb.COLUMN_NAME + " LIKE ? OR " +
-                        CacheDb.COLUMN_NAME + " LIKE ?", // SELECT query
-                        new String[] {
-                            WIDGET_PREFIX + packageName + "/%",
-                            SHORTCUT_PREFIX + packageName + "/%"} // args to SELECT query
-                            );
+                try {
+                    db.delete(CacheDb.TABLE_NAME,
+                            CacheDb.COLUMN_NAME + " LIKE ? OR " +
+                            CacheDb.COLUMN_NAME + " LIKE ?", // SELECT query
+                            new String[] {
+                                    WIDGET_PREFIX + packageName + "/%",
+                                    SHORTCUT_PREFIX + packageName + "/%"
+                            } // args to SELECT query
+                    );
+                } catch (SQLiteDiskIOException e) {
+                }
                 synchronized(sInvalidPackages) {
                     sInvalidPackages.remove(packageName);
                 }
@@ -382,9 +400,12 @@
         new AsyncTask<Void, Void, Void>() {
             public Void doInBackground(Void ... args) {
                 SQLiteDatabase db = cacheDb.getWritableDatabase();
-                db.delete(CacheDb.TABLE_NAME,
-                        CacheDb.COLUMN_NAME + " = ? ", // SELECT query
-                        new String[] { objectName }); // args to SELECT query
+                try {
+                    db.delete(CacheDb.TABLE_NAME,
+                            CacheDb.COLUMN_NAME + " = ? ", // SELECT query
+                            new String[] { objectName }); // args to SELECT query
+                } catch (SQLiteDiskIOException e) {
+                }
                 return null;
             }
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
@@ -396,14 +417,20 @@
                     CacheDb.COLUMN_SIZE + " = ?";
         }
         SQLiteDatabase db = mDb.getReadableDatabase();
-        Cursor result = db.query(CacheDb.TABLE_NAME,
-                new String[] { CacheDb.COLUMN_PREVIEW_BITMAP }, // cols to return
-                mCachedSelectQuery, // select query
-                new String[] { name, mSize }, // args to select query
-                null,
-                null,
-                null,
-                null);
+        Cursor result;
+        try {
+            result = db.query(CacheDb.TABLE_NAME,
+                    new String[] { CacheDb.COLUMN_PREVIEW_BITMAP }, // cols to return
+                    mCachedSelectQuery, // select query
+                    new String[] { name, mSize }, // args to select query
+                    null,
+                    null,
+                    null,
+                    null);
+        } catch (SQLiteDiskIOException e) {
+            recreateDb();
+            return null;
+        }
         if (result.getCount() > 0) {
             result.moveToFirst();
             byte[] blob = result.getBlob(0);