From e3f4516c2154539cb5778ef061abf8a0ccf90a5e Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 11 Mar 2009 12:11:58 -0700 Subject: auto import from //branches/cupcake/...@137873 --- src/com/android/camera/Camera.java | 49 +++-- src/com/android/camera/ImageManager.java | 3 + src/com/android/camera/MenuHelper.java | 12 +- src/com/android/camera/PhotoAppWidgetBind.java | 73 +++++++ .../android/camera/PhotoAppWidgetConfigure.java | 97 +++++++++ src/com/android/camera/PhotoAppWidgetProvider.java | 223 +++++++++++++++++++++ src/com/android/camera/PhotoGadgetBind.java | 73 ------- src/com/android/camera/PhotoGadgetConfigure.java | 97 --------- src/com/android/camera/PhotoGadgetProvider.java | 223 --------------------- src/com/android/camera/VideoCamera.java | 31 ++- src/com/android/camera/ViewImage.java | 22 +- 11 files changed, 478 insertions(+), 425 deletions(-) create mode 100644 src/com/android/camera/PhotoAppWidgetBind.java create mode 100644 src/com/android/camera/PhotoAppWidgetConfigure.java create mode 100644 src/com/android/camera/PhotoAppWidgetProvider.java delete mode 100644 src/com/android/camera/PhotoGadgetBind.java delete mode 100644 src/com/android/camera/PhotoGadgetConfigure.java delete mode 100644 src/com/android/camera/PhotoGadgetProvider.java (limited to 'src') diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java index 3564508..71ed339 100644 --- a/src/com/android/camera/Camera.java +++ b/src/com/android/camera/Camera.java @@ -129,7 +129,6 @@ public class Camera extends Activity implements View.OnClickListener, private android.hardware.Camera.Parameters mParameters; private VideoPreview mSurfaceView; private SurfaceHolder mSurfaceHolder = null; - private View mBlackout = null; private int mOriginalViewFinderWidth, mOriginalViewFinderHeight; private int mViewFinderWidth, mViewFinderHeight; @@ -204,7 +203,7 @@ public class Camera extends Activity implements View.OnClickListener, case RESTART_PREVIEW: { if (mStatus == SNAPSHOT_IN_PROGRESS) { // We are still in the processing of taking the picture, wait. - // This is is strange. Why are we polling? + // This is strange. Why are we polling? // TODO remove polling mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, 100); } else if (mStatus == SNAPSHOT_COMPLETED){ @@ -293,15 +292,20 @@ public class Camera extends Activity implements View.OnClickListener, mShutterCallbackTime = System.currentTimeMillis(); Log.v(TAG, "Shutter lag was " + (mShutterCallbackTime - mCaptureStartTime) + " ms."); } - if (mClickSound != null) { - mClickSound.start(); - } - mBlackout.setVisibility(View.VISIBLE); - Size pictureSize = mParameters.getPictureSize(); + // We are going to change the size of surface view and show captured + // image. Set it to invisible now and set it back to visible in + // surfaceChanged() so that users won't see the image is resized on + // the screen. + mSurfaceView.setVisibility(View.INVISIBLE); // Resize the SurfaceView to the aspect-ratio of the still image // and so that we can see the full image that was taken. + Size pictureSize = mParameters.getPictureSize(); mSurfaceView.setAspectRatio(pictureSize.width, pictureSize.height); + + if (mClickSound != null) { + mClickSound.start(); + } } }; @@ -314,7 +318,6 @@ public class Camera extends Activity implements View.OnClickListener, Log.v(TAG, (mRawPictureCallbackTime - mShutterCallbackTime) + "ms elapsed between" + " ShutterCallback and RawPictureCallback."); } - mBlackout.setVisibility(View.GONE); } }; @@ -326,6 +329,9 @@ public class Camera extends Activity implements View.OnClickListener, } public void onPictureTaken(byte [] jpegData, android.hardware.Camera camera) { + if (!canHandleCameraEvent()) { + return; + } if (Config.LOGV) Log.v(TAG, "got JpegPictureCallback..."); @@ -581,6 +587,9 @@ public class Camera extends Activity implements View.OnClickListener, } public void onSnap() { + if (!canHandleCameraEvent()) { + return; + } if (DEBUG_TIME_OPERATIONS) mCaptureStartTime = System.currentTimeMillis(); // If we are already in the middle of taking a snapshot then we should just save @@ -739,8 +748,6 @@ public class Camera extends Activity implements View.OnClickListener, holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); - mBlackout = findViewById(R.id.blackout); - if (!isImageCaptureIntent()) { mLastPictureButton = (ImageView) findViewById(R.id.last_picture_button); mLastPictureButton.setOnClickListener(this); @@ -823,6 +830,9 @@ public class Camera extends Activity implements View.OnClickListener, } private void doAttach() { + if (!canHandleCameraEvent()) { + return; + } Bitmap bitmap = mImageCapture.getLastBitmap(); String cropValue = null; @@ -928,7 +938,16 @@ public class Camera extends Activity implements View.OnClickListener, finish(); } + private boolean canHandleCameraEvent() { + // don't handle any shutter event before we have a valid + // imageCapture object. + return mImageCapture != null; + } + public void onShutterButtonFocus(ShutterButton button, boolean pressed) { + if (!canHandleCameraEvent()) { + return; + } switch (button.getId()) { case R.id.shutter_button: doFocus(pressed); @@ -937,6 +956,9 @@ public class Camera extends Activity implements View.OnClickListener, } public void onShutterButtonClick(ShutterButton button) { + if (!canHandleCameraEvent()) { + return; + } switch (button.getId()) { case R.id.shutter_button: doSnap(); @@ -1010,8 +1032,6 @@ public class Camera extends Activity implements View.OnClickListener, Log.w(TAG, "Exception caught while creating local tone generator: " + e); mFocusToneGenerator = null; } - - mBlackout.setVisibility(View.GONE); } private ImageManager.DataLocation dataLocation() { @@ -1129,7 +1149,7 @@ public class Camera extends Activity implements View.OnClickListener, mImageCapture.clearLastBitmap(); mImageCapture = null; hidePostCaptureAlert(); - + super.onPause(); } @@ -1279,10 +1299,11 @@ public class Camera extends Activity implements View.OnClickListener, } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + mSurfaceView.setVisibility(View.VISIBLE); // if we're creating the surface, start the preview as well. boolean preview = holder.isCreating(); setViewFinder(w, h, preview); - mCaptureObject = mImageCapture; + mCaptureObject = mImageCapture; } public void surfaceCreated(SurfaceHolder holder) { diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java index 6c3472b..b470f95 100755 --- a/src/com/android/camera/ImageManager.java +++ b/src/com/android/camera/ImageManager.java @@ -2095,6 +2095,9 @@ public class ImageManager { } catch (NullPointerException ex) { // we seem to get this if the file doesn't exist anymore Log.e(TAG, "couldn't open thumbnail " + thumbUri + "; " + ex); + } catch (OutOfMemoryError ex) { + Log.e(TAG, "failed to allocate memory for thumbnail " + + thumbUri + "; " + ex); } } } catch (Exception ex) { diff --git a/src/com/android/camera/MenuHelper.java b/src/com/android/camera/MenuHelper.java index 2bb532e..568b3a6 100644 --- a/src/com/android/camera/MenuHelper.java +++ b/src/com/android/camera/MenuHelper.java @@ -82,6 +82,8 @@ public class MenuHelper { static public final int MENU_VIDEO_SHARE = 24; static public final int MENU_VIDEO_TOSS = 27; + static private final long SHARE_FILE_LENGTH_LIMIT = 3L * 1024L * 1024L; + public static final int NO_STORAGE_ERROR = -1; public static final int CANNOT_STAT_ERROR = -2; @@ -226,8 +228,13 @@ public class MenuHelper { public boolean onMenuItemClick(MenuItem item) { onInvoke.run(new MenuCallback() { public void run(Uri u, ImageManager.IImage image) { - if (image == null) + if (image == null) return; + if (!isImage && getImageFileSize(image) > SHARE_FILE_LENGTH_LIMIT ) { + Toast.makeText(activity, + R.string.too_large_to_attach, Toast.LENGTH_LONG).show(); return; + } + Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); String mimeType = image.getMimeType(); @@ -564,6 +571,7 @@ public class MenuHelper { Uri target = Images.Media.INTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("bucketId", ImageManager.CAMERA_IMAGE_BUCKET_ID).build(); Intent intent = new Intent(Intent.ACTION_VIEW, target); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtra("windowTitle", activity.getString(windowTitleId)); intent.putExtra("mediaTypes", mediaTypes); // Request unspecified so that we match the current camera orientation rather than @@ -586,6 +594,7 @@ public class MenuHelper { new MenuItem.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); try { activity.startActivity(intent); } catch (android.content.ActivityNotFoundException e) { @@ -601,6 +610,7 @@ public class MenuHelper { new MenuItem.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); try { activity.startActivity(intent); } catch (android.content.ActivityNotFoundException e) { diff --git a/src/com/android/camera/PhotoAppWidgetBind.java b/src/com/android/camera/PhotoAppWidgetBind.java new file mode 100644 index 0000000..5e71a54 --- /dev/null +++ b/src/com/android/camera/PhotoAppWidgetBind.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.camera; + +import com.android.camera.PhotoAppWidgetProvider.PhotoDatabaseHelper; + +import android.app.Activity; +import android.appwidget.AppWidgetManager; +import android.content.Intent; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.util.Log; +import android.widget.RemoteViews; + +import java.util.ArrayList; + +public class PhotoAppWidgetBind extends Activity { + static final String TAG = "PhotoAppWidgetBind"; + + static final String EXTRA_APPWIDGET_BITMAPS = "com.android.camera.appwidgetbitmaps"; + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + finish(); + + // The caller has requested that we bind a given bitmap to a specific + // appWidgetId, which probably is happening during a Launcher upgrade. This + // is dangerous because the caller could set bitmaps on appWidgetIds they + // don't own, so we guard this call at the manifest level by requiring + // the BIND_APPWIDGET permission. + + final Intent intent = getIntent(); + final Bundle extras = intent.getExtras(); + + final int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); + final ArrayList bitmaps = extras.getParcelableArrayList(EXTRA_APPWIDGET_BITMAPS); + + if (appWidgetIds == null || bitmaps == null || + appWidgetIds.length != bitmaps.size()) { + Log.e(TAG, "Problem parsing photo widget bind request"); + return; + } + + AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); + PhotoDatabaseHelper helper = new PhotoDatabaseHelper(this); + for (int i = 0; i < appWidgetIds.length; i++) { + // Store the cropped photo in our database + int appWidgetId = appWidgetIds[i]; + helper.setPhoto(appWidgetId, bitmaps.get(i)); + + // Push newly updated widget to surface + RemoteViews views = PhotoAppWidgetProvider.buildUpdate(this, appWidgetId, helper); + appWidgetManager.updateAppWidget(new int[] { appWidgetId }, views); + } + helper.close(); + + } +} diff --git a/src/com/android/camera/PhotoAppWidgetConfigure.java b/src/com/android/camera/PhotoAppWidgetConfigure.java new file mode 100644 index 0000000..14e6112 --- /dev/null +++ b/src/com/android/camera/PhotoAppWidgetConfigure.java @@ -0,0 +1,97 @@ +/* + * 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.camera; + +import com.android.camera.PhotoAppWidgetProvider.PhotoDatabaseHelper; + +import android.app.Activity; +import android.appwidget.AppWidgetManager; +import android.content.ContentValues; +import android.content.Intent; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.Log; +import android.widget.RemoteViews; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class PhotoAppWidgetConfigure extends Activity { + static final private String TAG = "PhotoAppWidgetConfigure"; + + static final int REQUEST_GET_PHOTO = 2; + + int appWidgetId = -1; + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Someone is requesting that we configure the given appWidgetId, which means + // we prompt the user to pick and crop a photo. + + appWidgetId = getIntent().getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); + if (appWidgetId == -1) { + setResult(Activity.RESULT_CANCELED); + finish(); + } + + // TODO: get these values from constants somewhere + // TODO: Adjust the PhotoFrame's image size to avoid on the fly scaling + 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 && appWidgetId != -1) { + // Store the cropped photo in our database + Bitmap bitmap = (Bitmap) data.getParcelableExtra("data"); + + PhotoDatabaseHelper helper = new PhotoDatabaseHelper(this); + if (helper.setPhoto(appWidgetId, bitmap)) { + resultCode = Activity.RESULT_OK; + + // Push newly updated widget to surface + RemoteViews views = PhotoAppWidgetProvider.buildUpdate(this, appWidgetId, helper); + AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); + appWidgetManager.updateAppWidget(new int[] { appWidgetId }, views); + } + helper.close(); + } else { + resultCode = Activity.RESULT_CANCELED; + } + + // Make sure we pass back the original appWidgetId + Intent resultValue = new Intent(); + resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); + setResult(resultCode, resultValue); + finish(); + } + +} diff --git a/src/com/android/camera/PhotoAppWidgetProvider.java b/src/com/android/camera/PhotoAppWidgetProvider.java new file mode 100644 index 0000000..398528e --- /dev/null +++ b/src/com/android/camera/PhotoAppWidgetProvider.java @@ -0,0 +1,223 @@ +/* + * 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.camera; + +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.app.Activity; +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.database.SQLException; +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.net.Uri; +import android.os.Environment; +import android.provider.Settings; +import android.provider.Calendar.Attendees; +import android.provider.Calendar.Calendars; +import android.provider.Calendar.Instances; +import android.text.format.DateFormat; +import android.text.format.DateUtils; +import android.util.Config; +import android.util.Log; +import android.util.Xml; +import android.view.View; +import android.widget.RemoteViews; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +/** + * Simple widget to show a user-selected picture. + */ +public class PhotoAppWidgetProvider extends AppWidgetProvider { + static final String TAG = "PhotoAppWidgetProvider"; + static final boolean LOGD = Config.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; + } + + static class PhotoDatabaseHelper extends SQLiteOpenHelper { + private final Context mContext; + + private static final String DATABASE_NAME = "launcher.db"; + + private static final int DATABASE_VERSION = 1; + + 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); + mContext = context; + } + + @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(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(TAG, "Could not open database", e); + } catch (IOException e) { + Log.e(TAG, "Could not serialize photo", e); + } + if (LOGD) Log.d(TAG, "setPhoto success="+success); + return success; + } + + static final String[] PHOTOS_PROJECTION = { + FIELD_PHOTO_BLOB, + }; + + static final int INDEX_PHOTO_BLOB = 0; + + /** + * 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, selection, null, + null, null, null, null); + + if (c != null && LOGD) Log.d(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(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(TAG, "Could not delete photo from database", e); + } + } + } + +} + diff --git a/src/com/android/camera/PhotoGadgetBind.java b/src/com/android/camera/PhotoGadgetBind.java deleted file mode 100644 index fff19de..0000000 --- a/src/com/android/camera/PhotoGadgetBind.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.camera; - -import com.android.camera.PhotoGadgetProvider.PhotoDatabaseHelper; - -import android.app.Activity; -import android.content.Intent; -import android.gadget.GadgetManager; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.util.Log; -import android.widget.RemoteViews; - -import java.util.ArrayList; - -public class PhotoGadgetBind extends Activity { - static final String TAG = "PhotoGadgetBind"; - - static final String EXTRA_GADGET_BITMAPS = "com.android.camera.gadgetbitmaps"; - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - finish(); - - // The caller has requested that we bind a given bitmap to a specific - // gadgetId, which probably is happening during a Launcher upgrade. This - // is dangerous because the caller could set bitmaps on gadgetIds they - // don't own, so we guard this call at the manifest level by requiring - // the BIND_GADGET permission. - - final Intent intent = getIntent(); - final Bundle extras = intent.getExtras(); - - final int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS); - final ArrayList bitmaps = extras.getParcelableArrayList(EXTRA_GADGET_BITMAPS); - - if (gadgetIds == null || bitmaps == null || - gadgetIds.length != bitmaps.size()) { - Log.e(TAG, "Problem parsing photo gadget bind request"); - return; - } - - GadgetManager gadgetManager = GadgetManager.getInstance(this); - PhotoDatabaseHelper helper = new PhotoDatabaseHelper(this); - for (int i = 0; i < gadgetIds.length; i++) { - // Store the cropped photo in our database - int gadgetId = gadgetIds[i]; - helper.setPhoto(gadgetId, bitmaps.get(i)); - - // Push newly updated gadget to surface - RemoteViews views = PhotoGadgetProvider.buildUpdate(this, gadgetId, helper); - gadgetManager.updateGadget(new int[] { gadgetId }, views); - } - helper.close(); - - } -} diff --git a/src/com/android/camera/PhotoGadgetConfigure.java b/src/com/android/camera/PhotoGadgetConfigure.java deleted file mode 100644 index a94b5a3..0000000 --- a/src/com/android/camera/PhotoGadgetConfigure.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.camera; - -import com.android.camera.PhotoGadgetProvider.PhotoDatabaseHelper; - -import android.app.Activity; -import android.content.ContentValues; -import android.content.Intent; -import android.database.sqlite.SQLiteDatabase; -import android.gadget.GadgetManager; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.os.Parcelable; -import android.util.Log; -import android.widget.RemoteViews; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -public class PhotoGadgetConfigure extends Activity { - static final private String TAG = "PhotoGadgetConfigure"; - - static final int REQUEST_GET_PHOTO = 2; - - int gadgetId = -1; - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Someone is requesting that we configure the given gadgetId, which means - // we prompt the user to pick and crop a photo. - - gadgetId = getIntent().getIntExtra(GadgetManager.EXTRA_GADGET_ID, -1); - if (gadgetId == -1) { - setResult(Activity.RESULT_CANCELED); - finish(); - } - - // TODO: get these values from constants somewhere - // TODO: Adjust the PhotoFrame's image size to avoid on the fly scaling - 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 && gadgetId != -1) { - // Store the cropped photo in our database - Bitmap bitmap = (Bitmap) data.getParcelableExtra("data"); - - PhotoDatabaseHelper helper = new PhotoDatabaseHelper(this); - if (helper.setPhoto(gadgetId, bitmap)) { - resultCode = Activity.RESULT_OK; - - // Push newly updated gadget to surface - RemoteViews views = PhotoGadgetProvider.buildUpdate(this, gadgetId, helper); - GadgetManager gadgetManager = GadgetManager.getInstance(this); - gadgetManager.updateGadget(new int[] { gadgetId }, views); - } - helper.close(); - } else { - resultCode = Activity.RESULT_CANCELED; - } - - // Make sure we pass back the original gadgetId - Intent resultValue = new Intent(); - resultValue.putExtra(GadgetManager.EXTRA_GADGET_ID, gadgetId); - setResult(resultCode, resultValue); - finish(); - } - -} diff --git a/src/com/android/camera/PhotoGadgetProvider.java b/src/com/android/camera/PhotoGadgetProvider.java deleted file mode 100644 index b03217d..0000000 --- a/src/com/android/camera/PhotoGadgetProvider.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * 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.camera; - -import com.android.internal.util.XmlUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import android.app.Activity; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.database.SQLException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; -import android.database.sqlite.SQLiteOpenHelper; -import android.gadget.GadgetManager; -import android.gadget.GadgetProvider; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Environment; -import android.provider.Settings; -import android.provider.Calendar.Attendees; -import android.provider.Calendar.Calendars; -import android.provider.Calendar.Instances; -import android.text.format.DateFormat; -import android.text.format.DateUtils; -import android.util.Config; -import android.util.Log; -import android.util.Xml; -import android.view.View; -import android.widget.RemoteViews; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; - -/** - * Simple gadget to show a user-selected picture. - */ -public class PhotoGadgetProvider extends GadgetProvider { - static final String TAG = "PhotoGadgetProvider"; - static final boolean LOGD = Config.LOGD || true; - - @Override - public void onUpdate(Context context, GadgetManager gadgetManager, int[] gadgetIds) { - // Update each requested gadgetId with its unique photo - PhotoDatabaseHelper helper = new PhotoDatabaseHelper(context); - for (int gadgetId : gadgetIds) { - int[] specificGadget = new int[] { gadgetId }; - RemoteViews views = buildUpdate(context, gadgetId, helper); - if (LOGD) Log.d(TAG, "sending out views="+views+" for id="+gadgetId); - gadgetManager.updateGadget(specificGadget, views); - } - helper.close(); - } - - @Override - public void onDeleted(Context context, int[] gadgetIds) { - // Clean deleted photos out of our database - PhotoDatabaseHelper helper = new PhotoDatabaseHelper(context); - for (int gadgetId : gadgetIds) { - helper.deletePhoto(gadgetId); - } - helper.close(); - } - - /** - * Load photo for given gadget and build {@link RemoteViews} for it. - */ - static RemoteViews buildUpdate(Context context, int gadgetId, PhotoDatabaseHelper helper) { - RemoteViews views = null; - Bitmap bitmap = helper.getPhoto(gadgetId); - if (bitmap != null) { - views = new RemoteViews(context.getPackageName(), R.layout.photo_frame); - views.setImageViewBitmap(R.id.photo, bitmap); - } - return views; - } - - static class PhotoDatabaseHelper extends SQLiteOpenHelper { - private final Context mContext; - - private static final String DATABASE_NAME = "launcher.db"; - - private static final int DATABASE_VERSION = 1; - - static final String TABLE_PHOTOS = "photos"; - static final String FIELD_GADGET_ID = "gadgetId"; - static final String FIELD_PHOTO_BLOB = "photoBlob"; - - PhotoDatabaseHelper(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - mContext = context; - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + TABLE_PHOTOS + " (" + - FIELD_GADGET_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(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 gadgetId. - */ - public boolean setPhoto(int gadgetId, 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_GADGET_ID, gadgetId); - 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(TAG, "Could not open database", e); - } catch (IOException e) { - Log.e(TAG, "Could not serialize photo", e); - } - if (LOGD) Log.d(TAG, "setPhoto success="+success); - return success; - } - - static final String[] PHOTOS_PROJECTION = { - FIELD_PHOTO_BLOB, - }; - - static final int INDEX_PHOTO_BLOB = 0; - - /** - * Inflate and return a bitmap for the given gadgetId. - */ - public Bitmap getPhoto(int gadgetId) { - Cursor c = null; - Bitmap bitmap = null; - try { - SQLiteDatabase db = getReadableDatabase(); - String selection = String.format("%s=%d", FIELD_GADGET_ID, gadgetId); - c = db.query(TABLE_PHOTOS, PHOTOS_PROJECTION, selection, null, - null, null, null, null); - - if (c != null && LOGD) Log.d(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(TAG, "Could not load photo from database", e); - } finally { - if (c != null) { - c.close(); - } - } - return bitmap; - } - - /** - * Remove any bitmap associated with the given gadgetId. - */ - public void deletePhoto(int gadgetId) { - try { - SQLiteDatabase db = getWritableDatabase(); - String whereClause = String.format("%s=%d", FIELD_GADGET_ID, gadgetId); - db.delete(TABLE_PHOTOS, whereClause, null); - } catch (SQLiteException e) { - Log.e(TAG, "Could not delete photo from database", e); - } - } - } - -} - diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java index 70b1646..1fb22e1 100644 --- a/src/com/android/camera/VideoCamera.java +++ b/src/com/android/camera/VideoCamera.java @@ -84,6 +84,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, private static final long NO_STORAGE_ERROR = -1L; private static final long CANNOT_STAT_ERROR = -2L; private static final long LOW_STORAGE_THRESHOLD = 512L * 1024L; + private static final long SHARE_FILE_LENGTH_LIMIT = 3L * 1024L * 1024L; private static final int STORAGE_STATUS_OK = 0; private static final int STORAGE_STATUS_LOW = 1; @@ -264,6 +265,24 @@ public class VideoCamera extends Activity implements View.OnClickListener, mVideoFrame = (ImageView) findViewById(R.id.video_frame); } + private void startShareVideoActivity() { + long fileLength = new File(mCurrentVideoFilename).length(); + if (fileLength > SHARE_FILE_LENGTH_LIMIT) { + Toast.makeText(VideoCamera.this, + R.string.too_large_to_attach, Toast.LENGTH_LONG).show(); + return; + } + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_SEND); + intent.setType("video/3gpp"); + intent.putExtra(Intent.EXTRA_STREAM, mCurrentVideoUri); + try { + startActivity(Intent.createChooser(intent, getText(R.string.sendVideo))); + } catch (android.content.ActivityNotFoundException ex) { + Toast.makeText(VideoCamera.this, R.string.no_way_to_share_video, Toast.LENGTH_SHORT).show(); + } + } + public void onClick(View v) { switch (v.getId()) { @@ -285,16 +304,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, } case R.id.share: { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.setType("video/3gpp"); - intent.putExtra(Intent.EXTRA_STREAM, mCurrentVideoUri); - try { - startActivity(Intent.createChooser(intent, getText(R.string.sendVideo))); - } catch (android.content.ActivityNotFoundException ex) { - Toast.makeText(VideoCamera.this, R.string.no_way_to_share_video, Toast.LENGTH_SHORT).show(); - } - + startShareVideoActivity(); break; } @@ -932,6 +942,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, for(int id : hideIds) { mPostPictureAlert.findViewById(id).setVisibility(View.GONE); } + connectAndFadeIn(connectIds); connectAndFadeIn(alwaysOnIds); mPostPictureAlert.setVisibility(View.VISIBLE); diff --git a/src/com/android/camera/ViewImage.java b/src/com/android/camera/ViewImage.java index a5a3821..7963e66 100644 --- a/src/com/android/camera/ViewImage.java +++ b/src/com/android/camera/ViewImage.java @@ -249,14 +249,10 @@ public class ViewImage extends Activity implements View.OnClickListener mGestureDetector = new GestureDetector(getContext(), new MyGestureListener()); mGestureDetector.setOnDoubleTapListener(new MyDoubleTapListener()); mZoomButtonsController = new ZoomButtonsController(context, this); - mZoomButtonsController.setOverviewVisible(false); mZoomButtonsController.setCallback(new ZoomButtonsController.OnZoomListener() { public void onCenter(int x, int y) { } - public void onOverview() { - } - public void onVisibilityChanged(boolean visible) { if (visible) { updateButtonsEnabled(); @@ -338,7 +334,9 @@ public class ViewImage extends Activity implements View.OnClickListener // On double tap, we show the zoom controls. public boolean onDoubleTapEvent(MotionEvent e) { mViewImage.setMode(MODE_NORMAL); - mZoomButtonsController.handleDoubleTapEvent(e); + if (mZoomButtonsController.handleDoubleTapEvent(e)) { + ZoomButtonsController.finishZoomTutorial(mViewImage, true); + } return true; } @@ -901,7 +899,8 @@ public class ViewImage extends Activity implements View.OnClickListener return; } - final boolean left = mCurrentPosition > pos; + final boolean left = (pos == mCurrentPosition - 1); + final boolean right = (pos == mCurrentPosition + 1); mCurrentPosition = pos; @@ -919,7 +918,7 @@ public class ViewImage extends Activity implements View.OnClickListener if (left) { mImageViews[2].copyFrom(mImageViews[1]); mImageViews[1].copyFrom(mImageViews[0]); - } else { + } else if (right) { mImageViews[0].copyFrom(mImageViews[1]); mImageViews[1].copyFrom(mImageViews[2]); } @@ -1449,6 +1448,15 @@ public class ViewImage extends Activity implements View.OnClickListener } @Override + public void onWindowFocusChanged(boolean hasFocus) { + if (hasFocus) { + ZoomButtonsController.showZoomTutorialOnce(this); + } else { + ZoomButtonsController.finishZoomTutorial(this, false); + } + } + + @Override public void onPause() { super.onPause(); -- cgit v1.1