diff options
Diffstat (limited to 'src/com')
12 files changed, 742 insertions, 162 deletions
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index a207b2b71..b5ff0114c 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -19,8 +19,8 @@ package com.android.camera; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.content.Context; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; @@ -30,13 +30,14 @@ import android.os.Bundle; import android.os.IBinder; import android.provider.MediaStore; import android.provider.Settings; -import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.OrientationEventListener; import android.view.View; import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; import android.widget.FrameLayout; import com.android.camera.ui.CameraSwitcher; @@ -62,6 +63,7 @@ public class CameraActivity extends ActivityBase private int mCurrentModuleIndex; private MotionEvent mDown; private boolean mAutoRotateScreen; + private int mHeightOrWidth = -1; private MyOrientationEventListener mOrientationListener; // The degrees of the device rotated clockwise from its natural orientation. @@ -299,6 +301,15 @@ public class CameraActivity extends ActivityBase super.onConfigurationChanged(config); ViewGroup appRoot = (ViewGroup) findViewById(R.id.content); + boolean landscape = (config.orientation == Configuration.ORIENTATION_LANDSCAPE); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) appRoot.getLayoutParams(); + if (landscape) { + lp.rightMargin = getResources().getDimensionPixelSize(R.dimen.margin_systemui_offset); + } else { + lp.rightMargin = 0; + } + appRoot.setLayoutParams(lp); + // remove old switcher, shutter and shutter icon View cameraControlsView = findViewById(R.id.camera_shutter_switcher); appRoot.removeView(cameraControlsView); @@ -362,9 +373,23 @@ public class CameraActivity extends ActivityBase hideUI(); } super.onFullScreenChanged(full); + if (ApiHelper.HAS_ROTATION_ANIMATION) { + setRotationAnimation(full); + } mCurrentModule.onFullScreenChanged(full); } + private void setRotationAnimation(boolean fullscreen) { + int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; + if (fullscreen) { + rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; + } + Window win = getWindow(); + WindowManager.LayoutParams winParams = win.getAttributes(); + winParams.rotationAnimation = rotationAnimation; + win.setAttributes(winParams); + } + @Override protected void onStop() { super.onStop(); diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java index fd30ac080..516a19250 100644 --- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -60,9 +60,7 @@ import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; import com.android.gallery3d.filtershow.editors.EditorTinyPlanet; import com.android.gallery3d.filtershow.filters.*; import com.android.gallery3d.filtershow.imageshow.ImageCrop; -import com.android.gallery3d.filtershow.imageshow.ImageDraw; import com.android.gallery3d.filtershow.imageshow.ImageFlip; -import com.android.gallery3d.filtershow.imageshow.ImageRedEye; import com.android.gallery3d.filtershow.imageshow.ImageRotate; import com.android.gallery3d.filtershow.imageshow.ImageShow; import com.android.gallery3d.filtershow.imageshow.ImageStraighten; @@ -98,18 +96,12 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, private final PanelController mPanelController = new PanelController(); private ImageLoader mImageLoader = null; private ImageShow mImageShow = null; - private ImageDraw mImageDraw = null; private ImageStraighten mImageStraighten = null; private ImageCrop mImageCrop = null; private ImageRotate mImageRotate = null; private ImageFlip mImageFlip = null; private ImageTinyPlanet mImageTinyPlanet = null; - private View mListFx = null; - private View mListBorders = null; - private View mListGeometry = null; - private View mListColors = null; - private View mListFilterButtons = null; private View mSaveButton = null; private ImageButton mFxButton = null; @@ -117,10 +109,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, private ImageButton mGeometryButton = null; private ImageButton mColorsButton = null; - private LinearLayout listColors = null; - private LinearLayout listFilters = null; - private LinearLayout listBorders = null; - private EditorPlaceHolder mEditorPlaceHolder = new EditorPlaceHolder(this); private static final int SELECT_PICTURE = 1; @@ -132,8 +120,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, private boolean mShowingImageStatePanel = false; private final Vector<ImageShow> mImageViews = new Vector<ImageShow>(); - private final Vector<View> mListViews = new Vector<View>(); - private final Vector<ImageButton> mBottomPanelButtons = new Vector<ImageButton>(); private ShareActionProvider mShareActionProvider; private File mSharedOutputFile = null; @@ -141,14 +127,12 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, private boolean mSharingImage = false; private WeakReference<ProgressDialog> mSavingProgressDialog; - private static final int SEEK_BAR_MAX = 600; private LoadBitmapTask mLoadBitmapTask; private FilterIconButton mNullFxFilter; private FilterIconButton mNullBorderFilter; private int mIconSeedSize = 140; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -192,17 +176,12 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mImageLoader = new ImageLoader(this, getApplicationContext()); - listFilters = (LinearLayout) findViewById(R.id.listFilters); - listBorders = (LinearLayout) findViewById(R.id.listBorders); - listColors = (LinearLayout) findViewById(R.id.listColorsFx); - mImageShow = (ImageShow) findViewById(R.id.imageShow); mImageStraighten = (ImageStraighten) findViewById(R.id.imageStraighten); mImageCrop = (ImageCrop) findViewById(R.id.imageCrop); mImageRotate = (ImageRotate) findViewById(R.id.imageRotate); mImageFlip = (ImageFlip) findViewById(R.id.imageFlip); mImageTinyPlanet = (ImageTinyPlanet) findViewById(R.id.imageTinyPlanet); - mImageDraw = (ImageDraw) findViewById(R.id.imageDraw); mImageCrop.setAspectTextSize((int) getPixelsFromDip(18)); ImageCrop.setTouchTolerance((int) getPixelsFromDip(25)); @@ -226,34 +205,17 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mEditorPlaceHolder.hide(); - mListFx = findViewById(R.id.fxList); - mListBorders = findViewById(R.id.bordersList); - mListGeometry = findViewById(R.id.geometryList); - mListFilterButtons = findViewById(R.id.filterButtonsList); - mListColors = findViewById(R.id.colorsFxList); - mListViews.add(mListFx); - mListViews.add(mListBorders); - mListViews.add(mListGeometry); - mListViews.add(mListFilterButtons); - mListViews.add(mListColors); - mFxButton = (ImageButton) findViewById(R.id.fxButton); mBorderButton = (ImageButton) findViewById(R.id.borderButton); mGeometryButton = (ImageButton) findViewById(R.id.geometryButton); mColorsButton = (ImageButton) findViewById(R.id.colorsButton); - mBottomPanelButtons.add(mFxButton); - mBottomPanelButtons.add(mBorderButton); - mBottomPanelButtons.add(mGeometryButton); - mBottomPanelButtons.add(mColorsButton); - mImageShow.setImageLoader(mImageLoader); mImageStraighten.setImageLoader(mImageLoader); mImageCrop.setImageLoader(mImageLoader); mImageRotate.setImageLoader(mImageLoader); mImageFlip.setImageLoader(mImageLoader); mImageTinyPlanet.setImageLoader(mImageLoader); - mImageDraw.setImageLoader(mImageLoader); mPanelController.setActivity(this); mPanelController.setEditorPlaceHolder(mEditorPlaceHolder); @@ -264,18 +226,17 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mPanelController.addImageView(findViewById(R.id.imageRotate)); mPanelController.addImageView(findViewById(R.id.imageFlip)); mPanelController.addImageView(findViewById(R.id.imageTinyPlanet)); - mPanelController.addImageView(findViewById(R.id.imageDraw)); - mPanelController.addPanel(mFxButton, mListFx, 0); - mPanelController.addPanel(mBorderButton, mListBorders, 1); + mPanelController.addPanel(mFxButton, findViewById(R.id.fxList), 0); + mPanelController.addPanel(mBorderButton, findViewById(R.id.bordersList), 1); - mPanelController.addPanel(mGeometryButton, mListGeometry, 2); + mPanelController.addPanel(mGeometryButton, findViewById(R.id.geometryList), 2); mPanelController.addComponent(mGeometryButton, findViewById(R.id.straightenButton)); mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton)); mPanelController.addComponent(mGeometryButton, findViewById(R.id.rotateButton)); mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton)); - mPanelController.addPanel(mColorsButton, mListColors, 3); + mPanelController.addPanel(mColorsButton, findViewById(R.id.colorsFxList), 3); Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>(); @@ -283,7 +244,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, filtersManager.addEffects(filtersRepresentations); for (FilterRepresentation representation : filtersRepresentations) { - setupFilterRepresentationButton(representation, listColors, mColorsButton); + setupFilterRepresentationButton(representation, + (LinearLayout) findViewById(R.id.listColorsFx), mColorsButton); } mPanelController.addView(findViewById(R.id.applyEffect)); @@ -297,8 +259,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, imageStateList.setAdapter(mMasterImage.getState()); mImageLoader.setAdapter(mMasterImage.getHistory()); - fillListImages(listFilters); - LoadBordersTask loadBorders = new LoadBordersTask(listBorders); + fillListImages((LinearLayout) findViewById(R.id.listFilters)); + LoadBordersTask loadBorders = new LoadBordersTask((LinearLayout) findViewById(R.id.listBorders)); loadBorders.execute(); mPanelController.setRowPanel(findViewById(R.id.secondRowPanel)); @@ -483,22 +445,24 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, h = h * f; bmap = Bitmap.createScaledBitmap(bmap, (int) w, (int) h, true); + LinearLayout listColors = (LinearLayout) findViewById(R.id.listColorsFx); int num_colors_buttons = listColors.getChildCount(); for (int i = 0; i < num_colors_buttons; i++) { FilterIconButton b = (FilterIconButton) listColors.getChildAt(i); - b.setIcon(bmap); } + + LinearLayout listFilters = (LinearLayout) findViewById(R.id.listFilters); int num_filters_buttons = listFilters.getChildCount(); for (int i = 0; i < num_filters_buttons; i++) { FilterIconButton b = (FilterIconButton) listFilters.getChildAt(i); - b.setIcon(bmap); } + + LinearLayout listBorders = (LinearLayout) findViewById(R.id.listBorders); int num_borders_buttons = listBorders.getChildCount(); for (int i = 0; i < num_borders_buttons; i++) { FilterIconButton b = (FilterIconButton) listBorders.getChildAt(i); - b.setIcon(bmap); } @@ -521,9 +485,12 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, if (mLoadBitmapTask != null) { mLoadBitmapTask.cancel(false); } + // TODO: Using singletons is a bad design choice for many of these + // due static reference leaks and in general. Please refactor. MasterImage.reset(); FilteringPipeline.reset(); ImageFilter.resetStatics(); + FiltersManager.reset(); super.onDestroy(); } @@ -799,12 +766,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, // Some utility functions // TODO: finish the cleanup. - public void showOriginalViews(boolean value) { - for (ImageShow views : mImageViews) { - views.showOriginal(value); - } - } - public void invalidateViews() { for (ImageShow views : mImageViews) { views.invalidate(); @@ -812,12 +773,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, } } - public void hideListViews() { - for (View view : mListViews) { - view.setVisibility(View.GONE); - } - } - public void hideImageViews() { for (View view : mImageViews) { view.setVisibility(View.GONE); @@ -825,34 +780,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mEditorPlaceHolder.hide(); } - public void unselectBottomPanelButtons() { - for (ImageButton button : mBottomPanelButtons) { - button.setSelected(false); - } - } - - public void unselectPanelButtons(Vector<ImageButton> buttons) { - for (ImageButton button : buttons) { - button.setSelected(false); - } - } - - public void disableFilterButtons() { - for (ImageButton b : mBottomPanelButtons) { - b.setEnabled(false); - b.setClickable(false); - b.setAlpha(0.4f); - } - } - - public void enableFilterButtons() { - for (ImageButton b : mBottomPanelButtons) { - b.setEnabled(true); - b.setClickable(true); - b.setAlpha(1.0f); - } - } - // ////////////////////////////////////////////////////////////////////////////// // imageState panel... diff --git a/src/com/android/gallery3d/filtershow/PanelController.java b/src/com/android/gallery3d/filtershow/PanelController.java index 5bda246da..3c3de894e 100644 --- a/src/com/android/gallery3d/filtershow/PanelController.java +++ b/src/com/android/gallery3d/filtershow/PanelController.java @@ -46,7 +46,6 @@ public class PanelController implements OnClickListener { private static int HORIZONTAL_MOVE = 1; private static final int ANIM_DURATION = 200; private static final String LOGTAG = "PanelController"; - private boolean mDisableFilterButtons = false; private boolean mFixedAspect = false; public static boolean useAnimations() { @@ -312,10 +311,6 @@ public class PanelController implements OnClickListener { } } - if (mDisableFilterButtons) { - mActivity.enableFilterButtons(); - mDisableFilterButtons = false; - } } public boolean onBackPressed() { @@ -330,12 +325,6 @@ public class PanelController implements OnClickListener { if (mCurrentEditor != null) { mCurrentEditor.reflectCurrentFilter(); } - - if (mDisableFilterButtons) { - mActivity.enableFilterButtons(); - mActivity.resetHistory(); - mDisableFilterButtons = false; - } return false; } @@ -447,6 +436,10 @@ public class PanelController implements OnClickListener { return MasterImage.getImage().getPreset(); } + public void setEffectName(String ename) { + mUtilityPanel.setEffectName(ename); + } + public void useFilterRepresentation(FilterRepresentation filterRepresentation) { if (filterRepresentation == null) { return; @@ -537,10 +530,6 @@ public class PanelController implements OnClickListener { mCurrentImage = showImageView(R.id.imageTinyPlanet); String ename = mCurrentImage.getContext().getString(R.string.tinyplanet); mUtilityPanel.setEffectName(ename); - if (!mDisableFilterButtons) { - mActivity.disableFilterButtons(); - mDisableFilterButtons = true; - } break; } case R.id.straightenButton: { diff --git a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java index 0af406316..9c6415bc9 100644 --- a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java +++ b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java @@ -22,7 +22,6 @@ import android.os.Process; import android.support.v8.renderscript.*; import android.util.Log; -import com.android.gallery3d.filtershow.filters.BaseFiltersManager; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.filters.ImageFilterRS; import com.android.gallery3d.filtershow.imageshow.GeometryMetadata; @@ -250,7 +249,8 @@ public class FilteringPipeline implements Handler.Callback { setPresetParameters(preset); if (request.getType() == RenderingRequest.PARTIAL_RENDERING) { - bitmap = MasterImage.getImage().getImageLoader().getScaleOneImageForPreset(null, preset, request.getBounds(), request.getDestination(), false); + bitmap = MasterImage.getImage().getImageLoader().getScaleOneImageForPreset(null, preset, + request.getBounds(), request.getDestination(), false); if (bitmap == null) { return; } diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java index b502a2ffe..b5ed9eee0 100644 --- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java +++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java @@ -315,6 +315,7 @@ public class ImageLoader { // decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; + o2.inMutable = true; Utils.closeSilently(is); is = mContext.getContentResolver().openInputStream(uri); @@ -376,9 +377,9 @@ public class ImageLoader { mLoadingLock.lock(); Bitmap bmp = mZoomCache.getImage(imagePreset, bounds); if (force || bmp == null) { - BitmapFactory.Options options = null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inMutable = true; if (destination != null) { - options = new BitmapFactory.Options(); if (bounds.width() > destination.width()) { int sampleSize = 1; int w = bounds.width(); diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java index 377bd2b6f..4dbf91a33 100644 --- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java +++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java @@ -13,49 +13,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.gallery3d.filtershow.filters; -import com.android.gallery3d.filtershow.cache.ImageLoader; - import java.util.HashMap; +import java.util.Map; import java.util.Vector; -public class BaseFiltersManager { - - private static final String LOGTAG = "BaseFiltersManager"; - private static HashMap<Class, ImageFilter> mFilters = new HashMap<Class, ImageFilter>(); - - protected BaseFiltersManager() { - Vector<ImageFilter> filters = new Vector<ImageFilter>(); - addFilters(filters); - for (ImageFilter filter : filters) { - mFilters.put(filter.getClass(), filter); - } - } +public abstract class BaseFiltersManager { + protected HashMap<Class, ImageFilter> mFilters = null; - protected void addFilters(Vector<ImageFilter> filters) { - filters.add(new ImageFilterTinyPlanet()); - filters.add(new ImageFilterRedEye()); - filters.add(new ImageFilterWBalance()); - filters.add(new ImageFilterExposure()); - filters.add(new ImageFilterVignette()); - filters.add(new ImageFilterContrast()); - filters.add(new ImageFilterShadows()); - filters.add(new ImageFilterHighlights()); - filters.add(new ImageFilterVibrance()); - filters.add(new ImageFilterSharpen()); - filters.add(new ImageFilterCurves()); - filters.add(new ImageFilterDraw()); - filters.add(new ImageFilterHue()); - filters.add(new ImageFilterSaturated()); - filters.add(new ImageFilterBwFilter()); - filters.add(new ImageFilterNegative()); - filters.add(new ImageFilterEdge()); - filters.add(new ImageFilterKMeans()); - filters.add(new ImageFilterFx()); - filters.add(new ImageFilterBorder()); - filters.add(new ImageFilterParametricBorder()); + protected void addFilters(Map<Class, ImageFilter> filters) { + filters.put(ImageFilterTinyPlanet.class, new ImageFilterTinyPlanet()); + filters.put(ImageFilterRedEye.class, new ImageFilterRedEye()); + filters.put(ImageFilterWBalance.class, new ImageFilterWBalance()); + filters.put(ImageFilterExposure.class, new ImageFilterExposure()); + filters.put(ImageFilterVignette.class, new ImageFilterVignette()); + filters.put(ImageFilterContrast.class, new ImageFilterContrast()); + filters.put(ImageFilterShadows.class, new ImageFilterShadows()); + filters.put(ImageFilterHighlights.class, new ImageFilterHighlights()); + filters.put(ImageFilterVibrance.class, new ImageFilterVibrance()); + filters.put(ImageFilterSharpen.class, new ImageFilterSharpen()); + filters.put(ImageFilterCurves.class, new ImageFilterCurves()); + filters.put(ImageFilterDraw.class, new ImageFilterDraw()); + filters.put(ImageFilterHue.class, new ImageFilterHue()); + filters.put(ImageFilterSaturated.class, new ImageFilterSaturated()); + filters.put(ImageFilterBwFilter.class, new ImageFilterBwFilter()); + filters.put(ImageFilterNegative.class, new ImageFilterNegative()); + filters.put(ImageFilterEdge.class, new ImageFilterEdge()); + filters.put(ImageFilterKMeans.class, new ImageFilterKMeans()); + filters.put(ImageFilterFx.class, new ImageFilterFx()); + filters.put(ImageFilterBorder.class, new ImageFilterBorder()); + filters.put(ImageFilterParametricBorder.class, new ImageFilterParametricBorder()); } public ImageFilter getFilter(Class c) { @@ -79,7 +67,7 @@ public class BaseFiltersManager { } public void addLooks(Vector<FilterRepresentation> representations) { - // subclass can add representations + // Override } public void addEffects(Vector<FilterRepresentation> representations) { diff --git a/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java b/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java index b4ca8e1f1..a2a2e8568 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java +++ b/src/com/android/gallery3d/filtershow/imageshow/EclipseControl.java @@ -158,7 +158,24 @@ public class EclipseControl { } } - void paintPoint(Canvas canvas, float x, float y) { + public void paintGrayPoint(Canvas canvas, float x, float y) { + if (x == Float.NaN) { + return; + } + + Paint paint = new Paint(); + + paint.setStyle(Paint.Style.FILL); + paint.setColor(Color.BLUE); + int[] colors3 = new int[] { + Color.GRAY, Color.LTGRAY, 0x66000000, 0 }; + RadialGradient g = new RadialGradient(x, y, mCenterDotSize, colors3, new float[] { + 0, .3f, .31f, 1 }, Shader.TileMode.CLAMP); + paint.setShader(g); + canvas.drawCircle(x, y, mCenterDotSize, paint); + } + + public void paintPoint(Canvas canvas, float x, float y) { if (x == Float.NaN) { return; } diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java index 39e0cc82b..a52d383f2 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java @@ -289,11 +289,6 @@ public class ImageShow extends View implements OnGestureListener, } } - public void defaultDrawImage(Canvas canvas) { - drawImage(canvas, getFilteredImage()); - drawPartialImage(canvas, getGeometryOnlyImage()); - } - @Override public void onDraw(Canvas canvas) { MasterImage.getImage().setImageShowSize(getWidth(), getHeight()); @@ -306,7 +301,7 @@ public class ImageShow extends View implements OnGestureListener, canvas.scale(scaleFactor, scaleFactor, cx, cy); canvas.translate(translation.x, translation.y); drawBackground(canvas); - defaultDrawImage(canvas); + drawImage(canvas, getFilteredImage()); canvas.restore(); if (showTitle() && getImagePreset() != null) { @@ -326,6 +321,13 @@ public class ImageShow extends View implements OnGestureListener, Rect dest = new Rect(0, 0, getWidth(), getHeight()); canvas.drawBitmap(partialPreview, src, dest, mPaint); } + + canvas.save(); + canvas.scale(scaleFactor, scaleFactor, cx, cy); + canvas.translate(translation.x, translation.y); + drawPartialImage(canvas, getGeometryOnlyImage()); + canvas.restore(); + drawToast(canvas); } @@ -374,7 +376,7 @@ public class ImageShow extends View implements OnGestureListener, canvas.save(); if (image != null) { if (mShowOriginalDirection == 0) { - if ((mTouch.y - mTouchDown.y) > (mTouch.x - mTouchDown.x)) { + if (Math.abs(mTouch.y - mTouchDown.y) > Math.abs(mTouch.x - mTouchDown.x)) { mShowOriginalDirection = UNVEIL_VERTICAL; } else { mShowOriginalDirection = UNVEIL_HORIZONTAL; @@ -397,16 +399,18 @@ public class ImageShow extends View implements OnGestureListener, drawImage(canvas, image); Paint paint = new Paint(); paint.setColor(Color.BLACK); + paint.setStrokeWidth(3); if (mShowOriginalDirection == UNVEIL_VERTICAL) { - canvas.drawLine(mImageBounds.left, mTouch.y - 1, - mImageBounds.right, mTouch.y - 1, paint); + canvas.drawLine(mImageBounds.left, mTouch.y, + mImageBounds.right, mTouch.y, paint); } else { - canvas.drawLine(mTouch.x - 1, mImageBounds.top, - mTouch.x - 1, mImageBounds.bottom, paint); + canvas.drawLine(mTouch.x, mImageBounds.top, + mTouch.x, mImageBounds.bottom, paint); } Rect bounds = new Rect(); + paint.setAntiAlias(true); paint.setTextSize(mOriginalTextSize); paint.getTextBounds(mOriginalText, 0, mOriginalText.length(), bounds); paint.setColor(Color.BLACK); diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java index ae5a03414..1400fd4de 100644 --- a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java +++ b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java @@ -22,7 +22,6 @@ import android.util.Log; import com.android.gallery3d.filtershow.ImageStateAdapter; import com.android.gallery3d.filtershow.cache.ImageLoader; -import com.android.gallery3d.filtershow.filters.BaseFiltersManager; import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.filters.ImageFilter; @@ -428,6 +427,12 @@ public class ImagePreset { if (mGeoData.hasModifications()) { return false; } + if (mBorder != null && !mBorder.supportsPartialRendering()) { + return false; + } + if (ImageLoader.getZoomOrientation() != 0) { + return false; + } for (int i = 0; i < mFilters.size(); i++) { FilterRepresentation representation = null; synchronized (mFilters) { diff --git a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java index e54c83eff..3e52f5ee5 100644 --- a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java +++ b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java @@ -35,7 +35,6 @@ import android.widget.PopupMenu; import com.android.gallery3d.R; import com.android.gallery3d.filtershow.editors.EditorCurves; -import com.android.gallery3d.filtershow.filters.BaseFiltersManager; import com.android.gallery3d.filtershow.filters.FilterCurvesRepresentation; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.filters.ImageFilterCurves; diff --git a/src/com/android/photos/data/PhotoDatabase.java b/src/com/android/photos/data/PhotoDatabase.java new file mode 100644 index 000000000..64a857fcc --- /dev/null +++ b/src/com/android/photos/data/PhotoDatabase.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2013 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.photos.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import com.android.photos.data.PhotoProvider.Albums; +import com.android.photos.data.PhotoProvider.Metadata; +import com.android.photos.data.PhotoProvider.Photos; + +/** + * Used in PhotoProvider to create and access the database containing + * information about photo and video information stored on the server. + */ +public class PhotoDatabase extends SQLiteOpenHelper { + @SuppressWarnings("unused") + private static final String TAG = PhotoDatabase.class.getSimpleName(); + static final String DB_NAME = "photo.db"; + static final int DB_VERSION = 1; + + private static final String SQL_CREATE_TABLE = "CREATE TABLE "; + + private static final String[][] CREATE_PHOTO = { + { Photos._ID, "INTEGER PRIMARY KEY AUTOINCREMENT" }, + { Photos.SERVER_ID, "INTEGER UNIQUE" }, + { Photos.WIDTH, "INTEGER NOT NULL" }, + { Photos.HEIGHT, "INTEGER NOT NULL" }, + { Photos.DATE_TAKEN, "INTEGER NOT NULL" }, + // Photos.ALBUM_ID is a foreign key to Albums._ID + { Photos.ALBUM_ID, "INTEGER" }, + { Photos.MIME_TYPE, "TEXT NOT NULL" }, + }; + + private static final String[][] CREATE_ALBUM = { + { Albums._ID, "INTEGER PRIMARY KEY AUTOINCREMENT" }, + // Albums.PARENT_ID is a foriegn key to Albums._ID + { Albums.PARENT_ID, "INTEGER" }, + { Albums.NAME, "Text NOT NULL" }, + { Albums.VISIBILITY, "INTEGER NOT NULL" }, + { Albums.SERVER_ID, "INTEGER UNIQUE" }, + createUniqueConstraint(Albums.PARENT_ID, Albums.NAME), + }; + + private static final String[][] CREATE_METADATA = { + { Metadata._ID, "INTEGER PRIMARY KEY AUTOINCREMENT" }, + // Metadata.PHOTO_ID is a foreign key to Photos._ID + { Metadata.PHOTO_ID, "INTEGER NOT NULL" }, + { Metadata.KEY, "TEXT NOT NULL" }, + { Metadata.VALUE, "TEXT NOT NULL" }, + createUniqueConstraint(Metadata.PHOTO_ID, Metadata.KEY), + }; + + @Override + public void onCreate(SQLiteDatabase db) { + createTable(db, Albums.TABLE, CREATE_ALBUM); + createTable(db, Photos.TABLE, CREATE_PHOTO); + createTable(db, Metadata.TABLE, CREATE_METADATA); + } + + public PhotoDatabase(Context context) { + super(context, DB_NAME, null, DB_VERSION); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + } + + protected static void createTable(SQLiteDatabase db, String table, String[][] columns) { + StringBuilder create = new StringBuilder(SQL_CREATE_TABLE); + create.append(table).append('('); + boolean first = true; + for (String[] column : columns) { + if (!first) { + create.append(','); + } + first = false; + for (String val: column) { + create.append(val).append(' '); + } + } + create.append(')'); + db.beginTransaction(); + try { + db.execSQL(create.toString()); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + + protected static String[] createUniqueConstraint(String column1, String column2) { + return new String[] { + "UNIQUE(", column1, ",", column2, ")" + }; + } +} diff --git a/src/com/android/photos/data/PhotoProvider.java b/src/com/android/photos/data/PhotoProvider.java new file mode 100644 index 000000000..eefa37349 --- /dev/null +++ b/src/com/android/photos/data/PhotoProvider.java @@ -0,0 +1,514 @@ +/* + * Copyright (C) 2013 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.photos.data; + +import android.content.ContentProvider; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteStatement; +import android.net.Uri; +import android.os.CancellationSignal; +import android.provider.BaseColumns; + +import java.util.ArrayList; +import java.util.List; + +/** + * A provider that gives access to photo and video information for media stored + * on the server. Only media that is or will be put on the server will be + * accessed by this provider. Use Photos.CONTENT_URI to query all photos and + * videos. Use Albums.CONTENT_URI to query all albums. Use Metadata.CONTENT_URI + * to query metadata about a photo or video, based on the ID of the media. Use + * ImageCache.THUMBNAIL_CONTENT_URI, ImageCache.PREVIEW_CONTENT_URI, or + * ImageCache.ORIGINAL_CONTENT_URI to query the path of the thumbnail, preview, + * or original-sized image respectfully. <br/> + * To add or update metadata, use the update function rather than insert. All + * values for the metadata must be in the ContentValues, even if they are also + * in the selection. The selection and selectionArgs are not used when updating + * metadata. If the metadata values are null, the row will be deleted. + */ +public class PhotoProvider extends ContentProvider { + @SuppressWarnings("unused") + private static final String TAG = PhotoProvider.class.getSimpleName(); + static final String AUTHORITY = "com.android.gallery3d.photoprovider"; + static final Uri BASE_CONTENT_URI = new Uri.Builder().scheme("content").authority(AUTHORITY) + .build(); + + /** + * Contains columns that can be accessed via PHOTOS_CONTENT_URI. + */ + public static interface Photos extends BaseColumns { + /** + * Internal database table used for basic photo information. + */ + public static final String TABLE = "photo"; + /** + * Content URI for basic photo and video information. + */ + public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE); + /** + * Identifier used on the server. Long value. + */ + public static final String SERVER_ID = "server_id"; + /** + * Column name for the width of the original image. Integer value. + */ + public static final String WIDTH = "width"; + /** + * Column name for the height of the original image. Integer value. + */ + public static final String HEIGHT = "height"; + /** + * Column name for the date that the original image was taken. Long + * value indicating the milliseconds since epoch in the GMT time zone. + */ + public static final String DATE_TAKEN = "date_taken"; + /** + * Column name indicating the long value of the album id that this image + * resides in. Will be NULL if it it has not been uploaded to the + * server. + */ + public static final String ALBUM_ID = "album_id"; + /** + * The column name for the mime-type String. + */ + public static final String MIME_TYPE = "mime_type"; + } + + /** + * Contains columns and Uri for accessing album information. + */ + public static interface Albums extends BaseColumns { + /** + * Internal database table used album information. + */ + public static final String TABLE = "album"; + /** + * Content URI for album information. + */ + public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE); + /** + * Parent directory or null if this is in the root. + */ + public static final String PARENT_ID = "parent"; + /** + * Column name for the name of the album. String value. + */ + public static final String NAME = "name"; + /** + * Column name for the visibility level of the album. Can be any of the + * VISIBILITY_* values. + */ + public static final String VISIBILITY = "visibility"; + /** + * Column name for the server identifier for this album. NULL if the + * server doesn't have this album yet. + */ + public static final String SERVER_ID = "server_id"; + + // Privacy values for Albums.VISIBILITY + public static final int VISIBILITY_PRIVATE = 1; + public static final int VISIBILITY_SHARED = 2; + public static final int VISIBILITY_PUBLIC = 3; + } + + /** + * Contains columns and Uri for accessing photo and video metadata + */ + public static interface Metadata extends BaseColumns { + /** + * Internal database table used metadata information. + */ + public static final String TABLE = "metadata"; + /** + * Content URI for photo and video metadata. + */ + public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE); + /** + * Foreign key to photo_id. Long value. + */ + public static final String PHOTO_ID = "photo_id"; + /** + * Metadata key. String value + */ + public static final String KEY = "key"; + /** + * Metadata value. Type is based on key. + */ + public static final String VALUE = "value"; + } + + /** + * Contains columns and Uri for maintaining the image cache. + */ + public static interface ImageCache extends BaseColumns { + /** + * Internal database table used for the image cache + */ + public static final String TABLE = "image_cache"; + + /** + * The image_type query parameter required for accessing a specific + * image + */ + public static final String IMAGE_TYPE_QUERY_PARAMETER = "image_type"; + + // ImageCache.IMAGE_TYPE values + public static final int IMAGE_TYPE_THUMBNAIL = 1; + public static final int IMAGE_TYPE_PREVIEW = 2; + public static final int IMAGE_TYPE_ORIGINAL = 3; + + /** + * Content URI for retrieving image paths. The + * IMAGE_TYPE_QUERY_PARAMETER must be used in queries. + */ + public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE); + + /** + * Foreign key to the photos._id. Long value. + */ + public static final String PHOTO_ID = "photos_id"; + /** + * One of IMAGE_TYPE_* values. + */ + public static final String IMAGE_TYPE = "image_type"; + /** + * The String path to the image. + */ + public static final String PATH = "path"; + }; + + // SQL used within this class. + protected static final String WHERE_ID = BaseColumns._ID + " = ?"; + protected static final String WHERE_METADATA_ID = Metadata.PHOTO_ID + " = ? AND " + + Metadata.KEY + " = ?"; + + protected static final String SELECT_ALBUM_ID = "SELECT " + Albums._ID + " FROM " + + Albums.TABLE; + protected static final String SELECT_PHOTO_ID = "SELECT " + Photos._ID + " FROM " + + Photos.TABLE; + protected static final String SELECT_PHOTO_COUNT = "SELECT COUNT(*) FROM " + Photos.TABLE; + protected static final String DELETE_PHOTOS = "DELETE FROM " + Photos.TABLE; + protected static final String DELETE_METADATA = "DELETE FROM " + Metadata.TABLE; + protected static final String SELECT_METADATA_COUNT = "SELECT COUNT(*) FROM " + Metadata.TABLE; + protected static final String WHERE = " WHERE "; + protected static final String IN = " IN "; + protected static final String NESTED_SELECT_START = "("; + protected static final String NESTED_SELECT_END = ")"; + + /** + * For selecting the mime-type for an image. + */ + private static final String[] PROJECTION_MIME_TYPE = { + Photos.MIME_TYPE, + }; + + private SQLiteOpenHelper mOpenHelper; + protected static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + + protected static final int MATCH_PHOTO = 1; + protected static final int MATCH_PHOTO_ID = 2; + protected static final int MATCH_ALBUM = 3; + protected static final int MATCH_ALBUM_ID = 4; + protected static final int MATCH_METADATA = 5; + protected static final int MATCH_METADATA_ID = 6; + protected static final int MATCH_IMAGE = 7; + + static { + sUriMatcher.addURI(AUTHORITY, Photos.TABLE, MATCH_PHOTO); + // match against Photos._ID + sUriMatcher.addURI(AUTHORITY, Photos.TABLE + "/#", MATCH_PHOTO_ID); + sUriMatcher.addURI(AUTHORITY, Albums.TABLE, MATCH_ALBUM); + // match against Albums._ID + sUriMatcher.addURI(AUTHORITY, Albums.TABLE + "/#", MATCH_ALBUM_ID); + sUriMatcher.addURI(AUTHORITY, Metadata.TABLE, MATCH_METADATA); + // match against metadata/<Metadata._ID> + sUriMatcher.addURI(AUTHORITY, Metadata.TABLE + "/#", MATCH_METADATA_ID); + // match against image_cache/<ImageCache.PHOTO_ID> + sUriMatcher.addURI(AUTHORITY, ImageCache.TABLE + "/#", MATCH_IMAGE); + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + int match = matchUri(uri); + if (match == MATCH_IMAGE) { + throw new IllegalArgumentException("Cannot delete from image cache"); + } + selection = addIdToSelection(match, selection); + selectionArgs = addIdToSelectionArgs(match, uri, selectionArgs); + List<Uri> changeUris = new ArrayList<Uri>(); + int deleted = 0; + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + db.beginTransaction(); + try { + deleted = deleteCascade(db, match, selection, selectionArgs, changeUris, uri); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + for (Uri changeUri : changeUris) { + notifyChanges(changeUri); + } + return deleted; + } + + @Override + public String getType(Uri uri) { + Cursor cursor = query(uri, PROJECTION_MIME_TYPE, null, null, null); + String mimeType = null; + if (cursor.moveToNext()) { + mimeType = cursor.getString(0); + } + cursor.close(); + return mimeType; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + // Cannot insert into this ContentProvider + return null; + } + + @Override + public boolean onCreate() { + mOpenHelper = createDatabaseHelper(); + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return query(uri, projection, selection, selectionArgs, sortOrder, null); + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder, CancellationSignal cancellationSignal) { + int match = matchUri(uri); + selection = addIdToSelection(match, selection); + selectionArgs = addIdToSelectionArgs(match, uri, selectionArgs); + String table = getTableFromMatch(match, uri); + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + return db.query(false, table, projection, selection, selectionArgs, null, null, sortOrder, + null, cancellationSignal); + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + int match = matchUri(uri); + int rowsUpdated = 0; + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + db.beginTransaction(); + try { + if (match == MATCH_METADATA) { + rowsUpdated = modifyMetadata(db, values); + } else { + selection = addIdToSelection(match, selection); + selectionArgs = addIdToSelectionArgs(match, uri, selectionArgs); + String table = getTableFromMatch(match, uri); + rowsUpdated = db.update(table, values, selection, selectionArgs); + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + notifyChanges(uri); + return rowsUpdated; + } + + protected static String addIdToSelection(int match, String selection) { + String where; + switch (match) { + case MATCH_PHOTO_ID: + case MATCH_ALBUM_ID: + case MATCH_METADATA_ID: + where = WHERE_ID; + break; + default: + return selection; + } + return DatabaseUtils.concatenateWhere(selection, where); + } + + protected static String[] addIdToSelectionArgs(int match, Uri uri, String[] selectionArgs) { + String[] whereArgs; + switch (match) { + case MATCH_PHOTO_ID: + case MATCH_ALBUM_ID: + case MATCH_METADATA_ID: + whereArgs = new String[] { + uri.getPathSegments().get(1), + }; + break; + default: + return selectionArgs; + } + return DatabaseUtils.appendSelectionArgs(selectionArgs, whereArgs); + } + + protected static String[] addMetadataKeysToSelectionArgs(String[] selectionArgs, Uri uri) { + List<String> segments = uri.getPathSegments(); + String[] additionalArgs = { + segments.get(1), + segments.get(2), + }; + + return DatabaseUtils.appendSelectionArgs(selectionArgs, additionalArgs); + } + + protected static String getTableFromMatch(int match, Uri uri) { + String table; + switch (match) { + case MATCH_PHOTO: + case MATCH_PHOTO_ID: + table = Photos.TABLE; + break; + case MATCH_ALBUM: + case MATCH_ALBUM_ID: + table = Albums.TABLE; + break; + case MATCH_METADATA: + case MATCH_METADATA_ID: + table = Metadata.TABLE; + break; + default: + throw unknownUri(uri); + } + return table; + } + + protected final SQLiteOpenHelper getDatabaseHelper() { + return mOpenHelper; + } + + protected SQLiteOpenHelper createDatabaseHelper() { + return new PhotoDatabase(getContext()); + } + + private int modifyMetadata(SQLiteDatabase db, ContentValues values) { + String[] selectionArgs = { + values.getAsString(Metadata.PHOTO_ID), + values.getAsString(Metadata.KEY), + }; + int rowCount; + if (values.get(Metadata.VALUE) == null) { + rowCount = db.delete(Metadata.TABLE, WHERE_METADATA_ID, selectionArgs); + } else { + rowCount = (int) DatabaseUtils.queryNumEntries(db, Metadata.TABLE, WHERE_METADATA_ID, + selectionArgs); + if (rowCount > 0) { + db.update(Metadata.TABLE, values, WHERE_METADATA_ID, selectionArgs); + } else { + db.insert(Metadata.TABLE, null, values); + rowCount = 1; + } + } + return rowCount; + } + + private int matchUri(Uri uri) { + int match = sUriMatcher.match(uri); + if (match == UriMatcher.NO_MATCH) { + throw unknownUri(uri); + } + return match; + } + + protected void notifyChanges(Uri uri) { + ContentResolver resolver = getContext().getContentResolver(); + resolver.notifyChange(uri, null, false); + } + + protected static IllegalArgumentException unknownUri(Uri uri) { + return new IllegalArgumentException("Unknown Uri format: " + uri); + } + + protected static String nestSql(String base, String columnMatch, String nested) { + StringBuilder sql = new StringBuilder(base); + sql.append(WHERE); + sql.append(columnMatch); + sql.append(IN); + sql.append(NESTED_SELECT_START); + sql.append(nested); + sql.append(NESTED_SELECT_END); + return sql.toString(); + } + + protected static String addWhere(String base, String where) { + if (where == null || where.isEmpty()) { + return base; + } + return base + WHERE + where; + } + + protected static int deleteCascade(SQLiteDatabase db, int match, String selection, + String[] selectionArgs, List<Uri> changeUris, Uri uri) { + switch (match) { + case MATCH_PHOTO: + case MATCH_PHOTO_ID: { + String selectPhotoIdsSql = addWhere(SELECT_PHOTO_ID, selection); + deleteCascadeMetadata(db, selectPhotoIdsSql, selectionArgs, changeUris); + break; + } + case MATCH_ALBUM: + case MATCH_ALBUM_ID: { + String selectAlbumIdSql = addWhere(SELECT_ALBUM_ID, selection); + deleteCascadePhotos(db, selectAlbumIdSql, selectionArgs, changeUris); + break; + } + } + String table = getTableFromMatch(match, uri); + changeUris.add(uri); + return db.delete(table, selection, selectionArgs); + } + + protected static void execSql(SQLiteDatabase db, String sql, String[] args) { + if (args == null) { + db.execSQL(sql); + } else { + db.execSQL(sql, args); + } + } + + private static void deleteCascadePhotos(SQLiteDatabase db, String albumSelect, + String[] selectArgs, List<Uri> changeUris) { + String selectPhotoIdSql = nestSql(SELECT_PHOTO_ID, Photos.ALBUM_ID, albumSelect); + deleteCascadeMetadata(db, selectPhotoIdSql, selectArgs, changeUris); + String deletePhotoSql = nestSql(DELETE_PHOTOS, Photos.ALBUM_ID, albumSelect); + SQLiteStatement statement = db.compileStatement(deletePhotoSql); + statement.bindAllArgsAsStrings(selectArgs); + int deleted = statement.executeUpdateDelete(); + if (deleted > 0) { + changeUris.add(Photos.CONTENT_URI); + } + } + + private static void deleteCascadeMetadata(SQLiteDatabase db, String photosSelect, + String[] selectArgs, List<Uri> changeUris) { + String deleteMetadataSql = nestSql(DELETE_METADATA, Metadata.PHOTO_ID, photosSelect); + SQLiteStatement statement = db.compileStatement(deleteMetadataSql); + statement.bindAllArgsAsStrings(selectArgs); + int deleted = statement.executeUpdateDelete(); + if (deleted > 0) { + changeUris.add(Metadata.CONTENT_URI); + } + } +} |