15c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng/*
25c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Copyright (C) 2012 Google Inc.
35c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Licensed to The Android Open Source Project.
45c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng *
55c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
65c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * you may not use this file except in compliance with the License.
75c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * You may obtain a copy of the License at
85c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng *
95c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng *
115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Unless required by applicable law or agreed to in writing, software
125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * See the License for the specific language governing permissions and
155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * limitations under the License.
165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng */
175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengpackage com.android.deskclock.widget.swipeablelistview;
195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.content.Context;
215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.content.res.Configuration;
225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.graphics.Rect;
235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.util.AttributeSet;
245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.MotionEvent;
255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.View;
265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.view.ViewConfiguration;
275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.widget.ListView;
285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport com.android.deskclock.widget.swipeablelistview.SwipeHelper.Callback;
305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng/**
325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng * Copy of packages/apps/UnifiedEmail - com.android.mail.ui.Swipeable with changes.
335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng */
345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengpublic class SwipeableListView extends ListView implements Callback {
355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private SwipeHelper mSwipeHelper;
365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private boolean mEnableSwipe = false;
375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public static final String LOG_TAG = LogTag.getLogTag();
395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
405c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private OnItemSwipeListener mOnItemSwipeListener;
415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public SwipeableListView(Context context) {
435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        this(context, null);
445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public SwipeableListView(Context context, AttributeSet attrs) {
475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        this(context, attrs, -1);
485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public SwipeableListView(Context context, AttributeSet attrs, int defStyle) {
515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        super(context, attrs, defStyle);
525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        float densityScale = getResources().getDisplayMetrics().density;
535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        float pagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale,
555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                pagingTouchSlop);
565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        setItemsCanFocus(true);
575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    protected void onConfigurationChanged(Configuration newConfig) {
615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        super.onConfigurationChanged(newConfig);
625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        float densityScale = getResources().getDisplayMetrics().density;
635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mSwipeHelper.setDensityScale(densityScale);
645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
665c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
685c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        LogUtils.d(Utils.VIEW_DEBUGGING_TAG,
715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                "START CLF-ListView.onFocusChanged layoutRequested=%s root.layoutRequested=%s",
725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                isLayoutRequested(), getRootView().isLayoutRequested());
735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        LogUtils.d(Utils.VIEW_DEBUGGING_TAG, new Error(),
755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                "FINISH CLF-ListView.onFocusChanged layoutRequested=%s root.layoutRequested=%s",
765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                isLayoutRequested(), getRootView().isLayoutRequested());
775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void requestLayout() {
815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        Utils.checkRequestLayout(this);
825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        super.requestLayout();
835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
855c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    /**
865c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng     * Enable swipe gestures.
875c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng     */
885c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void enableSwipe(boolean enable) {
895c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mEnableSwipe = enable;
905c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
915c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
925c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public boolean isSwipeEnabled() {
935c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return mEnableSwipe;
945c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
955c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
965c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void setOnItemSwipeListener(OnItemSwipeListener listener) {
975c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        mOnItemSwipeListener = listener;
985c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1005c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
1015c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public boolean onInterceptTouchEvent(MotionEvent ev) {
1025c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (mEnableSwipe) {
1035c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            return mSwipeHelper.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev);
1045c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        } else {
1055c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            return super.onInterceptTouchEvent(ev);
1065c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
1075c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1085c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1095c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
1105c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public boolean onTouchEvent(MotionEvent ev) {
1115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (mEnableSwipe) {
1125c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            return mSwipeHelper.onTouchEvent(ev) || super.onTouchEvent(ev);
1135c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        } else {
1145c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            return super.onTouchEvent(ev);
1155c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
1165c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1185c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
1195c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public View getChildAtPosition(MotionEvent ev) {
1205c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        // find the view under the pointer, accounting for GONE views
1215c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        final int count = getChildCount();
1225c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        int touchY = (int) ev.getY();
1235c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        int childIdx = 0;
1245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        View slidingChild;
1255c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        for (; childIdx < count; childIdx++) {
1265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            slidingChild = getChildAt(childIdx);
1275c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            if (slidingChild.getVisibility() == GONE) {
1285c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                continue;
1295c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
1305c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            if (touchY >= slidingChild.getTop() && touchY <= slidingChild.getBottom()) {
1315c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                return slidingChild;
1325c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
1335c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
1345c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return null;
1355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1365c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1375c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
1385c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public View getChildContentView(View view) {
1395c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return view;
1405c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1415c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1425c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
1435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void onScroll() {
1445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
1475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public boolean canChildBeDismissed(View v) {
1485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return true;
1495c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1505c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1515c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
1525c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void onChildDismissed(final View v) {
1535c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (v != null) {
1545c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            if (mOnItemSwipeListener != null) {
1555c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                mOnItemSwipeListener.onSwipe(v);
1565c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
1575c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
1585c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1595c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1605c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
1615c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void onDragCancelled(View v) {
1625c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1635c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1645c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    private void redraw(View v) {
1655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        int start = getFirstVisiblePosition();
1665c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        for (int i=start, j = getLastVisiblePosition(); i <= j; i++) {
1675c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            if (v == getItemAtPosition(i)) {
1685c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                View view = getChildAt(i-start);
1695c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                getAdapter().getView(i, view, this);
1705c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            }
1715c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
1725c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1735c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1745c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    @Override
1755c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public void onBeginDrag(View v) {
1765c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        // We do this so the underlying ScrollView knows that it won't get
1775c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        // the chance to intercept events anymore
1785c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        requestDisallowInterceptTouchEvent(true);
1795c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1805c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1815c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public interface OnItemSwipeListener {
1825c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        public void onSwipe(View view);
1835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1845c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng}
185