diff options
Diffstat (limited to 'src/com/android')
68 files changed, 1392 insertions, 431 deletions
diff --git a/src/com/android/camera/MosaicFrameProcessor.java b/src/com/android/camera/MosaicFrameProcessor.java index c59e6b91b..efd4ad2ae 100644 --- a/src/com/android/camera/MosaicFrameProcessor.java +++ b/src/com/android/camera/MosaicFrameProcessor.java @@ -92,7 +92,8 @@ public class MosaicFrameProcessor { mPreviewBufferSize = bufSize; setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize); setStripType(Mosaic.STRIPTYPE_WIDE); - reset(); + // no need to call reset() here. reset() should be called by the client + // after this initialization before calling other methods of this object. } public void clear() { diff --git a/src/com/android/camera/MosaicPreviewRenderer.java b/src/com/android/camera/MosaicPreviewRenderer.java index e12fe432e..26ce733aa 100644 --- a/src/com/android/camera/MosaicPreviewRenderer.java +++ b/src/com/android/camera/MosaicPreviewRenderer.java @@ -90,6 +90,7 @@ public class MosaicPreviewRenderer { break; case MSG_RELEASE: doRelease(); + mEglThreadBlockVar.open(); break; } } @@ -203,7 +204,7 @@ public class MosaicPreviewRenderer { } public void release() { - mEglHandler.sendEmptyMessage(EGLHandler.MSG_RELEASE); + mEglHandler.sendMessageSync(EGLHandler.MSG_RELEASE); } public void showPreviewFrameSync() { diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 8d84e0074..b7bd20831 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -651,7 +651,7 @@ public class VideoModule implements CameraModule, if (mQuickCapture) { doReturnToCaller(!recordFail); } else if (!recordFail) { - showAlert(); + showCaptureResult(); } } } else if (!recordFail){ @@ -1657,14 +1657,14 @@ public class VideoModule implements CameraModule, } } - private void showAlert() { + private void showCaptureResult() { Bitmap bitmap = null; if (mVideoFileDescriptor != null) { bitmap = Thumbnail.createVideoThumbnailBitmap(mVideoFileDescriptor.getFileDescriptor(), - mPreviewFrameLayout.getWidth()); + mDesiredPreviewWidth); } else if (mCurrentVideoFilename != null) { bitmap = Thumbnail.createVideoThumbnailBitmap(mCurrentVideoFilename, - mPreviewFrameLayout.getWidth()); + mDesiredPreviewWidth); } if (bitmap != null) { // MetadataRetriever already rotates the thumbnail. We should rotate @@ -2052,7 +2052,7 @@ public class VideoModule implements CameraModule, if (mQuickCapture) { doReturnToCaller(true); } else { - showAlert(); + showCaptureResult(); } } } @@ -2175,6 +2175,7 @@ public class VideoModule implements CameraModule, mShutterButton = mActivity.getShutterButton(); mShutterButton.setImageResource(R.drawable.btn_new_shutter_video); mShutterButton.setOnShutterButtonListener(this); + mShutterButton.setVisibility(View.VISIBLE); mShutterButton.requestFocus(); mShutterButton.enableTouch(true); @@ -2202,7 +2203,6 @@ public class VideoModule implements CameraModule, @Override public void onConfigurationChanged(Configuration newConfig) { setDisplayOrientation(); - // Change layout in response to configuration change LayoutInflater inflater = mActivity.getLayoutInflater(); ((ViewGroup) mRootView).removeAllViews(); @@ -2222,6 +2222,9 @@ public class VideoModule implements CameraModule, initializeZoom(); onFullScreenChanged(mActivity.isInCameraApp()); updateOnScreenIndicators(); + if (mIsVideoCaptureIntent && mVideoFileDescriptor != null) { + showCaptureResult(); + } } @Override diff --git a/src/com/android/gallery3d/app/CommonControllerOverlay.java b/src/com/android/gallery3d/app/CommonControllerOverlay.java index 089872fa5..a5aa805ef 100644 --- a/src/com/android/gallery3d/app/CommonControllerOverlay.java +++ b/src/com/android/gallery3d/app/CommonControllerOverlay.java @@ -274,10 +274,6 @@ public abstract class CommonControllerOverlay extends FrameLayout implements mBackground.layout(0, y - mTimeBar.getBarHeight(), w, y); mTimeBar.layout(pl, y - mTimeBar.getPreferredHeight(), w - pr, y); - // Needed, otherwise the framework will not re-layout in case only the - // padding is changed - mTimeBar.requestLayout(); - // Put the play/pause/next/ previous button in the center of the screen layoutCenteredView(mPlayPauseReplayView, 0, 0, w, h); diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java index d7ec4c1bd..0660eda30 100644 --- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -16,7 +16,6 @@ package com.android.gallery3d.filtershow; -import android.annotation.TargetApi; import android.app.ActionBar; import android.app.Activity; import android.app.ProgressDialog; @@ -30,7 +29,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.Point; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; @@ -98,7 +96,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, private final PanelController mPanelController = new PanelController(); private ImageLoader mImageLoader = null; private ImageShow mImageShow = null; - private ImageRedEye mImageRedEye = null; private ImageDraw mImageDraw = null; private ImageStraighten mImageStraighten = null; private ImageCrop mImageCrop = null; @@ -201,7 +198,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mImageRotate = (ImageRotate) findViewById(R.id.imageRotate); mImageFlip = (ImageFlip) findViewById(R.id.imageFlip); mImageTinyPlanet = (ImageTinyPlanet) findViewById(R.id.imageTinyPlanet); - mImageRedEye = (ImageRedEye) findViewById(R.id.imageRedEyes); mImageDraw = (ImageDraw) findViewById(R.id.imageDraw); mImageCrop.setAspectTextSize((int) getPixelsFromDip(18)); @@ -213,7 +209,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mImageViews.add(mImageRotate); mImageViews.add(mImageFlip); mImageViews.add(mImageTinyPlanet); - mImageViews.add(mImageRedEye); mEditorPlaceHolder.setContainer((FrameLayout) findViewById(R.id.editorContainer)); mEditorPlaceHolder.addEditor(new EditorDraw()); @@ -254,7 +249,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mImageRotate.setImageLoader(mImageLoader); mImageFlip.setImageLoader(mImageLoader); mImageTinyPlanet.setImageLoader(mImageLoader); - mImageRedEye.setImageLoader(mImageLoader); mImageDraw.setImageLoader(mImageLoader); mPanelController.setActivity(this); @@ -266,7 +260,6 @@ 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.imageRedEyes)); mPanelController.addImageView(findViewById(R.id.imageDraw)); mPanelController.addPanel(mFxButton, mListFx, 0); @@ -277,17 +270,18 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mPanelController.addComponent(mGeometryButton, findViewById(R.id.cropButton)); mPanelController.addComponent(mGeometryButton, findViewById(R.id.rotateButton)); mPanelController.addComponent(mGeometryButton, findViewById(R.id.flipButton)); - mPanelController.addComponent(mGeometryButton, findViewById(R.id.redEyeButton)); mPanelController.addPanel(mColorsButton, mListColors, 3); Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>(); - FiltersManager.addFilterRepresentations(filtersRepresentations); + + FiltersManager filtersManager = FiltersManager.getManager(); + filtersManager.addEffects(filtersRepresentations); + for (FilterRepresentation representation : filtersRepresentations) { setupFilterRepresentationButton(representation, listColors, mColorsButton); } - mPanelController.addView(findViewById(R.id.applyEffect)); findViewById(R.id.resetOperationsButton).setOnClickListener( createOnClickResetOperationsButton()); @@ -775,6 +769,12 @@ public class FilterShowActivity extends Activity implements OnItemClickListener, mNullFxFilter = setupFilterRepresentationButton(nullFx, listFilters, mFxButton); mNullFxFilter.setSelected(true); + Vector<FilterRepresentation> filtersRepresentations = new Vector<FilterRepresentation>(); + FiltersManager.getManager().addLooks(filtersRepresentations); + for (FilterRepresentation representation : filtersRepresentations) { + setupFilterRepresentationButton(representation, listFilters, mFxButton); + } + for (int i = 0; i < p; i++) { setupFilterRepresentationButton(fxArray[i], listFilters, mFxButton); } diff --git a/src/com/android/gallery3d/filtershow/ImageStateAdapter.java b/src/com/android/gallery3d/filtershow/ImageStateAdapter.java index 5de96961c..58e0035bc 100644 --- a/src/com/android/gallery3d/filtershow/ImageStateAdapter.java +++ b/src/com/android/gallery3d/filtershow/ImageStateAdapter.java @@ -24,9 +24,10 @@ import android.widget.ArrayAdapter; import android.widget.TextView; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.filters.ImageFilter; -public class ImageStateAdapter extends ArrayAdapter<ImageFilter> { +public class ImageStateAdapter extends ArrayAdapter<FilterRepresentation> { private static final String LOGTAG = "ImageStateAdapter"; public ImageStateAdapter(Context context, int textViewResourceId) { @@ -41,13 +42,12 @@ public class ImageStateAdapter extends ArrayAdapter<ImageFilter> { Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.filtershow_imagestate_row, null); } - ImageFilter filter = getItem(position); + FilterRepresentation filter = getItem(position); if (filter != null) { TextView itemLabel = (TextView) view.findViewById(R.id.imagestate_label); itemLabel.setText(filter.getName()); TextView itemParameter = (TextView) view.findViewById(R.id.imagestate_parameter); - // TODO: fix the image state adapter - // itemParameter.setText("" + filter.getParameter()); + itemParameter.setText(filter.getStateRepresentation()); } return view; } diff --git a/src/com/android/gallery3d/filtershow/PanelController.java b/src/com/android/gallery3d/filtershow/PanelController.java index 561ac6c81..18a9585a6 100644 --- a/src/com/android/gallery3d/filtershow/PanelController.java +++ b/src/com/android/gallery3d/filtershow/PanelController.java @@ -445,49 +445,6 @@ public class PanelController implements OnClickListener { return MasterImage.getImage().getPreset(); } - /** - public ImageFilter setImagePreset(ImageFilter filter, String name) { - ImagePreset copy = new ImagePreset(getImagePreset()); - copy.add(filter); - copy.setHistoryName(name); - copy.setIsFx(false); - mMasterImage.setPreset(copy, true); - return filter; - } - */ - - // TODO: remove this. - public void ensureFilter(String name) { - /* - ImagePreset preset = getImagePreset(); - ImageFilter filter = preset.getFilter(name); - if (filter != null) { - // If we already have a filter, we might still want - // to push it onto the history stack. - ImagePreset copy = new ImagePreset(getImagePreset()); - copy.setHistoryName(name); - mMasterImage.setPreset(copy, true); - filter = copy.getFilter(name); - } - - if (filter == null) { - ImageFilter filterInstance = mFilters.get(name); - if (filterInstance != null) { - try { - ImageFilter newFilter = filterInstance.clone(); - newFilter.reset(); - filter = setImagePreset(newFilter, name); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - } - } - if (filter != null) { - mMasterImage.setCurrentFilter(filter); - } - */ - } - public void useFilterRepresentation(FilterRepresentation filterRepresentation) { if (filterRepresentation == null) { return; @@ -502,7 +459,7 @@ public class PanelController implements OnClickListener { copy.addFilter(filterRepresentation); } else { if (filterRepresentation.allowsMultipleInstances()) { - representation.useParametersFrom(filterRepresentation); + representation.updateTempParametersFrom(filterRepresentation); copy.setHistoryName(filterRepresentation.getName()); } filterRepresentation = representation; @@ -579,7 +536,6 @@ public class PanelController implements OnClickListener { mCurrentImage = showImageView(R.id.imageTinyPlanet).setShowControls(true); String ename = mCurrentImage.getContext().getString(R.string.tinyplanet); mUtilityPanel.setEffectName(ename); - ensureFilter(ename); if (!mDisableFilterButtons) { mActivity.disableFilterButtons(); mDisableFilterButtons = true; @@ -617,13 +573,6 @@ public class PanelController implements OnClickListener { mUtilityPanel.setShowParameter(false); break; } - case R.id.redEyeButton: { - mCurrentImage = showImageView(R.id.imageRedEyes).setShowControls(true); - String ename = mCurrentImage.getContext().getString(R.string.redeye); - mUtilityPanel.setEffectName(ename); - ensureFilter(ename); - break; - } case R.id.applyEffect: { if (MasterImage.getImage().getCurrentFilter() instanceof ImageFilterTinyPlanet) { mActivity.saveImage(); diff --git a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java index 472fad759..419abe85d 100644 --- a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java +++ b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java @@ -22,6 +22,8 @@ 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; import com.android.gallery3d.filtershow.imageshow.MasterImage; @@ -136,6 +138,10 @@ public class FilteringPipeline implements Handler.Callback { return false; } + if (DEBUG) { + Log.v(LOGTAG, "geometry has changed"); + } + RenderScript RS = ImageFilterRS.getRenderScriptContext(); if (mFiltersOnlyOriginalAllocation != null) { mFiltersOnlyOriginalAllocation.destroy(); @@ -151,6 +157,7 @@ public class FilteringPipeline implements Handler.Callback { mPreviousGeometry = new GeometryMetadata(geometry); + FiltersManager.getManager().resetBitmapsRS(); return true; } @@ -184,20 +191,44 @@ public class FilteringPipeline implements Handler.Callback { private void setPresetParameters(ImagePreset preset) { preset.setScaleFactor(mPreviewScaleFactor); if (mPreviewScaleFactor < 1.0f) { - preset.setIsHighQuality(false); + preset.setQuality(ImagePreset.QUALITY_PREVIEW); } else { - preset.setIsHighQuality(true); + preset.setQuality(ImagePreset.QUALITY_PREVIEW); } } + private String getType(RenderingRequest request) { + if (request.getType() == RenderingRequest.ICON_RENDERING) { + return "ICON_RENDERING"; + } + if (request.getType() == RenderingRequest.FILTERS_RENDERING) { + return "FILTERS_RENDERING"; + } + if (request.getType() == RenderingRequest.FULL_RENDERING) { + return "FULL_RENDERING"; + } + if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) { + return "GEOMETRY_RENDERING"; + } + return "UNKNOWN TYPE!"; + } + private void render(RenderingRequest request) { if (request.getBitmap() == null || request.getImagePreset() == null) { return; } + if (DEBUG) { + Log.v(LOGTAG, "render image of type " + getType(request)); + } + Bitmap bitmap = request.getBitmap(); ImagePreset preset = request.getImagePreset(); setPresetParameters(preset); + if (request.getType() == RenderingRequest.FILTERS_RENDERING) { + FiltersManager.getManager().resetBitmapsRS(); + } + if (request.getType() != RenderingRequest.ICON_RENDERING) { updateOriginalAllocation(preset); } @@ -218,6 +249,9 @@ public class FilteringPipeline implements Handler.Callback { Bitmap bmp = preset.apply(bitmap); request.setBitmap(bmp); } + if (request.getType() == RenderingRequest.FILTERS_RENDERING) { + FiltersManager.getManager().resetBitmapsRS(); + } } private void compute(TripleBufferBitmap buffer, ImagePreset preset, int type) { diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java index b47d13b9e..00fcf4e19 100644 --- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java +++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java @@ -280,7 +280,7 @@ public class ImageLoader { return null; } - static final int MAX_BITMAP_DIM = 2048; + static final int MAX_BITMAP_DIM = 900; private Bitmap loadScaledBitmap(Uri uri, int size) { InputStream is = null; @@ -392,7 +392,7 @@ public class ImageLoader { public void saveImage(ImagePreset preset, final FilterShowActivity filterShowActivity, File destination) { - preset.setIsHighQuality(true); + preset.setQuality(ImagePreset.QUALITY_FINAL); preset.setScaleFactor(1.0f); new SaveCopyTask(mContext, mUri, destination, new SaveCopyTask.Callback() { @@ -432,7 +432,7 @@ public class ImageLoader { public void returnFilteredResult(ImagePreset preset, final FilterShowActivity filterShowActivity) { - preset.setIsHighQuality(true); + preset.setQuality(ImagePreset.QUALITY_FINAL); preset.setScaleFactor(1.0f); BitmapTask.Callbacks<ImagePreset> cb = new BitmapTask.Callbacks<ImagePreset>() { @@ -448,7 +448,7 @@ public class ImageLoader { @Override public Bitmap onExecute(ImagePreset param) { - if (param == null) { + if (param == null || mUri == null) { return null; } Bitmap bitmap = loadMutableBitmap(mContext, mUri); diff --git a/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java b/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java index 2815936f8..1e9f6b83a 100644 --- a/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java +++ b/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java @@ -18,6 +18,7 @@ package com.android.gallery3d.filtershow.cache; import android.graphics.Bitmap; import com.android.gallery3d.app.Log; +import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.presets.ImagePreset; public class RenderingRequest { @@ -47,7 +48,9 @@ public class RenderingRequest { bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), mConfig); } request.setBitmap(bitmap); - request.setImagePreset(new ImagePreset(preset)); + ImagePreset passedPreset = new ImagePreset(preset); + passedPreset.setImageLoader(MasterImage.getImage().getImageLoader()); + request.setImagePreset(passedPreset); request.setType(type); request.setCaller(caller); request.post(); diff --git a/src/com/android/gallery3d/filtershow/editors/BasicEditor.java b/src/com/android/gallery3d/filtershow/editors/BasicEditor.java index b7f5d7d26..48aa5925a 100644 --- a/src/com/android/gallery3d/filtershow/editors/BasicEditor.java +++ b/src/com/android/gallery3d/filtershow/editors/BasicEditor.java @@ -65,7 +65,7 @@ public class BasicEditor extends Editor implements OnSeekBarChangeListener { if (getLocalRepresentation() != null && getLocalRepresentation() instanceof FilterBasicRepresentation) { FilterBasicRepresentation interval = (FilterBasicRepresentation) getLocalRepresentation(); boolean f = interval.showParameterValue(); - mSeekBar.setVisibility((f) ? View.VISIBLE : View.INVISIBLE); + mSeekBar.setVisibility((f) ? View.VISIBLE : View.GONE); int value = interval.getValue(); int min = interval.getMinimum(); int max = interval.getMaximum(); diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java index 128af8ec7..aa5ec61e8 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java @@ -120,6 +120,10 @@ public class EditorDraw extends Editor { } else if (item.getItemId() == R.id.draw_menu_style_line) { ImageDraw idraw = (ImageDraw) mImageShow; idraw.setStyle(ImageFilterDraw.SIMPLE_STYLE); + } else if (item.getItemId() == R.id.draw_menu_clear) { + ImageDraw idraw = (ImageDraw) mImageShow; + idraw.resetParameter(); + commitLocalRepresentation(); } mView.invalidate(); return true; diff --git a/src/com/android/gallery3d/filtershow/editors/EditorRedEye.java b/src/com/android/gallery3d/filtershow/editors/EditorRedEye.java index 271f16535..c37102b37 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorRedEye.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorRedEye.java @@ -51,10 +51,10 @@ public class EditorRedEye extends Editor { @Override public void reflectCurrentFilter() { super.reflectCurrentFilter(); - FilterRepresentation rep = getLocalRepresentation(); if (rep != null && getLocalRepresentation() instanceof FilterRedEyeRepresentation) { FilterRedEyeRepresentation redEyeRep = (FilterRedEyeRepresentation) rep; + mImageRedEyes.setRepresentation(redEyeRep); } } diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java new file mode 100644 index 000000000..43660d6a0 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java @@ -0,0 +1,113 @@ +/* + * 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.gallery3d.filtershow.filters; + +import com.android.gallery3d.filtershow.cache.ImageLoader; + +import java.util.HashMap; +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); + } + } + + 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 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()); + } + + public ImageFilter getFilter(Class c) { + return mFilters.get(c); + } + + public ImageFilter getFilterForRepresentation(FilterRepresentation representation) { + return mFilters.get(representation.getFilterClass()); + } + + public void addFilter(Class filterClass, ImageFilter filter) { + mFilters.put(filterClass, filter); + } + + public FilterRepresentation getRepresentation(Class c) { + ImageFilter filter = mFilters.get(c); + if (filter != null) { + return filter.getDefaultRepresentation(); + } + return null; + } + + public void addLooks(Vector<FilterRepresentation> representations) { + // subclass can add representations + } + + public void addEffects(Vector<FilterRepresentation> representations) { + representations.add(getRepresentation(ImageFilterTinyPlanet.class)); + representations.add(getRepresentation(ImageFilterRedEye.class)); + representations.add(getRepresentation(ImageFilterWBalance.class)); + representations.add(getRepresentation(ImageFilterExposure.class)); + representations.add(getRepresentation(ImageFilterVignette.class)); + representations.add(getRepresentation(ImageFilterContrast.class)); + representations.add(getRepresentation(ImageFilterShadows.class)); + representations.add(getRepresentation(ImageFilterVibrance.class)); + representations.add(getRepresentation(ImageFilterSharpen.class)); + representations.add(getRepresentation(ImageFilterCurves.class)); + representations.add(getRepresentation(ImageFilterDraw.class)); + representations.add(getRepresentation(ImageFilterHue.class)); + representations.add(getRepresentation(ImageFilterSaturated.class)); + representations.add(getRepresentation(ImageFilterBwFilter.class)); + representations.add(getRepresentation(ImageFilterNegative.class)); + representations.add(getRepresentation(ImageFilterEdge.class)); + representations.add(getRepresentation(ImageFilterKMeans.class)); + } + + public void resetBitmapsRS() { + for (Class c : mFilters.keySet()) { + ImageFilter filter = mFilters.get(c); + if (filter instanceof ImageFilterRS) { + ImageFilterRS filterRS = (ImageFilterRS) filter; + filterRS.resetBitmap(); + } + } + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java index f6f308dba..2410ebe72 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java @@ -121,4 +121,8 @@ public class FilterBasicRepresentation extends FilterRepresentation { public void setPreviewValue(int previewValue) { mPreviewValue = previewValue; } + + public String getStateRepresentation() { + return "" + getValue(); + } } diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java index b8fa0a3d4..e41f0a622 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java @@ -17,6 +17,8 @@ package com.android.gallery3d.filtershow.filters; import android.graphics.Path; +import android.util.Log; + import com.android.gallery3d.R; import com.android.gallery3d.filtershow.editors.EditorDraw; @@ -30,7 +32,7 @@ public class FilterDrawRepresentation extends FilterRepresentation { public Path mPath; public float mRadius; public int mColor; - + public int noPoints = 0; @Override public String toString() { return "stroke(" + mType + ", path(" + (mPath) + "), " + mRadius + " , " @@ -48,7 +50,7 @@ public class FilterDrawRepresentation extends FilterRepresentation { public FilterDrawRepresentation() { super("Draw"); setFilterClass(ImageFilterDraw.class); - setFilterType(FilterRepresentation.TYPE_VIGNETTE); + setPriority(FilterRepresentation.TYPE_VIGNETTE); setTextId(R.string.imageDraw); setButtonId(R.id.drawOnImageButton); setEditorId(EditorDraw.ID); @@ -57,7 +59,8 @@ public class FilterDrawRepresentation extends FilterRepresentation { @Override public String toString() { return getName() + " : strokes=" + mDrawing.size() - + ((mCurrent == null) ? " no current " : ("current=" + mCurrent.mType)); + + ((mCurrent == null) ? " no current " + : ("draw=" + mCurrent.mType + " " + mCurrent.noPoints)); } public Vector<StrokeData> getDrawing() { @@ -91,10 +94,15 @@ public class FilterDrawRepresentation extends FilterRepresentation { } if (representation.mDrawing != null) { mDrawing = (Vector<StrokeData>) representation.mDrawing.clone(); + } else { + mDrawing = null; } + } catch (CloneNotSupportedException e) { e.printStackTrace(); } + } else { + Log.v(LOGTAG, "cannot use parameters from " + a); } } @@ -104,8 +112,18 @@ public class FilterDrawRepresentation extends FilterRepresentation { return false; } if (representation instanceof FilterDrawRepresentation) { - // FIXME! - return true; + FilterDrawRepresentation fdRep = (FilterDrawRepresentation) representation; + if (fdRep.mDrawing.size() != mDrawing.size()) + return false; + if (fdRep.mCurrent == null && mCurrent.mPath == null) { + return true; + } + if (fdRep.mCurrent != null && mCurrent.mPath != null) { + if (fdRep.mCurrent.noPoints == mCurrent.noPoints) { + return true; + } + return false; + } } return false; } @@ -117,14 +135,17 @@ public class FilterDrawRepresentation extends FilterRepresentation { mCurrent.mType = type; mCurrent.mPath = new Path(); mCurrent.mPath.moveTo(x, y); + mCurrent.noPoints = 0; } public void addPoint(float x, float y) { + mCurrent.noPoints++; mCurrent.mPath.lineTo(x, y); } public void endSection(float x, float y) { mCurrent.mPath.lineTo(x, y); + mCurrent.noPoints++; mDrawing.add(mCurrent); mCurrent = null; } diff --git a/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java index fa3fe720b..859bf327c 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java @@ -31,7 +31,7 @@ public class FilterFxRepresentation extends FilterRepresentation { mBitmapResource = bitmapResource; mNameResource = nameResource; setFilterClass(ImageFilterFx.class); - setFilterType(FilterRepresentation.TYPE_FX); + setPriority(FilterRepresentation.TYPE_FX); setTextId(nameResource); setEditorId(ImageOnlyEditor.ID); setShowEditingControls(false); diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java index 38d3a696f..7779211df 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java @@ -31,10 +31,10 @@ public class FilterRedEyeRepresentation extends FilterRepresentation { public FilterRedEyeRepresentation() { super("RedEye"); setFilterClass(ImageFilterRedEye.class); - setFilterType(FilterRepresentation.TYPE_NORMAL); - setButtonId(R.id.redEyeButton); + setPriority(FilterRepresentation.TYPE_NORMAL); setTextId(R.string.redeye); setEditorId(EditorRedEye.ID); + setOverlayId(R.drawable.photoeditor_effect_redeye); } @Override @@ -65,6 +65,17 @@ public class FilterRedEyeRepresentation extends FilterRepresentation { this.mCandidates.add(c); } + @Override + public void useParametersFrom(FilterRepresentation a) { + if (a instanceof FilterRedEyeRepresentation) { + FilterRedEyeRepresentation representation = (FilterRedEyeRepresentation) a; + mCandidates.clear(); + for (RedEyeCandidate redEyeCandidate : representation.mCandidates) { + mCandidates.add(redEyeCandidate); + } + } + } + public void removeCandidate(RedEyeCandidate c) { this.mCandidates.remove(c); } diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java index f282d2966..513cdcdef 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java @@ -23,8 +23,7 @@ import com.android.gallery3d.filtershow.presets.ImagePreset; public class FilterRepresentation implements Cloneable { private static final String LOGTAG = "FilterRepresentation"; private String mName; - private int mPriority; - private ImagePreset mPreset; + private int mPriority = TYPE_NORMAL; private Class mFilterClass; private int mTextId = 0; private int mEditorId = BasicEditor.ID; @@ -40,7 +39,8 @@ public class FilterRepresentation implements Cloneable { public static final byte TYPE_VIGNETTE = 4; public static final byte TYPE_NORMAL = 5; public static final byte TYPE_TINYPLANET = 6; - private byte filterType = TYPE_NORMAL; + + public FilterRepresentation mTempRepresentation = null; public FilterRepresentation(String name) { mName = name; @@ -86,14 +86,6 @@ public class FilterRepresentation implements Cloneable { return mName; } - public byte getFilterType() { - return filterType; - } - - protected void setFilterType(byte type) { - filterType = type; - } - public void setName(String name) { mName = name; } @@ -110,10 +102,6 @@ public class FilterRepresentation implements Cloneable { return mPriority; } - public void setImagePreset(ImagePreset preset) { - mPreset = preset; - } - public boolean isNil() { return false; } @@ -121,6 +109,24 @@ public class FilterRepresentation implements Cloneable { public void useParametersFrom(FilterRepresentation a) { } + public synchronized void updateTempParametersFrom(FilterRepresentation representation) { + if (mTempRepresentation == null) { + try { + mTempRepresentation = representation.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + } else { + mTempRepresentation.useParametersFrom(representation); + } + } + + public synchronized void synchronizeRepresentation() { + if (mTempRepresentation != null) { + useParametersFrom(mTempRepresentation); + } + } + public boolean allowsMultipleInstances() { return false; } @@ -195,4 +201,9 @@ public class FilterRepresentation implements Cloneable { public void setShowUtilityPanel(boolean showUtilityPanel) { mShowUtilityPanel = showUtilityPanel; } + + public String getStateRepresentation() { + return ""; + } + } diff --git a/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java index 9bf2f0bf3..7b69ce9e0 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java @@ -27,7 +27,7 @@ public class FilterTinyPlanetRepresentation extends FilterBasicRepresentation { super("TinyPlanet", 0, 50, 100); setShowParameterValue(true); setFilterClass(ImageFilterTinyPlanet.class); - setFilterType(FilterRepresentation.TYPE_TINYPLANET); + setPriority(FilterRepresentation.TYPE_TINYPLANET); setTextId(R.string.tinyplanet); setButtonId(R.id.tinyplanetButton); setEditorId(EditorTinyPlanet.ID); diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java index d7a76d614..7c5a75232 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java @@ -22,7 +22,7 @@ import com.android.gallery3d.R; import com.android.gallery3d.filtershow.editors.BasicEditor; import com.android.gallery3d.filtershow.presets.ImagePreset; -public class ImageFilter implements Cloneable { +public abstract class ImageFilter implements Cloneable { private ImagePreset mImagePreset; @@ -37,7 +37,7 @@ public class ImageFilter implements Cloneable { return mName; } - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { // do nothing here, subclasses will implement filtering here return bitmap; } @@ -46,17 +46,20 @@ public class ImageFilter implements Cloneable { * Called on small bitmaps to create button icons for each filter. * Override this to provide filter-specific button icons. */ - public Bitmap iconApply(Bitmap bitmap, float scaleFactor, boolean highQuality) { - return apply(bitmap, scaleFactor, highQuality); + public Bitmap iconApply(Bitmap bitmap, float scaleFactor, int quality) { + return apply(bitmap, scaleFactor, quality); } public ImagePreset getImagePreset() { return mImagePreset; } - public void useRepresentation(FilterRepresentation representation) { + public void setImagePreset(ImagePreset imagePreset) { + mImagePreset = imagePreset; } + public abstract void useRepresentation(FilterRepresentation representation); + native protected void nativeApplyGradientFilter(Bitmap bitmap, int w, int h, int[] redGradient, int[] greenGradient, int[] blueGradient); diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java index 416af9417..70e7f2220 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java @@ -63,7 +63,7 @@ public class ImageFilterBorder extends ImageFilter { } @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null || getParameters().getDrawableResource() == 0) { return bitmap; } @@ -73,7 +73,7 @@ public class ImageFilterBorder extends ImageFilter { } @Override - public Bitmap iconApply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap iconApply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null || getParameters().getDrawableResource() == 0) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java index 3580dd693..c92ac012d 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java @@ -42,7 +42,7 @@ public class ImageFilterBwFilter extends SimpleImageFilter { native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, int r, int g, int b); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java index e2664269b..2f94e3d17 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java @@ -27,18 +27,23 @@ public class ImageFilterContrast extends SimpleImageFilter { } public FilterRepresentation getDefaultRepresentation() { - FilterRepresentation representation = super.getDefaultRepresentation(); + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); representation.setName("Contrast"); representation.setFilterClass(ImageFilterContrast.class); representation.setTextId(R.string.contrast); representation.setButtonId(R.id.contrastButton); + + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); return representation; } native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float strength); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java index 4b65a0016..aa4cf22e6 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java @@ -55,7 +55,7 @@ public class ImageFilterCurves extends ImageFilter { } @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (!mParameters.getSpline(Spline.RGB).isOriginal()) { int[] rgbGradient = new int[256]; populateArray(rgbGradient, Spline.RGB); diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java index a53d2f3b3..906467344 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java @@ -47,7 +47,7 @@ public class ImageFilterDownsample extends SimpleImageFilter { } @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } @@ -79,7 +79,7 @@ public class ImageFilterDownsample extends SimpleImageFilter { } @Override - public Bitmap iconApply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap iconApply(Bitmap bitmap, float scaleFactor, int quality) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Bitmap ret = Bitmap.createScaledBitmap(bitmap, w / ICON_DOWNSAMPLE_FRACTION, h diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java index d2b5507a1..4b21d3595 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java @@ -27,11 +27,13 @@ import android.graphics.Path; import android.graphics.PathMeasure; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; import android.util.Log; import com.android.gallery3d.R; import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation.StrokeData; import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.presets.ImagePreset; import java.util.Vector; @@ -85,7 +87,7 @@ public class ImageFilterDraw extends ImageFilter { public static interface DrawStyle { public void setType(byte type); public void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, - boolean highQuality); + int quality); } class SimpleDraw implements DrawStyle { @@ -98,7 +100,7 @@ public class ImageFilterDraw extends ImageFilter { @Override public void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, - boolean highQuality) { + int quality) { if (sd == null) { return; } @@ -139,7 +141,7 @@ public class ImageFilterDraw extends ImageFilter { @Override public void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, - boolean highQuality) { + int quality) { if (sd == null || sd.mPath == null) { return; } @@ -198,13 +200,13 @@ public class ImageFilterDraw extends ImageFilter { } void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, - boolean highQuality) { - mDrawingsTypes[sd.mType].paint(sd, canvas, toScrMatrix, highQuality); + int quality) { + mDrawingsTypes[sd.mType].paint(sd, canvas, toScrMatrix, quality); } - public void drawData(Canvas canvas, Matrix originalRotateToScreen, boolean highQuality) { + public void drawData(Canvas canvas, Matrix originalRotateToScreen, int quality) { Paint paint = new Paint(); - if (highQuality) { + if (quality == ImagePreset.QUALITY_FINAL) { paint.setAntiAlias(true); } paint.setStyle(Style.STROKE); @@ -214,16 +216,17 @@ public class ImageFilterDraw extends ImageFilter { if (mParameters.getDrawing().isEmpty() && mParameters.getCurrentDrawing() == null) { return; } - if (highQuality) { + if (quality == ImagePreset.QUALITY_FINAL) { for (FilterDrawRepresentation.StrokeData strokeData : mParameters.getDrawing()) { - paint(strokeData, canvas, originalRotateToScreen, highQuality); + paint(strokeData, canvas, originalRotateToScreen, quality); } return; } if (mOverlayBitmap == null || mOverlayBitmap.getWidth() != canvas.getWidth() || - mOverlayBitmap.getHeight() != canvas.getHeight()) { + mOverlayBitmap.getHeight() != canvas.getHeight() || + mParameters.getDrawing().size() < mCachedStrokes) { mOverlayBitmap = Bitmap.createBitmap( canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); @@ -237,7 +240,7 @@ public class ImageFilterDraw extends ImageFilter { StrokeData stroke = mParameters.getCurrentDrawing(); if (stroke != null) { - paint(stroke, canvas, originalRotateToScreen, highQuality); + paint(stroke, canvas, originalRotateToScreen, quality); } } @@ -247,29 +250,29 @@ public class ImageFilterDraw extends ImageFilter { int n = v.size(); for (int i = mCachedStrokes; i < n; i++) { - paint(v.get(i), drawCache, originalRotateToScreen, false); + paint(v.get(i), drawCache, originalRotateToScreen, ImagePreset.QUALITY_PREVIEW); } mCachedStrokes = n; } public void draw(Canvas canvas, Matrix originalRotateToScreen) { for (FilterDrawRepresentation.StrokeData strokeData : mParameters.getDrawing()) { - paint(strokeData, canvas, originalRotateToScreen, false); + paint(strokeData, canvas, originalRotateToScreen, ImagePreset.QUALITY_PREVIEW); } - mDrawingsTypes[mCurrentStyle].paint(null, canvas, originalRotateToScreen, false); + mDrawingsTypes[mCurrentStyle].paint( + null, canvas, originalRotateToScreen, ImagePreset.QUALITY_PREVIEW); } @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); - short[] rect = new short[4]; - - Matrix m = new Matrix(); - m.setScale(scaleFactor, scaleFactor); - drawData(new Canvas(bitmap), m, highQuality); - - + ImagePreset imgPreset = getImagePreset(); + Rect bounds = imgPreset.getImageLoader().getOriginalBounds(); + Matrix m = imgPreset.mGeoData.getOriginalToScreen(true, + bounds.width(), + bounds.height(), w, h); + drawData(new Canvas(bitmap), m, quality); return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java index 96839e4ab..55c709573 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java @@ -38,7 +38,7 @@ public class ImageFilterEdge extends SimpleImageFilter { native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float p); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java index e36f096ad..7a8df71af 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java @@ -27,18 +27,22 @@ public class ImageFilterExposure extends SimpleImageFilter { } public FilterRepresentation getDefaultRepresentation() { - FilterRepresentation representation = super.getDefaultRepresentation(); + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); representation.setName("Exposure"); representation.setFilterClass(ImageFilterExposure.class); representation.setTextId(R.string.exposure); representation.setButtonId(R.id.exposureButton); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); return representation; } native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float bright); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java index 0a3c8abd0..820ec3e51 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java @@ -40,7 +40,7 @@ public class ImageFilterFx extends ImageFilter { native protected void nativeApplyFilter(Bitmap bitmap, int w, int h,Bitmap fxBitmap, int fxw, int fxh); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null || getParameters().getFxBitmap() ==null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java index a778bee21..329ca81b9 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterGeometry.java @@ -67,7 +67,12 @@ public class ImageFilterGeometry extends ImageFilter { Bitmap dst, int dstWidth, int dstHeight, float straightenAngle); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public void useRepresentation(FilterRepresentation representation) { + + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { // TODO: implement bilinear or bicubic here... for now, just use // canvas to do a simple implementation... // TODO: and be more memory efficient! (do it in native?) diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java index ed28e57b7..8c484c72e 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java @@ -30,7 +30,8 @@ public class ImageFilterHue extends SimpleImageFilter { } public FilterRepresentation getDefaultRepresentation() { - FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation(); + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); representation.setName("Hue"); representation.setFilterClass(ImageFilterHue.class); representation.setMinimum(-180); @@ -44,7 +45,7 @@ public class ImageFilterHue extends SimpleImageFilter { native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float []matrix); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java index f28839744..f48bd047a 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java @@ -53,7 +53,7 @@ public class ImageFilterKMeans extends SimpleImageFilter { int swidth, int sheight, int p, int seed); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java index 14307c37d..841c5c913 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java @@ -3,6 +3,7 @@ package com.android.gallery3d.filtershow.filters; import android.graphics.Bitmap; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; public class ImageFilterNegative extends ImageFilter { @@ -17,13 +18,19 @@ public class ImageFilterNegative extends ImageFilter { representation.setButtonId(R.id.negativeButton); representation.setShowEditingControls(false); representation.setShowParameterValue(false); + representation.setEditorId(ImageOnlyEditor.ID); return representation; } native protected void nativeApplyFilter(Bitmap bitmap, int w, int h); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public void useRepresentation(FilterRepresentation representation) { + + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); nativeApplyFilter(bitmap, w, h); diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java index 36c86d847..316a286e8 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java @@ -63,14 +63,14 @@ public class ImageFilterParametricBorder extends ImageFilter { } @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { Canvas canvas = new Canvas(bitmap); applyHelper(canvas, bitmap.getWidth(), bitmap.getHeight()); return bitmap; } @Override - public Bitmap iconApply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap iconApply(Bitmap bitmap, float scaleFactor, int quality) { Canvas canvas = new Canvas(bitmap); applyHelper(canvas, bitmap.getWidth() * 4, bitmap.getHeight() * 4); return bitmap; diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java index 79c783a94..d5297904d 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java @@ -21,7 +21,7 @@ import android.graphics.Bitmap; import android.support.v8.renderscript.*; import android.util.Log; -public class ImageFilterRS extends ImageFilter { +public abstract class ImageFilterRS extends ImageFilter { private final String LOGTAG = "ImageFilterRS"; private static RenderScript mRS = null; @@ -33,7 +33,11 @@ public class ImageFilterRS extends ImageFilter { private final Bitmap.Config mBitmapConfig = Bitmap.Config.ARGB_8888; - public void prepare(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public void resetBitmap() { + mOldBitmap = null; + } + + public void prepare(Bitmap bitmap, float scaleFactor, int quality) { if (sOldBitmap == null || (bitmap.getWidth() != sOldBitmap.getWidth()) || (bitmap.getHeight() != sOldBitmap.getHeight())) { @@ -52,13 +56,13 @@ public class ImageFilterRS extends ImageFilter { } mInPixelsAllocation.copyFrom(bitmap); if (mOldBitmap != sOldBitmap) { - createFilter(mResources, scaleFactor, highQuality); + createFilter(mResources, scaleFactor, quality); mOldBitmap = sOldBitmap; } } public void createFilter(android.content.res.Resources res, - float scaleFactor, boolean highQuality) { + float scaleFactor, int quality) { // Stub } @@ -71,12 +75,12 @@ public class ImageFilterRS extends ImageFilter { } @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (bitmap == null) { return bitmap; } try { - prepare(bitmap, scaleFactor, highQuality); + prepare(bitmap, scaleFactor, quality); runFilter(); update(bitmap); } catch (android.renderscript.RSIllegalArgumentException e) { diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java index 177def7b7..42587c06f 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java @@ -17,8 +17,12 @@ package com.android.gallery3d.filtershow.filters; import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; import android.graphics.RectF; +import android.util.Log; import com.android.gallery3d.filtershow.imageshow.GeometryMetadata; @@ -34,9 +38,7 @@ public class ImageFilterRedEye extends ImageFilter { @Override public FilterRepresentation getDefaultRepresentation() { - FilterRedEyeRepresentation representation = new FilterRedEyeRepresentation(); - - return representation; + return new FilterRedEyeRepresentation(); } public boolean isNil() { @@ -63,12 +65,17 @@ public class ImageFilterRedEye extends ImageFilter { native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, short[] matrix); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public void useRepresentation(FilterRepresentation representation) { + FilterRedEyeRepresentation parameters = (FilterRedEyeRepresentation) representation; + mParameters = parameters; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); short[] rect = new short[4]; int size = mParameters.getNumberOfCandidates(); - for (int i = 0; i < size; i++) { RectF r = new RectF(mParameters.getCandidate(i).mRect); GeometryMetadata geo = getImagePreset().mGeoData; @@ -101,13 +108,14 @@ public class ImageFilterRedEye extends ImageFilter { if (r.bottom > h) { r.bottom = h; } + rect[0] = (short) r.left; rect[1] = (short) r.top; rect[2] = (short) r.width(); rect[3] = (short) r.height(); + nativeApplyFilter(bitmap, w, h, rect); } - return bitmap; } } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java index 747a03685..6cd833206 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java @@ -26,19 +26,24 @@ public class ImageFilterSaturated extends SimpleImageFilter { mName = "Saturated"; } + @Override public FilterRepresentation getDefaultRepresentation() { - FilterRepresentation representation = super.getDefaultRepresentation(); + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); representation.setName("Saturated"); representation.setFilterClass(ImageFilterSaturated.class); representation.setTextId(R.string.saturation); representation.setButtonId(R.id.saturationButton); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); return representation; } native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float saturation); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java index a2560b99e..e17823955 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java @@ -28,18 +28,22 @@ public class ImageFilterShadows extends SimpleImageFilter { } public FilterRepresentation getDefaultRepresentation() { - FilterRepresentation representation = super.getDefaultRepresentation(); + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); representation.setName("Shadows"); representation.setFilterClass(ImageFilterShadows.class); representation.setTextId(R.string.shadow_recovery); representation.setButtonId(R.id.shadowRecoveryButton); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); return representation; } native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float factor); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java index 92f9b1a6d..9c99d57d0 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java @@ -48,7 +48,7 @@ public class ImageFilterSharpen extends ImageFilterRS { @Override public void createFilter(android.content.res.Resources res, float scaleFactor, - boolean highQuality) { + int quality) { int w = mInPixelsAllocation.getType().getX(); int h = mInPixelsAllocation.getType().getY(); mScaleFactor = scaleFactor; diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterStraighten.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterStraighten.java index 3feec7bcc..a3bb6f980 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterStraighten.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterStraighten.java @@ -53,7 +53,12 @@ public class ImageFilterStraighten extends ImageFilter { } @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public void useRepresentation(FilterRepresentation representation) { + + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { // TODO: implement bilinear or bicubic here... for now, just use // canvas to do a simple implementation... // TODO: and be more memory efficient! (do it in native?) diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java index d8ec3900e..702cc664c 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java @@ -72,7 +72,7 @@ public class ImageFilterTinyPlanet extends SimpleImageFilter { float angle); @Override - public Bitmap apply(Bitmap bitmapIn, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmapIn, float scaleFactor, int quality) { int w = bitmapIn.getWidth(); int h = bitmapIn.getHeight(); int outputSize = (int) (w / 2f); diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java index 385921168..a57af71df 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java @@ -27,18 +27,22 @@ public class ImageFilterVibrance extends SimpleImageFilter { } public FilterRepresentation getDefaultRepresentation() { - FilterRepresentation representation = super.getDefaultRepresentation(); + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); representation.setName("Vibrance"); representation.setFilterClass(ImageFilterVibrance.class); representation.setTextId(R.string.vibrance); representation.setButtonId(R.id.vibranceButton); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); return representation; } native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float bright); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java index 3aad6bd15..465d90bfd 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java @@ -30,19 +30,25 @@ public class ImageFilterVignette extends SimpleImageFilter { } public FilterRepresentation getDefaultRepresentation() { - FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation(); + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); representation.setName("Vignette"); representation.setFilterClass(ImageFilterVignette.class); representation.setPriority(FilterRepresentation.TYPE_VIGNETTE); representation.setTextId(R.string.vignette); representation.setButtonId(R.id.vignetteButton); + + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); + return representation; } native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float strength); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { if (getParameters() == null) { return bitmap; } diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java index 28223b28d..2f4852306 100644 --- a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java @@ -17,6 +17,7 @@ package com.android.gallery3d.filtershow.filters; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; import android.graphics.Bitmap; @@ -30,17 +31,24 @@ public class ImageFilterWBalance extends ImageFilter { public FilterRepresentation getDefaultRepresentation() { FilterRepresentation representation = new FilterDirectRepresentation("WBalance"); representation.setFilterClass(ImageFilterWBalance.class); - representation.setFilterType(FilterRepresentation.TYPE_WBALANCE); + representation.setPriority(FilterRepresentation.TYPE_WBALANCE); representation.setTextId(R.string.wbalance); representation.setButtonId(R.id.wbalanceButton); representation.setShowEditingControls(false); + representation.setShowParameterValue(false); + representation.setEditorId(ImageOnlyEditor.ID); return representation; } + @Override + public void useRepresentation(FilterRepresentation representation) { + + } + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, int locX, int locY); @Override - public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); nativeApplyFilter(bitmap, w, h, -1, -1); diff --git a/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java b/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java index d494913cf..922a16a0f 100644 --- a/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java +++ b/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java @@ -38,9 +38,9 @@ public class SimpleImageFilter extends ImageFilter { } @Override - public Bitmap iconApply(Bitmap bitmap, float scaleFactor, boolean highQuality) { + public Bitmap iconApply(Bitmap bitmap, float scaleFactor, int quality) { FilterRepresentation representation = getDefaultRepresentation(); this.useRepresentation(representation); - return apply(bitmap, scaleFactor, highQuality); + return apply(bitmap, scaleFactor, quality); } } diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryListener.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryListener.java new file mode 100644 index 000000000..549c2e7a5 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryListener.java @@ -0,0 +1,21 @@ +/* + * 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.gallery3d.filtershow.imageshow; + +public interface GeometryListener { + public void geometryChanged(); +} diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java index b53284061..a3645d6f5 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java +++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMetadata.java @@ -86,12 +86,12 @@ public class GeometryMetadata { return false; } - public Bitmap apply(Bitmap original, float scaleFactor, boolean highQuality) { + public Bitmap apply(Bitmap original, float scaleFactor, int quality) { if (!hasModifications()) { return original; } mImageFilter.setGeometryMetadata(this); - Bitmap m = mImageFilter.apply(original, scaleFactor, highQuality); + Bitmap m = mImageFilter.apply(original, scaleFactor, quality); return m; } diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java index 2dc0221e4..0cd229968 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java @@ -5,8 +5,6 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; -import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; @@ -91,7 +89,6 @@ public class ImageDraw extends ImageShow { ImageFilterDraw filter = (ImageFilterDraw) getCurrentFilter(); if (event.getAction() == MotionEvent.ACTION_DOWN) { - mTmpPoint[0] = event.getX(); mTmpPoint[1] = event.getY(); mToOrig.mapPoints(mTmpPoint); @@ -116,8 +113,6 @@ public class ImageDraw extends ImageShow { mTmpPoint[1] = event.getY(); mToOrig.mapPoints(mTmpPoint); mFRep.endSection(mTmpPoint[0], mTmpPoint[1]); - this.resetImageCaches(this); - } mEditorDraw.commitLocalRepresentation(); invalidate(); diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java b/src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java index 2db9227b9..ba3dcdd1d 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageRedEye.java @@ -9,6 +9,7 @@ import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.RectF; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; import com.android.gallery3d.filtershow.editors.EditorRedEye; @@ -119,7 +120,6 @@ public class ImageRedEye extends ImageShow { Matrix originalRotateToScreen = geo.getOriginalToScreen(true, mImageLoader.getOriginalBounds().width(), mImageLoader.getOriginalBounds().height(), getWidth(), getHeight()); - if (mRedEyeRep != null) { for (RedEyeCandidate candidate : mRedEyeRep.getCandidates()) { RectF rect = candidate.getRect(); diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java index 1e830b04b..3172c79dc 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java +++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java @@ -19,7 +19,6 @@ package com.android.gallery3d.filtershow.imageshow; import android.graphics.Bitmap; import android.graphics.RectF; -import com.android.gallery3d.app.Log; import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.HistoryAdapter; import com.android.gallery3d.filtershow.ImageStateAdapter; @@ -54,6 +53,9 @@ public class MasterImage implements RenderingRequestCaller { private Vector<ImageShow> mObservers = new Vector<ImageShow>(); private FilterRepresentation mCurrentFilterRepresentation; + private Vector<GeometryListener> mGeometryListeners = new Vector<GeometryListener>(); + + private GeometryMetadata mPreviousGeometry = null; private MasterImage() { } @@ -101,6 +103,11 @@ public class MasterImage implements RenderingRequestCaller { mHistory.addHistoryItem(mPreset); } updatePresets(true); + GeometryMetadata geo = mPreset.mGeoData; + if (!geo.equals(mPreviousGeometry)) { + notifyGeometryChange(); + } + mPreviousGeometry = new GeometryMetadata(geo); } private void setGeometry() { @@ -246,4 +253,14 @@ public class MasterImage implements RenderingRequestCaller { public static void reset() { sMasterImage = null; } + + public void addGeometryListener(GeometryListener listener) { + mGeometryListeners.add(listener); + } + + public void notifyGeometryChange() { + for (GeometryListener listener : mGeometryListeners) { + listener.geometryChanged(); + } + } } diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java index c7d14e80b..84266c55d 100644 --- a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java +++ b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java @@ -21,6 +21,7 @@ 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; @@ -35,7 +36,10 @@ public class ImagePreset { private FilterRepresentation mBorder = null; private float mScaleFactor = 1.0f; - private boolean mIsHighQuality = false; + public static final int QUALITY_ICON = 0; + public static final int QUALITY_PREVIEW = 1; + public static final int QUALITY_FINAL = 2; + private int mQuality = QUALITY_PREVIEW; private ImageLoader mImageLoader = null; private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>(); @@ -72,7 +76,6 @@ public class ImagePreset { } for (int i = 0; i < source.mFilters.size(); i++) { FilterRepresentation representation = source.mFilters.elementAt(i).clone(); - representation.setImagePreset(this); addFilter(representation); } } catch (java.lang.CloneNotSupportedException e) { @@ -127,7 +130,7 @@ public class ImagePreset { synchronized (mFilters) { int position = getPositionForRepresentation(representation); FilterRepresentation old = mFilters.elementAt(position); - old.useParametersFrom(representation); + old.updateTempParametersFrom(representation); } MasterImage.getImage().invalidatePreview(); } @@ -351,7 +354,6 @@ public class ImagePreset { mFilters.add(representation); setHistoryName(representation.getName()); } - representation.setImagePreset(this); } public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) { @@ -380,14 +382,16 @@ public class ImagePreset { public Bitmap applyGeometry(Bitmap bitmap) { // Apply any transform -- 90 rotate, flip, straighten, crop // Returns a new bitmap. - return mGeoData.apply(bitmap, mScaleFactor, mIsHighQuality); + return mGeoData.apply(bitmap, mScaleFactor, mQuality); } public Bitmap applyBorder(Bitmap bitmap) { if (mBorder != null && mDoApplyGeometry) { ImageFilter filter = FiltersManager.getManager().getFilterForRepresentation(mBorder); + mBorder.synchronizeRepresentation(); filter.useRepresentation(mBorder); - bitmap = filter.apply(bitmap, mScaleFactor, mIsHighQuality); + filter.setImagePreset(this); + bitmap = filter.apply(bitmap, mScaleFactor, mQuality); } return bitmap; } @@ -405,10 +409,12 @@ public class ImagePreset { FilterRepresentation representation = null; synchronized (mFilters) { representation = mFilters.elementAt(i); + representation.synchronizeRepresentation(); } ImageFilter filter = FiltersManager.getManager().getFilterForRepresentation(representation); filter.useRepresentation(representation); - bitmap = filter.apply(bitmap, mScaleFactor, mIsHighQuality); + filter.setImagePreset(this); + bitmap = filter.apply(bitmap, mScaleFactor, mQuality); } } @@ -421,7 +427,7 @@ public class ImagePreset { } imageStateAdapter.clear(); // TODO: re-enable the state panel - // imageStateAdapter.addAll(mFilters); + imageStateAdapter.addAll(mFilters); imageStateAdapter.notifyDataSetChanged(); } @@ -429,12 +435,12 @@ public class ImagePreset { return mScaleFactor; } - public boolean isHighQuality() { - return mIsHighQuality; + public int getQuality() { + return mQuality; } - public void setIsHighQuality(boolean value) { - mIsHighQuality = value; + public void setQuality(int value) { + mQuality = value; } public void setScaleFactor(float value) { diff --git a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java index 38a9a3a2f..e378fe2b7 100644 --- a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java +++ b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java @@ -168,7 +168,7 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> { @Override protected Uri doInBackground(ImagePreset... params) { // TODO: Support larger dimensions for photo saving. - if (params[0] == null) { + if (params[0] == null || sourceUri == null) { return null; } ImagePreset preset = params[0]; diff --git a/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java b/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java index 19807e6af..de2e1e5dc 100644 --- a/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java +++ b/src/com/android/gallery3d/filtershow/ui/FilterIconButton.java @@ -24,20 +24,17 @@ import android.util.AttributeSet; import android.view.View; import android.widget.LinearLayout; -import com.android.gallery3d.app.Log; -import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.PanelController; -import com.android.gallery3d.filtershow.cache.FilteringPipeline; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.cache.RenderingRequest; import com.android.gallery3d.filtershow.cache.RenderingRequestCaller; import com.android.gallery3d.filtershow.filters.FilterRepresentation; -import com.android.gallery3d.filtershow.filters.FiltersManager; -import com.android.gallery3d.filtershow.filters.ImageFilter; +import com.android.gallery3d.filtershow.imageshow.GeometryListener; import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.presets.ImagePreset; -public class FilterIconButton extends IconButton implements View.OnClickListener, RenderingRequestCaller { +public class FilterIconButton extends IconButton implements View.OnClickListener, + RenderingRequestCaller, GeometryListener { private static final String LOGTAG = "FilterIconButton"; private Bitmap mOverlayBitmap = null; private PanelController mController = null; @@ -65,6 +62,7 @@ public class FilterIconButton extends IconButton implements View.OnClickListener setText(text); mParentContainer = parent; super.setOnClickListener(this); + MasterImage.getImage().addGeometryListener(this); invalidate(); } @@ -73,6 +71,8 @@ public class FilterIconButton extends IconButton implements View.OnClickListener if (mIconBitmap == null && mPreset == null) { ImageLoader loader = MasterImage.getImage().getLoader(); if (loader != null) { + ImagePreset geoPreset = new ImagePreset(MasterImage.getImage().getGeometryPreset()); + image = geoPreset.applyGeometry(image); dst = super.drawImage(dst, image, destination); ImagePreset mPreset = new ImagePreset(); mPreset.addFilter(mFilterRepresentation); @@ -127,4 +127,12 @@ public class FilterIconButton extends IconButton implements View.OnClickListener invalidate(); stale_icon = true; } + + @Override + public void geometryChanged() { + stale_icon = true; + mIconBitmap = null; + mPreset = null; + invalidate(); + } } diff --git a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java index ec2df6c08..f581fc733 100644 --- a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java +++ b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java @@ -26,7 +26,6 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.os.AsyncTask; import android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.MotionEvent; @@ -36,6 +35,7 @@ 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; @@ -65,11 +65,13 @@ public class ImageCurves extends ImageShow { public ImageCurves(Context context) { super(context); + setLayerType(LAYER_TYPE_SOFTWARE, gPaint); resetCurve(); } public ImageCurves(Context context, AttributeSet attrs) { super(context, attrs); + setLayerType(LAYER_TYPE_SOFTWARE, gPaint); resetCurve(); } diff --git a/src/com/android/gallery3d/ingest/IngestActivity.java b/src/com/android/gallery3d/ingest/IngestActivity.java index 4e603bed3..893f59572 100644 --- a/src/com/android/gallery3d/ingest/IngestActivity.java +++ b/src/com/android/gallery3d/ingest/IngestActivity.java @@ -22,11 +22,14 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.res.Configuration; +import android.database.DataSetObserver; import android.mtp.MtpObjectInfo; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; +import android.support.v4.view.ViewPager; import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.Menu; @@ -36,12 +39,16 @@ import android.view.View; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; -import android.widget.GridView; import android.widget.TextView; import com.android.gallery3d.R; +import com.android.gallery3d.ingest.adapter.CheckBroker; import com.android.gallery3d.ingest.adapter.MtpAdapter; +import com.android.gallery3d.ingest.adapter.MtpPagerAdapter; +import com.android.gallery3d.ingest.data.MtpBitmapFetch; import com.android.gallery3d.ingest.ui.DateTileView; +import com.android.gallery3d.ingest.ui.IngestGridView; +import com.android.gallery3d.ingest.ui.IngestGridView.OnClearChoicesListener; import java.lang.ref.WeakReference; import java.util.Collection; @@ -51,14 +58,22 @@ public class IngestActivity extends Activity implements private IngestService mHelperService; private boolean mActive = false; - private GridView mGridView; + private IngestGridView mGridView; private MtpAdapter mAdapter; private Handler mHandler; private ProgressDialog mProgressDialog; private ActionMode mActiveActionMode; - private View mWarningOverlay; - private TextView mWarningOverlayText; + private View mWarningView; + private TextView mWarningText; + private int mLastCheckedPosition = 0; + + private ViewPager mFullscreenPager; + private MtpPagerAdapter mPagerAdapter; + private boolean mFullscreenPagerVisible = false; + + private MenuItem mMenuSwitcherItem; + private MenuItem mActionMenuSwitcherItem; @Override protected void onCreate(Bundle savedInstanceState) { @@ -66,18 +81,25 @@ public class IngestActivity extends Activity implements doBindHelperService(); setContentView(R.layout.ingest_activity_item_list); - mGridView = (GridView) findViewById(R.id.ingest_gridview); + mGridView = (IngestGridView) findViewById(R.id.ingest_gridview); mAdapter = new MtpAdapter(this); + mAdapter.registerDataSetObserver(mMasterObserver); mGridView.setAdapter(mAdapter); mGridView.setMultiChoiceModeListener(mMultiChoiceModeListener); mGridView.setOnItemClickListener(mOnItemClickListener); + mGridView.setOnClearChoicesListener(mPositionMappingCheckBroker); + + mFullscreenPager = (ViewPager) findViewById(R.id.ingest_view_pager); mHandler = new ItemListHandler(this); + + MtpBitmapFetch.configureForContext(this); } private OnItemClickListener mOnItemClickListener = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View itemView, int position, long arg3) { + mLastCheckedPosition = position; mGridView.setItemChecked(position, !mGridView.getCheckedItemPositions().get(position)); } }; @@ -124,23 +146,18 @@ public class IngestActivity extends Activity implements mGridView.setItemChecked(i, rangeValue); } + mPositionMappingCheckBroker.onBulkCheckedChange(); mIgnoreItemCheckedStateChanges = false; + } else { + mPositionMappingCheckBroker.onCheckedChange(position, checked); } + mLastCheckedPosition = position; updateSelectedTitle(mode); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - switch (item.getItemId()) { - case R.id.import_items: - mHelperService.importSelectedItems( - mGridView.getCheckedItemPositions(), - mAdapter); - mode.finish(); - return true; - default: - return false; - } + return onOptionsItemSelected(item); } @Override @@ -149,12 +166,16 @@ public class IngestActivity extends Activity implements inflater.inflate(R.menu.ingest_menu_item_list_selection, menu); updateSelectedTitle(mode); mActiveActionMode = mode; + mActionMenuSwitcherItem = menu.findItem(R.id.ingest_switch_view); + setSwitcherMenuState(mActionMenuSwitcherItem, mFullscreenPagerVisible); return true; } @Override public void onDestroyActionMode(ActionMode mode) { mActiveActionMode = null; + mActionMenuSwitcherItem = null; + mHandler.sendEmptyMessage(ItemListHandler.MSG_BULK_CHECKED_CHANGE); } @Override @@ -164,6 +185,34 @@ public class IngestActivity extends Activity implements } }; + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.import_items: + if (mActiveActionMode != null) { + mHelperService.importSelectedItems( + mGridView.getCheckedItemPositions(), + mAdapter); + mActiveActionMode.finish(); + } + return true; + case R.id.ingest_switch_view: + setFullscreenPagerVisibility(!mFullscreenPagerVisible); + return true; + default: + return false; + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.ingest_menu_item_list_selection, menu); + mMenuSwitcherItem = menu.findItem(R.id.ingest_switch_view); + menu.findItem(R.id.import_items).setVisible(false); + setSwitcherMenuState(mMenuSwitcherItem, mFullscreenPagerVisible); + return true; + } + @Override protected void onDestroy() { super.onDestroy(); @@ -175,7 +224,7 @@ public class IngestActivity extends Activity implements DateTileView.refreshLocale(); mActive = true; if (mHelperService != null) mHelperService.setClientActivity(this); - updateWarningOverlay(); + updateWarningView(); super.onResume(); } @@ -187,31 +236,140 @@ public class IngestActivity extends Activity implements super.onPause(); } - private void showWarningOverlay(int textResId) { - if (mWarningOverlay == null) { - mWarningOverlay = findViewById(R.id.ingest_warning_overlay); - mWarningOverlayText = - (TextView)mWarningOverlay.findViewById(R.id.ingest_warning_overlay_text); + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + MtpBitmapFetch.configureForContext(this); + } + + private void showWarningView(int textResId) { + if (mWarningView == null) { + mWarningView = findViewById(R.id.ingest_warning_view); + mWarningText = + (TextView)mWarningView.findViewById(R.id.ingest_warning_view_text); } - mWarningOverlayText.setText(textResId); - mWarningOverlay.setVisibility(View.VISIBLE); + mWarningText.setText(textResId); + mWarningView.setVisibility(View.VISIBLE); + setFullscreenPagerVisibility(false); mGridView.setVisibility(View.GONE); } - private void hideWarningOverlay() { - if (mWarningOverlay != null) { - mWarningOverlay.setVisibility(View.GONE); - mGridView.setVisibility(View.VISIBLE); + private void hideWarningView() { + if (mWarningView != null) { + mWarningView.setVisibility(View.GONE); + setFullscreenPagerVisibility(false); } } - private void updateWarningOverlay() { + private PositionMappingCheckBroker mPositionMappingCheckBroker = new PositionMappingCheckBroker(); + + private class PositionMappingCheckBroker extends CheckBroker + implements OnClearChoicesListener { + private int mLastMappingPager = -1; + private int mLastMappingGrid = -1; + + private int mapPagerToGridPosition(int position) { + if (position != mLastMappingPager) { + mLastMappingPager = position; + mLastMappingGrid = mAdapter.translatePositionWithoutLabels(position); + } + return mLastMappingGrid; + } + + private int mapGridToPagerPosition(int position) { + if (position != mLastMappingGrid) { + mLastMappingGrid = position; + mLastMappingPager = mPagerAdapter.translatePositionWithLabels(position); + } + return mLastMappingPager; + } + + @Override + public void setItemChecked(int position, boolean checked) { + mGridView.setItemChecked(mapPagerToGridPosition(position), checked); + } + + @Override + public void onCheckedChange(int position, boolean checked) { + if (mPagerAdapter != null) { + super.onCheckedChange(mapGridToPagerPosition(position), checked); + } + } + + @Override + public boolean isItemChecked(int position) { + return mGridView.getCheckedItemPositions().get(mapPagerToGridPosition(position)); + } + + @Override + public void onClearChoices() { + onBulkCheckedChange(); + } + }; + + private DataSetObserver mMasterObserver = new DataSetObserver() { + @Override + public void onChanged() { + if (mPagerAdapter != null) mPagerAdapter.notifyDataSetChanged(); + } + + @Override + public void onInvalidated() { + if (mPagerAdapter != null) mPagerAdapter.notifyDataSetChanged(); + } + }; + + private int pickFullscreenStartingPosition() { + int firstVisiblePosition = mGridView.getFirstVisiblePosition(); + if (mLastCheckedPosition <= firstVisiblePosition + || mLastCheckedPosition > mGridView.getLastVisiblePosition()) { + return firstVisiblePosition; + } else { + return mLastCheckedPosition; + } + } + + private void setSwitcherMenuState(MenuItem menuItem, boolean inFullscreenMode) { + if (menuItem == null) return; + if (!inFullscreenMode) { + menuItem.setIcon(android.R.drawable.ic_menu_zoom); + menuItem.setTitle(R.string.switch_photo_fullscreen); + } else { + menuItem.setIcon(android.R.drawable.ic_dialog_dialer); + menuItem.setTitle(R.string.switch_photo_grid); + } + } + + private void setFullscreenPagerVisibility(boolean visible) { + mFullscreenPagerVisible = visible; + if (visible) { + if (mPagerAdapter == null) { + mPagerAdapter = new MtpPagerAdapter(this, mPositionMappingCheckBroker); + mPagerAdapter.setMtpDeviceIndex(mAdapter.getMtpDeviceIndex()); + } + mFullscreenPager.setAdapter(mPagerAdapter); + mFullscreenPager.setCurrentItem(mPagerAdapter.translatePositionWithLabels( + pickFullscreenStartingPosition()), false); + } else if (mPagerAdapter != null) { + mGridView.setSelection(mAdapter.translatePositionWithoutLabels( + mFullscreenPager.getCurrentItem())); + mFullscreenPager.setAdapter(null); + } + mGridView.setVisibility(visible ? View.INVISIBLE : View.VISIBLE); + mFullscreenPager.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + if (mActionMenuSwitcherItem != null) { + setSwitcherMenuState(mActionMenuSwitcherItem, visible); + } + setSwitcherMenuState(mMenuSwitcherItem, visible); + } + + private void updateWarningView() { if (!mAdapter.deviceConnected()) { - showWarningOverlay(R.string.ingest_no_device); + showWarningView(R.string.ingest_no_device); } else if (mAdapter.indexReady() && mAdapter.getCount() == 0) { - showWarningOverlay(R.string.ingest_empty_device); + showWarningView(R.string.ingest_empty_device); } else { - hideWarningOverlay(); + hideWarningView(); } } @@ -221,7 +379,7 @@ public class IngestActivity extends Activity implements mActiveActionMode.finish(); mActiveActionMode = null; } - updateWarningOverlay(); + updateWarningView(); } protected void notifyIndexChanged() { @@ -330,6 +488,7 @@ public class IngestActivity extends Activity implements public static final int MSG_PROGRESS_UPDATE = 0; public static final int MSG_PROGRESS_HIDE = 1; public static final int MSG_NOTIFY_CHANGED = 2; + public static final int MSG_BULK_CHECKED_CHANGE = 3; WeakReference<IngestActivity> mParentReference; @@ -352,6 +511,9 @@ public class IngestActivity extends Activity implements case MSG_NOTIFY_CHANGED: parent.UiThreadNotifyIndexChanged(); break; + case MSG_BULK_CHECKED_CHANGE: + parent.mPositionMappingCheckBroker.onBulkCheckedChange(); + break; default: break; } @@ -362,7 +524,9 @@ public class IngestActivity extends Activity implements public void onServiceConnected(ComponentName className, IBinder service) { mHelperService = ((IngestService.LocalBinder) service).getService(); mHelperService.setClientActivity(IngestActivity.this); - mAdapter.setMtpDeviceIndex(mHelperService.getIndex()); + MtpDeviceIndex index = mHelperService.getIndex(); + mAdapter.setMtpDeviceIndex(index); + if (mPagerAdapter != null) mPagerAdapter.setMtpDeviceIndex(index); } public void onServiceDisconnected(ComponentName className) { diff --git a/src/com/android/gallery3d/ingest/IngestService.java b/src/com/android/gallery3d/ingest/IngestService.java index 12b056b60..5e0ca0b68 100644 --- a/src/com/android/gallery3d/ingest/IngestService.java +++ b/src/com/android/gallery3d/ingest/IngestService.java @@ -37,7 +37,7 @@ import android.widget.Adapter; import com.android.gallery3d.R; import com.android.gallery3d.app.NotificationIds; import com.android.gallery3d.data.MtpClient; -import com.android.gallery3d.ingest.ui.MtpBitmapCache; +import com.android.gallery3d.ingest.data.MtpBitmapFetch; import com.android.gallery3d.util.BucketNames; import java.util.ArrayList; @@ -66,6 +66,7 @@ public class IngestService extends Service implements ImportTask.Listener, private boolean mRedeliverImportFinish = false; private Collection<MtpObjectInfo> mRedeliverObjectsNotImported; private boolean mRedeliverNotifyIndexChanged = false; + private boolean mRedeliverIndexFinish = false; private NotificationManager mNotificationManager; private NotificationCompat.Builder mNotificationBuilder; private long mLastProgressIndexTime = 0; @@ -108,13 +109,19 @@ public class IngestService extends Service implements ImportTask.Listener, mRedeliverImportFinish = false; mRedeliverObjectsNotImported = null; mRedeliverNotifyIndexChanged = false; + mRedeliverIndexFinish = false; mDevice = device; mIndex.setDevice(mDevice); if (mDevice != null) { MtpDeviceInfo deviceInfo = mDevice.getDeviceInfo(); - mDevicePrettyName = deviceInfo.getModel(); - mNotificationBuilder.setContentTitle(mDevicePrettyName); - new Thread(mIndex.getIndexRunnable()).start(); + if (deviceInfo == null) { + setDevice(null); + return; + } else { + mDevicePrettyName = deviceInfo.getModel(); + mNotificationBuilder.setContentTitle(mDevicePrettyName); + new Thread(mIndex.getIndexRunnable()).start(); + } } else { mDevicePrettyName = null; } @@ -144,6 +151,10 @@ public class IngestService extends Service implements ImportTask.Listener, mClientActivity.notifyIndexChanged(); mRedeliverNotifyIndexChanged = false; } + if (mRedeliverIndexFinish) { + mClientActivity.onIndexFinish(); + mRedeliverIndexFinish = false; + } } protected void importSelectedItems(SparseBooleanArray selected, Adapter adapter) { @@ -176,8 +187,8 @@ public class IngestService extends Service implements ImportTask.Listener, public void deviceRemoved(MtpDevice device) { if (device == mDevice) { setDevice(null); + MtpBitmapFetch.onDeviceDisconnected(device); } - MtpBitmapCache.onDeviceDisconnected(device); } @Override @@ -197,6 +208,7 @@ public class IngestService extends Service implements ImportTask.Listener, @Override public void onImportFinish(Collection<MtpObjectInfo> objectsNotImported) { + stopForeground(true); if (mClientActivity != null) { mClientActivity.onImportFinish(objectsNotImported); } else { @@ -207,7 +219,6 @@ public class IngestService extends Service implements ImportTask.Listener, mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_IMPORTING, mNotificationBuilder.build()); } - stopForeground(mClientActivity != null); } @Override @@ -241,6 +252,7 @@ public class IngestService extends Service implements ImportTask.Listener, .setContentText(getResources().getText(R.string.ingest_scanning_done)); mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_SCANNING, mNotificationBuilder.build()); + mRedeliverIndexFinish = true; } } diff --git a/src/com/android/gallery3d/ingest/MtpDeviceIndex.java b/src/com/android/gallery3d/ingest/MtpDeviceIndex.java index 28e115ab0..e873dd1ca 100644 --- a/src/com/android/gallery3d/ingest/MtpDeviceIndex.java +++ b/src/com/android/gallery3d/ingest/MtpDeviceIndex.java @@ -180,55 +180,90 @@ public class MtpDeviceIndex { * order */ public Object get(int position, SortOrder order) { + if (mProgress != Progress.Finished) return null; if(order == SortOrder.Ascending) { - return getAscending(position); + DateBucket bucket = mBuckets[mUnifiedLookupIndex[position]]; + if (bucket.unifiedStartIndex == position) { + return bucket.bucket; + } else { + return mMtpObjects[bucket.itemsStartIndex + position - 1 + - bucket.unifiedStartIndex]; + } } else { - return getDescending(position); + int zeroIndex = mUnifiedLookupIndex.length - 1 - position; + DateBucket bucket = mBuckets[mUnifiedLookupIndex[zeroIndex]]; + if (bucket.unifiedEndIndex == zeroIndex) { + return bucket.bucket; + } else { + return mMtpObjects[bucket.itemsStartIndex + zeroIndex + - bucket.unifiedStartIndex]; + } } } /** - * @param position Index of item to fetch, where 0 is the first item in - * ascending order - * @return position-th item in ascending order + * @param position Index of item to fetch from a view of the data that doesn't + * include labels and is in the specified order + * @return position-th item in specified order, when not including labels */ - public Object getAscending(int position) { + public MtpObjectInfo getWithoutLabels(int position, SortOrder order) { if (mProgress != Progress.Finished) return null; - DateBucket bucket = mBuckets[mUnifiedLookupIndex[position]]; - if (bucket.unifiedStartIndex == position) { - return bucket.bucket; + if (order == SortOrder.Ascending) { + return mMtpObjects[position]; } else { - return bucket.get(position - 1 - bucket.unifiedStartIndex); + return mMtpObjects[mMtpObjects.length - 1 - position]; } } /** - * @param position Index of item to fetch, where 0 is the last item in - * ascending order - * @return position-th item in descending order + * Although this is O(log(number of buckets)), and thus should not be used + * in hotspots, even if the attached device has items for every day for + * a five-year timeframe, it would still only take 11 iterations at most, + * so shouldn't be a huge issue. + * @param position Index of item to map from a view of the data that doesn't + * include labels and is in the specified order + * @param order + * @return position in a view of the data that does include labels */ - public Object getDescending(int position) { - if (mProgress != Progress.Finished) return null; - int zeroIndex = mUnifiedLookupIndex.length - 1 - position; - DateBucket bucket = mBuckets[mUnifiedLookupIndex[zeroIndex]]; - if (bucket.unifiedEndIndex == zeroIndex) { - return bucket.bucket; - } else { - return bucket.get(zeroIndex - bucket.unifiedStartIndex); + public int getPositionFromPositionWithoutLabels(int position, SortOrder order) { + if (mProgress != Progress.Finished) return -1; + if (order == SortOrder.Descending) { + position = mMtpObjects.length - 1 - position; + } + int bucketNumber = 0; + int iMin = 0; + int iMax = mBuckets.length - 1; + while (iMax >= iMin) { + int iMid = (iMax + iMin) / 2; + if (mBuckets[iMid].itemsStartIndex + mBuckets[iMid].numItems <= position) { + iMin = iMid + 1; + } else if (mBuckets[iMid].itemsStartIndex > position) { + iMax = iMid - 1; + } else { + bucketNumber = iMid; + break; + } } + int mappedPos = mBuckets[bucketNumber].unifiedStartIndex + + position - mBuckets[bucketNumber].itemsStartIndex; + if (order == SortOrder.Descending) { + mappedPos = mUnifiedLookupIndex.length - 1 - mappedPos; + } + return mappedPos; } - /** - * @param position Index of item to fetch from a view of the data that doesn't - * include labels and is in ascending order - * @return position-th item in ascending order, when not including labels - */ - public MtpObjectInfo getWithoutLabels(int position, SortOrder order) { - if (mProgress != Progress.Finished) return null; - if (order == SortOrder.Ascending) { - return mMtpObjects[position]; + public int getPositionWithoutLabelsFromPosition(int position, SortOrder order) { + if (mProgress != Progress.Finished) return -1; + if(order == SortOrder.Ascending) { + DateBucket bucket = mBuckets[mUnifiedLookupIndex[position]]; + if (bucket.unifiedStartIndex == position) position++; + return bucket.itemsStartIndex + position - 1 - bucket.unifiedStartIndex; } else { - return mMtpObjects[mMtpObjects.length - 1 - position]; + int zeroIndex = mUnifiedLookupIndex.length - 1 - position; + DateBucket bucket = mBuckets[mUnifiedLookupIndex[zeroIndex]]; + if (bucket.unifiedEndIndex == zeroIndex) zeroIndex--; + return mMtpObjects.length - 1 - bucket.itemsStartIndex + - zeroIndex + bucket.unifiedStartIndex; } } @@ -288,6 +323,7 @@ public class MtpDeviceIndex { int unifiedStartIndex; int unifiedEndIndex; int itemsStartIndex; + int numItems; public DateBucket(SimpleDate bucket) { this.bucket = bucket; @@ -302,10 +338,6 @@ public class MtpDeviceIndex { Collections.sort(tempElementsList, comparator); } - public MtpObjectInfo get(int position) { - return mMtpObjects[itemsStartIndex + position]; - } - @Override public String toString() { return bucket.toString(); @@ -413,7 +445,8 @@ public class MtpDeviceIndex { currentUnifiedIndexEntry = nextUnifiedEntry; bucket.itemsStartIndex = currentItemsEntry; - for (int j = 0; j < bucket.tempElementsList.size(); j++) { + bucket.numItems = bucket.tempElementsList.size(); + for (int j = 0; j < bucket.numItems; j++) { mMtpObjects[currentItemsEntry] = bucket.tempElementsList.get(j); currentItemsEntry++; } diff --git a/src/com/android/gallery3d/ingest/adapter/CheckBroker.java b/src/com/android/gallery3d/ingest/adapter/CheckBroker.java new file mode 100644 index 000000000..6783f23c5 --- /dev/null +++ b/src/com/android/gallery3d/ingest/adapter/CheckBroker.java @@ -0,0 +1,56 @@ +/* + * 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.gallery3d.ingest.adapter; + +import java.util.ArrayList; +import java.util.Collection; + +public abstract class CheckBroker { + private Collection<OnCheckedChangedListener> mListeners = + new ArrayList<OnCheckedChangedListener>(); + + public interface OnCheckedChangedListener { + public void onCheckedChanged(int position, boolean isChecked); + public void onBulkCheckedChanged(); + } + + public abstract void setItemChecked(int position, boolean checked); + + public void onCheckedChange(int position, boolean checked) { + if (isItemChecked(position) != checked) { + for (OnCheckedChangedListener l : mListeners) { + l.onCheckedChanged(position, checked); + } + } + } + + public void onBulkCheckedChange() { + for (OnCheckedChangedListener l : mListeners) { + l.onBulkCheckedChanged(); + } + } + + public abstract boolean isItemChecked(int position); + + public void registerOnCheckedChangeListener(OnCheckedChangedListener l) { + mListeners.add(l); + } + + public void unregisterOnCheckedChangeListener(OnCheckedChangedListener l) { + mListeners.remove(l); + } +} diff --git a/src/com/android/gallery3d/ingest/adapter/MtpAdapter.java b/src/com/android/gallery3d/ingest/adapter/MtpAdapter.java index 611d880db..e8dd69f8c 100644 --- a/src/com/android/gallery3d/ingest/adapter/MtpAdapter.java +++ b/src/com/android/gallery3d/ingest/adapter/MtpAdapter.java @@ -45,8 +45,7 @@ public class MtpAdapter extends BaseAdapter implements SectionIndexer { public MtpAdapter(Activity context) { super(); mContext = context; - mInflater = (LayoutInflater)context.getSystemService - (Context.LAYOUT_INFLATER_SERVICE); + mInflater = LayoutInflater.from(context); } public void setMtpDeviceIndex(MtpDeviceIndex index) { @@ -54,6 +53,10 @@ public class MtpAdapter extends BaseAdapter implements SectionIndexer { notifyDataSetChanged(); } + public MtpDeviceIndex getMtpDeviceIndex() { + return mModel; + } + @Override public void notifyDataSetChanged() { mGeneration++; @@ -177,4 +180,13 @@ public class MtpAdapter extends BaseAdapter implements SectionIndexer { public Object[] getSections() { return getCount() > 0 ? mModel.getBuckets(mSortOrder) : null; } + + public SortOrder getSortOrder() { + return mSortOrder; + } + + public int translatePositionWithoutLabels(int position) { + if (mModel == null) return -1; + return mModel.getPositionFromPositionWithoutLabels(position, mSortOrder); + } } diff --git a/src/com/android/gallery3d/ingest/adapter/MtpPagerAdapter.java b/src/com/android/gallery3d/ingest/adapter/MtpPagerAdapter.java new file mode 100644 index 000000000..9e7abc01d --- /dev/null +++ b/src/com/android/gallery3d/ingest/adapter/MtpPagerAdapter.java @@ -0,0 +1,102 @@ +/* + * 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.gallery3d.ingest.adapter; + +import android.content.Context; +import android.mtp.MtpObjectInfo; +import android.support.v4.view.PagerAdapter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.android.gallery3d.R; +import com.android.gallery3d.ingest.MtpDeviceIndex; +import com.android.gallery3d.ingest.MtpDeviceIndex.SortOrder; +import com.android.gallery3d.ingest.ui.MtpFullscreenView; + +public class MtpPagerAdapter extends PagerAdapter { + + private LayoutInflater mInflater; + private int mGeneration = 0; + private CheckBroker mBroker; + private MtpDeviceIndex mModel; + private SortOrder mSortOrder = SortOrder.Descending; + + private MtpFullscreenView mReusableView = null; + + public MtpPagerAdapter(Context context, CheckBroker broker) { + super(); + mInflater = LayoutInflater.from(context); + mBroker = broker; + } + + public void setMtpDeviceIndex(MtpDeviceIndex index) { + mModel = index; + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mModel != null ? mModel.sizeWithoutLabels() : 0; + } + + @Override + public void notifyDataSetChanged() { + mGeneration++; + super.notifyDataSetChanged(); + } + + public int translatePositionWithLabels(int position) { + if (mModel == null) return -1; + return mModel.getPositionWithoutLabelsFromPosition(position, mSortOrder); + } + + @Override + public void finishUpdate(ViewGroup container) { + mReusableView = null; + super.finishUpdate(container); + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + MtpFullscreenView v = (MtpFullscreenView)object; + container.removeView(v); + mBroker.unregisterOnCheckedChangeListener(v); + mReusableView = v; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + MtpFullscreenView v; + if (mReusableView != null) { + v = mReusableView; + mReusableView = null; + } else { + v = (MtpFullscreenView) mInflater.inflate(R.layout.ingest_fullsize, container, false); + } + MtpObjectInfo i = mModel.getWithoutLabels(position, mSortOrder); + v.getImageView().setMtpDeviceAndObjectInfo(mModel.getDevice(), i, mGeneration); + v.setPositionAndBroker(position, mBroker); + container.addView(v); + return v; + } +} diff --git a/src/com/android/gallery3d/ingest/data/BitmapWithMetadata.java b/src/com/android/gallery3d/ingest/data/BitmapWithMetadata.java new file mode 100644 index 000000000..bbc90f670 --- /dev/null +++ b/src/com/android/gallery3d/ingest/data/BitmapWithMetadata.java @@ -0,0 +1,29 @@ +/* + * 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.gallery3d.ingest.data; + +import android.graphics.Bitmap; + +public class BitmapWithMetadata { + public Bitmap bitmap; + public int rotationDegrees; + + public BitmapWithMetadata(Bitmap bitmap, int rotationDegrees) { + this.bitmap = bitmap; + this.rotationDegrees = rotationDegrees; + } +} diff --git a/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java new file mode 100644 index 000000000..88645e8d0 --- /dev/null +++ b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java @@ -0,0 +1,97 @@ +/* + * 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.gallery3d.ingest.data; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.mtp.MtpDevice; +import android.mtp.MtpObjectInfo; +import android.util.DisplayMetrics; +import android.view.WindowManager; + +import com.android.camera.Exif; +import com.android.gallery3d.common.Utils; +import com.android.gallery3d.data.BitmapPool; + +import java.util.ArrayList; + +public class MtpBitmapFetch { + private static final int BITMAP_POOL_SIZE = 32; + private static BitmapPool sThumbnailPool = new BitmapPool(BITMAP_POOL_SIZE); + private static int sMaxSize = 0; + + public static void recycleThumbnail(Bitmap b) { + if (b != null) { + sThumbnailPool.recycle(b); + } + } + + public static Bitmap getThumbnail(MtpDevice device, MtpObjectInfo info) { + byte[] imageBytes = device.getThumbnail(info.getObjectHandle()); + BitmapFactory.Options o = new BitmapFactory.Options(); + o.inJustDecodeBounds = true; + BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o); + if (o.outWidth == 0 || o.outHeight == 0) return null; + o.inBitmap = sThumbnailPool.getBitmap(o.outWidth, o.outHeight); + o.inMutable = true; + o.inJustDecodeBounds = false; + o.inSampleSize = 1; + return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o); + } + + public static BitmapWithMetadata getFullsize(MtpDevice device, MtpObjectInfo info) { + return getFullsize(device, info, sMaxSize); + } + + public static BitmapWithMetadata getFullsize(MtpDevice device, MtpObjectInfo info, int maxSide) { + byte[] imageBytes = device.getObject(info.getObjectHandle(), info.getCompressedSize()); + Bitmap created; + if (maxSide > 0) { + BitmapFactory.Options o = new BitmapFactory.Options(); + o.inJustDecodeBounds = true; + BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o); + int w = o.outWidth; + int h = o.outHeight; + int comp = Math.max(h, w); + int sampleSize = 1; + while ((comp >> 1) >= maxSide) { + comp = comp >> 1; + sampleSize++; + } + o.inSampleSize = sampleSize; + o.inJustDecodeBounds = false; + created = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o); + } else { + created = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); + } + if (created == null) return null; + + return new BitmapWithMetadata(created, Exif.getOrientation(imageBytes)); + } + + public static void onDeviceDisconnected(MtpDevice device) { + sThumbnailPool.clear(); + } + + public static void configureForContext(Context context) { + DisplayMetrics metrics = new DisplayMetrics(); + WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getMetrics(metrics); + sMaxSize = Math.max(metrics.heightPixels, metrics.widthPixels); + } +} diff --git a/src/com/android/gallery3d/ingest/ui/IngestGridView.java b/src/com/android/gallery3d/ingest/ui/IngestGridView.java new file mode 100644 index 000000000..c821259fe --- /dev/null +++ b/src/com/android/gallery3d/ingest/ui/IngestGridView.java @@ -0,0 +1,58 @@ +/* + * 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.gallery3d.ingest.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.GridView; + +/** + * This just extends GridView with the ability to listen for calls + * to clearChoices() + */ +public class IngestGridView extends GridView { + + public interface OnClearChoicesListener { + public void onClearChoices(); + } + + private OnClearChoicesListener mOnClearChoicesListener = null; + + public IngestGridView(Context context) { + super(context); + } + + public IngestGridView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public IngestGridView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public void setOnClearChoicesListener(OnClearChoicesListener l) { + mOnClearChoicesListener = l; + } + + @Override + public void clearChoices() { + super.clearChoices(); + if (mOnClearChoicesListener != null) { + mOnClearChoicesListener.onClearChoices(); + } + } +} diff --git a/src/com/android/gallery3d/ingest/ui/MtpBitmapCache.java b/src/com/android/gallery3d/ingest/ui/MtpBitmapCache.java deleted file mode 100644 index 307531d5b..000000000 --- a/src/com/android/gallery3d/ingest/ui/MtpBitmapCache.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.gallery3d.ingest.ui; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.mtp.MtpDevice; -import android.util.LruCache; - -public class MtpBitmapCache extends LruCache<Integer, Bitmap> { - private static final int PER_DEVICE_CACHE_MAX_BYTES = 4194304; - private static MtpBitmapCache sInstance; - - public synchronized static MtpBitmapCache getInstanceForDevice(MtpDevice device) { - if (sInstance == null || sInstance.mDevice != device) { - sInstance = new MtpBitmapCache(PER_DEVICE_CACHE_MAX_BYTES, device); - } - return sInstance; - } - - public synchronized static void onDeviceDisconnected(MtpDevice device) { - if (sInstance != null && sInstance.mDevice == device) { - synchronized (sInstance) { - sInstance.mDevice = null; - } - sInstance = null; - } - } - - private MtpDevice mDevice; - - private MtpBitmapCache(int maxSize, MtpDevice device) { - super(maxSize); - mDevice = device; - } - - @Override - protected int sizeOf(Integer key, Bitmap value) { - return value.getByteCount(); - } - - public Bitmap getOrCreate(Integer key) { - Bitmap b = get(key); - return b == null ? createAndInsert(key) : b; - } - - private Bitmap createAndInsert(Integer key) { - MtpDevice device; - synchronized (this) { - device = mDevice; - } - if (device == null) return null; - byte[] imageBytes = device.getThumbnail(key); - if (imageBytes == null) return null; - Bitmap created = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); - put(key, created); - return created; - } -} diff --git a/src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java b/src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java new file mode 100644 index 000000000..8d3884dc6 --- /dev/null +++ b/src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java @@ -0,0 +1,115 @@ +/* + * 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.gallery3d.ingest.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.CheckBox; +import android.widget.Checkable; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.RelativeLayout; + +import com.android.gallery3d.R; +import com.android.gallery3d.ingest.adapter.CheckBroker; + +public class MtpFullscreenView extends RelativeLayout implements Checkable, + CompoundButton.OnCheckedChangeListener, CheckBroker.OnCheckedChangedListener { + + private MtpImageView mImageView; + private CheckBox mCheckbox; + private int mPosition = -1; + private CheckBroker mBroker; + + public MtpFullscreenView(Context context) { + super(context); + } + + public MtpFullscreenView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public MtpFullscreenView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mImageView = (MtpImageView) findViewById(R.id.ingest_fullsize_image); + mCheckbox = (CheckBox) findViewById(R.id.ingest_fullsize_image_checkbox); + mCheckbox.setOnCheckedChangeListener(this); + } + + @Override + public boolean isChecked() { + return mCheckbox.isChecked(); + } + + @Override + public void setChecked(boolean checked) { + mCheckbox.setChecked(checked); + } + + @Override + public void toggle() { + mCheckbox.toggle(); + } + + @Override + public void onDetachedFromWindow() { + setPositionAndBroker(-1, null); + super.onDetachedFromWindow(); + } + + public MtpImageView getImageView() { + return mImageView; + } + + public int getPosition() { + return mPosition; + } + + public void setPositionAndBroker(int position, CheckBroker b) { + if (mBroker != null) { + mBroker.unregisterOnCheckedChangeListener(this); + } + mPosition = position; + mBroker = b; + if (mBroker != null) { + setChecked(mBroker.isItemChecked(position)); + mBroker.registerOnCheckedChangeListener(this); + } + } + + @Override + public void onCheckedChanged(CompoundButton arg0, boolean isChecked) { + if (mBroker != null) mBroker.setItemChecked(mPosition, isChecked); + } + + @Override + public void onCheckedChanged(int position, boolean isChecked) { + if (position == mPosition) { + setChecked(isChecked); + } + } + + @Override + public void onBulkCheckedChanged() { + if(mBroker != null) setChecked(mBroker.isItemChecked(mPosition)); + } +} diff --git a/src/com/android/gallery3d/ingest/ui/MtpImageView.java b/src/com/android/gallery3d/ingest/ui/MtpImageView.java new file mode 100644 index 000000000..9c197851e --- /dev/null +++ b/src/com/android/gallery3d/ingest/ui/MtpImageView.java @@ -0,0 +1,130 @@ +/* + * 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.gallery3d.ingest.ui; + +import android.content.Context; +import android.mtp.MtpDevice; +import android.mtp.MtpObjectInfo; +import android.os.AsyncTask; +import android.util.AttributeSet; +import android.widget.ImageView; + +import com.android.gallery3d.ingest.data.BitmapWithMetadata; +import com.android.gallery3d.ingest.data.MtpBitmapFetch; + +public class MtpImageView extends ImageView { + private static final int FADE_IN_TIME_MS = 80; + + private int mObjectHandle; + private int mGeneration; + + private void init() { + showPlaceholder(); + } + + public MtpImageView(Context context) { + super(context); + init(); + } + + public MtpImageView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public MtpImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void showPlaceholder() { + setImageResource(android.R.color.transparent); + } + + private LoadMtpImageTask mTask; + + public void setMtpDeviceAndObjectInfo(MtpDevice device, MtpObjectInfo object, int gen) { + int handle = object.getObjectHandle(); + if (handle == mObjectHandle && gen == mGeneration) { + return; + } + cancelLoadingAndClear(); + showPlaceholder(); + mGeneration = gen; + mObjectHandle = handle; + mTask = new LoadMtpImageTask(device); + mTask.execute(object); + } + + protected Object fetchMtpImageDataFromDevice(MtpDevice device, MtpObjectInfo info) { + return MtpBitmapFetch.getFullsize(device, info); + } + + protected void onMtpImageDataFetchedFromDevice(Object result) { + BitmapWithMetadata bitmapWithMetadata = (BitmapWithMetadata)result; + setImageBitmap(bitmapWithMetadata.bitmap); + setRotation(bitmapWithMetadata.rotationDegrees); + } + + private class LoadMtpImageTask extends AsyncTask<MtpObjectInfo, Void, Object> { + private MtpDevice mDevice; + + public LoadMtpImageTask(MtpDevice device) { + mDevice = device; + } + + @Override + protected Object doInBackground(MtpObjectInfo... args) { + Object result = null; + if (!isCancelled()) { + result = fetchMtpImageDataFromDevice(mDevice, args[0]); + } + mDevice = null; + return result; + } + + @Override + protected void onPostExecute(Object result) { + if (isCancelled() || result == null) { + return; + } + setAlpha(0f); + onMtpImageDataFetchedFromDevice(result); + animate().alpha(1f).setDuration(FADE_IN_TIME_MS); + } + + @Override + protected void onCancelled() { + } + } + + protected void cancelLoadingAndClear() { + if (mTask != null) { + mTask.cancel(true); + } + mTask = null; + animate().cancel(); + setImageResource(android.R.color.transparent); + setRotation(0); + } + + @Override + public void onDetachedFromWindow() { + cancelLoadingAndClear(); + super.onDetachedFromWindow(); + } +} diff --git a/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java b/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java index 2aeda73db..3307e78aa 100644 --- a/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java +++ b/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java @@ -22,26 +22,22 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.mtp.MtpDevice; import android.mtp.MtpObjectInfo; -import android.os.AsyncTask; import android.util.AttributeSet; -import android.view.View; import android.widget.Checkable; -import android.widget.ImageView; import com.android.gallery3d.R; +import com.android.gallery3d.ingest.data.MtpBitmapFetch; -public class MtpThumbnailTileView extends ImageView implements Checkable { - private static final int FADE_IN_TIME_MS = 80; + +public class MtpThumbnailTileView extends MtpImageView implements Checkable { private Paint mForegroundPaint; private boolean mIsChecked; - private int mObjectHandle; - private int mGeneration; + private Bitmap mBitmap; private void init() { mForegroundPaint = new Paint(); mForegroundPaint.setColor(getResources().getColor(R.color.ingest_highlight_semitransparent)); - showPlaceholder(); } public MtpThumbnailTileView(Context context) { @@ -66,9 +62,20 @@ public class MtpThumbnailTileView extends ImageView implements Checkable { } @Override + protected Object fetchMtpImageDataFromDevice(MtpDevice device, MtpObjectInfo info) { + return MtpBitmapFetch.getThumbnail(device, info); + } + + @Override + protected void onMtpImageDataFetchedFromDevice(Object result) { + mBitmap = (Bitmap)result; + setImageBitmap(mBitmap); + } + + @Override public void draw(Canvas canvas) { super.draw(canvas); - if (mIsChecked) { + if (isChecked()) { canvas.drawRect(canvas.getClipBounds(), mForegroundPaint); } } @@ -88,65 +95,12 @@ public class MtpThumbnailTileView extends ImageView implements Checkable { setChecked(!mIsChecked); } - private void showPlaceholder() { - setAlpha(0f); - } - - private LoadThumbnailTask mTask; - - public void setMtpDeviceAndObjectInfo(MtpDevice device, MtpObjectInfo object, int gen) { - int handle = object.getObjectHandle(); - if (handle == mObjectHandle && gen == mGeneration) { - return; - } - animate().cancel(); - if (mTask != null) { - mTask.cancel(true); - } - mGeneration = gen; - mObjectHandle = handle; - Bitmap thumbnail = MtpBitmapCache.getInstanceForDevice(device) - .get(handle); - if (thumbnail != null) { - setAlpha(1f); - setImageBitmap(thumbnail); - } else { - showPlaceholder(); - mTask = new LoadThumbnailTask(device); - mTask.execute(object); - } - } - - private class LoadThumbnailTask extends AsyncTask<MtpObjectInfo, Void, Bitmap> { - private MtpDevice mDevice; - - public LoadThumbnailTask(MtpDevice device) { - mDevice = device; - } - - @Override - protected Bitmap doInBackground(MtpObjectInfo... args) { - Bitmap result = null; - if (!isCancelled()) { - result = MtpBitmapCache.getInstanceForDevice(mDevice).getOrCreate( - args[0].getObjectHandle()); - } - mDevice = null; - return result; - } - - @Override - protected void onPostExecute(Bitmap result) { - if (isCancelled() || result == null) { - return; - } - setAlpha(0f); - setImageBitmap(result); - animate().alpha(1f).setDuration(FADE_IN_TIME_MS); - } - - @Override - protected void onCancelled() { + @Override + protected void cancelLoadingAndClear() { + super.cancelLoadingAndClear(); + if (mBitmap != null) { + MtpBitmapFetch.recycleThumbnail(mBitmap); + mBitmap = null; } } } |