android:orientation="horizontal">
<FrameLayout
+ android:id="@+id/central_panel_container"
+ android:layout_gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:visibility="gone"/>
+
+ <FrameLayout
android:id="@+id/editorContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
+ android:id="@+id/central_panel_container"
+ android:layout_gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:visibility="gone"/>
+
+ <FrameLayout
android:id="@+id/editorContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:custom="http://schemas.android.com/apk/res/com.android.gallery3d"
android:orientation="horizontal"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:background="@color/filtershow_categoryview_background">
<HorizontalScrollView
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:scrollbars="none"
- android:background="@color/background_main_toolbar" >
+ android:layout_weight="1"
+ android:scrollbars="none" >
<com.android.gallery3d.filtershow.category.CategoryTrack
android:id="@+id/listItems"
</HorizontalScrollView>
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <ImageButton
+ android:id="@+id/addButton"
+ android:layout_width="@dimen/category_panel_height"
+ android:layout_height="@dimen/category_panel_height"
+ android:src="@drawable/filtershow_add"
+ style="?android:attr/borderlessButtonStyle"
+ android:scaleType="fitCenter"
+ android:padding="16dp"
+ android:layout_marginBottom="6dp"
+ android:layout_gravity="center"/>
+
+ <TextView
+ android:id="@+id/addButtonText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="4dp"
+ android:layout_gravity="bottom|center"/>
+
+ </FrameLayout>
+
</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:background="#3a4e56"
+ android:padding="16dp">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <TextView
+ style="?android:textAppearanceLarge"
+ android:textStyle="bold"
+ android:textColor="#fff"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/filtershow_show_info_panel_name"/>
+
+ <TextView
+ android:id="@+id/imageName"
+ style="?android:textAppearanceSmall"
+ android:textStyle="bold"
+ android:textColor="#80ffffff"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ style="?android:textAppearanceLarge"
+ android:textStyle="bold"
+ android:textColor="#fff"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/filtershow_show_info_panel_size"/>
+
+ <TextView
+ android:id="@+id/imageSize"
+ style="?android:textAppearanceSmall"
+ android:textAllCaps="true"
+ android:textColor="#80ffffff"
+ android:textStyle="bold"
+ android:lineSpacingMultiplier="1.2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/imageThumbnail"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ android:scaleType="centerInside"
+ android:background="@null"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+
+ <TextView
+ style="?android:textAppearanceLarge"
+ android:textStyle="bold"
+ android:textColor="#fff"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/filtershow_show_info_panel_histogram"/>
+
+ <com.android.gallery3d.filtershow.info.HistogramView
+ android:id="@+id/histogramView"
+ android:layout_width="match_parent"
+ android:layout_height="250dp"
+ android:layout_margin="16dp"/>
+
+ <TextView
+ style="?android:textAppearanceLarge"
+ android:textStyle="bold"
+ android:textColor="#fff"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/filtershow_show_info_panel_exif"/>
+
+ <TextView
+ android:id="@+id/exifData"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
+ </ScrollView>
+
+</LinearLayout>
\ No newline at end of file
android:layout_weight="1" />
<FrameLayout android:id="@+id/category_panel_container"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:visibility="visible"
android:layout_height="0dip"
android:layout_gravity="center"
android:layout_height="1dip"
android:layout_width="match_parent"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
<HorizontalScrollView
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:scrollbars="none">
<com.android.gallery3d.filtershow.state.StatePanelTrack
</HorizontalScrollView>
+ <ImageButton
+ android:id="@+id/toggleVersionsPanel"
+ android:layout_width="wrap_content"
+ android:layout_height="48dip"
+ android:src="@drawable/filtershow_versions_compare"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_gravity="center"/>
+
+ </LinearLayout>
+
+ <View
+ android:background="@color/toolbar_separation_line"
+ android:layout_height="1dip"
+ android:layout_width="match_parent"/>
+
</LinearLayout>
android:id="@+id/resetHistoryButton"
android:title="@string/reset"/>
<item
+ android:id="@+id/showInfoPanel"
+ android:showAsAction="never"
+ android:visible="true"
+ android:title="@string/filtershow_show_info_panel" />
+ <item
android:id="@+id/showImageStateButton"
android:showAsAction="never"
android:visible="true"
<!-- Label for newly created user preset [CHAR LIMIT=30] -->
<string name="filtershow_new_preset">New Preset</string>
+ <!-- Label for showing the image information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_show_info_panel">Information</string>
+ <!-- Label for the information panel [CHAR LIMIT=30] -->
+ <string name="filtershow_show_info_panel_name">Image Name</string>
+ <!-- Label for the information panel [CHAR LIMIT=30] -->
+ <string name="filtershow_show_info_panel_size">Image Size</string>
+ <!-- Label for the information panel [CHAR LIMIT=30] -->
+ <string name="filtershow_show_info_panel_histogram">Histogram</string>
+ <!-- Label for the information panel [CHAR LIMIT=30] -->
+ <string name="filtershow_show_info_panel_exif">EXIF Data</string>
+
+ <!-- Label for the add button in the category panel [CHAR LIMIT=30] -->
+ <string name="filtershow_add_button_looks">Preset</string>
+ <!-- Label for the add button in the versions panel [CHAR LIMIT=30] -->
+ <string name="filtershow_add_button_versions">Version</string>
+ <!-- Label for the Original version in the versions panel [CHAR LIMIT=30] -->
+ <string name="filtershow_version_original">Original</string>
+ <!-- Label for the Current version in the versions panel [CHAR LIMIT=30] -->
+ <string name="filtershow_version_current">Current</string>
+
+ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_exif_model">Model</string>
+ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_exif_aperture">Aperture</string>
+ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_exif_focal_length">Focal Length</string>
+ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_exif_iso">ISO</string>
+ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_exif_subject_distance">Subject Distance</string>
+ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_exif_date">Date taken</string>
+ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_exif_f_stop">F Stop</string>
+ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_exif_exposure_time">Exposure Time</string>
+ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] -->
+ <string name="filtershow_exif_copyright">Copyright</string>
+
</resources>
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewPropertyAnimator;
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.category.SwipableView;
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.imageshow.ImageShow;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.imageshow.Spline;
+import com.android.gallery3d.filtershow.info.InfoPanel;
import com.android.gallery3d.filtershow.pipeline.CachingPipeline;
import com.android.gallery3d.filtershow.pipeline.ImagePreset;
import com.android.gallery3d.filtershow.pipeline.ProcessingService;
private boolean mShowingTinyPlanet = false;
private boolean mShowingImageStatePanel = false;
+ private boolean mShowingVersionsPanel = false;
+ private boolean mShowingInformationPanel = false;
private final Vector<ImageShow> mImageViews = new Vector<ImageShow>();
private CategoryAdapter mCategoryBordersAdapter = null;
private CategoryAdapter mCategoryGeometryAdapter = null;
private CategoryAdapter mCategoryFiltersAdapter = null;
+ private CategoryAdapter mCategoryVersionsAdapter = null;
private int mCurrentPanel = MainPanel.LOOKS;
+ private Vector<FilterUserPresetRepresentation> mVersions =
+ new Vector<FilterUserPresetRepresentation>();
+ private int mVersionsCounter = 0;
+
+ private boolean mHandlingSwipeButton = false;
+ private View mHandledSwipeView = null;
+ private float mHandledSwipeViewLastDelta = 0;
+ private float mSwipeStartY = 0;
private ProcessingService mBoundService;
private boolean mIsBound = false;
}
}
+ private void hideInformationPanel() {
+ FrameLayout infoLayout = (FrameLayout) findViewById(R.id.central_panel_container);
+ infoLayout.setVisibility(View.GONE);
+ Fragment fragment = getSupportFragmentManager().findFragmentByTag(InfoPanel.FRAGMENT_TAG);
+ if (fragment != null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.remove(fragment);
+ transaction.commit();
+ }
+ mShowingInformationPanel = false;
+ }
+
+ public void showInformationPanel() {
+ mShowingInformationPanel = !mShowingInformationPanel;
+ if (!mShowingInformationPanel) {
+ hideInformationPanel();
+ showDefaultImageView();
+ return;
+ }
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
+ FrameLayout infoLayout = (FrameLayout) findViewById(R.id.central_panel_container);
+ infoLayout.setVisibility(View.VISIBLE);
+ mEditorPlaceHolder.hide();
+ mImageShow.setVisibility(View.GONE);
+
+ InfoPanel panel = new InfoPanel();
+ transaction.replace(R.id.central_panel_container, panel, InfoPanel.FRAGMENT_TAG);
+ transaction.commit();
+ }
+
private void loadXML() {
setContentView(R.layout.filtershow_activity);
fillBorders();
fillTools();
fillEffects();
+ fillVersions();
}
public void setupStatePanel() {
MasterImage.getImage().setHistoryManager(mMasterImage.getHistory());
}
+ private void fillVersions() {
+ mCategoryVersionsAdapter = new CategoryAdapter(this);
+ mCategoryVersionsAdapter.setShowAddButton(true);
+ }
+
+ public void updateVersions() {
+ mCategoryVersionsAdapter.clear();
+ FilterUserPresetRepresentation originalRep = new FilterUserPresetRepresentation(
+ getString(R.string.filtershow_version_original), new ImagePreset(), -1);
+ mCategoryVersionsAdapter.add(
+ new Action(this, originalRep, Action.FULL_VIEW));
+ ImagePreset current = new ImagePreset(MasterImage.getImage().getPreset());
+ FilterUserPresetRepresentation currentRep = new FilterUserPresetRepresentation(
+ getString(R.string.filtershow_version_current), current, -1);
+ mCategoryVersionsAdapter.add(
+ new Action(this, currentRep, Action.FULL_VIEW));
+ for (FilterUserPresetRepresentation rep : mVersions) {
+ mCategoryVersionsAdapter.add(
+ new Action(this, rep, Action.FULL_VIEW));
+ }
+ mCategoryVersionsAdapter.notifyDataSetInvalidated();
+ }
+
+ public void addCurrentVersion() {
+ ImagePreset current = new ImagePreset(MasterImage.getImage().getPreset());
+ mVersionsCounter++;
+ FilterUserPresetRepresentation rep = new FilterUserPresetRepresentation(
+ "" + mVersionsCounter, current, -1);
+ mVersions.add(rep);
+ updateVersions();
+ }
+
+ public void removeVersion(Action action) {
+ mVersions.remove(action.getRepresentation());
+ updateVersions();
+ }
+
private void fillEffects() {
FiltersManager filtersManager = FiltersManager.getManager();
ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getEffects();
return mCategoryFiltersAdapter;
}
+ public CategoryAdapter getCategoryVersionsAdapter() {
+ return mCategoryVersionsAdapter;
+ }
+
public void removeFilterRepresentation(FilterRepresentation filterRepresentation) {
if (filterRepresentation == null) {
return;
// show representation
Editor mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId());
loadEditorPanel(representation, mCurrentEditor);
+ hideInformationPanel();
}
public Editor getEditor(int editorID) {
Bitmap largeBitmap = MasterImage.getImage().getOriginalBitmapLarge();
mBoundService.setOriginalBitmap(largeBitmap);
+ MasterImage.getImage().resetGeometryImages();
float previewScale = (float) largeBitmap.getWidth()
/ (float) MasterImage.getImage().getOriginalBounds().width();
manageUserPresets();
return true;
}
+ case R.id.showInfoPanel: {
+ showInformationPanel();
+ return true;
+ }
}
return false;
}
}
}
+ public void toggleVersionsPanel() {
+ mShowingVersionsPanel = !mShowingVersionsPanel;
+ Fragment panel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
+ if (panel != null && panel instanceof MainPanel) {
+ MainPanel mainPanel = (MainPanel) panel;
+ mainPanel.loadCategoryVersionsPanel();
+ }
+ }
+
@Override
public void onConfigurationChanged(Configuration newConfig)
{
}
public void showDefaultImageView() {
+ hideInformationPanel();
mEditorPlaceHolder.hide();
mImageShow.setVisibility(View.VISIBLE);
MasterImage.getImage().setCurrentFilter(null);
return mSelectedImageUri;
}
+ public void setHandlesSwipeForView(View view, float startY) {
+ if (view != null) {
+ mHandlingSwipeButton = true;
+ } else {
+ mHandlingSwipeButton = false;
+ }
+ mHandledSwipeView = view;
+ int[] location = new int[2];
+ view.getLocationInWindow(location);
+ mSwipeStartY = location[1] + startY;
+ }
+
+ public boolean dispatchTouchEvent (MotionEvent ev) {
+ if (mHandlingSwipeButton) {
+ if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
+ float delta = ev.getY() - mSwipeStartY;
+ mHandledSwipeView.setTranslationY(delta);
+ delta = Math.abs(delta);
+ float transparency = Math.min(1, delta / mHandledSwipeView.getHeight());
+ mHandledSwipeView.setAlpha(1.f - transparency);
+ mHandledSwipeViewLastDelta = delta;
+ }
+ if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL
+ || ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ mHandledSwipeView.setTranslationY(0);
+ mHandledSwipeView.setAlpha(1.f);
+ mHandlingSwipeButton = false;
+ if (mHandledSwipeViewLastDelta > mHandledSwipeView.getHeight()) {
+ ((SwipableView) mHandledSwipeView).delete();
+ }
+ }
+ return true;
+ }
+ return super.dispatchTouchEvent(ev);
+ }
}
import android.content.ContentResolver;
import android.content.Context;
-import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import com.adobe.xmp.XMPException;
import com.adobe.xmp.XMPMeta;
-import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.exif.ExifInterface;
+import com.android.gallery3d.exif.ExifTag;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.tools.XmpPresets;
import com.android.gallery3d.util.XmpUtilHelper;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
public final class ImageLoader {
return ret;
}
+ public static String getLocalPathFromUri(Context context, Uri uri) {
+ Cursor cursor = context.getContentResolver().query(uri,
+ new String[]{MediaStore.Images.Media.DATA}, null, null, null);
+ int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
+ cursor.moveToFirst();
+ return cursor.getString(index);
+ }
+
/**
* Returns the image's orientation flag. Defaults to ORI_NORMAL if no valid
* orientation was found.
Utils.closeSilently(is);
}
}
+
+ public static List<ExifTag> getExif(Context context, Uri uri) {
+ String path = getLocalPathFromUri(context, uri);
+ if (path != null) {
+ Uri localUri = Uri.parse(path);
+ String mimeType = getMimeType(localUri);
+ if (!JPEG_MIME_TYPE.equals(mimeType)) {
+ return null;
+ }
+ try {
+ ExifInterface exif = new ExifInterface();
+ exif.readExif(path);
+ List<ExifTag> taglist = exif.getAllTags();
+ return taglist;
+ } catch (IOException e) {
+ Log.w(LOGTAG, "Failed to read EXIF tags", e);
+ }
+ }
+ return null;
+ }
}
import android.widget.ArrayAdapter;
import android.widget.ListView;
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.filters.FilterTinyPlanetRepresentation;
import com.android.gallery3d.filtershow.pipeline.ImagePreset;
private int mSelectedPosition;
int mCategory;
private int mOrientation;
+ private boolean mShowAddButton = false;
+ private String mAddButtonText;
public CategoryAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
mSelectedPosition = -1;
if (category == MainPanel.LOOKS) {
mSelectedPosition = 0;
+ mAddButtonText = getContext().getString(R.string.filtershow_add_button_looks);
}
if (category == MainPanel.BORDERS) {
mSelectedPosition = 0;
}
+ if (category == MainPanel.VERSIONS) {
+ mAddButtonText = getContext().getString(R.string.filtershow_add_button_versions);
+ }
}
@Override
if (action.getRepresentation() != null
&& action.getRepresentation()
instanceof FilterTinyPlanetRepresentation) {
- remove(action);
+ super.remove(action);
return;
}
}
}
+ @Override
+ public void remove(Action action) {
+ if (mCategory != MainPanel.VERSIONS) {
+ return;
+ }
+ super.remove(action);
+ FilterShowActivity activity = (FilterShowActivity) getContext();
+ activity.removeVersion(action);
+ }
+
public void setOrientation(int orientation) {
mOrientation = orientation;
}
this.notifyDataSetChanged();
}
}
+
+ public boolean showAddButton() {
+ return mShowAddButton;
+ }
+
+ public void setShowAddButton(boolean showAddButton) {
+ mShowAddButton = showAddButton;
+ }
+
+ public String getAddButtonText() {
+ return mAddButtonText;
+ }
}
package com.android.gallery3d.filtershow.category;
import android.app.Activity;
+import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
+import android.widget.TextView;
import com.android.gallery3d.R;
import com.android.gallery3d.filtershow.FilterShowActivity;
-public class CategoryPanel extends Fragment {
+public class CategoryPanel extends Fragment implements View.OnClickListener {
public static final String FRAGMENT_TAG = "CategoryPanel";
private static final String PARAMETER_TAG = "currentPanel";
private int mCurrentAdapter = MainPanel.LOOKS;
private CategoryAdapter mAdapter;
+ private ImageButton mAddButton;
+ private TextView mAddButtonText;
public void setAdapter(int value) {
mCurrentAdapter = value;
mAdapter.initializeSelection(MainPanel.FILTERS);
break;
}
+ case MainPanel.VERSIONS: {
+ mAdapter = activity.getCategoryVersionsAdapter();
+ mAdapter.initializeSelection(MainPanel.VERSIONS);
+ break;
+ }
}
+ updateAddButtonVisibility();
}
@Override
panel.setAdapter(mAdapter);
mAdapter.setContainer(panel);
}
+
+ mAddButton = (ImageButton) main.findViewById(R.id.addButton);
+ mAddButtonText = (TextView) main.findViewById(R.id.addButtonText);
+ if (mAddButton != null) {
+ mAddButton.setOnClickListener(this);
+ updateAddButtonVisibility();
+ }
return main;
}
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.addButton:
+ FilterShowActivity activity = (FilterShowActivity) getActivity();
+ activity.addCurrentVersion();
+ break;
+ }
+ }
+
+ public void updateAddButtonVisibility() {
+ if (mAddButton == null) {
+ return;
+ }
+ FilterShowActivity activity = (FilterShowActivity) getActivity();
+ if (activity.isShowingImageStatePanel() && mAdapter.showAddButton()) {
+ mAddButton.setVisibility(View.VISIBLE);
+ if (mAdapter != null) {
+ mAddButtonText.setText(mAdapter.getAddButtonText());
+ }
+ } else {
+ mAddButton.setVisibility(View.GONE);
+ }
+ }
}
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import com.android.gallery3d.R;
private CategoryAdapter mAdapter;
private int mElemSize;
+ private View mSelectedView;
+ private float mStartTouchY;
private DataSetObserver mDataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
- invalidate();
+ if (getChildCount() != mAdapter.getCount()) {
+ fillContent();
+ } else {
+ invalidate();
+ }
}
@Override
public void onInvalidated() {
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
+import android.util.Log;
+import android.view.MotionEvent;
import android.view.View;
import com.android.gallery3d.R;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.ui.SelectionRenderer;
-public class CategoryView extends View implements View.OnClickListener {
+public class CategoryView extends View
+ implements View.OnClickListener, SwipableView{
private static final String LOGTAG = "CategoryView";
public static final int VERTICAL = 0;
private Paint mBorderPaint;
private int mBorderStroke;
private int mOrientation = VERTICAL;
+ private float mStartTouchY = 0;
+ private float mDeleteSlope = 20;
public CategoryView(Context context) {
super(context);
public void setOrientation(int orientation) {
mOrientation = orientation;
}
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mStartTouchY = event.getY();
+ }
+ if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ setTranslationY(0);
+ }
+ if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
+ float delta = event.getY() - mStartTouchY;
+ if (Math.abs(delta) > mDeleteSlope) {
+ FilterShowActivity activity = (FilterShowActivity) getContext();
+ activity.setHandlesSwipeForView(this, mStartTouchY);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void delete() {
+ mAdapter.remove(mAction);
+ }
}
public static final int BORDERS = 1;
public static final int GEOMETRY = 2;
public static final int FILTERS = 3;
+ public static final int VERSIONS = 4;
private int mCurrentSelected = -1;
+ private int mPreviousToggleVersions = -1;
private void selection(int position, boolean value) {
if (value) {
public void loadCategoryLookPanel() {
if (mCurrentSelected == LOOKS) {
+
return;
}
boolean fromRight = isRightAnimation(LOOKS);
selection(mCurrentSelected, true);
}
+ public void loadCategoryVersionsPanel() {
+ if (mCurrentSelected == VERSIONS) {
+ return;
+ }
+ FilterShowActivity activity = (FilterShowActivity) getActivity();
+ activity.updateVersions();
+ boolean fromRight = isRightAnimation(VERSIONS);
+ selection(mCurrentSelected, false);
+ CategoryPanel categoryPanel = new CategoryPanel();
+ categoryPanel.setAdapter(VERSIONS);
+ setCategoryFragment(categoryPanel, fromRight);
+ mCurrentSelected = VERSIONS;
+ selection(mCurrentSelected, true);
+ }
+
public void showPanel(int currentPanel) {
switch (currentPanel) {
case LOOKS: {
loadCategoryFiltersPanel();
break;
}
+ case VERSIONS: {
+ loadCategoryVersionsPanel();
+ break;
+ }
}
}
+ public void setToggleVersionsPanelButton(ImageButton button) {
+ if (button == null) {
+ return;
+ }
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mCurrentSelected == VERSIONS) {
+ showPanel(mPreviousToggleVersions);
+ } else {
+ mPreviousToggleVersions = mCurrentSelected;
+ showPanel(VERSIONS);
+ }
+ }
+ });
+ }
+
public void showImageStatePanel(boolean show) {
if (mMainView.findViewById(R.id.state_panel_container) == null) {
return;
}
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
final View container = mMainView.findViewById(R.id.state_panel_container);
+ int currentPanel = mCurrentSelected;
if (show) {
container.setVisibility(View.VISIBLE);
StatePanel statePanel = new StatePanel();
+ statePanel.setMainPanel(this);
+ FilterShowActivity activity = (FilterShowActivity) getActivity();
+ activity.updateVersions();
transaction.replace(R.id.state_panel_container, statePanel, StatePanel.FRAGMENT_TAG);
} else {
container.setVisibility(View.GONE);
if (statePanel != null) {
transaction.remove(statePanel);
}
+ if (currentPanel == VERSIONS) {
+ currentPanel = LOOKS;
+ }
}
+ mCurrentSelected = -1;
+ showPanel(currentPanel);
transaction.commit();
}
}
--- /dev/null
+/*
+ * 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.category;
+
+public interface SwipableView {
+ public void delete();
+}
import android.os.Handler;
import android.os.Message;
+import com.android.gallery3d.exif.ExifTag;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.pipeline.SharedPreset;
import com.android.gallery3d.filtershow.state.StateAdapter;
+import java.util.List;
import java.util.Vector;
public class MasterImage implements RenderingRequestCaller {
private Point mImageShowSize = new Point();
private boolean mShowsOriginal;
+ private List<ExifTag> mEXIF;
private MasterImage() {
}
public boolean loadBitmap(Uri uri, int size) {
setUri(uri);
+ mEXIF = ImageLoader.getExif(getActivity(), uri);
mOrientation = ImageLoader.getMetadataOrientation(mActivity, uri);
Rect originalBounds = new Rect();
mOriginalBitmapLarge = ImageLoader.loadOrientedConstrainedBitmap(uri, mActivity,
return mLoadedPreset;
}
+ public List<ExifTag> getEXIF() {
+ return mEXIF;
+ }
+
}
--- /dev/null
+/*
+ * 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.info;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.os.AsyncTask;
+import android.util.AttributeSet;
+import android.view.View;
+import com.android.gallery3d.filtershow.imageshow.Spline;
+
+public class HistogramView extends View {
+
+ private Bitmap mBitmap;
+ int[] redHistogram = new int[256];
+ int[] greenHistogram = new int[256];
+ int[] blueHistogram = new int[256];
+ Path gHistoPath = new Path();
+
+ class ComputeHistogramTask extends AsyncTask<Bitmap, Void, int[]> {
+ @Override
+ protected int[] doInBackground(Bitmap... params) {
+ int[] histo = new int[256 * 3];
+ Bitmap bitmap = params[0];
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ int[] pixels = new int[w * h];
+ bitmap.getPixels(pixels, 0, w, 0, 0, w, h);
+ for (int i = 0; i < w; i++) {
+ for (int j = 0; j < h; j++) {
+ int index = j * w + i;
+ int r = Color.red(pixels[index]);
+ int g = Color.green(pixels[index]);
+ int b = Color.blue(pixels[index]);
+ histo[r]++;
+ histo[256 + g]++;
+ histo[512 + b]++;
+ }
+ }
+ return histo;
+ }
+
+ @Override
+ protected void onPostExecute(int[] result) {
+ System.arraycopy(result, 0, redHistogram, 0, 256);
+ System.arraycopy(result, 256, greenHistogram, 0, 256);
+ System.arraycopy(result, 512, blueHistogram, 0, 256);
+ invalidate();
+ }
+ }
+
+ public HistogramView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setBitmap(Bitmap bitmap) {
+ mBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
+ new ComputeHistogramTask().execute(mBitmap);
+ }
+
+ private void drawHistogram(Canvas canvas, int[] histogram, int color, PorterDuff.Mode mode) {
+ int max = 0;
+ for (int i = 0; i < histogram.length; i++) {
+ if (histogram[i] > max) {
+ max = histogram[i];
+ }
+ }
+ float w = getWidth() - Spline.curveHandleSize();
+ float h = getHeight() - Spline.curveHandleSize() / 2.0f;
+ float dx = Spline.curveHandleSize() / 2.0f;
+ float wl = w / histogram.length;
+ float wh = (0.3f * h) / max;
+ Paint paint = new Paint();
+ paint.setARGB(100, 255, 255, 255);
+ paint.setStrokeWidth((int) Math.ceil(wl));
+
+ // Draw grid
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawRect(dx, 0, dx + w, h, paint);
+ canvas.drawLine(dx + w / 3, 0, dx + w / 3, h, paint);
+ canvas.drawLine(dx + 2 * w / 3, 0, dx + 2 * w / 3, h, paint);
+ paint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+ Paint paint2 = new Paint();
+ paint2.setColor(color);
+ paint2.setStrokeWidth(6);
+ paint2.setXfermode(new PorterDuffXfermode(mode));
+ gHistoPath.reset();
+ gHistoPath.moveTo(dx, h);
+ boolean firstPointEncountered = false;
+ float prev = 0;
+ float last = 0;
+ for (int i = 0; i < histogram.length; i++) {
+ float x = i * wl + dx;
+ float l = histogram[i] * wh;
+ if (l != 0) {
+ float v = h - (l + prev) / 2.0f;
+ if (!firstPointEncountered) {
+ gHistoPath.lineTo(x, h);
+ firstPointEncountered = true;
+ }
+ gHistoPath.lineTo(x, v);
+ prev = l;
+ last = x;
+ }
+ }
+ gHistoPath.lineTo(last, h);
+ gHistoPath.lineTo(w, h);
+ gHistoPath.close();
+ canvas.drawPath(gHistoPath, paint2);
+ paint2.setStrokeWidth(2);
+ paint2.setStyle(Paint.Style.STROKE);
+ paint2.setARGB(255, 200, 200, 200);
+ canvas.drawPath(gHistoPath, paint2);
+ }
+
+ public void onDraw(Canvas canvas) {
+ canvas.drawARGB(0, 0, 0, 0);
+ drawHistogram(canvas, redHistogram, Color.RED, PorterDuff.Mode.SCREEN);
+ drawHistogram(canvas, greenHistogram, Color.GREEN, PorterDuff.Mode.SCREEN);
+ drawHistogram(canvas, blueHistogram, Color.BLUE, PorterDuff.Mode.SCREEN);
+ }
+}
--- /dev/null
+/*
+ * 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.info;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Html;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.gallery3d.R;
+import com.android.gallery3d.exif.ExifInterface;
+import com.android.gallery3d.exif.ExifTag;
+import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+
+import java.util.List;
+
+public class InfoPanel extends Fragment {
+ public static final String FRAGMENT_TAG = "InfoPanel";
+ private static final String LOGTAG = FRAGMENT_TAG;
+ private LinearLayout mMainView;
+ private ImageView mImageThumbnail;
+ private TextView mImageName;
+ private TextView mImageSize;
+ private TextView mExifData;
+
+ private String createStringFromIfFound(ExifTag exifTag, int tag, int str) {
+ String exifString = "";
+ short tagId = exifTag.getTagId();
+ if (tagId == ExifInterface.getTrueTagKey(tag)) {
+ String label = getActivity().getString(str);
+ exifString += "<b>" + label + ": </b>";
+ exifString += exifTag.forceGetValueAsString();
+ exifString += "<br>";
+ }
+ return exifString;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ mMainView = (LinearLayout) inflater.inflate(
+ R.layout.filtershow_info_panel, null, false);
+
+ mImageThumbnail = (ImageView) mMainView.findViewById(R.id.imageThumbnail);
+ Bitmap bitmap = MasterImage.getImage().getFilteredImage();
+ mImageThumbnail.setImageBitmap(bitmap);
+
+ mImageName = (TextView) mMainView.findViewById(R.id.imageName);
+ mImageSize = (TextView) mMainView.findViewById(R.id.imageSize);
+ mExifData = (TextView) mMainView.findViewById(R.id.exifData);
+ HistogramView histogramView = (HistogramView) mMainView.findViewById(R.id.histogramView);
+
+ histogramView.setBitmap(bitmap);
+
+ Uri uri = MasterImage.getImage().getUri();
+ String path = ImageLoader.getLocalPathFromUri(getActivity(), uri);
+ Uri localUri = null;
+ if (path != null) {
+ localUri = Uri.parse(path);
+ }
+
+ if (localUri != null) {
+ mImageName.setText(localUri.getLastPathSegment());
+ }
+ Rect originalBounds = MasterImage.getImage().getOriginalBounds();
+ mImageSize.setText("" + originalBounds.width() + " x " + originalBounds.height());
+
+ List<ExifTag> exif = MasterImage.getImage().getEXIF();
+ String exifString = "";
+ if (exif != null) {
+ for (ExifTag tag : exif) {
+ exifString += createStringFromIfFound(tag,
+ ExifInterface.TAG_MODEL,
+ R.string.filtershow_exif_model);
+ exifString += createStringFromIfFound(tag,
+ ExifInterface.TAG_APERTURE_VALUE,
+ R.string.filtershow_exif_aperture);
+ exifString += createStringFromIfFound(tag,
+ ExifInterface.TAG_FOCAL_LENGTH,
+ R.string.filtershow_exif_focal_length);
+ exifString += createStringFromIfFound(tag,
+ ExifInterface.TAG_ISO_SPEED_RATINGS,
+ R.string.filtershow_exif_iso);
+ exifString += createStringFromIfFound(tag,
+ ExifInterface.TAG_SUBJECT_DISTANCE,
+ R.string.filtershow_exif_subject_distance);
+ exifString += createStringFromIfFound(tag,
+ ExifInterface.TAG_DATE_TIME_ORIGINAL,
+ R.string.filtershow_exif_date);
+ exifString += createStringFromIfFound(tag,
+ ExifInterface.TAG_F_NUMBER,
+ R.string.filtershow_exif_f_stop);
+ exifString += createStringFromIfFound(tag,
+ ExifInterface.TAG_EXPOSURE_TIME,
+ R.string.filtershow_exif_exposure_time);
+ exifString += createStringFromIfFound(tag,
+ ExifInterface.TAG_COPYRIGHT,
+ R.string.filtershow_exif_copyright);
+ }
+ }
+ mExifData.setText(Html.fromHtml(exifString));
+ return mMainView;
+ }
+}
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageButton;
import android.widget.LinearLayout;
import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.category.MainPanel;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
public class StatePanel extends Fragment {
private static final String LOGTAG = "StatePanel";
+ private MainPanel mMainPanel;
private StatePanelTrack track;
private LinearLayout mMainView;
+ private ImageButton mToggleVersionsPanel;
public static final String FRAGMENT_TAG = "StatePanel";
+ public void setMainPanel(MainPanel mainPanel) {
+ mMainPanel = mainPanel;
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View panel = mMainView.findViewById(R.id.listStates);
track = (StatePanelTrack) panel;
track.setAdapter(MasterImage.getImage().getState());
+ mToggleVersionsPanel = (ImageButton) mMainView.findViewById(R.id.toggleVersionsPanel);
+ if (mMainPanel != null) {
+ mMainPanel.setToggleVersionsPanelButton(mToggleVersionsPanel);
+ } else {
+ mToggleVersionsPanel.setVisibility(View.GONE);
+ }
return mMainView;
}
}