am 60b76533: Merge "Move photo gadget to the new gallery." into gingerbread

Merge commit '60b765330cc496b5ebac87ae7772b136045487b5' into gingerbread-plus-aosp

* commit '60b765330cc496b5ebac87ae7772b136045487b5':
  Move photo gadget to the new gallery.
diff --git a/new3d/AndroidManifest.xml b/new3d/AndroidManifest.xml
index 1c7681e..2821ba9 100644
--- a/new3d/AndroidManifest.xml
+++ b/new3d/AndroidManifest.xml
@@ -4,7 +4,7 @@
     android:versionName="1.1.30682"
     xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.gallery3d">
 
-    <original-package android:name="com.cooliris.media" />
+    <original-package android:name="com.android.gallery3d" />
 
     <uses-permission android:name="android.permission.SET_WALLPAPER" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -97,17 +97,17 @@
                 <data android:mimeType="image/*" />
             </intent-filter>
             <intent-filter>
-                <action android:name="com.cooliris.media.action.REVIEW" />
+                <action android:name="com.android.gallery3d.action.REVIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="vnd.android.cursor.dir/image" />
             </intent-filter>
             <intent-filter>
-                <action android:name="com.cooliris.media.action.REVIEW" />
+                <action android:name="com.android.gallery3d.action.REVIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="image/*" />
             </intent-filter>
             <intent-filter>
-                <action android:name="com.cooliris.media.action.REVIEW" />
+                <action android:name="com.android.gallery3d.action.REVIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="video/*" />
              </intent-filter>
@@ -136,5 +136,20 @@
             </intent-filter>
             <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter" />
         </service>
+
+        <receiver android:name="com.android.gallery3d.gadget.PhotoAppWidgetProvider"
+                android:label="@string/gadget_title">
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+            </intent-filter>
+            <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_info" />
+        </receiver>
+
+        <!-- We configure a widget by asking to pick a photo, then crop it, and store the config internally-->
+        <activity android:name="com.android.gallery3d.gadget.PhotoAppWidgetConfigure">
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/new3d/res/xml/appwidget_info.xml b/new3d/res/xml/appwidget_info.xml
index b6893bc..60c3586 100644
--- a/new3d/res/xml/appwidget_info.xml
+++ b/new3d/res/xml/appwidget_info.xml
@@ -19,6 +19,4 @@
     android:minHeight="146dip"
     android:updatePeriodMillis="0"
     android:initialLayout="@layout/photo_frame"
-    android:configure="com.cooliris.media.PhotoAppWidgetConfigure"
-    >
-</appwidget-provider>
+    android:configure="com.android.gallery3d.gadget.PhotoAppWidgetConfigure"/>
diff --git a/new3d/src/com/android/gallery3d/gadget/PhotoAppWidgetConfigure.java b/new3d/src/com/android/gallery3d/gadget/PhotoAppWidgetConfigure.java
new file mode 100644
index 0000000..c075079
--- /dev/null
+++ b/new3d/src/com/android/gallery3d/gadget/PhotoAppWidgetConfigure.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.gadget;
+
+import android.app.Activity;
+import android.appwidget.AppWidgetManager;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.widget.RemoteViews;
+
+public class PhotoAppWidgetConfigure extends Activity {
+
+    @SuppressWarnings("unused")
+    private static final String TAG = "PhotoAppWidgetConfigure";
+    static final int REQUEST_GET_PHOTO = 2;
+
+    private int mAppWidgetId = -1;
+
+    @Override
+    protected void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+
+        // Someone is requesting that we configure the given mAppWidgetId, which
+        // means we prompt the user to pick and crop a photo.
+        mAppWidgetId = getIntent().getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+
+        if (mAppWidgetId == -1) {
+            setResult(Activity.RESULT_CANCELED);
+            finish();
+            return;
+        }
+
+        // TODO: get these values from constants somewhere
+        // TODO: Adjust the PhotoFrame's image size to avoid on the fly scaling
+        // TODO: we should handle it in two steps: Send a GET_CONTENT
+        //       intent and then a CROP intent.
+        Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
+        intent.setType("image/*");
+        intent.putExtra("crop", "true");
+        intent.putExtra("aspectX", 1);
+        intent.putExtra("aspectY", 1);
+        intent.putExtra("outputX", 192);
+        intent.putExtra("outputY", 192);
+        intent.putExtra("noFaceDetection", true);
+        intent.putExtra("return-data", true);
+
+        startActivityForResult(intent, REQUEST_GET_PHOTO);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode == RESULT_OK && mAppWidgetId != -1) {
+            // Store the cropped photo in our database
+            Bitmap bitmap = (Bitmap) data.getParcelableExtra("data");
+
+            PhotoDatabaseHelper helper = new PhotoDatabaseHelper(this);
+            if (helper.setPhoto(mAppWidgetId, bitmap)) {
+                resultCode = Activity.RESULT_OK;
+
+                // Push newly updated widget to surface
+                RemoteViews views = PhotoAppWidgetProvider.buildUpdate(this, mAppWidgetId, helper);
+                AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
+                appWidgetManager.updateAppWidget(new int[] { mAppWidgetId }, views);
+            }
+            helper.close();
+        } else {
+            resultCode = Activity.RESULT_CANCELED;
+        }
+
+        // Make sure we pass back the original mAppWidgetId
+        Intent resultValue = new Intent();
+        resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
+        setResult(resultCode, resultValue);
+        finish();
+    }
+}
diff --git a/new3d/src/com/android/gallery3d/gadget/PhotoAppWidgetProvider.java b/new3d/src/com/android/gallery3d/gadget/PhotoAppWidgetProvider.java
new file mode 100644
index 0000000..b4d330e
--- /dev/null
+++ b/new3d/src/com/android/gallery3d/gadget/PhotoAppWidgetProvider.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.gadget;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import com.android.gallery3d.R;
+
+/**
+ * Simple widget to show a user-selected picture.
+ */
+public class PhotoAppWidgetProvider extends AppWidgetProvider {
+    static final String TAG = "PhotoAppWidgetProvider";
+    static final boolean LOGD = true;
+
+    @Override
+    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+        // Update each requested appWidgetId with its unique photo
+        PhotoDatabaseHelper helper = new PhotoDatabaseHelper(context);
+        for (int appWidgetId : appWidgetIds) {
+            int[] specificAppWidget = new int[] {appWidgetId};
+            RemoteViews views = buildUpdate(context, appWidgetId, helper);
+            if (LOGD) {
+                Log.d(TAG, "sending out views=" + views + " for id=" + appWidgetId);
+            }
+            appWidgetManager.updateAppWidget(specificAppWidget, views);
+        }
+        helper.close();
+    }
+
+    @Override
+    public void onDeleted(Context context, int[] appWidgetIds) {
+        // Clean deleted photos out of our database
+        PhotoDatabaseHelper helper = new PhotoDatabaseHelper(context);
+        for (int appWidgetId : appWidgetIds) {
+            helper.deletePhoto(appWidgetId);
+        }
+        helper.close();
+    }
+
+    /**
+     * Load photo for given widget and build {@link RemoteViews} for it.
+     */
+    static RemoteViews buildUpdate(Context context, int appWidgetId, PhotoDatabaseHelper helper) {
+        RemoteViews views = null;
+        Bitmap bitmap = helper.getPhoto(appWidgetId);
+        if (bitmap != null) {
+            views = new RemoteViews(context.getPackageName(), R.layout.photo_frame);
+            views.setImageViewBitmap(R.id.photo, bitmap);
+        }
+        return views;
+    }
+
+}
diff --git a/new3d/src/com/android/gallery3d/gadget/PhotoDatabaseHelper.java b/new3d/src/com/android/gallery3d/gadget/PhotoDatabaseHelper.java
new file mode 100644
index 0000000..17591f4
--- /dev/null
+++ b/new3d/src/com/android/gallery3d/gadget/PhotoDatabaseHelper.java
@@ -0,0 +1,130 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package com.android.gallery3d.gadget;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+class PhotoDatabaseHelper extends SQLiteOpenHelper {
+    private static final String DATABASE_NAME = "launcher.db";
+
+    private static final int DATABASE_VERSION = 2;
+
+    static final String TABLE_PHOTOS = "photos";
+    static final String FIELD_APPWIDGET_ID = "appWidgetId";
+    static final String FIELD_PHOTO_BLOB = "photoBlob";
+
+    PhotoDatabaseHelper(Context context) {
+        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        db.execSQL("CREATE TABLE " + TABLE_PHOTOS + " ("
+                + FIELD_APPWIDGET_ID + " INTEGER PRIMARY KEY,"
+                + FIELD_PHOTO_BLOB + " BLOB" + ");");
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        int version = oldVersion;
+
+        if (version != DATABASE_VERSION) {
+            Log.w(PhotoAppWidgetProvider.TAG, "Destroying all old data.");
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_PHOTOS);
+            onCreate(db);
+        }
+    }
+
+    /**
+     * Store the given bitmap in this database for the given appWidgetId.
+     */
+    public boolean setPhoto(int appWidgetId, Bitmap bitmap) {
+        boolean success = false;
+        try {
+            // Try go guesstimate how much space the icon will take when
+            // serialized to avoid unnecessary allocations/copies during
+            // the write.
+            int size = bitmap.getWidth() * bitmap.getHeight() * 4;
+            ByteArrayOutputStream out = new ByteArrayOutputStream(size);
+            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+            out.flush();
+            out.close();
+
+            ContentValues values = new ContentValues();
+            values.put(PhotoDatabaseHelper.FIELD_APPWIDGET_ID, appWidgetId);
+            values.put(PhotoDatabaseHelper.FIELD_PHOTO_BLOB, out.toByteArray());
+
+            SQLiteDatabase db = getWritableDatabase();
+            db.insertOrThrow(PhotoDatabaseHelper.TABLE_PHOTOS, null, values);
+
+            success = true;
+        } catch (SQLiteException e) {
+            Log.e(PhotoAppWidgetProvider.TAG, "Could not open database", e);
+        } catch (IOException e) {
+            Log.e(PhotoAppWidgetProvider.TAG, "Could not serialize photo", e);
+        }
+        if (PhotoAppWidgetProvider.LOGD) {
+            Log.d(PhotoAppWidgetProvider.TAG, "setPhoto success=" + success);
+        }
+        return success;
+    }
+
+    private static final String[] PHOTOS_PROJECTION = {FIELD_PHOTO_BLOB};
+    private static final int INDEX_PHOTO_BLOB = 0;
+    private static final String WHERE_CLAUSE = FIELD_APPWIDGET_ID + " = ?";
+
+    /**
+     * Inflate and return a bitmap for the given appWidgetId.
+     */
+    public Bitmap getPhoto(int appWidgetId) {
+        Cursor c = null;
+        Bitmap bitmap = null;
+        try {
+            SQLiteDatabase db = getReadableDatabase();
+            String selection = String.format("%s=%d", FIELD_APPWIDGET_ID, appWidgetId);
+            c = db.query(TABLE_PHOTOS, PHOTOS_PROJECTION,
+                    WHERE_CLAUSE, new String[]{String.valueOf(appWidgetId)},
+                    null, null, null, null);
+
+            if (c != null && PhotoAppWidgetProvider.LOGD) {
+                Log.d(PhotoAppWidgetProvider.TAG, "getPhoto query count=" + c.getCount());
+            }
+
+            if (c != null && c.moveToFirst()) {
+                byte[] data = c.getBlob(INDEX_PHOTO_BLOB);
+                if (data != null) {
+                    bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
+                }
+            }
+        } catch (SQLiteException e) {
+            Log.e(PhotoAppWidgetProvider.TAG, "Could not load photo from database", e);
+        } finally {
+            if (c != null) c.close();
+        }
+        return bitmap;
+    }
+
+    /**
+     * Remove any bitmap associated with the given appWidgetId.
+     */
+    public void deletePhoto(int appWidgetId) {
+        try {
+            SQLiteDatabase db = getWritableDatabase();
+            String whereClause = String.format("%s=%d", FIELD_APPWIDGET_ID, appWidgetId);
+            db.delete(TABLE_PHOTOS, whereClause, null);
+        } catch (SQLiteException e) {
+            Log.e(PhotoAppWidgetProvider.TAG, "Could not delete photo from database", e);
+        }
+    }
+}
\ No newline at end of file