Android Open Source - yammp Touch Interceptor






From Project

Back to project page yammp.

License

The source code is released under:

GNU Lesser General Public License

If you think the Android project yammp listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2008 The Android Open Source Project
 */*www  . ja  va 2  s . com*/
 * 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 org.yammp.widget;

import org.yammp.R;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;

public class TouchInterceptor extends ListView {

  private ImageView mDragView;

  private WindowManager mWindowManager;

  private WindowManager.LayoutParams mWindowParams;

  private int mDragPos;
  private int mSrcDragPos;
  private int mDragPointX;
  private int mDragPointY;
  private int mXOffset;
  private int mYOffset;
  private OnDragListener mDragListener;
  private OnDropListener mDropListener;
  private OnRemoveListener mRemoveListener;
  private int mUpperBound;
  private int mLowerBound;
  private int mHeight;
  private GestureDetector mGestureDetector;
  private Rect mTempRect = new Rect();
  private Bitmap mDragBitmap;
  private final int mTouchSlop;
  private int mItemHeightNormal;
  private int mItemHeightExpanded;
  private int mItemHeightHalf;
  private int mStartX, mStartY = 0;
  private boolean mSortDragging, mRemoveDragging = false;

  public TouchInterceptor(Context context, AttributeSet attrs) {

    super(context, attrs);
    mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    Resources res = getResources();
    mItemHeightNormal = res.getDimensionPixelSize(R.dimen.normal_height);
    mItemHeightHalf = mItemHeightNormal / 2;
    mItemHeightExpanded = mItemHeightNormal * 2;
  }

  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {

    if (mDragListener != null || mDropListener != null) {
      switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
          int x = (int) ev.getX();
          int y = (int) ev.getY();
          int itemnum = pointToPosition(x, y);
          if (itemnum == AdapterView.INVALID_POSITION) {
            break;
          }
          ViewGroup item = (ViewGroup) getChildAt(itemnum - getFirstVisiblePosition());
          mDragPointX = x - item.getLeft();
          mDragPointY = y - item.getTop();
          mXOffset = (int) ev.getRawX() - x;
          mYOffset = (int) ev.getRawY() - y;
          // The left side of the item is the grabber for dragging the
          // item
          if (x < mItemHeightNormal) {
            item.setDrawingCacheEnabled(true);
            // Create a copy of the drawing cache so that it does
            // not get recycled by the framework when the list
            // tries to clean up memory
            Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());
            item.setVisibility(View.INVISIBLE);
            startDragging(bitmap, x, y);
            mDragPos = itemnum;
            mSrcDragPos = mDragPos;
            mHeight = getHeight();
            int touchSlop = mTouchSlop;
            mUpperBound = Math.min(y - touchSlop, mHeight / 3);
            mLowerBound = Math.max(y + touchSlop, mHeight * 2 / 3);
            return false;
          }
          stopDragging();
          break;
      }
    }
    return super.onInterceptTouchEvent(ev);
  }

  @Override
  public boolean onTouchEvent(MotionEvent ev) {

    if (mGestureDetector != null) {
      mGestureDetector.onTouchEvent(ev);
    }
    if ((mDragListener != null || mDropListener != null) && mDragView != null) {
      int action = ev.getAction();
      switch (action) {
        case MotionEvent.ACTION_UP:
          mStartX = 0;
          mStartY = 0;
        case MotionEvent.ACTION_CANCEL:
          Rect r = mTempRect;
          mDragView.getDrawingRect(r);
          stopDragging();
          if (mDragPos >= 0 && mDragPos < getCount()) {
            if (mDropListener != null && mSortDragging && !mRemoveDragging) {
              mDropListener.onDrop(mSrcDragPos, mDragPos);

            } else if (mRemoveListener != null
                && mRemoveDragging
                && !mSortDragging
                && ev.getX() >= mWindowManager.getDefaultDisplay().getWidth()
                    - mItemHeightNormal) {
              mRemoveListener.onRemove(mDragPos);
            }
          }
          unExpandViews(false);
          break;
        case MotionEvent.ACTION_DOWN:
          mSortDragging = false;
          mRemoveDragging = false;
          mStartX = (int) ev.getX();
          mStartY = (int) ev.getY();
        case MotionEvent.ACTION_MOVE:
          int x = (int) ev.getX();
          int y = (int) ev.getY();

          if (Math.abs(x - mStartX) >= mItemHeightNormal / 2
              && Math.abs(y - mStartY) < mItemHeightNormal / 2 && !mRemoveDragging) {
            mRemoveDragging = true;
          } else if (Math.abs(x - mStartX) < mItemHeightNormal / 2
              && Math.abs(y - mStartY) >= mItemHeightNormal / 2 && !mSortDragging) {
            mSortDragging = true;
          }

          int itemnum = getItemForPosition(y);
          if (itemnum >= 0) {
            if (mSortDragging && !mRemoveDragging) {
              dragView(x, y);
              if (action == MotionEvent.ACTION_DOWN || itemnum != mDragPos) {
                if (mDragListener != null) {
                  mDragListener.onDrag(mDragPos, itemnum);
                }
                mDragPos = itemnum;
                doExpansion();
              }
              int speed = 0;
              adjustScrollBounds(y);
              if (y > mLowerBound) {
                // scroll the list up a bit
                if (getLastVisiblePosition() < getCount() - 1) {
                  speed = y > (mHeight + mLowerBound) / 2 ? 16 : 4;
                } else {
                  speed = 1;
                }
              } else if (y < mUpperBound) {
                // scroll the list down a bit
                speed = y < mUpperBound / 2 ? -16 : -4;
                if (getFirstVisiblePosition() == 0
                    && getChildAt(0).getTop() >= getPaddingTop()) {
                  // if we're already at the top, don't try to
                  // scroll, because it causes the framework
                  // to do some extra drawing that messes up
                  // our animation
                  speed = 0;
                }
              }
              if (speed != 0) {
                smoothScrollBy(speed, 30);
              }
            } else if (!mSortDragging && mRemoveDragging) {
              dragView(x, y);
            }
          }
          break;
      }
      return true;
    }
    return super.onTouchEvent(ev);
  }

  public void setDragListener(OnDragListener listener) {

    mDragListener = listener;
  }

  public void setDropListener(OnDropListener listener) {

    mDropListener = listener;
  }

  public void setRemoveListener(OnRemoveListener listener) {

    mRemoveListener = listener;
  }

  private void adjustScrollBounds(int y) {

    if (y >= mHeight / 3) {
      mUpperBound = mHeight / 3;
    }
    if (y <= mHeight * 2 / 3) {
      mLowerBound = mHeight * 2 / 3;
    }
  }

  /**
   * pointToPosition() doesn't consider invisible views, but we need to, so
   * implement a slightly different version.
   */
  private int betterPointToPosition(int x, int y) {

    if (y < 0) {
      // when dragging off the top of the screen, calculate position
      // by going back from a visible item
      int pos = betterPointToPosition(x, y + mItemHeightNormal);
      if (pos > 0) return pos - 1;
    }

    Rect frame = mTempRect;
    final int count = getChildCount();
    for (int i = count - 1; i >= 0; i--) {
      final View child = getChildAt(i);
      child.getHitRect(frame);
      if (frame.contains(x, y)) return getFirstVisiblePosition() + i;
    }
    return INVALID_POSITION;
  }

  /**
   * Adjust visibility and size to make it appear as though an item is being
   * dragged around and other items are making room for it: If dropping the
   * item would result in it still being in the same place, then make the
   * dragged listitem's size normal, but make the item invisible. Otherwise,
   * if the dragged listitem is still on screen, make it as small as possible
   * and expand the item below the insert point. If the dragged item is not on
   * screen, only expand the item below the current insertpoint.
   */
  private void doExpansion() {

    int childnum = mDragPos - getFirstVisiblePosition();
    if (mDragPos > mSrcDragPos) {
      childnum++;
    }
    int numheaders = getHeaderViewsCount();

    View first = getChildAt(mSrcDragPos - getFirstVisiblePosition());
    for (int i = 0;; i++) {
      View vv = getChildAt(i);
      if (vv == null) {
        break;
      }

      int height = mItemHeightNormal;
      int visibility = View.VISIBLE;
      if (mDragPos < numheaders && i == numheaders) {
        // dragging on top of the header item, so adjust the item below
        // instead
        if (vv.equals(first)) {
          visibility = View.INVISIBLE;
        } else {
          height = mItemHeightExpanded;
        }
      } else if (vv.equals(first)) {
        // processing the item that is being dragged
        if (mDragPos == mSrcDragPos || getPositionForView(vv) == getCount() - 1) {
          // hovering over the original location
          visibility = View.INVISIBLE;
        } else {
          // not hovering over it
          // Ideally the item would be completely gone, but neither
          // setting its size to 0 nor settings visibility to GONE
          // has the desired effect.
          height = 1;
        }
      } else if (i == childnum) {
        if (mDragPos >= numheaders && mDragPos < getCount() - 1) {
          height = mItemHeightExpanded;
        }
      }
      ViewGroup.LayoutParams params = vv.getLayoutParams();
      params.height = height;
      vv.setLayoutParams(params);
      vv.setVisibility(visibility);
    }
  }

  private void dragView(int x, int y) {

    if (mRemoveDragging && !mSortDragging) {
      mWindowParams.x = x + mXOffset;
      if (x >= mWindowManager.getDefaultDisplay().getWidth() - mItemHeightNormal) {
        mDragView.setBackgroundResource(R.drawable.playlist_tile_discard);
      } else {
        mDragView.setBackgroundResource(R.drawable.playlist_tile_drag);
      }
    } else if (!mRemoveDragging && mSortDragging) {
      mWindowParams.x = mXOffset;
      mWindowParams.y = y - mDragPointY + mYOffset;
    }
    mWindowManager.updateViewLayout(mDragView, mWindowParams);

  }

  private int getItemForPosition(int y) {

    int adjustedy = y - mDragPointY - mItemHeightHalf;
    int pos = betterPointToPosition(0, adjustedy);
    if (pos >= 0) {
      if (pos <= mSrcDragPos) {
        pos += 1;
      }
    } else if (adjustedy < 0) {
      // this shouldn't happen anymore now that myPointToPosition deals
      // with this situation
      pos = 0;
    }
    return pos;
  }

  private void startDragging(Bitmap bm, int x, int y) {

    stopDragging();

    mWindowParams = new WindowManager.LayoutParams();
    mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
    mWindowParams.x = x - mDragPointX + mXOffset;
    mWindowParams.y = y - mDragPointY + mYOffset;

    mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
    mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
    mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
    mWindowParams.format = PixelFormat.TRANSLUCENT;
    mWindowParams.windowAnimations = 0;

    Context context = getContext();
    ImageView v = new ImageView(context);
    v.setBackgroundResource(R.drawable.playlist_tile_drag);
    v.setPadding(0, 0, 0, 0);
    v.setImageBitmap(bm);
    mDragBitmap = bm;

    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    mWindowManager.addView(v, mWindowParams);
    mDragView = v;
  }

  private void stopDragging() {

    if (mDragView != null) {
      mDragView.setVisibility(GONE);
      WindowManager wm = (WindowManager) getContext()
          .getSystemService(Context.WINDOW_SERVICE);
      wm.removeView(mDragView);
      mDragView.setImageDrawable(null);
      mDragView = null;
    }
    if (mDragBitmap != null) {
      mDragBitmap.recycle();
      mDragBitmap = null;
    }
  }

  /**
   * Restore size and visibility for all listitems
   */
  private void unExpandViews(boolean deletion) {

    for (int i = 0;; i++) {
      View v = getChildAt(i);
      if (v == null) {
        if (deletion) {
          // HACK force update of mItemCount
          int position = getFirstVisiblePosition();
          int y = getChildAt(0).getTop();
          setAdapter(getAdapter());
          setSelectionFromTop(position, y);
          // end hack
        }
        try {
          layoutChildren(); // force children to be recreated where
                    // needed
          v = getChildAt(i);
        } catch (IllegalStateException ex) {
          // layoutChildren throws this sometimes, presumably because
          // we're in the process of being torn down but are still
          // getting touch events
        }
        if (v == null) return;
      }
      ViewGroup.LayoutParams params = v.getLayoutParams();
      params.height = mItemHeightNormal;
      v.setLayoutParams(params);
      v.setVisibility(View.VISIBLE);
    }
  }

  public interface OnDragListener {

    void onDrag(int from, int to);
  }

  public interface OnDropListener {

    void onDrop(int from, int to);
  }

  public interface OnRemoveListener {

    void onRemove(int which);
  }
}




