Home | History | Annotate | Download | only in state
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.gallery3d.filtershow.state;
     18 
     19 import android.animation.LayoutTransition;
     20 import android.content.Context;
     21 import android.content.res.TypedArray;
     22 import android.database.DataSetObserver;
     23 import android.graphics.Canvas;
     24 import android.graphics.Point;
     25 import android.graphics.Rect;
     26 import android.util.AttributeSet;
     27 import android.util.Log;
     28 import android.view.GestureDetector;
     29 import android.view.MotionEvent;
     30 import android.view.View;
     31 import android.view.ViewGroup;
     32 import android.widget.Adapter;
     33 import android.widget.LinearLayout;
     34 import com.android.gallery3d.R;
     35 import com.android.gallery3d.filtershow.FilterShowActivity;
     36 import com.android.gallery3d.filtershow.editors.ImageOnlyEditor;
     37 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
     38 import com.android.gallery3d.filtershow.imageshow.MasterImage;
     39 
     40 public class StatePanelTrack extends LinearLayout implements PanelTrack {
     41 
     42     private static final String LOGTAG = "StatePanelTrack";
     43     private Point mTouchPoint;
     44     private StateView mCurrentView;
     45     private StateView mCurrentSelectedView;
     46     private boolean mExited = false;
     47     private boolean mStartedDrag = false;
     48     private StateAdapter mAdapter;
     49     private DragListener mDragListener = new DragListener(this);
     50     private float mDeleteSlope = 0.2f;
     51     private GestureDetector mGestureDetector;
     52     private int mElemWidth;
     53     private int mElemHeight;
     54     private int mElemSize;
     55     private int mElemEndSize;
     56     private int mEndElemWidth;
     57     private int mEndElemHeight;
     58     private long mTouchTime;
     59     private int mMaxTouchDelay = 300; // 300ms delay for touch
     60     private static final boolean ALLOWS_DRAG = false;
     61     private static final boolean ALLOWS_DUPLICATES = false;
     62     private DataSetObserver mObserver = new DataSetObserver() {
     63         @Override
     64         public void onChanged() {
     65             super.onChanged();
     66             fillContent(false);
     67         }
     68 
     69         @Override
     70         public void onInvalidated() {
     71             super.onInvalidated();
     72             fillContent(false);
     73         }
     74     };
     75 
     76     public StatePanelTrack(Context context, AttributeSet attrs) {
     77         super(context, attrs);
     78         TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.StatePanelTrack);
     79         mElemSize = a.getDimensionPixelSize(R.styleable.StatePanelTrack_elemSize, 0);
     80         mElemEndSize = a.getDimensionPixelSize(R.styleable.StatePanelTrack_elemEndSize, 0);
     81         if (getOrientation() == LinearLayout.HORIZONTAL) {
     82             mElemWidth = mElemSize;
     83             mElemHeight = LayoutParams.MATCH_PARENT;
     84             mEndElemWidth = mElemEndSize;
     85             mEndElemHeight = LayoutParams.MATCH_PARENT;
     86         } else {
     87             mElemWidth = LayoutParams.MATCH_PARENT;
     88             mElemHeight = mElemSize;
     89             mEndElemWidth = LayoutParams.MATCH_PARENT;
     90             mEndElemHeight = mElemEndSize;
     91         }
     92         GestureDetector.SimpleOnGestureListener simpleOnGestureListener
     93                 = new GestureDetector.SimpleOnGestureListener(){
     94             @Override
     95             public void onLongPress(MotionEvent e) {
     96                 longPress(e);
     97             }
     98             @Override
     99             public boolean onDoubleTap(MotionEvent e) {
    100                 addDuplicate(e);
    101                 return true;
    102             }
    103         };
    104         mGestureDetector = new GestureDetector(context, simpleOnGestureListener);
    105     }
    106 
    107     private void addDuplicate(MotionEvent e) {
    108         if (!ALLOWS_DUPLICATES) {
    109             return;
    110         }
    111         if (mCurrentSelectedView == null) {
    112             return;
    113         }
    114         int pos = findChild(mCurrentSelectedView);
    115         if (pos != -1) {
    116             mAdapter.insert(new State(mCurrentSelectedView.getState()), pos);
    117             fillContent(true);
    118         }
    119     }
    120 
    121     private void longPress(MotionEvent e) {
    122         if (!ALLOWS_DUPLICATES) {
    123             return;
    124         }
    125         View view = findChildAt((int) e.getX(), (int) e.getY());
    126         if (view == null) {
    127             return;
    128         }
    129         if (view instanceof StateView) {
    130             StateView stateView = (StateView) view;
    131             stateView.setDuplicateButton(true);
    132         }
    133     }
    134 
    135     public void setAdapter(StateAdapter adapter) {
    136         mAdapter = adapter;
    137         mAdapter.registerDataSetObserver(mObserver);
    138         mAdapter.setOrientation(getOrientation());
    139         fillContent(false);
    140         requestLayout();
    141     }
    142 
    143     public StateView findChildWithState(State state) {
    144         for (int i = 0; i < getChildCount(); i++) {
    145             StateView view = (StateView) getChildAt(i);
    146             if (view.getState() == state) {
    147                 return view;
    148             }
    149         }
    150         return null;
    151     }
    152 
    153     public void fillContent(boolean animate) {
    154         if (!animate) {
    155             this.setLayoutTransition(null);
    156         }
    157         int n = mAdapter.getCount();
    158         for (int i = 0; i < getChildCount(); i++) {
    159             StateView child = (StateView) getChildAt(i);
    160             child.resetPosition();
    161             if (!mAdapter.contains(child.getState())) {
    162                 removeView(child);
    163             }
    164         }
    165         LayoutParams params = new LayoutParams(mElemWidth, mElemHeight);
    166         for (int i = 0; i < n; i++) {
    167             State s = mAdapter.getItem(i);
    168             if (findChildWithState(s) == null) {
    169                 View view = mAdapter.getView(i, null, this);
    170                 addView(view, i, params);
    171             }
    172         }
    173 
    174         for (int i = 0; i < n; i++) {
    175             State state = mAdapter.getItem(i);
    176             StateView view = (StateView) getChildAt(i);
    177             view.setState(state);
    178             if (i == 0) {
    179                 view.setType(StateView.BEGIN);
    180             } else if (i == n - 1) {
    181                 view.setType(StateView.END);
    182             } else {
    183                 view.setType(StateView.DEFAULT);
    184             }
    185             view.resetPosition();
    186         }
    187 
    188         if (!animate) {
    189             this.setLayoutTransition(new LayoutTransition());
    190         }
    191     }
    192 
    193     public void onTouch(MotionEvent event, StateView view) {
    194         if (!view.isDraggable()) {
    195             return;
    196         }
    197         mCurrentView = view;
    198         if (mCurrentSelectedView == mCurrentView) {
    199             return;
    200         }
    201         if (mCurrentSelectedView != null) {
    202             mCurrentSelectedView.setSelected(false);
    203         }
    204         // We changed the current view -- let's reset the
    205         // gesture detector.
    206         MotionEvent cancelEvent = MotionEvent.obtain(event);
    207         cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
    208         mGestureDetector.onTouchEvent(cancelEvent);
    209         mCurrentSelectedView = mCurrentView;
    210         // We have to send the event to the gesture detector
    211         mGestureDetector.onTouchEvent(event);
    212         mTouchTime = System.currentTimeMillis();
    213     }
    214 
    215     @Override
    216     public boolean onInterceptTouchEvent(MotionEvent event) {
    217         if (mCurrentView != null) {
    218             return true;
    219         }
    220         return false;
    221     }
    222 
    223     @Override
    224     public boolean onTouchEvent(MotionEvent event) {
    225         if (mCurrentView == null) {
    226             return false;
    227         }
    228         if (mTouchTime == 0) {
    229             mTouchTime = System.currentTimeMillis();
    230         }
    231         mGestureDetector.onTouchEvent(event);
    232         if (mTouchPoint == null) {
    233             mTouchPoint = new Point();
    234             mTouchPoint.x = (int) event.getX();
    235             mTouchPoint.y = (int) event.getY();
    236         }
    237 
    238         if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
    239             float translation = event.getY() - mTouchPoint.y;
    240             float alpha = 1.0f - (Math.abs(translation) / mCurrentView.getHeight());
    241             if (getOrientation() == LinearLayout.VERTICAL) {
    242                 translation = event.getX() - mTouchPoint.x;
    243                 alpha = 1.0f - (Math.abs(translation) / mCurrentView.getWidth());
    244                 mCurrentView.setTranslationX(translation);
    245             } else {
    246                 mCurrentView.setTranslationY(translation);
    247             }
    248             mCurrentView.setBackgroundAlpha(alpha);
    249             if (ALLOWS_DRAG && alpha < 0.7) {
    250                 setOnDragListener(mDragListener);
    251                 DragShadowBuilder shadowBuilder = new DragShadowBuilder(mCurrentView);
    252                 mCurrentView.startDrag(null, shadowBuilder, mCurrentView, 0);
    253                 mStartedDrag = true;
    254             }
    255         }
    256         if (!mExited && mCurrentView != null
    257                 && mCurrentView.getBackgroundAlpha() > mDeleteSlope
    258                 && event.getActionMasked() == MotionEvent.ACTION_UP
    259                 && System.currentTimeMillis() - mTouchTime < mMaxTouchDelay) {
    260             FilterRepresentation representation = mCurrentView.getState().getFilterRepresentation();
    261             mCurrentView.setSelected(true);
    262             if (representation != MasterImage.getImage().getCurrentFilterRepresentation()) {
    263                 FilterShowActivity activity = (FilterShowActivity) getContext();
    264                 activity.showRepresentation(representation);
    265                 mCurrentView.setSelected(false);
    266             }
    267         }
    268         if (event.getActionMasked() == MotionEvent.ACTION_UP
    269                 || (!mStartedDrag && event.getActionMasked() == MotionEvent.ACTION_CANCEL)) {
    270             checkEndState();
    271             if (mCurrentView != null) {
    272                 FilterRepresentation representation = mCurrentView.getState().getFilterRepresentation();
    273                 if (representation.getEditorId() == ImageOnlyEditor.ID) {
    274                     mCurrentView.setSelected(false);
    275                 }
    276             }
    277         }
    278         return true;
    279     }
    280 
    281     public void checkEndState() {
    282         mTouchPoint = null;
    283         mTouchTime = 0;
    284         if (mExited || mCurrentView.getBackgroundAlpha() < mDeleteSlope) {
    285             int origin = findChild(mCurrentView);
    286             if (origin != -1) {
    287                 State current = mAdapter.getItem(origin);
    288                 FilterRepresentation currentRep = MasterImage.getImage().getCurrentFilterRepresentation();
    289                 FilterRepresentation removedRep = current.getFilterRepresentation();
    290                 mAdapter.remove(current);
    291                 fillContent(true);
    292                 if (currentRep != null && removedRep != null
    293                         && currentRep.getFilterClass() == removedRep.getFilterClass()) {
    294                     FilterShowActivity activity = (FilterShowActivity) getContext();
    295                     activity.backToMain();
    296                     return;
    297                 }
    298             }
    299         } else {
    300             mCurrentView.setBackgroundAlpha(1.0f);
    301             mCurrentView.setTranslationX(0);
    302             mCurrentView.setTranslationY(0);
    303         }
    304         if (mCurrentSelectedView != null) {
    305             mCurrentSelectedView.invalidate();
    306         }
    307         if (mCurrentView != null) {
    308             mCurrentView.invalidate();
    309         }
    310         mCurrentView = null;
    311         mExited = false;
    312         mStartedDrag = false;
    313     }
    314 
    315     public View findChildAt(int x, int y) {
    316         Rect frame = new Rect();
    317         int scrolledXInt = getScrollX() + x;
    318         int scrolledYInt = getScrollY() + y;
    319         for (int i = 0; i < getChildCount(); i++) {
    320             View child = getChildAt(i);
    321             child.getHitRect(frame);
    322             if (frame.contains(scrolledXInt, scrolledYInt)) {
    323                 return child;
    324             }
    325         }
    326         return null;
    327     }
    328 
    329     public int findChild(View view) {
    330         for (int i = 0; i < getChildCount(); i++) {
    331             View child = getChildAt(i);
    332             if (child == view) {
    333                 return i;
    334             }
    335         }
    336         return -1;
    337     }
    338 
    339     public StateView getCurrentView() {
    340         return mCurrentView;
    341     }
    342 
    343     public void setCurrentView(View currentView) {
    344         mCurrentView = (StateView) currentView;
    345     }
    346 
    347     public void setExited(boolean value) {
    348         mExited = value;
    349     }
    350 
    351     public Point getTouchPoint() {
    352         return mTouchPoint;
    353     }
    354 
    355     public Adapter getAdapter() {
    356         return mAdapter;
    357     }
    358 }
    359