diff options
Diffstat (limited to 'src/com/android/gallery3d/filtershow/FilterShowActivity.java')
-rw-r--r-- | src/com/android/gallery3d/filtershow/FilterShowActivity.java | 1121 |
1 files changed, 1121 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java new file mode 100644 index 000000000..4700fccfe --- /dev/null +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -0,0 +1,1121 @@ +/* + * Copyright (C) 2012 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; + +import android.app.ActionBar; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.ComponentName; +import android.content.ContentValues; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewPropertyAnimator; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.FrameLayout; +import android.widget.ShareActionProvider; +import android.widget.ShareActionProvider.OnShareTargetSelectedListener; +import android.widget.Toast; + +import com.android.gallery3d.R; +import com.android.gallery3d.app.PhotoPage; +import com.android.gallery3d.data.LocalAlbum; +import com.android.gallery3d.filtershow.cache.ImageLoader; +import com.android.gallery3d.filtershow.category.Action; +import com.android.gallery3d.filtershow.category.CategoryAdapter; +import com.android.gallery3d.filtershow.category.MainPanel; +import com.android.gallery3d.filtershow.data.UserPresetsManager; +import com.android.gallery3d.filtershow.editors.BasicEditor; +import com.android.gallery3d.filtershow.editors.Editor; +import com.android.gallery3d.filtershow.editors.EditorChanSat; +import com.android.gallery3d.filtershow.editors.EditorCrop; +import com.android.gallery3d.filtershow.editors.EditorDraw; +import com.android.gallery3d.filtershow.editors.EditorGrad; +import com.android.gallery3d.filtershow.editors.EditorManager; +import com.android.gallery3d.filtershow.editors.EditorMirror; +import com.android.gallery3d.filtershow.editors.EditorPanel; +import com.android.gallery3d.filtershow.editors.EditorRedEye; +import com.android.gallery3d.filtershow.editors.EditorRotate; +import com.android.gallery3d.filtershow.editors.EditorStraighten; +import com.android.gallery3d.filtershow.editors.EditorTinyPlanet; +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; +import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; +import com.android.gallery3d.filtershow.filters.FiltersManager; +import com.android.gallery3d.filtershow.filters.ImageFilter; +import com.android.gallery3d.filtershow.history.HistoryItem; +import com.android.gallery3d.filtershow.history.HistoryManager; +import com.android.gallery3d.filtershow.imageshow.ImageShow; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.imageshow.Spline; +import com.android.gallery3d.filtershow.pipeline.CachingPipeline; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; +import com.android.gallery3d.filtershow.pipeline.ProcessingService; +import com.android.gallery3d.filtershow.presets.PresetManagementDialog; +import com.android.gallery3d.filtershow.presets.UserPresetsAdapter; +import com.android.gallery3d.filtershow.provider.SharedImageProvider; +import com.android.gallery3d.filtershow.state.StateAdapter; +import com.android.gallery3d.filtershow.tools.SaveImage; +import com.android.gallery3d.filtershow.tools.XmpPresets; +import com.android.gallery3d.filtershow.tools.XmpPresets.XMresults; +import com.android.gallery3d.filtershow.ui.ExportDialog; +import com.android.gallery3d.filtershow.ui.FramedTextButton; +import com.android.gallery3d.util.GalleryUtils; +import com.android.gallery3d.util.UsageStatistics; +import com.android.photos.data.GalleryBitmapPool; + +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Vector; + +public class FilterShowActivity extends FragmentActivity implements OnItemClickListener, + OnShareTargetSelectedListener { + + private String mAction = ""; + MasterImage mMasterImage = null; + + private static final long LIMIT_SUPPORTS_HIGHRES = 134217728; // 128Mb + + public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET"; + public static final String LAUNCH_FULLSCREEN = "launch-fullscreen"; + private ImageShow mImageShow = null; + + private View mSaveButton = null; + + private EditorPlaceHolder mEditorPlaceHolder = new EditorPlaceHolder(this); + + private static final int SELECT_PICTURE = 1; + private static final String LOGTAG = "FilterShowActivity"; + + private boolean mShowingTinyPlanet = false; + private boolean mShowingImageStatePanel = false; + + private final Vector<ImageShow> mImageViews = new Vector<ImageShow>(); + + private ShareActionProvider mShareActionProvider; + private File mSharedOutputFile = null; + + private boolean mSharingImage = false; + + private WeakReference<ProgressDialog> mSavingProgressDialog; + + private LoadBitmapTask mLoadBitmapTask; + + private Uri mOriginalImageUri = null; + private ImagePreset mOriginalPreset = null; + + private Uri mSelectedImageUri = null; + + private UserPresetsManager mUserPresetsManager = null; + private UserPresetsAdapter mUserPresetsAdapter = null; + private CategoryAdapter mCategoryLooksAdapter = null; + private CategoryAdapter mCategoryBordersAdapter = null; + private CategoryAdapter mCategoryGeometryAdapter = null; + private CategoryAdapter mCategoryFiltersAdapter = null; + private int mCurrentPanel = MainPanel.LOOKS; + + private ProcessingService mBoundService; + private boolean mIsBound = false; + + public ProcessingService getProcessingService() { + return mBoundService; + } + + public boolean isSimpleEditAction() { + return !PhotoPage.ACTION_NEXTGEN_EDIT.equalsIgnoreCase(mAction); + } + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + /* + * This is called when the connection with the service has been + * established, giving us the service object we can use to + * interact with the service. Because we have bound to a explicit + * service that we know is running in our own process, we can + * cast its IBinder to a concrete class and directly access it. + */ + mBoundService = ((ProcessingService.LocalBinder)service).getService(); + mBoundService.setFiltershowActivity(FilterShowActivity.this); + mBoundService.onStart(); + } + + public void onServiceDisconnected(ComponentName className) { + /* + * This is called when the connection with the service has been + * unexpectedly disconnected -- that is, its process crashed. + * Because it is running in our same process, we should never + * see this happen. + */ + mBoundService = null; + } + }; + + void doBindService() { + /* + * Establish a connection with the service. We use an explicit + * class name because we want a specific service implementation that + * we know will be running in our own process (and thus won't be + * supporting component replacement by other applications). + */ + bindService(new Intent(FilterShowActivity.this, ProcessingService.class), + mConnection, Context.BIND_AUTO_CREATE); + mIsBound = true; + } + + void doUnbindService() { + if (mIsBound) { + // Detach our existing connection. + unbindService(mConnection); + mIsBound = false; + } + } + + private void setupPipeline() { + doBindService(); + ImageFilter.setActivityForMemoryToasts(this); + mUserPresetsManager = new UserPresetsManager(this); + mUserPresetsAdapter = new UserPresetsAdapter(this); + mCategoryLooksAdapter = new CategoryAdapter(this); + } + + public void updateUIAfterServiceStarted() { + fillCategories(); + loadMainPanel(); + setDefaultPreset(); + extractXMPData(); + processIntent(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + boolean onlyUsePortrait = getResources().getBoolean(R.bool.only_use_portrait); + if (onlyUsePortrait) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + MasterImage.setMaster(mMasterImage); + + clearGalleryBitmapPool(); + setupPipeline(); + + setupMasterImage(); + setDefaultValues(); + fillEditors(); + + loadXML(); + UsageStatistics.onContentViewChanged(UsageStatistics.COMPONENT_EDITOR, "Main"); + UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, + UsageStatistics.CATEGORY_LIFECYCLE, UsageStatistics.LIFECYCLE_START); + } + + public boolean isShowingImageStatePanel() { + return mShowingImageStatePanel; + } + + public void loadMainPanel() { + if (findViewById(R.id.main_panel_container) == null) { + return; + } + MainPanel panel = new MainPanel(); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG); + transaction.commit(); + } + + public void loadEditorPanel(FilterRepresentation representation, + final Editor currentEditor) { + if (representation.getEditorId() == ImageOnlyEditor.ID) { + currentEditor.reflectCurrentFilter(); + return; + } + final int currentId = currentEditor.getID(); + Runnable showEditor = new Runnable() { + @Override + public void run() { + EditorPanel panel = new EditorPanel(); + panel.setEditor(currentId); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.remove(getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG)); + transaction.replace(R.id.main_panel_container, panel, MainPanel.FRAGMENT_TAG); + transaction.commit(); + } + }; + Fragment main = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); + boolean doAnimation = false; + if (mShowingImageStatePanel + && getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + doAnimation = true; + } + if (doAnimation && main != null && main instanceof MainPanel) { + MainPanel mainPanel = (MainPanel) main; + View container = mainPanel.getView().findViewById(R.id.category_panel_container); + View bottom = mainPanel.getView().findViewById(R.id.bottom_panel); + int panelHeight = container.getHeight() + bottom.getHeight(); + ViewPropertyAnimator anim = mainPanel.getView().animate(); + anim.translationY(panelHeight).start(); + final Handler handler = new Handler(); + handler.postDelayed(showEditor, anim.getDuration()); + } else { + showEditor.run(); + } + } + + private void loadXML() { + setContentView(R.layout.filtershow_activity); + + ActionBar actionBar = getActionBar(); + actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); + actionBar.setCustomView(R.layout.filtershow_actionbar); + + mSaveButton = actionBar.getCustomView(); + mSaveButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + saveImage(); + } + }); + + mImageShow = (ImageShow) findViewById(R.id.imageShow); + mImageViews.add(mImageShow); + + setupEditors(); + + mEditorPlaceHolder.hide(); + mImageShow.bindAsImageLoadListener(); + + setupStatePanel(); + } + + public void fillCategories() { + fillLooks(); + loadUserPresets(); + fillBorders(); + fillTools(); + fillEffects(); + } + + public void setupStatePanel() { + MasterImage.getImage().setHistoryManager(mMasterImage.getHistory()); + } + + private void fillEffects() { + FiltersManager filtersManager = FiltersManager.getManager(); + ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getEffects(); + mCategoryFiltersAdapter = new CategoryAdapter(this); + for (FilterRepresentation representation : filtersRepresentations) { + if (representation.getTextId() != 0) { + representation.setName(getString(representation.getTextId())); + } + mCategoryFiltersAdapter.add(new Action(this, representation)); + } + } + + private void fillTools() { + FiltersManager filtersManager = FiltersManager.getManager(); + ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getTools(); + mCategoryGeometryAdapter = new CategoryAdapter(this); + for (FilterRepresentation representation : filtersRepresentations) { + mCategoryGeometryAdapter.add(new Action(this, representation)); + } + } + + private void processIntent() { + Intent intent = getIntent(); + if (intent.getBooleanExtra(LAUNCH_FULLSCREEN, false)) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + mAction = intent.getAction(); + mSelectedImageUri = intent.getData(); + Uri loadUri = mSelectedImageUri; + if (mOriginalImageUri != null) { + loadUri = mOriginalImageUri; + } + if (loadUri != null) { + startLoadBitmap(loadUri); + } else { + pickImage(); + } + } + + private void setupEditors() { + mEditorPlaceHolder.setContainer((FrameLayout) findViewById(R.id.editorContainer)); + EditorManager.addEditors(mEditorPlaceHolder); + mEditorPlaceHolder.setOldViews(mImageViews); + } + + private void fillEditors() { + mEditorPlaceHolder.addEditor(new EditorChanSat()); + mEditorPlaceHolder.addEditor(new EditorGrad()); + mEditorPlaceHolder.addEditor(new EditorDraw()); + mEditorPlaceHolder.addEditor(new BasicEditor()); + mEditorPlaceHolder.addEditor(new ImageOnlyEditor()); + mEditorPlaceHolder.addEditor(new EditorTinyPlanet()); + mEditorPlaceHolder.addEditor(new EditorRedEye()); + mEditorPlaceHolder.addEditor(new EditorCrop()); + mEditorPlaceHolder.addEditor(new EditorMirror()); + mEditorPlaceHolder.addEditor(new EditorRotate()); + mEditorPlaceHolder.addEditor(new EditorStraighten()); + } + + private void setDefaultValues() { + Resources res = getResources(); + + // TODO: get those values from XML. + FramedTextButton.setTextSize((int) getPixelsFromDip(14)); + FramedTextButton.setTrianglePadding((int) getPixelsFromDip(4)); + FramedTextButton.setTriangleSize((int) getPixelsFromDip(10)); + + Drawable curveHandle = res.getDrawable(R.drawable.camera_crop); + int curveHandleSize = (int) res.getDimension(R.dimen.crop_indicator_size); + Spline.setCurveHandle(curveHandle, curveHandleSize); + Spline.setCurveWidth((int) getPixelsFromDip(3)); + } + + private void startLoadBitmap(Uri uri) { + final View loading = findViewById(R.id.loading); + final View imageShow = findViewById(R.id.imageShow); + imageShow.setVisibility(View.INVISIBLE); + loading.setVisibility(View.VISIBLE); + mShowingTinyPlanet = false; + mLoadBitmapTask = new LoadBitmapTask(); + mLoadBitmapTask.execute(uri); + } + + private void fillBorders() { + FiltersManager filtersManager = FiltersManager.getManager(); + ArrayList<FilterRepresentation> borders = filtersManager.getBorders(); + + for (int i = 0; i < borders.size(); i++) { + FilterRepresentation filter = borders.get(i); + filter.setName(getString(R.string.borders)); + if (i == 0) { + filter.setName(getString(R.string.none)); + } + } + + mCategoryBordersAdapter = new CategoryAdapter(this); + for (FilterRepresentation representation : borders) { + if (representation.getTextId() != 0) { + representation.setName(getString(representation.getTextId())); + } + mCategoryBordersAdapter.add(new Action(this, representation, Action.FULL_VIEW)); + } + } + + public UserPresetsAdapter getUserPresetsAdapter() { + return mUserPresetsAdapter; + } + + public CategoryAdapter getCategoryLooksAdapter() { + return mCategoryLooksAdapter; + } + + public CategoryAdapter getCategoryBordersAdapter() { + return mCategoryBordersAdapter; + } + + public CategoryAdapter getCategoryGeometryAdapter() { + return mCategoryGeometryAdapter; + } + + public CategoryAdapter getCategoryFiltersAdapter() { + return mCategoryFiltersAdapter; + } + + public void removeFilterRepresentation(FilterRepresentation filterRepresentation) { + if (filterRepresentation == null) { + return; + } + ImagePreset oldPreset = MasterImage.getImage().getPreset(); + ImagePreset copy = new ImagePreset(oldPreset); + copy.removeFilter(filterRepresentation); + MasterImage.getImage().setPreset(copy, copy.getLastRepresentation(), true); + if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) { + FilterRepresentation lastRepresentation = copy.getLastRepresentation(); + MasterImage.getImage().setCurrentFilterRepresentation(lastRepresentation); + } + } + + public void useFilterRepresentation(FilterRepresentation filterRepresentation) { + if (filterRepresentation == null) { + return; + } + if (MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) { + return; + } + ImagePreset oldPreset = MasterImage.getImage().getPreset(); + ImagePreset copy = new ImagePreset(oldPreset); + FilterRepresentation representation = copy.getRepresentation(filterRepresentation); + if (representation == null) { + copy.addFilter(filterRepresentation); + } else if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { + filterRepresentation = representation; + } else { + if (filterRepresentation.allowsSingleInstanceOnly()) { + // Don't just update the filter representation. Centralize the + // logic in the addFilter(), such that we can keep "None" as + // null. + copy.removeFilter(representation); + copy.addFilter(filterRepresentation); + } + } + MasterImage.getImage().setPreset(copy, filterRepresentation, true); + MasterImage.getImage().setCurrentFilterRepresentation(filterRepresentation); + } + + public void showRepresentation(FilterRepresentation representation) { + if (representation == null) { + return; + } + + useFilterRepresentation(representation); + + // show representation + Editor mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId()); + loadEditorPanel(representation, mCurrentEditor); + } + + public Editor getEditor(int editorID) { + return mEditorPlaceHolder.getEditor(editorID); + } + + public void setCurrentPanel(int currentPanel) { + mCurrentPanel = currentPanel; + } + + public int getCurrentPanel() { + return mCurrentPanel; + } + + public void updateCategories() { + ImagePreset preset = mMasterImage.getPreset(); + mCategoryLooksAdapter.reflectImagePreset(preset); + mCategoryBordersAdapter.reflectImagePreset(preset); + } + + private class LoadHighresBitmapTask extends AsyncTask<Void, Void, Boolean> { + @Override + protected Boolean doInBackground(Void... params) { + MasterImage master = MasterImage.getImage(); + Rect originalBounds = master.getOriginalBounds(); + if (master.supportsHighRes()) { + int highresPreviewSize = master.getOriginalBitmapLarge().getWidth() * 2; + if (highresPreviewSize > originalBounds.width()) { + highresPreviewSize = originalBounds.width(); + } + Rect bounds = new Rect(); + Bitmap originalHires = ImageLoader.loadOrientedConstrainedBitmap(master.getUri(), + master.getActivity(), highresPreviewSize, + master.getOrientation(), bounds); + master.setOriginalBounds(bounds); + master.setOriginalBitmapHighres(originalHires); + mBoundService.setOriginalBitmapHighres(originalHires); + master.warnListeners(); + } + return true; + } + + @Override + protected void onPostExecute(Boolean result) { + Bitmap highresBitmap = MasterImage.getImage().getOriginalBitmapHighres(); + if (highresBitmap != null) { + float highResPreviewScale = (float) highresBitmap.getWidth() + / (float) MasterImage.getImage().getOriginalBounds().width(); + mBoundService.setHighresPreviewScaleFactor(highResPreviewScale); + } + } + } + + private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> { + int mBitmapSize; + + public LoadBitmapTask() { + mBitmapSize = getScreenImageSize(); + } + + @Override + protected Boolean doInBackground(Uri... params) { + if (!MasterImage.getImage().loadBitmap(params[0], mBitmapSize)) { + return false; + } + publishProgress(ImageLoader.queryLightCycle360(MasterImage.getImage().getActivity())); + return true; + } + + @Override + protected void onProgressUpdate(Boolean... values) { + super.onProgressUpdate(values); + if (isCancelled()) { + return; + } + if (values[0]) { + mShowingTinyPlanet = true; + } + } + + @Override + protected void onPostExecute(Boolean result) { + MasterImage.setMaster(mMasterImage); + if (isCancelled()) { + return; + } + + if (!result) { + cannotLoadImage(); + } + + if (null == CachingPipeline.getRenderScriptContext()){ + Log.v(LOGTAG,"RenderScript context destroyed during load"); + return; + } + final View loading = findViewById(R.id.loading); + loading.setVisibility(View.GONE); + final View imageShow = findViewById(R.id.imageShow); + imageShow.setVisibility(View.VISIBLE); + + Bitmap largeBitmap = MasterImage.getImage().getOriginalBitmapLarge(); + mBoundService.setOriginalBitmap(largeBitmap); + + float previewScale = (float) largeBitmap.getWidth() + / (float) MasterImage.getImage().getOriginalBounds().width(); + mBoundService.setPreviewScaleFactor(previewScale); + if (!mShowingTinyPlanet) { + mCategoryFiltersAdapter.removeTinyPlanet(); + } + mCategoryLooksAdapter.imageLoaded(); + mCategoryBordersAdapter.imageLoaded(); + mCategoryGeometryAdapter.imageLoaded(); + mCategoryFiltersAdapter.imageLoaded(); + mLoadBitmapTask = null; + + if (mOriginalPreset != null) { + MasterImage.getImage().setLoadedPreset(mOriginalPreset); + MasterImage.getImage().setPreset(mOriginalPreset, + mOriginalPreset.getLastRepresentation(), true); + mOriginalPreset = null; + } + + if (mAction == TINY_PLANET_ACTION) { + showRepresentation(mCategoryFiltersAdapter.getTinyPlanet()); + } + LoadHighresBitmapTask highresLoad = new LoadHighresBitmapTask(); + highresLoad.execute(); + super.onPostExecute(result); + } + + } + + private void clearGalleryBitmapPool() { + (new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + // Free memory held in Gallery's Bitmap pool. May be O(n) for n bitmaps. + GalleryBitmapPool.getInstance().clear(); + return null; + } + }).execute(); + } + + @Override + protected void onDestroy() { + if (mLoadBitmapTask != null) { + mLoadBitmapTask.cancel(false); + } + mUserPresetsManager.close(); + doUnbindService(); + super.onDestroy(); + } + + // TODO: find a more robust way of handling image size selection + // for high screen densities. + private int getScreenImageSize() { + DisplayMetrics outMetrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(outMetrics); + return (int) Math.max(outMetrics.heightPixels, outMetrics.widthPixels); + } + + private void showSavingProgress(String albumName) { + ProgressDialog progress; + if (mSavingProgressDialog != null) { + progress = mSavingProgressDialog.get(); + if (progress != null) { + progress.show(); + return; + } + } + // TODO: Allow cancellation of the saving process + String progressText; + if (albumName == null) { + progressText = getString(R.string.saving_image); + } else { + progressText = getString(R.string.filtershow_saving_image, albumName); + } + progress = ProgressDialog.show(this, "", progressText, true, false); + mSavingProgressDialog = new WeakReference<ProgressDialog>(progress); + } + + private void hideSavingProgress() { + if (mSavingProgressDialog != null) { + ProgressDialog progress = mSavingProgressDialog.get(); + if (progress != null) + progress.dismiss(); + } + } + + public void completeSaveImage(Uri saveUri) { + if (mSharingImage && mSharedOutputFile != null) { + // Image saved, we unblock the content provider + Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, + Uri.encode(mSharedOutputFile.getAbsolutePath())); + ContentValues values = new ContentValues(); + values.put(SharedImageProvider.PREPARE, false); + getContentResolver().insert(uri, values); + } + setResult(RESULT_OK, new Intent().setData(saveUri)); + hideSavingProgress(); + finish(); + } + + @Override + public boolean onShareTargetSelected(ShareActionProvider arg0, Intent arg1) { + // First, let's tell the SharedImageProvider that it will need to wait + // for the image + Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, + Uri.encode(mSharedOutputFile.getAbsolutePath())); + ContentValues values = new ContentValues(); + values.put(SharedImageProvider.PREPARE, true); + getContentResolver().insert(uri, values); + mSharingImage = true; + + // Process and save the image in the background. + showSavingProgress(null); + mImageShow.saveImage(this, mSharedOutputFile); + return true; + } + + private Intent getDefaultShareIntent() { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setType(SharedImageProvider.MIME_TYPE); + mSharedOutputFile = SaveImage.getNewFile(this, MasterImage.getImage().getUri()); + Uri uri = Uri.withAppendedPath(SharedImageProvider.CONTENT_URI, + Uri.encode(mSharedOutputFile.getAbsolutePath())); + intent.putExtra(Intent.EXTRA_STREAM, uri); + return intent; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu); + MenuItem showState = menu.findItem(R.id.showImageStateButton); + if (mShowingImageStatePanel) { + showState.setTitle(R.string.hide_imagestate_panel); + } else { + showState.setTitle(R.string.show_imagestate_panel); + } + mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share) + .getActionProvider(); + mShareActionProvider.setShareIntent(getDefaultShareIntent()); + mShareActionProvider.setOnShareTargetSelectedListener(this); + + MenuItem undoItem = menu.findItem(R.id.undoButton); + MenuItem redoItem = menu.findItem(R.id.redoButton); + MenuItem resetItem = menu.findItem(R.id.resetHistoryButton); + mMasterImage.getHistory().setMenuItems(undoItem, redoItem, resetItem); + return true; + } + + @Override + public void onPause() { + super.onPause(); + if (mShareActionProvider != null) { + mShareActionProvider.setOnShareTargetSelectedListener(null); + } + } + + @Override + public void onResume() { + super.onResume(); + if (mShareActionProvider != null) { + mShareActionProvider.setOnShareTargetSelectedListener(this); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.undoButton: { + HistoryManager adapter = mMasterImage.getHistory(); + int position = adapter.undo(); + mMasterImage.onHistoryItemClick(position); + backToMain(); + invalidateViews(); + UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, + UsageStatistics.CATEGORY_BUTTON_PRESS, "Undo"); + return true; + } + case R.id.redoButton: { + HistoryManager adapter = mMasterImage.getHistory(); + int position = adapter.redo(); + mMasterImage.onHistoryItemClick(position); + invalidateViews(); + UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, + UsageStatistics.CATEGORY_BUTTON_PRESS, "Redo"); + return true; + } + case R.id.resetHistoryButton: { + resetHistory(); + UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, + UsageStatistics.CATEGORY_BUTTON_PRESS, "ResetHistory"); + return true; + } + case R.id.showImageStateButton: { + toggleImageStatePanel(); + UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, + UsageStatistics.CATEGORY_BUTTON_PRESS, + mShowingImageStatePanel ? "ShowPanel" : "HidePanel"); + return true; + } + case R.id.exportFlattenButton: { + showExportOptionsDialog(); + return true; + } + case android.R.id.home: { + saveImage(); + return true; + } + case R.id.manageUserPresets: { + manageUserPresets(); + return true; + } + } + return false; + } + + private void manageUserPresets() { + DialogFragment dialog = new PresetManagementDialog(); + dialog.show(getSupportFragmentManager(), "NoticeDialogFragment"); + } + + private void showExportOptionsDialog() { + DialogFragment dialog = new ExportDialog(); + dialog.show(getSupportFragmentManager(), "ExportDialogFragment"); + } + + public void updateUserPresetsFromAdapter(UserPresetsAdapter adapter) { + ArrayList<FilterUserPresetRepresentation> representations = + adapter.getDeletedRepresentations(); + for (FilterUserPresetRepresentation representation : representations) { + deletePreset(representation.getId()); + } + ArrayList<FilterUserPresetRepresentation> changedRepresentations = + adapter.getChangedRepresentations(); + for (FilterUserPresetRepresentation representation : changedRepresentations) { + updatePreset(representation); + } + adapter.clearDeletedRepresentations(); + adapter.clearChangedRepresentations(); + loadUserPresets(); + } + + public void loadUserPresets() { + mUserPresetsManager.load(); + } + + public void updateUserPresetsFromManager() { + ArrayList<FilterUserPresetRepresentation> presets = mUserPresetsManager.getRepresentations(); + if (presets == null) { + return; + } + if (mCategoryLooksAdapter != null) { + fillLooks(); + } + mUserPresetsAdapter.clear(); + for (int i = 0; i < presets.size(); i++) { + FilterUserPresetRepresentation representation = presets.get(i); + mCategoryLooksAdapter.add( + new Action(this, representation, Action.FULL_VIEW)); + mUserPresetsAdapter.add(new Action(this, representation, Action.FULL_VIEW)); + } + mCategoryLooksAdapter.notifyDataSetInvalidated(); + + } + + public void saveCurrentImagePreset() { + mUserPresetsManager.save(MasterImage.getImage().getPreset()); + } + + private void deletePreset(int id) { + mUserPresetsManager.delete(id); + } + + private void updatePreset(FilterUserPresetRepresentation representation) { + mUserPresetsManager.update(representation); + } + + public void enableSave(boolean enable) { + if (mSaveButton != null) { + mSaveButton.setEnabled(enable); + } + } + + private void fillLooks() { + FiltersManager filtersManager = FiltersManager.getManager(); + ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getLooks(); + + mCategoryLooksAdapter.clear(); + int verticalItemHeight = (int) getResources().getDimension(R.dimen.action_item_height); + mCategoryLooksAdapter.setItemHeight(verticalItemHeight); + for (FilterRepresentation representation : filtersRepresentations) { + mCategoryLooksAdapter.add(new Action(this, representation, Action.FULL_VIEW)); + } + } + + public void setDefaultPreset() { + // Default preset (original) + ImagePreset preset = new ImagePreset(); // empty + mMasterImage.setPreset(preset, preset.getLastRepresentation(), true); + } + + // ////////////////////////////////////////////////////////////////////////////// + // Some utility functions + // TODO: finish the cleanup. + + public void invalidateViews() { + for (ImageShow views : mImageViews) { + views.updateImage(); + } + } + + public void hideImageViews() { + for (View view : mImageViews) { + view.setVisibility(View.GONE); + } + mEditorPlaceHolder.hide(); + } + + // ////////////////////////////////////////////////////////////////////////////// + // imageState panel... + + public void toggleImageStatePanel() { + invalidateOptionsMenu(); + mShowingImageStatePanel = !mShowingImageStatePanel; + Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); + if (panel != null) { + if (panel instanceof EditorPanel) { + EditorPanel editorPanel = (EditorPanel) panel; + editorPanel.showImageStatePanel(mShowingImageStatePanel); + } else if (panel instanceof MainPanel) { + MainPanel mainPanel = (MainPanel) panel; + mainPanel.showImageStatePanel(mShowingImageStatePanel); + } + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) + { + super.onConfigurationChanged(newConfig); + setDefaultValues(); + loadXML(); + fillCategories(); + loadMainPanel(); + + // mLoadBitmapTask==null implies you have looked at the intent + if (!mShowingTinyPlanet && (mLoadBitmapTask == null)) { + mCategoryFiltersAdapter.removeTinyPlanet(); + } + final View loading = findViewById(R.id.loading); + loading.setVisibility(View.GONE); + } + + public void setupMasterImage() { + + HistoryManager historyManager = new HistoryManager(); + StateAdapter imageStateAdapter = new StateAdapter(this, 0); + MasterImage.reset(); + mMasterImage = MasterImage.getImage(); + mMasterImage.setHistoryManager(historyManager); + mMasterImage.setStateAdapter(imageStateAdapter); + mMasterImage.setActivity(this); + + if (Runtime.getRuntime().maxMemory() > LIMIT_SUPPORTS_HIGHRES) { + mMasterImage.setSupportsHighRes(true); + } else { + mMasterImage.setSupportsHighRes(false); + } + } + + void resetHistory() { + HistoryManager adapter = mMasterImage.getHistory(); + adapter.reset(); + HistoryItem historyItem = adapter.getItem(0); + ImagePreset original = new ImagePreset(historyItem.getImagePreset()); + mMasterImage.setPreset(original, historyItem.getFilterRepresentation(), true); + invalidateViews(); + backToMain(); + } + + public void showDefaultImageView() { + mEditorPlaceHolder.hide(); + mImageShow.setVisibility(View.VISIBLE); + MasterImage.getImage().setCurrentFilter(null); + MasterImage.getImage().setCurrentFilterRepresentation(null); + } + + public void backToMain() { + Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); + if (currentPanel instanceof MainPanel) { + return; + } + loadMainPanel(); + showDefaultImageView(); + } + + @Override + public void onBackPressed() { + Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); + if (currentPanel instanceof MainPanel) { + if (!mImageShow.hasModifications()) { + done(); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.unsaved).setTitle(R.string.save_before_exit); + builder.setPositiveButton(R.string.save_and_exit, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + saveImage(); + } + }); + builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + done(); + } + }); + builder.show(); + } + } else { + backToMain(); + } + } + + public void cannotLoadImage() { + Toast.makeText(this, R.string.cannot_load_image, Toast.LENGTH_SHORT).show(); + finish(); + } + + // ////////////////////////////////////////////////////////////////////////////// + + public float getPixelsFromDip(float value) { + Resources r = getResources(); + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, + r.getDisplayMetrics()); + } + + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, + long id) { + mMasterImage.onHistoryItemClick(position); + invalidateViews(); + } + + public void pickImage() { + Intent intent = new Intent(); + intent.setType("image/*"); + intent.setAction(Intent.ACTION_GET_CONTENT); + startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)), + SELECT_PICTURE); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK) { + if (requestCode == SELECT_PICTURE) { + Uri selectedImageUri = data.getData(); + startLoadBitmap(selectedImageUri); + } + } + } + + + public void saveImage() { + if (mImageShow.hasModifications()) { + // Get the name of the album, to which the image will be saved + File saveDir = SaveImage.getFinalSaveDirectory(this, mSelectedImageUri); + int bucketId = GalleryUtils.getBucketId(saveDir.getPath()); + String albumName = LocalAlbum.getLocalizedName(getResources(), bucketId, null); + showSavingProgress(albumName); + mImageShow.saveImage(this, null); + } else { + done(); + } + } + + + public void done() { + hideSavingProgress(); + if (mLoadBitmapTask != null) { + mLoadBitmapTask.cancel(false); + } + finish(); + } + + private void extractXMPData() { + XMresults res = XmpPresets.extractXMPData( + getBaseContext(), mMasterImage, getIntent().getData()); + if (res == null) + return; + + mOriginalImageUri = res.originalimage; + mOriginalPreset = res.preset; + } + + public Uri getSelectedImageUri() { + return mSelectedImageUri; + } + +} |