Java Source Code List

org.yammp.Constants.java
org.yammp.MediaAppWidgetProvider4x1.java
org.yammp.MediaAppWidgetProvider4x2.java
org.yammp.MediaButtonIntentReceiver.java
org.yammp.MusicPlaybackService.java
org.yammp.app.AlbumFragment.java
org.yammp.app.AppearanceSettingsActivity.java
org.yammp.app.ArtistFragment.java
org.yammp.app.Equalizer.java
org.yammp.app.GenreFragment.java
org.yammp.app.LyricsFragment.java
org.yammp.app.MusicBrowserActivity.java
org.yammp.app.MusicBrowserFragment.java
org.yammp.app.MusicPlaybackActivity.java
org.yammp.app.MusicSettingsActivity.java
org.yammp.app.PlaylistFragment.java
org.yammp.app.PluginFragment.java
org.yammp.app.PluginsManagerActivity.java
org.yammp.app.QueryBrowserActivity.java
org.yammp.app.QueryFragment.java
org.yammp.app.TrackBrowserActivity.java
org.yammp.app.TrackFragment.java
org.yammp.dialog.DeleteDialog.java
org.yammp.dialog.PlayShortcut.java
org.yammp.dialog.PlaylistDialog.java
org.yammp.dialog.PlaylistPickerDialog.java
org.yammp.dialog.PlaylistPicker.java
org.yammp.dialog.ScanningProgress.java
org.yammp.dialog.SearchDialog.java
org.yammp.dialog.SleepTimerDialog.java
org.yammp.dialog.VerticalTextSpinnerDialog.java
org.yammp.dialog.WeekSelector.java
org.yammp.util.ColorAnalyser.java
org.yammp.util.EqualizerWrapper.java
org.yammp.util.ImageDownloader.java
org.yammp.util.LazyImageLoader.java
org.yammp.util.LyricsDownloader.java
org.yammp.util.LyricsParser.java
org.yammp.util.LyricsSplitter.java
org.yammp.util.MusicUtils.java
org.yammp.util.PreferencesEditor.java
org.yammp.util.ServiceToken.java
org.yammp.util.ShakeListener.java
org.yammp.util.SortCursor.java
org.yammp.util.VisualizerCompatAudioFX.java
org.yammp.util.VisualizerCompatScoop.java
org.yammp.util.VisualizerCompat.java
org.yammp.util.VisualizerWrapper.java
org.yammp.view.EqualizerView.java
org.yammp.view.SliderView.java
org.yammp.view.TouchPaintView.java
org.yammp.view.VerticalTextSpinner.java
org.yammp.view.VisualizerViewFftSpectrum.java
org.yammp.view.VisualizerViewWaveForm.java
org.yammp.widget.CheckableRelativeLayout.java
org.yammp.widget.RepeatingImageButton.java
org.yammp.widget.SeparatedListAdapter.java
org.yammp.widget.TextScrollView.java
org.yammp.widget.TouchInterceptor.java