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