mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-31 00:07:14 +00:00
Merge branch 'ubilabs--rcapp--develop-update-libs' into ubilabs--rcapp--develop
This commit is contained in:
commit
1f8d3a7719
1072 files changed
+153715
-7157
No files matched your search
@@ -1,16 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sailing.domain.common"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sailing.domain.shared.android"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sse.common"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sailing.server.gateway.serialization.shared.android"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sse.shared.android"/>
|
||||
<classpathentry kind="lib" path="/google-play-services_lib/libs/google-play-services.jar"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/org.json.simple"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sailing.domain.common"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sailing.domain.shared.android"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sse.common"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sailing.server.gateway.serialization.shared.android"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/com.sap.sse.shared.android"/>
|
||||
<classpathentry kind="lib" path="/google-play-services_lib/libs/google-play-services.jar"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/org.json.simple"/>
|
||||
<classpathentry exported="true" kind="var" path="ANDROID_HOME/extras/android/m2repository/com/android/support/support-annotations/22.2.1/support-annotations-22.2.1.jar"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
@@ -16,3 +16,5 @@ android.library=true
|
||||
|
||||
android.library.reference.1=../google-android-support-v7-appcompat_lib
|
||||
android.library.reference.2=../licensesdialog_lib/de.psdev.licensesdialog
|
||||
android.library.reference.3=../google-android-support-v4
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="tests-jvm/src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/org.json.simple"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
||||
<classpathentry kind="lib" path="/com.sap.sailing.targetplatform.base/plugins/target-test/mockito-core-1.10.14.jar"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="tests-jvm/src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/org.json.simple"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
||||
<classpathentry kind="lib" path="/com.sap.sailing.targetplatform.base/plugins/target-test/mockito-core-1.10.14.jar"/>
|
||||
<classpathentry kind="var" path="ANDROID_HOME/extras/android/m2repository/com/android/support/support-annotations/22.2.1/support-annotations-22.2.1.jar"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
@@ -72,7 +72,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.6.2"
|
||||
compile "com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.7.4"
|
||||
|
||||
/* support libraries */
|
||||
compile "com.android.support:appcompat-v7:${rootProject.ext.support}"
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>com.h6ah4i.android.widget.advrecyclerview</groupId>
|
||||
<artifactId>advrecyclerview</artifactId>
|
||||
<version>0.6.2</version>
|
||||
<version>0.7.4</version>
|
||||
<type>aar</type>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
|
||||
# Project target.
|
||||
target=Google Inc.:Google APIs:22
|
||||
android.library.reference.1=../google-play-services_lib
|
||||
android.library.reference.2=../com.sap.sailing.android.shared
|
||||
android.library.reference.3=../google-android-support-v7-recyclerview_lib
|
||||
android.library.reference.4=../github-advrecyclerview_lib
|
||||
android.library.reference.5=../licensesdialog_lib/de.psdev.licensesdialog
|
||||
android.library.reference.1=..\\google-play-services_lib
|
||||
android.library.reference.2=..\\com.sap.sailing.android.shared
|
||||
android.library.reference.3=..\\google-android-support-v7-recyclerview_lib
|
||||
android.library.reference.4=..\\github-advrecyclerview_lib
|
||||
android.library.reference.5=..\\licensesdialog_lib\\de.psdev.licensesdialog
|
||||
android.library.reference.6=../google-android-support-v13
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
package com.sap.sailing.racecommittee.app.ui.adapters;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemViewHolder;
|
||||
|
||||
public abstract class BaseDraggableSwipeViewHolder extends RecyclerView.ViewHolder
|
||||
implements DraggableItemViewHolder, SwipeableItemViewHolder {
|
||||
|
||||
private int mDragStateFlags;
|
||||
private int mSwipeStateFlags;
|
||||
private int mSwipeResult = RecyclerViewSwipeManager.RESULT_NONE;
|
||||
private int mAfterSwipeReaction = RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_DEFAULT;
|
||||
private float mSwipeAmount;
|
||||
|
||||
public BaseDraggableSwipeViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDragStateFlags(int flags) {
|
||||
mDragStateFlags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDragStateFlags() {
|
||||
return mDragStateFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSwipeStateFlags(int flags) {
|
||||
mSwipeStateFlags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeStateFlags() {
|
||||
return mSwipeStateFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSwipeResult(int result) {
|
||||
mSwipeResult = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeResult() {
|
||||
return mSwipeResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAfterSwipeReaction(int reaction) {
|
||||
mAfterSwipeReaction = reaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAfterSwipeReaction() {
|
||||
return mAfterSwipeReaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSwipeItemSlideAmount(float amount) {
|
||||
mSwipeAmount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSwipeItemSlideAmount() {
|
||||
return mSwipeAmount;
|
||||
}
|
||||
}
|
||||
+19
-20
@@ -2,6 +2,17 @@ package com.sap.sailing.racecommittee.app.ui.adapters;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder;
|
||||
import com.sap.sailing.android.shared.util.BitmapHelper;
|
||||
import com.sap.sailing.android.shared.util.ViewHelper;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.domain.impl.CompetitorResultWithIdImpl;
|
||||
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
@@ -10,16 +21,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager;
|
||||
import com.sap.sailing.android.shared.util.BitmapHelper;
|
||||
import com.sap.sailing.android.shared.util.ViewHelper;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.domain.impl.CompetitorResultWithIdImpl;
|
||||
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
|
||||
|
||||
public class FinishListAdapter extends BaseDraggableSwipeAdapter<FinishListAdapter.ViewHolder> {
|
||||
|
||||
private Context mContext;
|
||||
@@ -80,7 +81,7 @@ public class FinishListAdapter extends BaseDraggableSwipeAdapter<FinishListAdapt
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCheckCanStartDrag(ViewHolder holder, int x, int y) {
|
||||
public boolean onCheckCanStartDrag(ViewHolder holder, int position, int x, int y) {
|
||||
// x, y --- relative from the itemView's top-left
|
||||
View containerView = holder.container;
|
||||
View dragHandleView = holder.dragHandle;
|
||||
@@ -92,7 +93,7 @@ public class FinishListAdapter extends BaseDraggableSwipeAdapter<FinishListAdapt
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDraggableRange onGetItemDraggableRange(ViewHolder viewHolder) {
|
||||
public ItemDraggableRange onGetItemDraggableRange(ViewHolder viewHolder, int position) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -113,8 +114,8 @@ public class FinishListAdapter extends BaseDraggableSwipeAdapter<FinishListAdapt
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onGetSwipeReactionType(ViewHolder holder, int x, int y) {
|
||||
if (onCheckCanStartDrag(holder, x, y)) {
|
||||
public int onGetSwipeReactionType(ViewHolder holder, int position, int x, int y) {
|
||||
if (onCheckCanStartDrag(holder, position, x, y)) {
|
||||
return RecyclerViewSwipeManager.REACTION_CAN_NOT_SWIPE_BOTH;
|
||||
} else {
|
||||
return RecyclerViewSwipeManager.REACTION_CAN_SWIPE_BOTH;
|
||||
@@ -122,7 +123,7 @@ public class FinishListAdapter extends BaseDraggableSwipeAdapter<FinishListAdapt
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetSwipeBackground(ViewHolder viewHolder, int type) {
|
||||
public void onSetSwipeBackground(ViewHolder viewHolder, int position, int type) {
|
||||
int bgRes = 0;
|
||||
switch (type) {
|
||||
case RecyclerViewSwipeManager.DRAWABLE_SWIPE_NEUTRAL_BACKGROUND:
|
||||
@@ -142,7 +143,7 @@ public class FinishListAdapter extends BaseDraggableSwipeAdapter<FinishListAdapt
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onSwipeItem(ViewHolder viewHolder, int result) {
|
||||
public int onSwipeItem(ViewHolder viewHolder, int position, int result) {
|
||||
switch (result) {
|
||||
case RecyclerViewSwipeManager.RESULT_SWIPED_LEFT:
|
||||
case RecyclerViewSwipeManager.RESULT_SWIPED_RIGHT:
|
||||
@@ -154,11 +155,9 @@ public class FinishListAdapter extends BaseDraggableSwipeAdapter<FinishListAdapt
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPerformAfterSwipeReaction(ViewHolder holder, int result, int reaction) {
|
||||
public void onPerformAfterSwipeReaction(ViewHolder holder, int position, int result, int reaction) {
|
||||
switch (reaction) {
|
||||
case RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_REMOVE_ITEM:
|
||||
int position = holder.getAdapterPosition();
|
||||
|
||||
if (mListener != null) {
|
||||
mListener.onItemRemoved(mCompetitor.get(position));
|
||||
mCompetitor.remove(position);
|
||||
@@ -181,7 +180,7 @@ public class FinishListAdapter extends BaseDraggableSwipeAdapter<FinishListAdapt
|
||||
void onEditItem(CompetitorResultWithIdImpl item, int position);
|
||||
}
|
||||
|
||||
public class ViewHolder extends BaseDraggableSwipeViewHolder implements View.OnLongClickListener {
|
||||
public class ViewHolder extends AbstractDraggableSwipeableItemViewHolder implements View.OnLongClickListener {
|
||||
public View container;
|
||||
public View dragHandle;
|
||||
public View editItem;
|
||||
|
||||
+22
-25
@@ -3,6 +3,20 @@ package com.sap.sailing.racecommittee.app.ui.adapters.coursedesign;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder;
|
||||
import com.sap.sailing.android.shared.logging.ExLog;
|
||||
import com.sap.sailing.android.shared.util.BitmapHelper;
|
||||
import com.sap.sailing.android.shared.util.ViewHelper;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.domain.impl.CourseListDataElementWithIdImpl;
|
||||
import com.sap.sailing.racecommittee.app.ui.adapters.BaseDraggableSwipeAdapter;
|
||||
import com.sap.sailing.racecommittee.app.ui.utils.MarkImageHelper;
|
||||
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
@@ -13,20 +27,6 @@ import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager;
|
||||
import com.sap.sailing.android.shared.logging.ExLog;
|
||||
import com.sap.sailing.android.shared.util.BitmapHelper;
|
||||
import com.sap.sailing.android.shared.util.ViewHelper;
|
||||
import com.sap.sailing.domain.common.PassingInstruction;
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.domain.impl.CourseListDataElementWithIdImpl;
|
||||
import com.sap.sailing.racecommittee.app.ui.adapters.BaseDraggableSwipeAdapter;
|
||||
import com.sap.sailing.racecommittee.app.ui.adapters.BaseDraggableSwipeViewHolder;
|
||||
import com.sap.sailing.racecommittee.app.ui.utils.MarkImageHelper;
|
||||
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
|
||||
|
||||
public class CourseElementAdapter extends BaseDraggableSwipeAdapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private final static String TAG = CourseElementAdapter.class.getName();
|
||||
@@ -195,7 +195,7 @@ public class CourseElementAdapter extends BaseDraggableSwipeAdapter<RecyclerView
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCheckCanStartDrag(RecyclerView.ViewHolder holder, int x, int y) {
|
||||
public boolean onCheckCanStartDrag(RecyclerView.ViewHolder holder, int position, int x, int y) {
|
||||
if (holder instanceof ItemViewHolder) {
|
||||
ItemViewHolder itemHolder = (ItemViewHolder) holder;
|
||||
// x, y --- relative from the itemView's top-left
|
||||
@@ -212,7 +212,7 @@ public class CourseElementAdapter extends BaseDraggableSwipeAdapter<RecyclerView
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDraggableRange onGetItemDraggableRange(RecyclerView.ViewHolder holder) {
|
||||
public ItemDraggableRange onGetItemDraggableRange(RecyclerView.ViewHolder holder, int position) {
|
||||
if (mElements == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -233,8 +233,8 @@ public class CourseElementAdapter extends BaseDraggableSwipeAdapter<RecyclerView
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onGetSwipeReactionType(RecyclerView.ViewHolder holder, int x, int y) {
|
||||
if (onCheckCanStartDrag(holder, x, y)) {
|
||||
public int onGetSwipeReactionType(RecyclerView.ViewHolder holder, int position, int x, int y) {
|
||||
if (onCheckCanStartDrag(holder, position, x, y)) {
|
||||
return RecyclerViewSwipeManager.REACTION_CAN_NOT_SWIPE_BOTH;
|
||||
} else {
|
||||
return RecyclerViewSwipeManager.REACTION_CAN_SWIPE_BOTH;
|
||||
@@ -242,7 +242,7 @@ public class CourseElementAdapter extends BaseDraggableSwipeAdapter<RecyclerView
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetSwipeBackground(RecyclerView.ViewHolder holder, int type) {
|
||||
public void onSetSwipeBackground(RecyclerView.ViewHolder holder, int position, int type) {
|
||||
if (holder instanceof ItemViewHolder) {
|
||||
int bgRes = 0;
|
||||
switch (type) {
|
||||
@@ -265,7 +265,7 @@ public class CourseElementAdapter extends BaseDraggableSwipeAdapter<RecyclerView
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onSwipeItem(RecyclerView.ViewHolder holder, int result) {
|
||||
public int onSwipeItem(RecyclerView.ViewHolder holder, int position, int result) {
|
||||
if (holder instanceof ItemViewHolder) {
|
||||
switch (result) {
|
||||
case RecyclerViewSwipeManager.RESULT_SWIPED_LEFT:
|
||||
@@ -281,12 +281,9 @@ public class CourseElementAdapter extends BaseDraggableSwipeAdapter<RecyclerView
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPerformAfterSwipeReaction(RecyclerView.ViewHolder holder, int result, int reaction) {
|
||||
public void onPerformAfterSwipeReaction(RecyclerView.ViewHolder holder, int position, int result, int reaction) {
|
||||
ExLog.i(mContext, TAG, "onPerformAfterSwipeReaction() called with: " + "holder = [" + holder + "], result = [" + result + "], reaction = [" + reaction + "]");
|
||||
|
||||
int position = holder.getAdapterPosition();
|
||||
CourseListDataElementWithIdImpl element = mElements.get(position);
|
||||
|
||||
switch (reaction) {
|
||||
case RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_REMOVE_ITEM:
|
||||
mElements.remove(element);
|
||||
@@ -335,7 +332,7 @@ public class CourseElementAdapter extends BaseDraggableSwipeAdapter<RecyclerView
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemViewHolder extends BaseDraggableSwipeViewHolder implements View.OnClickListener {
|
||||
public class ItemViewHolder extends AbstractDraggableSwipeableItemViewHolder implements View.OnClickListener {
|
||||
|
||||
public ViewGroup container;
|
||||
public View dragHandle;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/google-android-support-v4"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/google-android-support-v7-appcompat_lib"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/google-android-support-v7-recyclerview_lib"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
@@ -1,3 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 Haruki Hasegawa
|
||||
|
||||
@@ -14,10 +15,12 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.h6ah4i.android.widget.advrecyclerview">
|
||||
package="com.h6ah4i.android.widget.advrecyclerview"
|
||||
android:versionCode="9"
|
||||
android:versionName="0.7.4" >
|
||||
|
||||
<application>
|
||||
<!--suppress AndroidDomInspection -->
|
||||
<activity android:name=".TestActivity"/>
|
||||
</application>
|
||||
</manifest>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="9"
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
</manifest>
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
advrecyclerview-0.7.4 ist the last version that depends on Android 22.2.1 which is what we're currently using.
|
||||
See http://jcenter.bintray.com/com/h6ah4i/android/widget/advrecyclerview/advrecyclerview/0.7.4/.
|
||||
@@ -12,6 +12,4 @@
|
||||
|
||||
# Project target.
|
||||
target=android-22
|
||||
android.library.reference.1=../google-android-support-v7-recyclerview_lib
|
||||
android.library=true
|
||||
android.library.reference.2=../google-android-support-v7-appcompat_lib
|
||||
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+6
-6
@@ -36,7 +36,7 @@ public abstract class GeneralItemAnimator extends BaseItemAnimator {
|
||||
private ItemChangeAnimationManager mChangeAnimationsManager;
|
||||
private ItemMoveAnimationManager mMoveAnimationsManager;
|
||||
|
||||
GeneralItemAnimator() {
|
||||
protected GeneralItemAnimator() {
|
||||
setup();
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public abstract class GeneralItemAnimator extends BaseItemAnimator {
|
||||
@Override
|
||||
public boolean animateRemove(final RecyclerView.ViewHolder holder) {
|
||||
if (mDebug) {
|
||||
Log.d(TAG, "animateRemove(id = " + holder.getItemId() + ", position = " + holder.getPosition() + ")");
|
||||
Log.d(TAG, "animateRemove(id = " + holder.getItemId() + ", position = " + holder.getLayoutPosition() + ")");
|
||||
}
|
||||
|
||||
return mRemoveAnimationManager.addPendingAnimation(holder);
|
||||
@@ -74,7 +74,7 @@ public abstract class GeneralItemAnimator extends BaseItemAnimator {
|
||||
@Override
|
||||
public boolean animateAdd(final RecyclerView.ViewHolder holder) {
|
||||
if (mDebug) {
|
||||
Log.d(TAG, "animateAdd(id = " + holder.getItemId() + ", position = " + holder.getPosition() + ")");
|
||||
Log.d(TAG, "animateAdd(id = " + holder.getItemId() + ", position = " + holder.getLayoutPosition() + ")");
|
||||
}
|
||||
|
||||
return mAddAnimationsManager.addPendingAnimation(holder);
|
||||
@@ -83,7 +83,7 @@ public abstract class GeneralItemAnimator extends BaseItemAnimator {
|
||||
@Override
|
||||
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
|
||||
if (mDebug) {
|
||||
Log.d(TAG, "animateMove(id = " + holder.getItemId() + ", position = " + holder.getPosition() + ", fromX = " + fromX + ", fromY = " + fromY + ", toX = " + toX + ", toY = " + toY + ")");
|
||||
Log.d(TAG, "animateMove(id = " + holder.getItemId() + ", position = " + holder.getLayoutPosition() + ", fromX = " + fromX + ", fromY = " + fromY + ", toX = " + toX + ", toY = " + toY + ")");
|
||||
}
|
||||
|
||||
return mMoveAnimationsManager.addPendingAnimation(holder, fromX, fromY, toX, toY);
|
||||
@@ -94,9 +94,9 @@ public abstract class GeneralItemAnimator extends BaseItemAnimator {
|
||||
RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
|
||||
if (mDebug) {
|
||||
final String oldId = (oldHolder != null) ? Long.toString(oldHolder.getItemId()) : "-";
|
||||
final String oldPosition = (oldHolder != null) ? Long.toString(oldHolder.getPosition()) : "-";
|
||||
final String oldPosition = (oldHolder != null) ? Long.toString(oldHolder.getLayoutPosition()) : "-";
|
||||
final String newId = (newHolder != null) ? Long.toString(newHolder.getItemId()) : "-";
|
||||
final String newPosition = (newHolder != null) ? Long.toString(newHolder.getPosition()) : "-";
|
||||
final String newPosition = (newHolder != null) ? Long.toString(newHolder.getLayoutPosition()) : "-";
|
||||
|
||||
Log.d(TAG, "animateChange(old.id = " + oldId + ", old.position = " + oldPosition + ", new.id = " + newId + ", new.position = " + newPosition
|
||||
+ ", fromX = " + fromX + ", fromY = " + fromY + ", toX = " + toX + ", toY = " + toY + ")");
|
||||
|
||||
Regular → Executable
+4
-4
@@ -48,7 +48,7 @@ public class RefactoredDefaultItemAnimator extends GeneralItemAnimator {
|
||||
/**
|
||||
* Item Animation manager for ADD operation (Same behavior as DefaultItemAnimator class)
|
||||
*/
|
||||
private static class DefaultItemAddAnimationManager extends ItemAddAnimationManager {
|
||||
protected static class DefaultItemAddAnimationManager extends ItemAddAnimationManager {
|
||||
|
||||
public DefaultItemAddAnimationManager(BaseItemAnimator itemAnimator) {
|
||||
super(itemAnimator);
|
||||
@@ -93,7 +93,7 @@ public class RefactoredDefaultItemAnimator extends GeneralItemAnimator {
|
||||
/**
|
||||
* Item Animation manager for REMOVE operation (Same behavior as DefaultItemAnimator class)
|
||||
*/
|
||||
private static class DefaultItemRemoveAnimationManager extends ItemRemoveAnimationManager {
|
||||
protected static class DefaultItemRemoveAnimationManager extends ItemRemoveAnimationManager {
|
||||
|
||||
public DefaultItemRemoveAnimationManager(BaseItemAnimator itemAnimator) {
|
||||
super(itemAnimator);
|
||||
@@ -137,7 +137,7 @@ public class RefactoredDefaultItemAnimator extends GeneralItemAnimator {
|
||||
/**
|
||||
* Item Animation manager for CHANGE operation (Same behavior as DefaultItemAnimator class)
|
||||
*/
|
||||
private static class DefaultItemChangeAnimationManager extends ItemChangeAnimationManager {
|
||||
protected static class DefaultItemChangeAnimationManager extends ItemChangeAnimationManager {
|
||||
public DefaultItemChangeAnimationManager(BaseItemAnimator itemAnimator) {
|
||||
super(itemAnimator);
|
||||
}
|
||||
@@ -220,7 +220,7 @@ public class RefactoredDefaultItemAnimator extends GeneralItemAnimator {
|
||||
/**
|
||||
* Item Animation manager for MOVE operation (Same behavior as DefaultItemAnimator class)
|
||||
*/
|
||||
private static class DefaultItemMoveAnimationManager extends ItemMoveAnimationManager {
|
||||
protected static class DefaultItemMoveAnimationManager extends ItemMoveAnimationManager {
|
||||
|
||||
public DefaultItemMoveAnimationManager(BaseItemAnimator itemAnimator) {
|
||||
super(itemAnimator);
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
-2
@@ -78,8 +78,6 @@ public class ItemShadowDecorator extends RecyclerView.ItemDecoration {
|
||||
}
|
||||
|
||||
c.restoreToCount(savedCount);
|
||||
|
||||
ViewCompat.postInvalidateOnAnimation(parent);
|
||||
}
|
||||
|
||||
private static boolean shouldDrawDropShadow(View child) {
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+5
-3
@@ -24,22 +24,24 @@ public interface DraggableItemAdapter<T extends RecyclerView.ViewHolder> {
|
||||
* Called when user is attempt to drag the item.
|
||||
*
|
||||
* @param holder The ViewHolder which is associated to item user is attempt to start dragging.
|
||||
* @param position The position of the item within the adapter's data set.
|
||||
* @param x Touched X position. Relative from the itemView's top-left.
|
||||
* @param y Touched Y position. Relative from the itemView's top-left.
|
||||
|
||||
* @return Whether can start dragging.
|
||||
*/
|
||||
boolean onCheckCanStartDrag(T holder, int x, int y);
|
||||
boolean onCheckCanStartDrag(T holder, int position, int x, int y);
|
||||
|
||||
/**
|
||||
* Called after the {@link #onCheckCanStartDrag(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method returned true.
|
||||
* Called after the {@link #onCheckCanStartDrag(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method returned true.
|
||||
*
|
||||
* @param holder The ViewHolder which is associated to item user is attempt to start dragging.
|
||||
* @param position The position of the item within the adapter's data set.
|
||||
*
|
||||
* @return null: no constraints (= new ItemDraggableRange(0, getItemCount() - 1)),
|
||||
* otherwise: the range specified item can be drag-sortable.
|
||||
*/
|
||||
ItemDraggableRange onGetItemDraggableRange(T holder);
|
||||
ItemDraggableRange onGetItemDraggableRange(T holder, int position);
|
||||
|
||||
/**
|
||||
* Called when item is moved. Should apply the move operation result to data set.
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+107
-18
@@ -20,16 +20,19 @@ import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.utils.BaseWrapperAdapter;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils;
|
||||
|
||||
class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends BaseWrapperAdapter<VH> {
|
||||
class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends BaseWrapperAdapter<VH> implements SwipeableItemAdapter<VH> {
|
||||
private static final String TAG = "ARVDraggableWrapper";
|
||||
|
||||
private static final int STATE_FLAG_INITIAL_VALUE = -1;
|
||||
|
||||
private static final boolean LOCAL_LOGV = false;
|
||||
private static final boolean LOCAL_LOGD = false;
|
||||
private static final boolean LOCAL_LOGI = true;
|
||||
private static final boolean DEBUG_BYPASS_MOVE_OPERATION_MODE = false;
|
||||
|
||||
private RecyclerViewDragDropManager mDragDropManager;
|
||||
@@ -83,7 +86,15 @@ class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
position, mDraggingItemInitialPosition, mDraggingItemCurrentPosition);
|
||||
|
||||
if (itemId == mDraggingItemId && holder != mDraggingItem) {
|
||||
Log.w(TAG, "an another view holder object for the currently dragging item is assigned");
|
||||
if (mDraggingItem == null) {
|
||||
if (LOCAL_LOGI) {
|
||||
Log.i(TAG, "a new view holder object for the currently dragging item is assigned");
|
||||
}
|
||||
mDraggingItem = holder;
|
||||
mDragDropManager.onNewDraggingItemViewBinded(holder);
|
||||
} else {
|
||||
Log.e(TAG, "an another view holder object for the currently dragging item is assigned");
|
||||
}
|
||||
}
|
||||
|
||||
int flags = RecyclerViewDragDropManager.STATE_FLAG_DRAGGING;
|
||||
@@ -223,7 +234,7 @@ class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
throw new IllegalStateException("dragging target must provides valid ID");
|
||||
}
|
||||
|
||||
mDraggingItemInitialPosition = holder.getPosition();
|
||||
mDraggingItemInitialPosition = holder.getAdapterPosition();
|
||||
mDraggingItemCurrentPosition = mDraggingItemInitialPosition;
|
||||
mDraggingItem = holder;
|
||||
mDraggingItemId = holder.getItemId();
|
||||
@@ -238,7 +249,7 @@ class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
Log.d(TAG, "onDragItemFinished(holder = " + holder + ", result = " + result + ")");
|
||||
}
|
||||
|
||||
if (holder != mDraggingItem) {
|
||||
if (holder != null && holder != mDraggingItem) {
|
||||
throw new IllegalStateException("onDragItemFinished() - may be a bug (mDraggingItem != holder)");
|
||||
}
|
||||
|
||||
@@ -248,8 +259,9 @@ class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
|
||||
if (result && (mDraggingItemCurrentPosition != mDraggingItemInitialPosition)) {
|
||||
// apply to wrapped adapter
|
||||
((DraggableItemAdapter) getWrappedAdapter()).onMoveItem(
|
||||
mDraggingItemInitialPosition, mDraggingItemCurrentPosition);
|
||||
DraggableItemAdapter adapter = WrapperAdapterUtils.findWrappedAdapter(
|
||||
getWrappedAdapter(), DraggableItemAdapter.class);
|
||||
adapter.onMoveItem(mDraggingItemInitialPosition, mDraggingItemCurrentPosition);
|
||||
}
|
||||
|
||||
mDraggingItemInitialPosition = RecyclerView.NO_POSITION;
|
||||
@@ -265,13 +277,11 @@ class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
public void onViewRecycled(VH holder) {
|
||||
if (isDragging()) {
|
||||
if (holder == mDraggingItem) {
|
||||
try {
|
||||
throw new IllegalStateException("onViewRecycled() - may be a bug. dragging item should be recycled.");
|
||||
} catch (IllegalStateException e) {
|
||||
// TODO is there any way to prevent the dragging item from be recycled...?
|
||||
|
||||
mDragDropManager.cancelDrag();
|
||||
if (LOCAL_LOGI) {
|
||||
Log.i(TAG, "a view holder object which is bound to currently dragging item is recycled");
|
||||
}
|
||||
mDraggingItem = null;
|
||||
mDragDropManager.onDraggingItemViewRecycled();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,21 +291,21 @@ class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
// NOTE: This method is called from RecyclerViewDragDropManager
|
||||
/*package*/
|
||||
@SuppressWarnings("unchecked")
|
||||
boolean canStartDrag(RecyclerView.ViewHolder holder, int x, int y) {
|
||||
boolean canStartDrag(RecyclerView.ViewHolder holder, int position, int x, int y) {
|
||||
if (LOCAL_LOGV) {
|
||||
Log.v(TAG, "canStartDrag(holder = " + holder + ", x = " + x + ", y = " + y + ")");
|
||||
Log.v(TAG, "canStartDrag(holder = " + holder + ", position = " + position + ", x = " + x + ", y = " + y + ")");
|
||||
}
|
||||
return mDraggableItemAdapter.onCheckCanStartDrag(holder, x, y);
|
||||
return mDraggableItemAdapter.onCheckCanStartDrag(holder, position, x, y);
|
||||
}
|
||||
|
||||
// NOTE: This method is called from RecyclerViewDragDropManager
|
||||
/*package*/
|
||||
@SuppressWarnings("unchecked")
|
||||
ItemDraggableRange getItemDraggableRange(RecyclerView.ViewHolder holder) {
|
||||
ItemDraggableRange getItemDraggableRange(RecyclerView.ViewHolder holder, int position) {
|
||||
if (LOCAL_LOGV) {
|
||||
Log.v(TAG, "getItemDraggableRange(holder = " + holder + ")");
|
||||
Log.v(TAG, "getItemDraggableRange(holder = " + holder + ", position = " + position + ")");
|
||||
}
|
||||
return mDraggableItemAdapter.onGetItemDraggableRange(holder);
|
||||
return mDraggableItemAdapter.onGetItemDraggableRange(holder, position);
|
||||
}
|
||||
|
||||
// NOTE: This method is called from RecyclerViewDragDropManager
|
||||
@@ -335,6 +345,14 @@ class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
return mDragDropManager.isDragging();
|
||||
}
|
||||
|
||||
/*package*/ int getDraggingItemInitialPosition() {
|
||||
return mDraggingItemInitialPosition;
|
||||
}
|
||||
|
||||
/*package*/ int getDraggingItemCurrentPosition() {
|
||||
return mDraggingItemCurrentPosition;
|
||||
}
|
||||
|
||||
private static void safeUpdateFlags(RecyclerView.ViewHolder holder, int flags) {
|
||||
if (!(holder instanceof DraggableItemViewHolder)) {
|
||||
return;
|
||||
@@ -356,4 +374,75 @@ class DraggableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
private static DraggableItemAdapter getDraggableItemAdapter(RecyclerView.Adapter adapter) {
|
||||
return WrapperAdapterUtils.findWrappedAdapter(adapter, DraggableItemAdapter.class);
|
||||
}
|
||||
|
||||
private int getOriginalPosition(int position) {
|
||||
int correctedPosition;
|
||||
|
||||
if (isDragging()) {
|
||||
correctedPosition = convertToOriginalPosition(
|
||||
position, mDraggingItemInitialPosition, mDraggingItemCurrentPosition);
|
||||
} else {
|
||||
correctedPosition = position;
|
||||
}
|
||||
return correctedPosition;
|
||||
}
|
||||
|
||||
//
|
||||
// SwipeableItemAdapter implementations
|
||||
//
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public int onGetSwipeReactionType(VH holder, int position, int x, int y) {
|
||||
RecyclerView.Adapter adapter = getWrappedAdapter();
|
||||
if (!(adapter instanceof SwipeableItemAdapter)) {
|
||||
return RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_DEFAULT;
|
||||
}
|
||||
|
||||
int correctedPosition = getOriginalPosition(position);
|
||||
|
||||
SwipeableItemAdapter<VH> swipeableItemAdapter = (SwipeableItemAdapter<VH>) adapter;
|
||||
return swipeableItemAdapter.onGetSwipeReactionType(holder, correctedPosition, x, y);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onSetSwipeBackground(VH holder, int position, int type) {
|
||||
RecyclerView.Adapter adapter = getWrappedAdapter();
|
||||
if (!(adapter instanceof SwipeableItemAdapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int correctedPosition = getOriginalPosition(position);
|
||||
|
||||
SwipeableItemAdapter<VH> swipeableItemAdapter = (SwipeableItemAdapter<VH>) adapter;
|
||||
swipeableItemAdapter.onSetSwipeBackground(holder, correctedPosition, type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public int onSwipeItem(VH holder, int position, int result) {
|
||||
RecyclerView.Adapter adapter = getWrappedAdapter();
|
||||
if (!(adapter instanceof SwipeableItemAdapter)) {
|
||||
return RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_DEFAULT;
|
||||
}
|
||||
|
||||
int correctedPosition = getOriginalPosition(position);
|
||||
|
||||
SwipeableItemAdapter<VH> swipeableItemAdapter = (SwipeableItemAdapter<VH>) adapter;
|
||||
return swipeableItemAdapter.onSwipeItem(holder, correctedPosition, result);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onPerformAfterSwipeReaction(VH holder, int position, int result, int reaction) {
|
||||
RecyclerView.Adapter adapter = getWrappedAdapter();
|
||||
if (!(adapter instanceof SwipeableItemAdapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int correctedPosition = getOriginalPosition(position);
|
||||
|
||||
SwipeableItemAdapter<VH> swipeableItemAdapter = (SwipeableItemAdapter<VH>) adapter;
|
||||
swipeableItemAdapter.onPerformAfterSwipeReaction(holder, correctedPosition, result, reaction);
|
||||
}
|
||||
}
|
||||
Regular → Executable
+36
-5
@@ -104,10 +104,14 @@ class DraggingItemDecorator extends BaseDraggableItemDecorator {
|
||||
|
||||
// return to default position
|
||||
updateDraggingItemPosition(mTranslationY);
|
||||
moveToDefaultPosition(mDraggingItem.itemView, animate);
|
||||
if (mDraggingItem != null) {
|
||||
moveToDefaultPosition(mDraggingItem.itemView, animate);
|
||||
}
|
||||
|
||||
// show
|
||||
mDraggingItem.itemView.setVisibility(View.VISIBLE);
|
||||
if (mDraggingItem != null) {
|
||||
mDraggingItem.itemView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
mDraggingItem = null;
|
||||
|
||||
if (mDraggingItemImage != null) {
|
||||
@@ -178,6 +182,13 @@ class DraggingItemDecorator extends BaseDraggableItemDecorator {
|
||||
mTranslationY = Math.min(Math.max(mTranslationY, mTranslationTopLimit), mTranslationBottomLimit);
|
||||
}
|
||||
|
||||
public boolean isReachedToTopLimit() {
|
||||
return (mTranslationY == mTranslationTopLimit);
|
||||
}
|
||||
|
||||
public boolean isReachedToBottomLimit() {
|
||||
return (mTranslationY == mTranslationBottomLimit);
|
||||
}
|
||||
|
||||
private Bitmap createDraggingItemImage(View v, NinePatchDrawable shadow) {
|
||||
int width = v.getWidth() + mShadowPadding.left + mShadowPadding.right;
|
||||
@@ -204,7 +215,9 @@ class DraggingItemDecorator extends BaseDraggableItemDecorator {
|
||||
|
||||
private void updateDraggingItemPosition(int translationY) {
|
||||
// NOTE: Need to update the view position to make other decorations work properly while dragging
|
||||
setItemTranslationY(mRecyclerView, mDraggingItem, translationY - mDraggingItem.itemView.getTop());
|
||||
if (mDraggingItem != null) {
|
||||
setItemTranslationY(mRecyclerView, mDraggingItem, translationY - mDraggingItem.itemView.getTop());
|
||||
}
|
||||
}
|
||||
|
||||
public void setIsScrolling(boolean isScrolling) {
|
||||
@@ -238,7 +251,7 @@ class DraggingItemDecorator extends BaseDraggableItemDecorator {
|
||||
final RecyclerView.ViewHolder vh = rv.getChildViewHolder(v2);
|
||||
|
||||
if (vh != null) {
|
||||
final int position = vh.getPosition();
|
||||
final int position = vh.getLayoutPosition();
|
||||
|
||||
if ((position >= firstVisiblePosition) &&
|
||||
(position <= lastVisiblePosition) &&
|
||||
@@ -266,7 +279,7 @@ class DraggingItemDecorator extends BaseDraggableItemDecorator {
|
||||
final RecyclerView.ViewHolder vh = rv.getChildViewHolder(v2);
|
||||
|
||||
if (vh != null) {
|
||||
final int position = vh.getPosition();
|
||||
final int position = vh.getLayoutPosition();
|
||||
|
||||
if ((position >= firstVisiblePosition) &&
|
||||
(position <= lastVisiblePosition) &&
|
||||
@@ -279,4 +292,22 @@ class DraggingItemDecorator extends BaseDraggableItemDecorator {
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public void invalidateDraggingItem() {
|
||||
if (mDraggingItem != null) {
|
||||
mDraggingItem.itemView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
mDraggingItem = null;
|
||||
}
|
||||
|
||||
public void setDraggingItemViewHolder(RecyclerView.ViewHolder holder) {
|
||||
if (mDraggingItem != null) {
|
||||
throw new IllegalStateException("A new view holder is attempt to be assigned before invalidating the older one");
|
||||
}
|
||||
|
||||
mDraggingItem = holder;
|
||||
|
||||
holder.itemView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
Regular → Executable
+22
-21
@@ -82,16 +82,15 @@ public class EdgeEffectDecorator extends RecyclerView.ItemDecoration {
|
||||
public void pullTopGlow(float deltaDistance) {
|
||||
ensureTopGlow(mRecyclerView);
|
||||
|
||||
if (mTopGlow.onPull(deltaDistance)) {
|
||||
if (mTopGlow.onPull(deltaDistance, 0.5f)) {
|
||||
ViewCompat.postInvalidateOnAnimation(mRecyclerView);
|
||||
}
|
||||
}
|
||||
|
||||
public void pullBottom(float deltaDistance) {
|
||||
ensureBottomGlow(mRecyclerView);
|
||||
mBottomGlow.onPull(deltaDistance);
|
||||
|
||||
if (mBottomGlow.onPull(deltaDistance)) {
|
||||
if (mBottomGlow.onPull(deltaDistance, 0.5f)) {
|
||||
ViewCompat.postInvalidateOnAnimation(mRecyclerView);
|
||||
}
|
||||
}
|
||||
@@ -114,31 +113,33 @@ public class EdgeEffectDecorator extends RecyclerView.ItemDecoration {
|
||||
}
|
||||
|
||||
private void ensureTopGlow(RecyclerView rv) {
|
||||
if (mTopGlow != null) {
|
||||
return;
|
||||
}
|
||||
mTopGlow = new EdgeEffectCompat(rv.getContext());
|
||||
if (getClipToPadding(rv)) {
|
||||
mTopGlow.setSize(
|
||||
rv.getMeasuredWidth() - rv.getPaddingLeft() - rv.getPaddingRight(),
|
||||
rv.getMeasuredHeight() - rv.getPaddingTop() - rv.getPaddingBottom());
|
||||
} else {
|
||||
mTopGlow.setSize(rv.getMeasuredWidth(), rv.getMeasuredHeight());
|
||||
if (mTopGlow == null) {
|
||||
mTopGlow = new EdgeEffectCompat(rv.getContext());
|
||||
}
|
||||
|
||||
updateGlowSize(rv, mTopGlow);
|
||||
}
|
||||
|
||||
private void ensureBottomGlow(RecyclerView rv) {
|
||||
if (mBottomGlow != null) {
|
||||
return;
|
||||
if (mBottomGlow == null) {
|
||||
mBottomGlow = new EdgeEffectCompat(rv.getContext());
|
||||
}
|
||||
mBottomGlow = new EdgeEffectCompat(rv.getContext());
|
||||
updateGlowSize(rv, mBottomGlow);
|
||||
}
|
||||
|
||||
private static void updateGlowSize(RecyclerView rv, EdgeEffectCompat topGlow) {
|
||||
int width = rv.getMeasuredWidth();
|
||||
int height = rv.getMeasuredHeight();
|
||||
|
||||
if (getClipToPadding(rv)) {
|
||||
mBottomGlow.setSize(
|
||||
rv.getMeasuredWidth() - rv.getPaddingLeft() - rv.getPaddingRight(),
|
||||
rv.getMeasuredHeight() - rv.getPaddingTop() - rv.getPaddingBottom());
|
||||
} else {
|
||||
mBottomGlow.setSize(rv.getMeasuredWidth(), rv.getMeasuredHeight());
|
||||
width -= rv.getPaddingLeft() - rv.getPaddingRight();
|
||||
height -= rv.getPaddingTop() - rv.getPaddingBottom();
|
||||
}
|
||||
|
||||
width = Math.max(0, width);
|
||||
height = Math.max(0, height);
|
||||
|
||||
topGlow.setSize(width, height);
|
||||
}
|
||||
|
||||
private static boolean getClipToPadding(RecyclerView rv) {
|
||||
|
||||
Regular → Executable
+5
-1
@@ -41,9 +41,13 @@ public class ItemDraggableRange {
|
||||
return ((position >= mStart) && (position <= mEnd));
|
||||
}
|
||||
|
||||
protected String getClassName() {
|
||||
return "ItemDraggableRange";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ItemDraggableRange{" +
|
||||
return getClassName() + "{" +
|
||||
"mStart=" + mStart +
|
||||
", mEnd=" + mEnd +
|
||||
'}';
|
||||
|
||||
Regular → Executable
+283
-41
@@ -19,6 +19,8 @@ package com.h6ah4i.android.widget.advrecyclerview.draggable;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.NinePatchDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.support.v4.view.MotionEventCompat;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
@@ -81,6 +83,29 @@ public class RecyclerViewDragDropManager {
|
||||
|
||||
// ---
|
||||
|
||||
/**
|
||||
* Used for listening item drag events
|
||||
*/
|
||||
public interface OnItemDragEventListener {
|
||||
/**
|
||||
* Callback method to be invoked when dragging is started.
|
||||
*
|
||||
* @param position The position of the item.
|
||||
*/
|
||||
void onItemDragStarted(int position);
|
||||
|
||||
/**
|
||||
* Callback method to be invoked when dragging is finished.
|
||||
*
|
||||
* @param fromPosition Previous position of the item.
|
||||
* @param toPosition New position of the item.
|
||||
* @param result Indicates whether the dragging operation was succeeded.
|
||||
*/
|
||||
void onItemDragFinished(int fromPosition, int toPosition, boolean result);
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
private static final int SCROLL_DIR_NONE = 0;
|
||||
private static final int SCROLL_DIR_UP = (1 << 0);
|
||||
private static final int SCROLL_DIR_DOWN = (1 << 1);
|
||||
@@ -90,7 +115,6 @@ public class RecyclerViewDragDropManager {
|
||||
|
||||
private static final float SCROLL_THRESHOLD = 0.3f; // 0.0f < X < 0.5f
|
||||
private static final float SCROLL_AMOUNT_COEFF = 25;
|
||||
private static final float EDGE_EFFECT_THRESHOLD = 0.5f; // <= 1.0f
|
||||
private static final float SCROLL_TOUCH_SLOP_MULTIPLY = 1.5f;
|
||||
|
||||
private RecyclerView mRecyclerView;
|
||||
@@ -109,6 +133,8 @@ public class RecyclerViewDragDropManager {
|
||||
private int mScrollTouchSlop;
|
||||
private int mInitialTouchY;
|
||||
private long mInitialTouchItemId = RecyclerView.NO_ID;
|
||||
private boolean mInitiateOnLongPress;
|
||||
private boolean mInitiateOnMove = true;
|
||||
|
||||
private boolean mInScrollByMethod;
|
||||
private int mActualScrollByAmount;
|
||||
@@ -135,6 +161,8 @@ public class RecyclerViewDragDropManager {
|
||||
private int mGrabbedItemHeight;
|
||||
private int mOrigOverScrollMode;
|
||||
private ItemDraggableRange mDraggableRange;
|
||||
private InternalHandler mHandler;
|
||||
private OnItemDragEventListener mItemDragEventListener;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -150,6 +178,11 @@ public class RecyclerViewDragDropManager {
|
||||
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
|
||||
RecyclerViewDragDropManager.this.onTouchEvent(rv, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
RecyclerViewDragDropManager.this.onRequestDisallowInterceptTouchEvent(disallowIntercept);
|
||||
}
|
||||
};
|
||||
|
||||
mInternalUseOnScrollListener = new RecyclerView.OnScrollListener() {
|
||||
@@ -171,7 +204,6 @@ public class RecyclerViewDragDropManager {
|
||||
* Create wrapped adapter.
|
||||
*
|
||||
* @param adapter The target adapter.
|
||||
*
|
||||
* @return Wrapped adapter which is associated to this {@link RecyclerViewDragDropManager} instance.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -204,6 +236,7 @@ public class RecyclerViewDragDropManager {
|
||||
* @param rv The {@link android.support.v7.widget.RecyclerView} instance
|
||||
*/
|
||||
public void attachRecyclerView(RecyclerView rv) {
|
||||
//noinspection deprecation
|
||||
attachRecyclerView(rv, null);
|
||||
}
|
||||
|
||||
@@ -214,10 +247,11 @@ public class RecyclerViewDragDropManager {
|
||||
* the wrapped adapter instance which is returned by the
|
||||
* {@link #createWrappedAdapter(android.support.v7.widget.RecyclerView.Adapter)} method.
|
||||
*
|
||||
* @param rv The {@link android.support.v7.widget.RecyclerView} instance
|
||||
* @param rv The {@link android.support.v7.widget.RecyclerView} instance
|
||||
* @param scrollEventDistributor The distributor for {@link android.support.v7.widget.RecyclerView.OnScrollListener} event
|
||||
*/
|
||||
public void attachRecyclerView(RecyclerView rv, RecyclerViewOnScrollEventDistributor scrollEventDistributor) {
|
||||
@Deprecated
|
||||
public void attachRecyclerView(RecyclerView rv, @SuppressWarnings("deprecation") RecyclerViewOnScrollEventDistributor scrollEventDistributor) {
|
||||
if (rv == null) {
|
||||
throw new IllegalArgumentException("RecyclerView cannot be null");
|
||||
}
|
||||
@@ -248,7 +282,7 @@ public class RecyclerViewDragDropManager {
|
||||
scrollEventDistributor.add(mInternalUseOnScrollListener);
|
||||
mScrollEventRegisteredToDistributor = true;
|
||||
} else {
|
||||
mRecyclerView.setOnScrollListener(mInternalUseOnScrollListener);
|
||||
mRecyclerView.addOnScrollListener(mInternalUseOnScrollListener);
|
||||
mScrollEventRegisteredToDistributor = false;
|
||||
}
|
||||
|
||||
@@ -257,6 +291,7 @@ public class RecyclerViewDragDropManager {
|
||||
mDisplayDensity = mRecyclerView.getResources().getDisplayMetrics().density;
|
||||
mTouchSlop = ViewConfiguration.get(mRecyclerView.getContext()).getScaledTouchSlop();
|
||||
mScrollTouchSlop = (int) (mTouchSlop * SCROLL_TOUCH_SLOP_MULTIPLY + 0.5f);
|
||||
mHandler = new InternalHandler(this);
|
||||
|
||||
if (supportsEdgeEffect()) {
|
||||
// edge effect is available on ICS or later
|
||||
@@ -273,6 +308,11 @@ public class RecyclerViewDragDropManager {
|
||||
public void release() {
|
||||
cancelDrag();
|
||||
|
||||
if (mHandler != null) {
|
||||
mHandler.release();
|
||||
mHandler = null;
|
||||
}
|
||||
|
||||
if (mEdgeEffectDecorator != null) {
|
||||
mEdgeEffectDecorator.finish();
|
||||
mEdgeEffectDecorator = null;
|
||||
@@ -284,7 +324,7 @@ public class RecyclerViewDragDropManager {
|
||||
mInternalUseOnItemTouchListener = null;
|
||||
|
||||
if (mRecyclerView != null && mInternalUseOnScrollListener != null && mScrollEventRegisteredToDistributor) {
|
||||
mRecyclerView.setOnScrollListener(null);
|
||||
mRecyclerView.removeOnScrollListener(mInternalUseOnScrollListener);
|
||||
}
|
||||
mInternalUseOnScrollListener = null;
|
||||
|
||||
@@ -304,7 +344,7 @@ public class RecyclerViewDragDropManager {
|
||||
* @return True if currently performing item dragging
|
||||
*/
|
||||
public boolean isDragging() {
|
||||
return (mDraggingItem != null) && (mDeferredCancelProcess == null);
|
||||
return (mDraggingItemId != RecyclerView.NO_ID) && (mDeferredCancelProcess == null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,6 +365,42 @@ public class RecyclerViewDragDropManager {
|
||||
mSwapTargetTranslationInterpolator = interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether dragging starts on a long press or not.
|
||||
*
|
||||
* @return True if dragging starts on a long press, false otherwise.
|
||||
*/
|
||||
public boolean isInitiateOnLongPressEnabled() {
|
||||
return mInitiateOnLongPress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether dragging starts on a long press. (default: false)
|
||||
*
|
||||
* @param initiateOnLongPress True to initiate dragging on long press.
|
||||
*/
|
||||
public void setInitiateOnLongPress(boolean initiateOnLongPress) {
|
||||
mInitiateOnLongPress = initiateOnLongPress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether dragging starts on move motions.
|
||||
*
|
||||
* @return True if dragging starts on move motions, false otherwise.
|
||||
*/
|
||||
public boolean isInitiateOnMoveEnabled() {
|
||||
return mInitiateOnMove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether dragging starts on move motions. (default: true)
|
||||
*
|
||||
* @param initiateOnMove True to initiate dragging on move motions.
|
||||
*/
|
||||
public void setInitiateOnMove(boolean initiateOnMove) {
|
||||
mInitiateOnMove = initiateOnMove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the interpolator which ise used for determining the position of the swapping item.
|
||||
*
|
||||
@@ -334,6 +410,23 @@ public class RecyclerViewDragDropManager {
|
||||
return mSwapTargetTranslationInterpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets OnItemDragEventListener listener
|
||||
* @return The listener object
|
||||
*/
|
||||
public OnItemDragEventListener getOnItemDragEventListener() {
|
||||
return mItemDragEventListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets OnItemDragEventListener listener
|
||||
*
|
||||
* @param listener The listener object
|
||||
*/
|
||||
public void setOnItemDragEventListener(OnItemDragEventListener listener) {
|
||||
mItemDragEventListener = listener;
|
||||
}
|
||||
|
||||
/*package*/ boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
|
||||
final int action = MotionEventCompat.getActionMasked(e);
|
||||
|
||||
@@ -393,6 +486,13 @@ public class RecyclerViewDragDropManager {
|
||||
}
|
||||
}
|
||||
|
||||
/*package */ void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
if (disallowIntercept) {
|
||||
cancelDrag(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*package*/ void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||
if (LOCAL_LOGV) {
|
||||
Log.v(TAG, "onScrolled(dx = " + dx + ", dy = " + dy + ")");
|
||||
@@ -410,6 +510,7 @@ public class RecyclerViewDragDropManager {
|
||||
}
|
||||
|
||||
private boolean handleActionDown(RecyclerView rv, MotionEvent e) {
|
||||
|
||||
final RecyclerView.ViewHolder holder = CustomRecyclerViewUtils.findChildViewHolderUnderWithoutTranslation(rv, e.getX(), e.getY());
|
||||
|
||||
if (!checkTouchedItemState(rv, holder)) {
|
||||
@@ -419,13 +520,25 @@ public class RecyclerViewDragDropManager {
|
||||
mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f);
|
||||
mInitialTouchItemId = holder.getItemId();
|
||||
|
||||
if (mInitiateOnLongPress) {
|
||||
mHandler.startLongPressDetection(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleOnLongPress(MotionEvent e) {
|
||||
if (mInitiateOnLongPress) {
|
||||
checkConditionAndStartDragging(mRecyclerView, e, false);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void startDragging(RecyclerView rv, MotionEvent e, RecyclerView.ViewHolder holder, ItemDraggableRange range) {
|
||||
safeEndAnimation(rv, holder);
|
||||
|
||||
mHandler.cancelLongPressDetection();
|
||||
|
||||
mDraggingItem = holder;
|
||||
|
||||
// XXX if setIsRecyclable() is used, another view holder objects will be created
|
||||
@@ -461,7 +574,7 @@ public class RecyclerViewDragDropManager {
|
||||
mAdapter.onDragItemStarted(mDraggingItem, mDraggableRange);
|
||||
|
||||
// setup decorators
|
||||
mAdapter.onBindViewHolder(mDraggingItem, mDraggingItem.getPosition());
|
||||
mAdapter.onBindViewHolder(mDraggingItem, mDraggingItem.getLayoutPosition());
|
||||
|
||||
mDraggingItemDecorator = new DraggingItemDecorator(mRecyclerView, mDraggingItem, mDraggableRange);
|
||||
mDraggingItemDecorator.setShadowDrawable(mShadowDrawable);
|
||||
@@ -477,6 +590,10 @@ public class RecyclerViewDragDropManager {
|
||||
if (mEdgeEffectDecorator != null) {
|
||||
mEdgeEffectDecorator.reorderToTop();
|
||||
}
|
||||
|
||||
if (mItemDragEventListener != null) {
|
||||
mItemDragEventListener.onItemDragStarted(mAdapter.getDraggingItemInitialPosition());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -490,7 +607,7 @@ public class RecyclerViewDragDropManager {
|
||||
if (immediately) {
|
||||
finishDragging(false);
|
||||
} else {
|
||||
if (mDraggingItem != null) {
|
||||
if (isDragging()) {
|
||||
if (mDeferredCancelProcess == null) {
|
||||
mDeferredCancelProcess = new Runnable() {
|
||||
@Override
|
||||
@@ -510,6 +627,10 @@ public class RecyclerViewDragDropManager {
|
||||
private void finishDragging(boolean result) {
|
||||
final RecyclerView.ViewHolder draggedItem = mDraggingItem;
|
||||
|
||||
if (draggedItem == null) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
// cancel deferred request
|
||||
if (mDeferredCancelProcess != null) {
|
||||
mRecyclerView.removeCallbacks(mDeferredCancelProcess);
|
||||
@@ -543,6 +664,10 @@ public class RecyclerViewDragDropManager {
|
||||
mRecyclerView.getParent().requestDisallowInterceptTouchEvent(false);
|
||||
}
|
||||
|
||||
if (mRecyclerView != null) {
|
||||
mRecyclerView.invalidate();
|
||||
}
|
||||
|
||||
mDraggableRange = null;
|
||||
mDraggingItemDecorator = null;
|
||||
mSwapTargetItemOperator = null;
|
||||
@@ -556,19 +681,34 @@ public class RecyclerViewDragDropManager {
|
||||
mGrabbedPositionY = 0;
|
||||
mGrabbedItemHeight = 0;
|
||||
|
||||
|
||||
int draggingItemInitialPosition = RecyclerView.NO_POSITION;
|
||||
int draggingItemCurrentPosition = RecyclerView.NO_POSITION;
|
||||
|
||||
// raise onDragItemFinished() event
|
||||
if ((mAdapter != null) && (draggedItem != null)) {
|
||||
if (mAdapter != null) {
|
||||
draggingItemInitialPosition = mAdapter.getDraggingItemInitialPosition();
|
||||
draggingItemCurrentPosition = mAdapter.getDraggingItemCurrentPosition();
|
||||
mAdapter.onDragItemFinished(draggedItem, result);
|
||||
}
|
||||
|
||||
// if (draggedItem != null) {
|
||||
// draggedItem.setIsRecyclable(true);
|
||||
// }
|
||||
|
||||
if (mItemDragEventListener != null) {
|
||||
mItemDragEventListener.onItemDragFinished(
|
||||
draggingItemInitialPosition,
|
||||
draggingItemCurrentPosition,
|
||||
result);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleActionUpOrCancel(RecyclerView rv, MotionEvent e) {
|
||||
final boolean result = (MotionEventCompat.getActionMasked(e) == MotionEvent.ACTION_UP);
|
||||
|
||||
mHandler.cancelLongPressDetection();
|
||||
|
||||
mInitialTouchY = 0;
|
||||
mLastTouchY = 0;
|
||||
mDragStartTouchY = 0;
|
||||
@@ -588,6 +728,18 @@ public class RecyclerViewDragDropManager {
|
||||
}
|
||||
|
||||
private boolean handleActionMoveWhileNotDragging(RecyclerView rv, MotionEvent e) {
|
||||
if (mInitiateOnMove) {
|
||||
return checkConditionAndStartDragging(rv, e, true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkConditionAndStartDragging(RecyclerView rv, MotionEvent e, boolean checkTouchSlop) {
|
||||
if (mDraggingItem != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int touchX = (int) (e.getX() + 0.5f);
|
||||
final int touchY = (int) (e.getY() + 0.5f);
|
||||
|
||||
@@ -597,19 +749,24 @@ public class RecyclerViewDragDropManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(Math.abs(touchY - mInitialTouchY) > mTouchSlop)) {
|
||||
return false;
|
||||
if (checkTouchSlop) {
|
||||
if (!(Math.abs(touchY - mInitialTouchY) > mTouchSlop)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final RecyclerView.ViewHolder holder = CustomRecyclerViewUtils.findChildViewHolderUnderWithoutTranslation(rv, e.getX(), e.getY());
|
||||
|
||||
if (!checkTouchedItemState(rv, holder)) {
|
||||
if (!checkTouchedItemState(rv, holder) || holder.getItemId() != mInitialTouchItemId) {
|
||||
mInitialTouchItemId = RecyclerView.NO_ID;
|
||||
mHandler.cancelLongPressDetection();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (holder.getItemId() != mInitialTouchItemId) {
|
||||
mInitialTouchItemId = RecyclerView.NO_ID;
|
||||
int position = CustomRecyclerViewUtils.getSynchronizedPosition(holder);
|
||||
|
||||
if (position == RecyclerView.NO_POSITION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -619,11 +776,11 @@ public class RecyclerViewDragDropManager {
|
||||
final int viewX = touchX - (view.getLeft() + translateX);
|
||||
final int viewY = touchY - (view.getTop() + translateY);
|
||||
|
||||
if (!mAdapter.canStartDrag(holder, viewX, viewY)) {
|
||||
if (!mAdapter.canStartDrag(holder, position, viewX, viewY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemDraggableRange range = mAdapter.getItemDraggableRange(holder);
|
||||
ItemDraggableRange range = mAdapter.getItemDraggableRange(holder, position);
|
||||
|
||||
if (range == null) {
|
||||
range = new ItemDraggableRange(0, Math.max(0, mAdapter.getItemCount() - 1));
|
||||
@@ -639,7 +796,6 @@ public class RecyclerViewDragDropManager {
|
||||
startDragging(rv, e, holder, range);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private void verifyItemDraggableRange(ItemDraggableRange range, RecyclerView.ViewHolder holder) {
|
||||
@@ -658,14 +814,15 @@ public class RecyclerViewDragDropManager {
|
||||
throw new IllegalStateException("Invalid range specified --- end >= count (range = " + range + ")");
|
||||
}
|
||||
|
||||
if (!range.checkInRange(holder.getPosition())) {
|
||||
if (!range.checkInRange(holder.getAdapterPosition())) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid range specified --- does not contain drag target item"
|
||||
+ " (range = " + range + ", position = " + holder.getPosition() + ")");
|
||||
+ " (range = " + range + ", position = " + holder.getAdapterPosition() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleActionMoveWhileDragging(RecyclerView rv, MotionEvent e) {
|
||||
|
||||
mLastTouchY = (int) (e.getY() + 0.5f);
|
||||
mDragMinTouchY = Math.min(mDragMinTouchY, mLastTouchY);
|
||||
mDragMaxTouchY = Math.max(mDragMaxTouchY, mLastTouchY);
|
||||
@@ -765,6 +922,7 @@ public class RecyclerViewDragDropManager {
|
||||
}
|
||||
}
|
||||
|
||||
// scroll
|
||||
if ((!reachedToTopHardLimit && (scrollAmount < 0)) ||
|
||||
(!reachedToBottomHardLimit && (scrollAmount > 0))) {
|
||||
safeEndAnimations(rv);
|
||||
@@ -788,34 +946,67 @@ public class RecyclerViewDragDropManager {
|
||||
|
||||
|
||||
if (mEdgeEffectDecorator != null) {
|
||||
final float edgeEffectStrength = 0.005f;
|
||||
|
||||
final int draggingItemTop = mDraggingItemDecorator.getTranslatedItemPositionTop();
|
||||
final int draggingItemBottom = mDraggingItemDecorator.getTranslatedItemPositionBottom();
|
||||
final int draggingItemCenter = (draggingItemTop + draggingItemBottom) / 2;
|
||||
final int nearEdgePosition = ((draggingItemCenter < (height / 2)) ? draggingItemTop : draggingItemBottom);
|
||||
final int nearEdgePosition;
|
||||
|
||||
if (firstVisibleChild == 0 && lastVisibleChild == 0) {
|
||||
// has only 1 item
|
||||
nearEdgePosition = (scrollAmount < 0) ? draggingItemTop : draggingItemBottom;
|
||||
} else {
|
||||
nearEdgePosition = (draggingItemCenter < (height / 2)) ? draggingItemTop : draggingItemBottom;
|
||||
}
|
||||
|
||||
final float nearEdgeOffset = (nearEdgePosition * invHeight) - 0.5f;
|
||||
final float absNearEdgeOffset = Math.abs(nearEdgeOffset);
|
||||
final float edgeEffectAcceleration = Math.max(0.0f, threshold - (0.5f - absNearEdgeOffset)) * invThreshold;
|
||||
float edgeEffectPullDistance = 0;
|
||||
|
||||
if ((edgeEffectAcceleration >= EDGE_EFFECT_THRESHOLD) && (scrollAmount != 0) && !actualIsScrolling) {
|
||||
// over scrolled
|
||||
final float distance = edgeEffectAcceleration * 0.02f;
|
||||
|
||||
if (scrollAmount < 0) {
|
||||
if ((absNearEdgeOffset > 0.4f) && (scrollAmount != 0) && !actualIsScrolling) {
|
||||
if (nearEdgeOffset < 0) {
|
||||
// upward
|
||||
mEdgeEffectDecorator.pullTopGlow(distance);
|
||||
if (mDraggingItemDecorator.isReachedToTopLimit()) {
|
||||
edgeEffectPullDistance = -mDisplayDensity * edgeEffectStrength;
|
||||
}
|
||||
} else {
|
||||
// downward
|
||||
mEdgeEffectDecorator.pullBottom(distance);
|
||||
if (mDraggingItemDecorator.isReachedToBottomLimit()) {
|
||||
edgeEffectPullDistance = mDisplayDensity * edgeEffectStrength;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mEdgeEffectDecorator.releaseBothGlows();
|
||||
}
|
||||
|
||||
updateEdgeEffect(edgeEffectPullDistance);
|
||||
}
|
||||
|
||||
checkItemSwapping(rv);
|
||||
ViewCompat.postOnAnimation(mRecyclerView, mCheckItemSwappingRunnable);
|
||||
}
|
||||
|
||||
private void updateEdgeEffect(float distance) {
|
||||
if (distance != 0.0f) {
|
||||
if (distance < 0) {
|
||||
// upward
|
||||
mEdgeEffectDecorator.pullTopGlow(distance);
|
||||
} else {
|
||||
// downward
|
||||
mEdgeEffectDecorator.pullBottom(distance);
|
||||
}
|
||||
} else {
|
||||
mEdgeEffectDecorator.releaseBothGlows();
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable mCheckItemSwappingRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mDraggingItem != null) {
|
||||
checkItemSwapping(mRecyclerView);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private int scrollByYAndGetScrolledAmount(int ry) {
|
||||
// NOTE: mActualScrollByAmount --- Hackish! To detect over scrolling.
|
||||
|
||||
@@ -843,8 +1034,8 @@ public class RecyclerViewDragDropManager {
|
||||
|
||||
private void swapItems(RecyclerView rv, RecyclerView.ViewHolder draggingItem, RecyclerView.ViewHolder swapTargetHolder) {
|
||||
final Rect swapTargetMargins = CustomRecyclerViewUtils.getLayoutMargins(swapTargetHolder.itemView, mTmpRect1);
|
||||
final int fromPosition = draggingItem.getPosition();
|
||||
final int toPosition = swapTargetHolder.getPosition();
|
||||
final int fromPosition = draggingItem.getAdapterPosition();
|
||||
final int toPosition = swapTargetHolder.getAdapterPosition();
|
||||
final int diffPosition = Math.abs(fromPosition - toPosition);
|
||||
boolean performSwapping = false;
|
||||
|
||||
@@ -903,11 +1094,13 @@ public class RecyclerViewDragDropManager {
|
||||
firstVisibleTopItem = rv.getChildViewHolder(child);
|
||||
}
|
||||
}
|
||||
final int prevTopItemPosition = (firstVisibleTopItem != null) ? firstVisibleTopItem.getPosition() : RecyclerView.NO_POSITION;
|
||||
|
||||
final int prevTopItemPosition = (firstVisibleTopItem != null) ? firstVisibleTopItem.getAdapterPosition() : RecyclerView.NO_POSITION;
|
||||
|
||||
// NOTE: This method invokes notifyItemMoved() method internally. Be careful!
|
||||
mAdapter.moveItem(fromPosition, toPosition);
|
||||
|
||||
safeEndAnimations(rv);
|
||||
|
||||
if (fromPosition == prevTopItemPosition) {
|
||||
//noinspection UnnecessaryLocalVariable
|
||||
final Rect margins = swapTargetMargins;
|
||||
@@ -933,7 +1126,7 @@ public class RecyclerViewDragDropManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int itemPosition = holder.getPosition();
|
||||
final int itemPosition = holder.getAdapterPosition();
|
||||
final RecyclerView.Adapter adapter = rv.getAdapter();
|
||||
|
||||
// verify the touched item is valid state
|
||||
@@ -975,7 +1168,7 @@ public class RecyclerViewDragDropManager {
|
||||
static RecyclerView.ViewHolder findSwapTargetItem(
|
||||
RecyclerView rv, RecyclerView.ViewHolder draggingItem,
|
||||
long draggingItemId, int overlayItemTop, ItemDraggableRange range) {
|
||||
final int draggingItemPosition = draggingItem.getPosition();
|
||||
final int draggingItemPosition = draggingItem.getAdapterPosition();
|
||||
final int draggingViewTop = draggingItem.itemView.getTop();
|
||||
RecyclerView.ViewHolder swapTargetHolder = null;
|
||||
|
||||
@@ -984,18 +1177,18 @@ public class RecyclerViewDragDropManager {
|
||||
draggingItem.getItemId() == draggingItemId) {
|
||||
if (overlayItemTop < draggingViewTop) {
|
||||
if (draggingItemPosition > 0) {
|
||||
swapTargetHolder = rv.findViewHolderForPosition(draggingItemPosition - 1);
|
||||
swapTargetHolder = rv.findViewHolderForAdapterPosition(draggingItemPosition - 1);
|
||||
}
|
||||
} else if (overlayItemTop > draggingViewTop) {
|
||||
if (draggingItemPosition < (rv.getAdapter().getItemCount() - 1)) {
|
||||
swapTargetHolder = rv.findViewHolderForPosition(draggingItemPosition + 1);
|
||||
swapTargetHolder = rv.findViewHolderForAdapterPosition(draggingItemPosition + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check range
|
||||
if (swapTargetHolder != null && range != null) {
|
||||
if (!range.checkInRange(swapTargetHolder.getPosition())) {
|
||||
if (!range.checkInRange(swapTargetHolder.getAdapterPosition())) {
|
||||
swapTargetHolder = null;
|
||||
}
|
||||
}
|
||||
@@ -1039,6 +1232,15 @@ public class RecyclerViewDragDropManager {
|
||||
return mItemSettleBackIntoPlaceAnimationInterpolator;
|
||||
}
|
||||
|
||||
/*package*/ void onDraggingItemViewRecycled() {
|
||||
mDraggingItemDecorator.invalidateDraggingItem();
|
||||
}
|
||||
|
||||
/*package*/ void onNewDraggingItemViewBinded(RecyclerView.ViewHolder holder) {
|
||||
mDraggingItem = holder;
|
||||
mDraggingItemDecorator.setDraggingItemViewHolder(holder);
|
||||
}
|
||||
|
||||
private static class ScrollOnDraggingProcessRunnable implements Runnable {
|
||||
private final WeakReference<RecyclerViewDragDropManager> mHolderRef;
|
||||
private boolean mStarted;
|
||||
@@ -1107,4 +1309,44 @@ public class RecyclerViewDragDropManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class InternalHandler extends Handler {
|
||||
private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();// + ViewConfiguration.getTapTimeout();
|
||||
private static final int MSG_LONGPRESS = 1;
|
||||
|
||||
private RecyclerViewDragDropManager mHolder;
|
||||
private MotionEvent mDownMotionEvent;
|
||||
|
||||
public InternalHandler(RecyclerViewDragDropManager holder) {
|
||||
mHolder = holder;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
removeCallbacks(null);
|
||||
mHolder = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_LONGPRESS:
|
||||
mHolder.handleOnLongPress(mDownMotionEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void startLongPressDetection(MotionEvent e) {
|
||||
cancelLongPressDetection();
|
||||
mDownMotionEvent = MotionEvent.obtain(e);
|
||||
sendEmptyMessageAtTime(MSG_LONGPRESS, e.getDownTime() + LONGPRESS_TIMEOUT);
|
||||
}
|
||||
|
||||
public void cancelLongPressDetection() {
|
||||
removeMessages(MSG_LONGPRESS);
|
||||
if (mDownMotionEvent != null) {
|
||||
mDownMotionEvent.recycle();
|
||||
mDownMotionEvent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Regular → Executable
+4
-4
@@ -94,8 +94,8 @@ class SwapTargetItemOperator extends BaseDraggableItemDecorator {
|
||||
private float calculateTranslationPhase(RecyclerView.ViewHolder draggingItem, RecyclerView.ViewHolder swapTargetItem) {
|
||||
final View swapItemView = swapTargetItem.itemView;
|
||||
|
||||
final int pos1 = draggingItem.getPosition();
|
||||
final int pos2 = swapTargetItem.getPosition();
|
||||
final int pos1 = draggingItem.getLayoutPosition();
|
||||
final int pos2 = swapTargetItem.getLayoutPosition();
|
||||
|
||||
CustomRecyclerViewUtils.getDecorationOffsets(
|
||||
mRecyclerView.getLayoutManager(), swapItemView, mSwapTargetDecorationOffsets);
|
||||
@@ -132,8 +132,8 @@ class SwapTargetItemOperator extends BaseDraggableItemDecorator {
|
||||
private void updateSwapTargetTranslation(RecyclerView.ViewHolder draggingItem, RecyclerView.ViewHolder swapTargetItem, float translationPhase) {
|
||||
final View swapItemView = swapTargetItem.itemView;
|
||||
|
||||
final int pos1 = draggingItem.getPosition();
|
||||
final int pos2 = swapTargetItem.getPosition();
|
||||
final int pos1 = draggingItem.getLayoutPosition();
|
||||
final int pos2 = swapTargetItem.getLayoutPosition();
|
||||
|
||||
final Rect m1 = mDraggingItemMargins;
|
||||
final Rect d1 = mDraggingItemDecorationOffsets;
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+13
-3
@@ -20,6 +20,12 @@ import android.support.v7.widget.RecyclerView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* Please use {@link RecyclerView#addOnScrollListener(RecyclerView.OnScrollListener)} and {@link RecyclerView#removeOnScrollListener(RecyclerView.OnScrollListener)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class RecyclerViewOnScrollEventDistributor extends BaseRecyclerViewEventDistributor<RecyclerView.OnScrollListener> {
|
||||
|
||||
private InternalOnScrollListener mInternalOnScrollListener;
|
||||
@@ -34,17 +40,20 @@ public class RecyclerViewOnScrollEventDistributor extends BaseRecyclerViewEventD
|
||||
protected void onRecyclerViewAttached(RecyclerView rv) {
|
||||
super.onRecyclerViewAttached(rv);
|
||||
|
||||
rv.setOnScrollListener(mInternalOnScrollListener);
|
||||
rv.addOnScrollListener(mInternalOnScrollListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRelease() {
|
||||
super.onRelease();
|
||||
|
||||
if (mInternalOnScrollListener != null) {
|
||||
if (mRecyclerView != null) {
|
||||
mRecyclerView.removeOnScrollListener(mInternalOnScrollListener);
|
||||
}
|
||||
mInternalOnScrollListener.release();
|
||||
mInternalOnScrollListener = null;
|
||||
}
|
||||
|
||||
super.onRelease();
|
||||
}
|
||||
|
||||
/*package*/ void handleOnScrollStateChanged(RecyclerView recyclerView, int newState) {
|
||||
@@ -67,6 +76,7 @@ public class RecyclerViewOnScrollEventDistributor extends BaseRecyclerViewEventD
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static class InternalOnScrollListener extends RecyclerView.OnScrollListener {
|
||||
private WeakReference<RecyclerViewOnScrollEventDistributor> mRefDistributor;
|
||||
|
||||
|
||||
Regular → Executable
File mode changed.
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Haruki Hasegawa
|
||||
*
|
||||
* 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.h6ah4i.android.widget.advrecyclerview.expandable;
|
||||
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
|
||||
|
||||
public class ChildPositionItemDraggableRange extends ItemDraggableRange {
|
||||
public ChildPositionItemDraggableRange(int start, int end) {
|
||||
super(start, end);
|
||||
}
|
||||
|
||||
protected String getClassName() {
|
||||
return "ChildPositionItemDraggableRange";
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+23
-1
@@ -125,7 +125,7 @@ public interface ExpandableItemAdapter<GVH extends RecyclerView.ViewHolder, CVH
|
||||
void onBindChildViewHolder(CVH holder, int groupPosition, int childPosition, int viewType);
|
||||
|
||||
/**
|
||||
* Called when the user attempt to expand/collapse the group item.
|
||||
* Called when a user attempt to expand/collapse a group item by tapping.
|
||||
*
|
||||
* @param holder The ViewHolder which is associated to group item user is attempt to expand/collapse
|
||||
* @param groupPosition Group position
|
||||
@@ -136,4 +136,26 @@ public interface ExpandableItemAdapter<GVH extends RecyclerView.ViewHolder, CVH
|
||||
* @return Whether to perform expand/collapse operation.
|
||||
*/
|
||||
boolean onCheckCanExpandOrCollapseGroup(GVH holder, int groupPosition, int x, int y, boolean expand);
|
||||
|
||||
/**
|
||||
* Called when a group attempt to expand by user operation or by
|
||||
* {@link com.h6ah4i.android.widget.advrecyclerview.expandable.RecyclerViewExpandableItemManager#expandGroup(int)} method.
|
||||
*
|
||||
* @param groupPosition The position of the group item within the adapter's data set
|
||||
* @param fromUser Whether the expand request is issued by a user operation
|
||||
*
|
||||
* @return Whether the group can be expanded. If returns false, the group keeps collapsed.
|
||||
*/
|
||||
boolean onHookGroupExpand(int groupPosition, boolean fromUser);
|
||||
|
||||
/**
|
||||
* Called when a group attempt to expand by user operation or by
|
||||
* {@link com.h6ah4i.android.widget.advrecyclerview.expandable.RecyclerViewExpandableItemManager#collapseGroup(int)} method.
|
||||
*
|
||||
* @param groupPosition The position of the group item within the adapter's data set
|
||||
* @param fromUser Whether the collapse request is issued by a user operation
|
||||
*
|
||||
* @return Whether the group can be collapsed. If returns false, the group keeps expanded.
|
||||
*/
|
||||
boolean onHookGroupCollapse(int groupPosition, boolean fromUser);
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+199
-45
@@ -21,6 +21,8 @@ import android.support.v7.widget.RecyclerView;
|
||||
import java.util.Arrays;
|
||||
|
||||
class ExpandablePositionTranslator {
|
||||
private final int ALLOCATE_UNIT = 256;
|
||||
|
||||
private final static long FLAG_EXPANDED = 0x0000000080000000l;
|
||||
private final static long LOWER_31BIT_MASK = 0x000000007fffffffl;
|
||||
private final static long LOWER_32BIT_MASK = 0x00000000ffffffffl;
|
||||
@@ -42,6 +44,7 @@ class ExpandablePositionTranslator {
|
||||
private int mExpandedGroupCount;
|
||||
private int mExpandedChildCount;
|
||||
private int mEndOfCalculatedOffsetGroupPosition = RecyclerView.NO_POSITION;
|
||||
private ExpandableItemAdapter mAdapter;
|
||||
|
||||
public ExpandablePositionTranslator() {
|
||||
}
|
||||
@@ -49,12 +52,7 @@ class ExpandablePositionTranslator {
|
||||
public void build(ExpandableItemAdapter adapter) {
|
||||
final int groupCount = adapter.getGroupCount();
|
||||
|
||||
if (mCachedGroupPosInfo == null || mCachedGroupPosInfo.length < groupCount) {
|
||||
mCachedGroupPosInfo = new long[groupCount];
|
||||
}
|
||||
if (mCachedGroupId == null || mCachedGroupId.length < groupCount) {
|
||||
mCachedGroupId = new int[groupCount];
|
||||
}
|
||||
enlargeArraysIfNeeded(groupCount, false);
|
||||
|
||||
final long[] info = mCachedGroupPosInfo;
|
||||
final int[] ids = mCachedGroupId;
|
||||
@@ -66,13 +64,18 @@ class ExpandablePositionTranslator {
|
||||
ids[i] = (int) (groupId & LOWER_32BIT_MASK);
|
||||
}
|
||||
|
||||
mAdapter = adapter;
|
||||
mGroupCount = groupCount;
|
||||
mExpandedGroupCount = 0;
|
||||
mExpandedChildCount = 0;
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.max(0, groupCount - 1);
|
||||
}
|
||||
|
||||
public void restoreExpandedGroupItems(int[] restoreGroupIds) {
|
||||
public void restoreExpandedGroupItems(
|
||||
int[] restoreGroupIds,
|
||||
ExpandableItemAdapter adapter,
|
||||
RecyclerViewExpandableItemManager.OnGroupExpandListener expandListener,
|
||||
RecyclerViewExpandableItemManager.OnGroupCollapseListener collapseListener) {
|
||||
if (restoreGroupIds == null || restoreGroupIds.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -82,16 +85,17 @@ class ExpandablePositionTranslator {
|
||||
}
|
||||
|
||||
// make ID + position packed array
|
||||
final long [] idAndPos = new long[mGroupCount];
|
||||
final long[] idAndPos = new long[mGroupCount];
|
||||
|
||||
for (int i = 0; i < mGroupCount; i++) {
|
||||
idAndPos[i] = ((long) mCachedGroupId[i] << 32) | i;
|
||||
}
|
||||
|
||||
// sort both arrays
|
||||
Arrays.sort(restoreGroupIds);
|
||||
Arrays.sort(idAndPos);
|
||||
|
||||
final boolean fromUser = false;
|
||||
|
||||
// find matched items & apply
|
||||
int index = 0;
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
@@ -100,24 +104,53 @@ class ExpandablePositionTranslator {
|
||||
|
||||
for (int j = index; j < idAndPos.length; j++) {
|
||||
final int id2 = (int) (idAndPos[j] >> 32);
|
||||
final int position = (int) (idAndPos[j] & LOWER_31BIT_MASK);
|
||||
|
||||
if (id2 < id1) {
|
||||
index = j;
|
||||
|
||||
if (adapter == null || adapter.onHookGroupCollapse(position, fromUser)) {
|
||||
if (collapseGroup(position)) {
|
||||
if (collapseListener != null) {
|
||||
collapseListener.onGroupCollapse(position, fromUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (id2 == id1) {
|
||||
// matched
|
||||
final int position = (int) (idAndPos[j] & LOWER_31BIT_MASK);
|
||||
index = j + 1;
|
||||
expandGroup(position);
|
||||
break;
|
||||
|
||||
if (adapter == null || adapter.onHookGroupExpand(position, fromUser)) {
|
||||
if (expandGroup(position)) {
|
||||
if (expandListener != null) {
|
||||
expandListener.onGroupExpand(position, fromUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // id2 > id1
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (adapter != null || collapseListener != null) {
|
||||
for (int i = index; i < idAndPos.length; i++) {
|
||||
final int id2 = (int) (idAndPos[i] >> 32);
|
||||
final int position = (int) (idAndPos[i] & LOWER_31BIT_MASK);
|
||||
|
||||
if (adapter == null || adapter.onHookGroupCollapse(position, fromUser)) {
|
||||
if (collapseGroup(position)) {
|
||||
if (collapseListener != null) {
|
||||
collapseListener.onGroupCollapse(position, fromUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int[] getSavedStateArray() {
|
||||
int [] expandedGroups = new int[mExpandedGroupCount];
|
||||
int[] expandedGroups = new int[mExpandedGroupCount];
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < mGroupCount; i++) {
|
||||
@@ -132,6 +165,8 @@ class ExpandablePositionTranslator {
|
||||
throw new IllegalStateException("may be a bug (index = " + index + ", mExpandedGroupCount = " + mExpandedGroupCount + ")");
|
||||
}
|
||||
|
||||
Arrays.sort(expandedGroups);
|
||||
|
||||
return expandedGroups;
|
||||
}
|
||||
|
||||
@@ -165,14 +200,11 @@ class ExpandablePositionTranslator {
|
||||
mCachedGroupPosInfo[groupPosition] &= (~FLAG_EXPANDED);
|
||||
mExpandedGroupCount -= 1;
|
||||
|
||||
if (childCount > 0) {
|
||||
mExpandedChildCount -= childCount;
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, groupPosition);
|
||||
// requires notifyItemRangeRemoved()
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
mExpandedChildCount -= childCount;
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, groupPosition);
|
||||
|
||||
// requires notifyItemRangeRemoved()
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean expandGroup(int groupPosition) {
|
||||
@@ -185,14 +217,11 @@ class ExpandablePositionTranslator {
|
||||
mCachedGroupPosInfo[groupPosition] |= FLAG_EXPANDED;
|
||||
mExpandedGroupCount += 1;
|
||||
|
||||
if (childCount > 0) {
|
||||
mExpandedChildCount += childCount;
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, groupPosition);
|
||||
// requires notifyItemRangeInserted()
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
mExpandedChildCount += childCount;
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, groupPosition);
|
||||
|
||||
// requires notifyItemRangeInserted()
|
||||
return true;
|
||||
}
|
||||
|
||||
public void moveGroupItem(int fromGroupPosition, int toGroupPosition) {
|
||||
@@ -223,7 +252,7 @@ class ExpandablePositionTranslator {
|
||||
final int minPosition = Math.min(fromGroupPosition, toGroupPosition);
|
||||
|
||||
if (minPosition > 0) {
|
||||
mEndOfCalculatedOffsetGroupPosition = minPosition - 1;
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, minPosition - 1);
|
||||
} else {
|
||||
mEndOfCalculatedOffsetGroupPosition = RecyclerView.NO_POSITION;
|
||||
}
|
||||
@@ -258,7 +287,7 @@ class ExpandablePositionTranslator {
|
||||
final int minPosition = Math.min(fromGroupPosition, toGroupPosition);
|
||||
|
||||
if (minPosition > 0) {
|
||||
mEndOfCalculatedOffsetGroupPosition = minPosition - 1;
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, minPosition - 1);
|
||||
} else {
|
||||
mEndOfCalculatedOffsetGroupPosition = RecyclerView.NO_POSITION;
|
||||
}
|
||||
@@ -330,7 +359,7 @@ class ExpandablePositionTranslator {
|
||||
}
|
||||
|
||||
// final int startIndex = 0;
|
||||
final int startIndex = Math.min(groupPosition, mEndOfCalculatedOffsetGroupPosition);
|
||||
final int startIndex = Math.max(0, Math.min(groupPosition, mEndOfCalculatedOffsetGroupPosition));
|
||||
int endOfCalculatedOffsetGroupPosition = mEndOfCalculatedOffsetGroupPosition;
|
||||
int offset = (int) (mCachedGroupPosInfo[startIndex] >>> 32);
|
||||
int flatPosition = RecyclerView.NO_POSITION;
|
||||
@@ -399,30 +428,155 @@ class ExpandablePositionTranslator {
|
||||
return lastS;
|
||||
}
|
||||
|
||||
public void removeGroupItem(int groupPosition) {
|
||||
final long t = mCachedGroupPosInfo[groupPosition];
|
||||
public void removeChildItem(int groupPosition, int childPosition) {
|
||||
removeChildItems(groupPosition, childPosition, 1);
|
||||
}
|
||||
|
||||
if ((t & FLAG_EXPANDED) != 0) {
|
||||
mExpandedChildCount -= (int) (t & LOWER_31BIT_MASK);
|
||||
mExpandedGroupCount -= 1;
|
||||
public void removeChildItems(int groupPosition, int childPositionStart, int count) {
|
||||
final long t = mCachedGroupPosInfo[groupPosition];
|
||||
final int curCount = (int) (t & LOWER_31BIT_MASK);
|
||||
|
||||
if (!((childPositionStart >= 0) && ((childPositionStart + count) <= curCount))) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid child position " +
|
||||
"removeChildItems(groupPosition = " + groupPosition + ", childPosition = " + childPositionStart + ", count = " + count + ")");
|
||||
}
|
||||
|
||||
mGroupCount -= 1;
|
||||
if ((t & FLAG_EXPANDED) != 0) {
|
||||
mExpandedChildCount -= count;
|
||||
}
|
||||
|
||||
mCachedGroupPosInfo[groupPosition] = (t & (UPPER_32BIT_MASK | FLAG_EXPANDED)) | (curCount - count);
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, groupPosition - 1);
|
||||
}
|
||||
|
||||
public void insertChildItem(int groupPosition, int childPosition) {
|
||||
insertChildItems(groupPosition, childPosition, 1);
|
||||
}
|
||||
|
||||
public void insertChildItems(int groupPosition, int childPositionStart, int count) {
|
||||
final long t = mCachedGroupPosInfo[groupPosition];
|
||||
final int curCount = (int) (t & LOWER_31BIT_MASK);
|
||||
|
||||
if (!((childPositionStart >= 0) && (childPositionStart <= curCount))) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid child position " +
|
||||
"insertChildItems(groupPosition = " + groupPosition + ", childPositionStart = " + childPositionStart + ", count = " + count + ")");
|
||||
}
|
||||
|
||||
if ((t & FLAG_EXPANDED) != 0) {
|
||||
mExpandedChildCount += count;
|
||||
}
|
||||
|
||||
mCachedGroupPosInfo[groupPosition] = (t & (UPPER_32BIT_MASK | FLAG_EXPANDED)) | (curCount + count);
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, groupPosition);
|
||||
}
|
||||
|
||||
public int insertGroupItems(int groupPosition, int count) {
|
||||
if (count <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final int n = count;
|
||||
|
||||
enlargeArraysIfNeeded(mGroupCount + n, true);
|
||||
|
||||
// shift to backward
|
||||
final ExpandableItemAdapter adapter = mAdapter;
|
||||
final long[] info = mCachedGroupPosInfo;
|
||||
final int[] ids = mCachedGroupId;
|
||||
|
||||
int start = mGroupCount - 1 + n;
|
||||
int end = groupPosition - 1 + n;
|
||||
for (int i = start; i > end; i--) {
|
||||
info[i] = info[i - n];
|
||||
ids[i] = ids[i - n];
|
||||
}
|
||||
|
||||
int end2 = groupPosition + n;
|
||||
for (int i = groupPosition; i < end2; i++) {
|
||||
final long groupId = adapter.getGroupId(i);
|
||||
final int childCount = adapter.getChildCount(i);
|
||||
|
||||
info[i] = (((long) i << 32) | childCount);
|
||||
ids[i] = (int) (groupId & LOWER_32BIT_MASK);
|
||||
}
|
||||
|
||||
mGroupCount += n;
|
||||
|
||||
int calculatedOffset = (mGroupCount == 0) ? RecyclerView.NO_POSITION : (groupPosition - 1);
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, calculatedOffset);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
public int insertGroupItem(int groupPosition) {
|
||||
return insertGroupItems(groupPosition, 1);
|
||||
}
|
||||
|
||||
public int removeGroupItems(int groupPosition, int count) {
|
||||
if (count <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final int n = count;
|
||||
int removedVisibleItemCount = 0;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
final long t = mCachedGroupPosInfo[groupPosition + i];
|
||||
|
||||
if ((t & FLAG_EXPANDED) != 0) {
|
||||
int visibleChildCount = (int) (t & LOWER_31BIT_MASK);
|
||||
removedVisibleItemCount += visibleChildCount;
|
||||
mExpandedChildCount -= visibleChildCount;
|
||||
mExpandedGroupCount -= 1;
|
||||
}
|
||||
}
|
||||
removedVisibleItemCount += n;
|
||||
mGroupCount -= n;
|
||||
|
||||
// shift to forward
|
||||
for (int i = groupPosition; i < mGroupCount; i++) {
|
||||
mCachedGroupPosInfo[i] = mCachedGroupPosInfo[i + 1];
|
||||
mCachedGroupId[i] = mCachedGroupId[i + 1];
|
||||
mCachedGroupPosInfo[i] = mCachedGroupPosInfo[i + n];
|
||||
mCachedGroupId[i] = mCachedGroupId[i + n];
|
||||
}
|
||||
|
||||
int calculatedOffset = (mGroupCount == 0) ? RecyclerView.NO_POSITION : (groupPosition - 1);
|
||||
mEndOfCalculatedOffsetGroupPosition = Math.min(mEndOfCalculatedOffsetGroupPosition, calculatedOffset);
|
||||
|
||||
return removedVisibleItemCount;
|
||||
}
|
||||
|
||||
public void removeChildItem(int groupPosition, int childPosition) {
|
||||
final long t = mCachedGroupPosInfo[groupPosition];
|
||||
public int removeGroupItem(int groupPosition) {
|
||||
return removeGroupItems(groupPosition, 1);
|
||||
}
|
||||
|
||||
if ((t & FLAG_EXPANDED) != 0) {
|
||||
mExpandedChildCount -= 1;
|
||||
|
||||
private void enlargeArraysIfNeeded(int size, boolean preserveData) {
|
||||
int allocSize = (size + (2 * ALLOCATE_UNIT - 1)) & ~(ALLOCATE_UNIT - 1);
|
||||
|
||||
long[] curInfo = mCachedGroupPosInfo;
|
||||
int[] curId = mCachedGroupId;
|
||||
long[] newInfo = curInfo;
|
||||
int[] newId = curId;
|
||||
|
||||
if (curInfo == null || curInfo.length < size) {
|
||||
newInfo = new long[allocSize];
|
||||
}
|
||||
if (curId == null || curId.length < size) {
|
||||
newId = new int[allocSize];
|
||||
}
|
||||
|
||||
mCachedGroupPosInfo[groupPosition] = (t & (UPPER_32BIT_MASK | FLAG_EXPANDED)) | ((t & LOWER_31BIT_MASK) - 1);
|
||||
if (preserveData) {
|
||||
if (curInfo != null && curInfo != newInfo) {
|
||||
System.arraycopy(curInfo, 0, newInfo, 0, curInfo.length);
|
||||
}
|
||||
if (curId != null && curId != newId) {
|
||||
System.arraycopy(curId, 0, newId, 0, curId.length);
|
||||
}
|
||||
}
|
||||
|
||||
mCachedGroupPosInfo = newInfo;
|
||||
mCachedGroupId = newId;
|
||||
}
|
||||
}
|
||||
Regular → Executable
+300
-43
@@ -41,7 +41,13 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
private ExpandableItemAdapter mExpandableItemAdapter;
|
||||
private RecyclerViewExpandableItemManager mExpandableListManager;
|
||||
private ExpandablePositionTranslator mPositionTranslator;
|
||||
private int mDraggingItemGroupPosition = RecyclerView.NO_POSITION;
|
||||
private int mDraggingItemGroupRangeStart = RecyclerView.NO_POSITION;
|
||||
private int mDraggingItemGroupRangeEnd = RecyclerView.NO_POSITION;
|
||||
private int mDraggingItemChildRangeStart = RecyclerView.NO_POSITION;
|
||||
private int mDraggingItemChildRangeEnd = RecyclerView.NO_POSITION;
|
||||
|
||||
private RecyclerViewExpandableItemManager.OnGroupExpandListener mOnGroupExpandListener;
|
||||
private RecyclerViewExpandableItemManager.OnGroupCollapseListener mOnGroupCollapseListener;
|
||||
|
||||
public ExpandableRecyclerViewWrapperAdapter(RecyclerViewExpandableItemManager manager, RecyclerView.Adapter<RecyclerView.ViewHolder> adapter, int[] expandedItemsSavedState) {
|
||||
super(adapter);
|
||||
@@ -61,7 +67,8 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
mPositionTranslator.build(mExpandableItemAdapter);
|
||||
|
||||
if (expandedItemsSavedState != null) {
|
||||
mPositionTranslator.restoreExpandedGroupItems(expandedItemsSavedState);
|
||||
// NOTE: do not call hook routines and listener methods
|
||||
mPositionTranslator.restoreExpandedGroupItems(expandedItemsSavedState, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +78,8 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
|
||||
mExpandableItemAdapter = null;
|
||||
mExpandableListManager = null;
|
||||
mOnGroupExpandListener = null;
|
||||
mOnGroupCollapseListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -174,7 +183,7 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
|
||||
safeUpdateExpandStateFlags(holder, flags);
|
||||
|
||||
correctItemDragStateFlags(holder, groupPosition);
|
||||
correctItemDragStateFlags(holder, groupPosition, childPosition);
|
||||
|
||||
if (childPosition == RecyclerView.NO_POSITION) {
|
||||
mExpandableItemAdapter.onBindGroupViewHolder(holder, groupPosition, viewType);
|
||||
@@ -187,7 +196,9 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
if (mPositionTranslator != null) {
|
||||
int [] savedState = mPositionTranslator.getSavedStateArray();
|
||||
mPositionTranslator.build(mExpandableItemAdapter);
|
||||
mPositionTranslator.restoreExpandedGroupItems(savedState);
|
||||
|
||||
// NOTE: do not call hook routines and listener methods
|
||||
mPositionTranslator.restoreExpandedGroupItems(savedState, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,14 +246,14 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean onCheckCanStartDrag(RecyclerView.ViewHolder holder, int x, int y) {
|
||||
public boolean onCheckCanStartDrag(RecyclerView.ViewHolder holder, int position, int x, int y) {
|
||||
if (!(mExpandableItemAdapter instanceof ExpandableDraggableItemAdapter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ExpandableDraggableItemAdapter adapter = (ExpandableDraggableItemAdapter) mExpandableItemAdapter;
|
||||
|
||||
final int flatPosition = holder.getPosition();
|
||||
final int flatPosition = position;
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(flatPosition);
|
||||
final int groupPosition = ExpandableAdapterHelper.getPackedPositionGroup(expandablePosition);
|
||||
final int childPosition = ExpandableAdapterHelper.getPackedPositionChild(expandablePosition);
|
||||
@@ -254,14 +265,17 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
canStart = adapter.onCheckChildCanStartDrag(holder, groupPosition, childPosition, x, y);
|
||||
}
|
||||
|
||||
mDraggingItemGroupPosition = (canStart) ? groupPosition : RecyclerView.NO_POSITION;
|
||||
mDraggingItemGroupRangeStart = RecyclerView.NO_POSITION;
|
||||
mDraggingItemGroupRangeEnd = RecyclerView.NO_POSITION;
|
||||
mDraggingItemChildRangeStart = RecyclerView.NO_POSITION;
|
||||
mDraggingItemChildRangeEnd = RecyclerView.NO_POSITION;
|
||||
|
||||
return canStart;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ItemDraggableRange onGetItemDraggableRange(RecyclerView.ViewHolder holder) {
|
||||
public ItemDraggableRange onGetItemDraggableRange(RecyclerView.ViewHolder holder, int position) {
|
||||
if (!(mExpandableItemAdapter instanceof ExpandableDraggableItemAdapter)) {
|
||||
return null;
|
||||
}
|
||||
@@ -272,66 +286,109 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
|
||||
final ExpandableDraggableItemAdapter adapter = (ExpandableDraggableItemAdapter) mExpandableItemAdapter;
|
||||
|
||||
final int flatPosition = holder.getPosition();
|
||||
final int flatPosition = position;
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(flatPosition);
|
||||
final int groupPosition = ExpandableAdapterHelper.getPackedPositionGroup(expandablePosition);
|
||||
final int childPosition = ExpandableAdapterHelper.getPackedPositionChild(expandablePosition);
|
||||
|
||||
if (childPosition == RecyclerView.NO_POSITION) {
|
||||
// group
|
||||
final ItemDraggableRange groupRange = adapter.onGetGroupItemDraggableRange(holder, groupPosition);
|
||||
final ItemDraggableRange range = adapter.onGetGroupItemDraggableRange(holder, groupPosition);
|
||||
|
||||
if (groupRange == null) {
|
||||
if (range == null) {
|
||||
final int lastGroup = Math.max(0, mExpandableItemAdapter.getGroupCount() - 1);
|
||||
final int start = 0;
|
||||
final int end = Math.max(start, mPositionTranslator.getItemCount() - mPositionTranslator.getVisibleChildCount(lastGroup) - 1);
|
||||
|
||||
return new ItemDraggableRange(start, end);
|
||||
} else {
|
||||
final long startPackedGroupPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupRange.getStart());
|
||||
final long endPackedGroupPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupRange.getEnd());
|
||||
} else if (isGroupPositionRange(range)) {
|
||||
final long startPackedGroupPosition = ExpandableAdapterHelper.getPackedPositionForGroup(range.getStart());
|
||||
final long endPackedGroupPosition = ExpandableAdapterHelper.getPackedPositionForGroup(range.getEnd());
|
||||
final int start = mPositionTranslator.getFlatPosition(startPackedGroupPosition);
|
||||
int end = mPositionTranslator.getFlatPosition(endPackedGroupPosition);
|
||||
|
||||
if (groupRange.getEnd() > groupPosition) {
|
||||
end += mPositionTranslator.getVisibleChildCount(groupRange.getEnd());
|
||||
if (range.getEnd() > groupPosition) {
|
||||
end += mPositionTranslator.getVisibleChildCount(range.getEnd());
|
||||
}
|
||||
|
||||
mDraggingItemGroupRangeStart = range.getStart();
|
||||
mDraggingItemGroupRangeEnd = range.getEnd();
|
||||
|
||||
return new ItemDraggableRange(start, end);
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid range specified: " + range);
|
||||
}
|
||||
} else {
|
||||
// child
|
||||
final ItemDraggableRange groupRange = adapter.onGetChildItemDraggableRange(holder, groupPosition, childPosition);
|
||||
final ItemDraggableRange range = adapter.onGetChildItemDraggableRange(holder, groupPosition, childPosition);
|
||||
|
||||
// NOTE:
|
||||
// This method returns actual drag-sortable range, but the visual drag-sortable range would be different.
|
||||
// Thus appending the STATE_FLAG_IS_IN_RANGE flag at correctItemDragStateFlags() to avoid visual corruption.
|
||||
if (groupRange == null) {
|
||||
if (range == null) {
|
||||
final int start = 1; // 1 --- to avoid swapping with the first group item
|
||||
|
||||
return new ItemDraggableRange(start, Math.max(start, mPositionTranslator.getItemCount() - 1));
|
||||
} else {
|
||||
final long startPackedGroupPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupRange.getStart());
|
||||
final long endPackedGroupPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupRange.getEnd());
|
||||
} else if (isGroupPositionRange(range)) {
|
||||
final long startPackedGroupPosition = ExpandableAdapterHelper.getPackedPositionForGroup(range.getStart());
|
||||
final long endPackedGroupPosition = ExpandableAdapterHelper.getPackedPositionForGroup(range.getEnd());
|
||||
final int end = mPositionTranslator.getFlatPosition(endPackedGroupPosition)
|
||||
+ mPositionTranslator.getVisibleChildCount(groupRange.getEnd());
|
||||
+ mPositionTranslator.getVisibleChildCount(range.getEnd());
|
||||
|
||||
int start = mPositionTranslator.getFlatPosition(startPackedGroupPosition) + 1;
|
||||
|
||||
start = Math.min(start, end);
|
||||
|
||||
mDraggingItemGroupRangeStart = range.getStart();
|
||||
mDraggingItemGroupRangeEnd = range.getEnd();
|
||||
|
||||
return new ItemDraggableRange(start, end);
|
||||
} else if (isChildPositionRange(range)) {
|
||||
final int maxChildrenPos = Math.max(mPositionTranslator.getVisibleChildCount(groupPosition) - 1, 0);
|
||||
final int childStart = Math.min(range.getStart(), maxChildrenPos);
|
||||
final int childEnd = Math.min(range.getEnd(), maxChildrenPos);
|
||||
final long startPackedChildPosition = ExpandableAdapterHelper.getPackedPositionForChild(groupPosition, childStart);
|
||||
final long endPackedChildPosition = ExpandableAdapterHelper.getPackedPositionForChild(groupPosition, childEnd);
|
||||
final int start = mPositionTranslator.getFlatPosition(startPackedChildPosition);
|
||||
final int end = mPositionTranslator.getFlatPosition(endPackedChildPosition);
|
||||
|
||||
mDraggingItemChildRangeStart = childStart;
|
||||
mDraggingItemChildRangeEnd = childEnd;
|
||||
|
||||
return new ItemDraggableRange(start, end);
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid range specified: " + range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isGroupPositionRange(ItemDraggableRange range) {
|
||||
if (range.getClass().equals(GroupPositionItemDraggableRange.class)) {
|
||||
return true;
|
||||
} else if (range.getClass().equals(ItemDraggableRange.class)) {
|
||||
// NOTE: ItemDraggableRange is regarded as group position
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isChildPositionRange(ItemDraggableRange range) {
|
||||
if (range.getClass().equals(ChildPositionItemDraggableRange.class)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoveItem(int fromPosition, int toPosition) {
|
||||
if (!(mExpandableItemAdapter instanceof ExpandableDraggableItemAdapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDraggingItemGroupPosition = RecyclerView.NO_POSITION;
|
||||
mDraggingItemGroupRangeStart = RecyclerView.NO_POSITION;
|
||||
mDraggingItemGroupRangeEnd = RecyclerView.NO_POSITION;
|
||||
mDraggingItemChildRangeStart = RecyclerView.NO_POSITION;
|
||||
mDraggingItemChildRangeEnd = RecyclerView.NO_POSITION;
|
||||
|
||||
if (fromPosition == toPosition) {
|
||||
return;
|
||||
@@ -436,14 +493,15 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public int onGetSwipeReactionType(RecyclerView.ViewHolder holder, int x, int y) {
|
||||
public int onGetSwipeReactionType(RecyclerView.ViewHolder holder, int position, int x, int y) {
|
||||
if (!(mExpandableItemAdapter instanceof ExpandableSwipeableItemAdapter)) {
|
||||
return RecyclerViewSwipeManager.REACTION_CAN_NOT_SWIPE_BOTH;
|
||||
}
|
||||
|
||||
final ExpandableSwipeableItemAdapter adapter = (ExpandableSwipeableItemAdapter) mExpandableItemAdapter;
|
||||
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(holder.getPosition());
|
||||
final int flatPosition = position;
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(flatPosition);
|
||||
final int groupPosition = ExpandableAdapterHelper.getPackedPositionGroup(expandablePosition);
|
||||
final int childPosition = ExpandableAdapterHelper.getPackedPositionChild(expandablePosition);
|
||||
|
||||
@@ -456,14 +514,15 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onSetSwipeBackground(RecyclerView.ViewHolder holder, int type) {
|
||||
public void onSetSwipeBackground(RecyclerView.ViewHolder holder, int position, int type) {
|
||||
if (!(mExpandableItemAdapter instanceof ExpandableSwipeableItemAdapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ExpandableSwipeableItemAdapter adapter = (ExpandableSwipeableItemAdapter) mExpandableItemAdapter;
|
||||
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(holder.getPosition());
|
||||
final int flatPosition = position;
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(flatPosition);
|
||||
final int groupPosition = ExpandableAdapterHelper.getPackedPositionGroup(expandablePosition);
|
||||
final int childPosition = ExpandableAdapterHelper.getPackedPositionChild(expandablePosition);
|
||||
|
||||
@@ -476,14 +535,15 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public int onSwipeItem(RecyclerView.ViewHolder holder, int result) {
|
||||
public int onSwipeItem(RecyclerView.ViewHolder holder, int position, int result) {
|
||||
if (!(mExpandableItemAdapter instanceof ExpandableSwipeableItemAdapter)) {
|
||||
return RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_DEFAULT;
|
||||
}
|
||||
|
||||
final ExpandableSwipeableItemAdapter adapter = (ExpandableSwipeableItemAdapter) mExpandableItemAdapter;
|
||||
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(holder.getPosition());
|
||||
final int flatPosition = position;
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(flatPosition);
|
||||
final int groupPosition = ExpandableAdapterHelper.getPackedPositionGroup(expandablePosition);
|
||||
final int childPosition = ExpandableAdapterHelper.getPackedPositionChild(expandablePosition);
|
||||
|
||||
@@ -496,14 +556,15 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onPerformAfterSwipeReaction(RecyclerView.ViewHolder holder, int result, int reaction) {
|
||||
public void onPerformAfterSwipeReaction(RecyclerView.ViewHolder holder, int position, int result, int reaction) {
|
||||
if (!(mExpandableItemAdapter instanceof ExpandableSwipeableItemAdapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ExpandableSwipeableItemAdapter adapter = (ExpandableSwipeableItemAdapter) mExpandableItemAdapter;
|
||||
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(holder.getPosition());
|
||||
final int flatPosition = position;
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(flatPosition);
|
||||
final int groupPosition = ExpandableAdapterHelper.getPackedPositionGroup(expandablePosition);
|
||||
final int childPosition = ExpandableAdapterHelper.getPackedPositionChild(expandablePosition);
|
||||
|
||||
@@ -513,16 +574,17 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
adapter.onPerformAfterSwipeChildReaction(holder, groupPosition, childPosition, result, reaction);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This method is called from RecyclerViewExpandableItemManager
|
||||
/*package*/
|
||||
@SuppressWarnings("unchecked")
|
||||
boolean onTapItem(RecyclerView.ViewHolder holder, int x, int y) {
|
||||
boolean onTapItem(RecyclerView.ViewHolder holder, int position, int x, int y) {
|
||||
if (mExpandableItemAdapter == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int position = holder.getPosition();
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(position);
|
||||
final int flatPosition = position;
|
||||
final long expandablePosition = mPositionTranslator.getExpandablePosition(flatPosition);
|
||||
final int groupPosition = ExpandableAdapterHelper.getPackedPositionGroup(expandablePosition);
|
||||
final int childPosition = ExpandableAdapterHelper.getPackedPositionChild(expandablePosition);
|
||||
|
||||
@@ -539,19 +601,24 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
}
|
||||
|
||||
if (expand) {
|
||||
expandGroup(groupPosition);
|
||||
expandGroup(groupPosition, true);
|
||||
} else {
|
||||
collapseGroup(groupPosition);
|
||||
collapseGroup(groupPosition, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*package*/ boolean collapseGroup(int groupPosition) {
|
||||
/*package*/ boolean collapseGroup(int groupPosition, boolean fromUser) {
|
||||
if (!mPositionTranslator.isGroupExpanded(groupPosition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// call hook method
|
||||
if (!mExpandableItemAdapter.onHookGroupCollapse(groupPosition, fromUser)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mPositionTranslator.collapseGroup(groupPosition)) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupPosition);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
@@ -568,14 +635,23 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
notifyItemChanged(flatPosition);
|
||||
}
|
||||
|
||||
// raise onGroupCollapse() event
|
||||
if (mOnGroupCollapseListener != null) {
|
||||
mOnGroupCollapseListener.onGroupCollapse(groupPosition, fromUser);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*package*/ boolean expandGroup(int groupPosition) {
|
||||
/*package*/ boolean expandGroup(int groupPosition, boolean fromUser) {
|
||||
if (mPositionTranslator.isGroupExpanded(groupPosition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// call hook method
|
||||
if (!mExpandableItemAdapter.onHookGroupExpand(groupPosition, fromUser)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mPositionTranslator.expandGroup(groupPosition)) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupPosition);
|
||||
@@ -592,6 +668,11 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
notifyItemChanged(flatPosition);
|
||||
}
|
||||
|
||||
// raise onGroupExpand() event
|
||||
if (mOnGroupExpandListener != null) {
|
||||
mOnGroupExpandListener.onGroupExpand(groupPosition, fromUser);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -615,6 +696,161 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void setOnGroupExpandListener(RecyclerViewExpandableItemManager.OnGroupExpandListener listener) {
|
||||
mOnGroupExpandListener = listener;
|
||||
}
|
||||
|
||||
/*package*/ void setOnGroupCollapseListener(RecyclerViewExpandableItemManager.OnGroupCollapseListener listener) {
|
||||
mOnGroupCollapseListener = listener;
|
||||
}
|
||||
|
||||
/*package*/ void restoreState(int[] adapterSavedState, boolean callHook, boolean callListeners) {
|
||||
mPositionTranslator.restoreExpandedGroupItems(
|
||||
adapterSavedState,
|
||||
(callHook ? mExpandableItemAdapter : null),
|
||||
(callListeners ? mOnGroupExpandListener : null),
|
||||
(callListeners ? mOnGroupCollapseListener : null));
|
||||
}
|
||||
|
||||
/*package*/ void notifyGroupItemChanged(int groupPosition) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupPosition);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
if (flatPosition != RecyclerView.NO_POSITION) {
|
||||
notifyItemChanged(flatPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyGroupAndChildrenItemsChanged(int groupPosition) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupPosition);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
final int visibleChildCount = mPositionTranslator.getVisibleChildCount(groupPosition);
|
||||
|
||||
if (flatPosition != RecyclerView.NO_POSITION) {
|
||||
notifyItemRangeChanged(flatPosition, 1 + visibleChildCount);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyChildrenOfGroupItemChanged(int groupPosition) {
|
||||
final int visibleChildCount = mPositionTranslator.getVisibleChildCount(groupPosition);
|
||||
|
||||
// notify if the group is expanded
|
||||
if (visibleChildCount > 0) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForChild(groupPosition, 0);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
if (flatPosition != RecyclerView.NO_POSITION) {
|
||||
notifyItemRangeChanged(flatPosition, visibleChildCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyChildItemChanged(int groupPosition, int childPosition) {
|
||||
notifyChildItemRangeChanged(groupPosition, childPosition, 1);
|
||||
}
|
||||
|
||||
/*package*/ void notifyChildItemRangeChanged(int groupPosition, int childPositionStart, int itemCount) {
|
||||
final int visibleChildCount = mPositionTranslator.getVisibleChildCount(groupPosition);
|
||||
|
||||
// notify if the group is expanded
|
||||
if ((visibleChildCount > 0) && (childPositionStart < visibleChildCount)) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForChild(groupPosition, 0);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
if (flatPosition != RecyclerView.NO_POSITION) {
|
||||
final int startPosition = flatPosition + childPositionStart;
|
||||
final int count = Math.min(itemCount, (visibleChildCount - childPositionStart));
|
||||
|
||||
notifyItemRangeChanged(startPosition, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyChildItemInserted(int groupPosition, int childPosition) {
|
||||
mPositionTranslator.insertChildItem(groupPosition, childPosition);
|
||||
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForChild(groupPosition, childPosition);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
if (flatPosition != RecyclerView.NO_POSITION) {
|
||||
notifyItemInserted(flatPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyChildItemRangeInserted(int groupPosition, int childPositionStart, int itemCount) {
|
||||
mPositionTranslator.insertChildItems(groupPosition, childPositionStart, itemCount);
|
||||
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForChild(groupPosition, childPositionStart);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
if (flatPosition != RecyclerView.NO_POSITION) {
|
||||
notifyItemRangeInserted(flatPosition, itemCount);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyChildItemRemoved(int groupPosition, int childPosition) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForChild(groupPosition, childPosition);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
mPositionTranslator.removeChildItem(groupPosition, childPosition);
|
||||
|
||||
if (flatPosition != RecyclerView.NO_POSITION) {
|
||||
notifyItemRemoved(flatPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyChildItemRangeRemoved(int groupPosition, int childPositionStart, int itemCount) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForChild(groupPosition, childPositionStart);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
mPositionTranslator.removeChildItems(groupPosition, childPositionStart, itemCount);
|
||||
|
||||
if (flatPosition != RecyclerView.NO_POSITION) {
|
||||
notifyItemRangeRemoved(flatPosition, itemCount);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyGroupItemInserted(int groupPosition) {
|
||||
int insertedCount = mPositionTranslator.insertGroupItem(groupPosition);
|
||||
if (insertedCount > 0) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupPosition);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
notifyItemInserted(flatPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyGroupItemRangeInserted(int groupPositionStart, int count) {
|
||||
int insertedCount = mPositionTranslator.insertGroupItems(groupPositionStart, count);
|
||||
if (insertedCount > 0) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupPositionStart);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
notifyItemRangeInserted(flatPosition, insertedCount);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyGroupItemRemoved(int groupPosition) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupPosition);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
int removedCount = mPositionTranslator.removeGroupItem(groupPosition);
|
||||
if (removedCount > 0) {
|
||||
notifyItemRangeRemoved(flatPosition, removedCount);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void notifyGroupItemRangeRemoved(int groupPositionStart, int count) {
|
||||
final long packedPosition = ExpandableAdapterHelper.getPackedPositionForGroup(groupPositionStart);
|
||||
final int flatPosition = mPositionTranslator.getFlatPosition(packedPosition);
|
||||
|
||||
int removedCount = mPositionTranslator.removeGroupItems(groupPositionStart, count);
|
||||
if (removedCount > 0) {
|
||||
notifyItemRangeRemoved(flatPosition, removedCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static ExpandableItemAdapter getExpandableItemAdapter(RecyclerView.Adapter adapter) {
|
||||
return WrapperAdapterUtils.findWrappedAdapter(adapter, ExpandableItemAdapter.class);
|
||||
}
|
||||
@@ -637,22 +873,43 @@ class ExpandableRecyclerViewWrapperAdapter
|
||||
holder2.setExpandStateFlags(flags);
|
||||
}
|
||||
|
||||
private void correctItemDragStateFlags(RecyclerView.ViewHolder holder, int groupPosition) {
|
||||
private void correctItemDragStateFlags(RecyclerView.ViewHolder holder, int groupPosition, int childPosition) {
|
||||
if (!(holder instanceof DraggableItemViewHolder)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final DraggableItemViewHolder holder2 = (DraggableItemViewHolder) holder;
|
||||
|
||||
final boolean groupRangeSpecified =
|
||||
(mDraggingItemGroupRangeStart != RecyclerView.NO_POSITION) &&
|
||||
(mDraggingItemGroupRangeEnd != RecyclerView.NO_POSITION);
|
||||
final boolean childRangeSpecified =
|
||||
(mDraggingItemChildRangeStart != RecyclerView.NO_POSITION) &&
|
||||
(mDraggingItemChildRangeEnd != RecyclerView.NO_POSITION);
|
||||
final boolean isInGroupRange =
|
||||
(groupPosition >= mDraggingItemGroupRangeStart) &&
|
||||
(groupPosition <= mDraggingItemGroupRangeEnd);
|
||||
final boolean isInChildRange =
|
||||
(groupPosition != RecyclerView.NO_POSITION) &&
|
||||
(childPosition >= mDraggingItemChildRangeStart) &&
|
||||
(childPosition <= mDraggingItemChildRangeEnd);
|
||||
|
||||
final int flags = holder2.getDragStateFlags();
|
||||
boolean needCorrection = false;
|
||||
|
||||
if (((flags & RecyclerViewDragDropManager.STATE_FLAG_DRAGGING) != 0) &&
|
||||
((flags & RecyclerViewDragDropManager.STATE_FLAG_IS_IN_RANGE) == 0)) {
|
||||
if (mDraggingItemGroupPosition == groupPosition) {
|
||||
holder2.setDragStateFlags(
|
||||
flags | RecyclerViewDragDropManager.STATE_FLAG_IS_IN_RANGE |
|
||||
RecyclerViewDragDropManager.STATE_FLAG_IS_UPDATED);
|
||||
if (!groupRangeSpecified || isInGroupRange) {
|
||||
if (!childRangeSpecified || (childRangeSpecified && isInChildRange)) {
|
||||
needCorrection = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needCorrection) {
|
||||
holder2.setDragStateFlags(
|
||||
flags | RecyclerViewDragDropManager.STATE_FLAG_IS_IN_RANGE |
|
||||
RecyclerViewDragDropManager.STATE_FLAG_IS_UPDATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Haruki Hasegawa
|
||||
*
|
||||
* 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.h6ah4i.android.widget.advrecyclerview.expandable;
|
||||
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
|
||||
|
||||
public class GroupPositionItemDraggableRange extends ItemDraggableRange {
|
||||
public GroupPositionItemDraggableRange(int start, int end) {
|
||||
super(start, end);
|
||||
}
|
||||
|
||||
protected String getClassName() {
|
||||
return "GroupPositionItemDraggableRange";
|
||||
}
|
||||
}
|
||||
Regular → Executable
+356
-8
@@ -64,6 +64,35 @@ public class RecyclerViewExpandableItemManager {
|
||||
*/
|
||||
public static final int STATE_FLAG_IS_UPDATED = (1 << 31);
|
||||
|
||||
|
||||
// ---
|
||||
|
||||
/**
|
||||
* Used for being notified when a group is expanded
|
||||
*/
|
||||
public interface OnGroupExpandListener {
|
||||
/**
|
||||
* Callback method to be invoked when a group in this expandable list has been expanded.
|
||||
*
|
||||
* @param groupPosition The group position that was expanded
|
||||
* @param fromUser Whether the expand request is issued by a user operation
|
||||
*/
|
||||
void onGroupExpand(int groupPosition, boolean fromUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for being notified when a group is collapsed
|
||||
*/
|
||||
public interface OnGroupCollapseListener {
|
||||
/**
|
||||
* Callback method to be invoked when a group in this expandable list has been collapsed.
|
||||
*
|
||||
* @param groupPosition The group position that was collapsed
|
||||
* @param fromUser Whether the collapse request is issued by a user operation
|
||||
*/
|
||||
void onGroupCollapse(int groupPosition, boolean fromUser);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
private SavedState mSavedState;
|
||||
@@ -71,6 +100,8 @@ public class RecyclerViewExpandableItemManager {
|
||||
private RecyclerView mRecyclerView;
|
||||
private ExpandableRecyclerViewWrapperAdapter mAdapter;
|
||||
private RecyclerView.OnItemTouchListener mInternalUseOnItemTouchListener;
|
||||
private OnGroupExpandListener mOnGroupExpandListener;
|
||||
private OnGroupCollapseListener mOnGroupCollapseListener;
|
||||
|
||||
private long mTouchedItemId = RecyclerView.NO_ID;
|
||||
private int mTouchSlop;
|
||||
@@ -92,6 +123,10 @@ public class RecyclerViewExpandableItemManager {
|
||||
@Override
|
||||
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
}
|
||||
};
|
||||
|
||||
if (savedState instanceof SavedState) {
|
||||
@@ -145,6 +180,8 @@ public class RecyclerViewExpandableItemManager {
|
||||
mRecyclerView.removeOnItemTouchListener(mInternalUseOnItemTouchListener);
|
||||
}
|
||||
mInternalUseOnItemTouchListener = null;
|
||||
mOnGroupExpandListener = null;
|
||||
mOnGroupCollapseListener = null;
|
||||
mRecyclerView = null;
|
||||
mSavedState = null;
|
||||
}
|
||||
@@ -167,6 +204,13 @@ public class RecyclerViewExpandableItemManager {
|
||||
|
||||
mAdapter = new ExpandableRecyclerViewWrapperAdapter(this, adapter, adapterSavedState);
|
||||
|
||||
// move listeners to wrapper adapter
|
||||
mAdapter.setOnGroupExpandListener(mOnGroupExpandListener);
|
||||
mOnGroupExpandListener = null;
|
||||
|
||||
mAdapter.setOnGroupCollapseListener(mOnGroupCollapseListener);
|
||||
mOnGroupCollapseListener = null;
|
||||
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
@@ -201,7 +245,8 @@ public class RecyclerViewExpandableItemManager {
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (handleActionUpOrCancel(rv, e)) {
|
||||
return true;
|
||||
// NOTE: it requires to return false to work click effect properly (issue #44)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -215,7 +260,7 @@ public class RecyclerViewExpandableItemManager {
|
||||
mInitialTouchX = (int) (e.getX() + 0.5f);
|
||||
mInitialTouchY = (int) (e.getY() + 0.5f);
|
||||
|
||||
if (holder != null) {
|
||||
if (holder instanceof ExpandableItemViewHolder) {
|
||||
mTouchedItemId = holder.getItemId();
|
||||
} else {
|
||||
mTouchedItemId = RecyclerView.NO_ID;
|
||||
@@ -251,13 +296,19 @@ public class RecyclerViewExpandableItemManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int position = CustomRecyclerViewUtils.getSynchronizedPosition(holder);
|
||||
|
||||
if (position == RecyclerView.NO_POSITION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final View view = holder.itemView;
|
||||
final int translateX = (int) (ViewCompat.getTranslationX(view) + 0.5f);
|
||||
final int translateY = (int) (ViewCompat.getTranslationY(view) + 0.5f);
|
||||
final int viewX = touchX - (view.getLeft() + translateX);
|
||||
final int viewY = touchY - (view.getTop() + translateY);
|
||||
|
||||
return mAdapter.onTapItem(holder, viewX, viewY);
|
||||
return mAdapter.onTapItem(holder, position, viewX, viewY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,10 +316,10 @@ public class RecyclerViewExpandableItemManager {
|
||||
*
|
||||
* @param groupPosition The group position to be expanded
|
||||
*
|
||||
* @return True if the group was expanded,false otherwise (If the group was already expanded, this will return false)
|
||||
* @return True if the group was expanded, false otherwise (If the group was already expanded, this will return false)
|
||||
*/
|
||||
public boolean expandGroup(int groupPosition) {
|
||||
return (mAdapter != null) && mAdapter.expandGroup(groupPosition);
|
||||
return (mAdapter != null) && mAdapter.expandGroup(groupPosition, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,10 +327,10 @@ public class RecyclerViewExpandableItemManager {
|
||||
*
|
||||
* @param groupPosition The group position to be collapsed
|
||||
*
|
||||
* @return True if the group was collapsed,false otherwise (If the group was already collapsed, this will return false)
|
||||
* @return True if the group was collapsed, false otherwise (If the group was already collapsed, this will return false)
|
||||
*/
|
||||
public boolean collapseGroup(int groupPosition) {
|
||||
return (mAdapter != null) && mAdapter.collapseGroup(groupPosition);
|
||||
return (mAdapter != null) && mAdapter.collapseGroup(groupPosition, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,7 +379,7 @@ public class RecyclerViewExpandableItemManager {
|
||||
* Returns the packed position representation of a child position.
|
||||
*
|
||||
* In general, a packed position should be used in situations where the position given to/returned from
|
||||
* {@link RecyclerViewExpandableItemManager} method can eirther be a child or group.
|
||||
* {@link RecyclerViewExpandableItemManager} method can either be a child or group.
|
||||
* The two positions are packed into a single long which can be unpacked using {@link #getPackedPositionChild(long)} and
|
||||
* {@link #getPackedPositionGroup(long)}.
|
||||
*
|
||||
@@ -438,6 +489,303 @@ public class RecyclerViewExpandableItemManager {
|
||||
return ExpandableAdapterHelper.getChildViewType(rawViewType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when an group item has been expanded.
|
||||
*
|
||||
* @param listener The callback that will be invoked.
|
||||
*/
|
||||
public void setOnGroupExpandListener(OnGroupExpandListener listener) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.setOnGroupExpandListener(listener);
|
||||
} else {
|
||||
// pending
|
||||
mOnGroupExpandListener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when an group item has been collapsed.
|
||||
*
|
||||
* @param listener The callback that will be invoked.
|
||||
*/
|
||||
public void setOnGroupCollapseListener(OnGroupCollapseListener listener) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.setOnGroupCollapseListener(listener);
|
||||
} else {
|
||||
// pending
|
||||
mOnGroupCollapseListener = listener;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore saves state. See {@link #restoreState(android.os.Parcelable, boolean, boolean)}.
|
||||
* (This method does not invoke any hook methods and listener events)
|
||||
*
|
||||
* @param savedState The saved state object
|
||||
*/
|
||||
public void restoreState(Parcelable savedState) {
|
||||
restoreState(savedState, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore saves state.
|
||||
*
|
||||
* This method is useful when the adapter can not be prepared (because data loading may takes time and processed asynchronously)
|
||||
* before creating this manager instance.
|
||||
*
|
||||
* @param savedState The saved state object
|
||||
* @param callHooks Whether to call hook routines
|
||||
* ({@link ExpandableItemAdapter#onHookGroupExpand(int, boolean)},
|
||||
* {@link ExpandableItemAdapter#onHookGroupCollapse(int, boolean)})
|
||||
* @param callListeners Whether to invoke {@link OnGroupExpandListener} and/or {@link OnGroupCollapseListener} listener events
|
||||
*/
|
||||
public void restoreState(Parcelable savedState, boolean callHooks, boolean callListeners) {
|
||||
if (savedState == null) {
|
||||
return; // do nothing
|
||||
}
|
||||
|
||||
if (!(savedState instanceof SavedState)) {
|
||||
throw new IllegalArgumentException("Illegal saved state object passed");
|
||||
}
|
||||
|
||||
if (!((mAdapter != null) && (mRecyclerView != null))) {
|
||||
throw new IllegalStateException("RecyclerView has not been attached");
|
||||
}
|
||||
|
||||
mAdapter.restoreState(((SavedState) savedState).adapterSavedState, callHooks, callListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the group item at <code>groupPosition</code> has changed.
|
||||
*
|
||||
* <p>This is an group item change event, not a structural change event. It indicates that any
|
||||
* reflection of the data at <code>groupPosition</code> is out of date and should be updated.
|
||||
* The item at <code>groupPosition</code> retains the same identity.</p>
|
||||
*
|
||||
* <p>This method does not notify for children that are contained in the specified group.
|
||||
* If children have also changed, use {@link #notifyGroupAndChildrenItemsChanged(int)} instead.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item that has changed
|
||||
*
|
||||
* @see #notifyGroupAndChildrenItemsChanged(int)
|
||||
*/
|
||||
public void notifyGroupItemChanged(int groupPosition) {
|
||||
mAdapter.notifyGroupItemChanged(groupPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the group and children items at <code>groupPosition</code> have changed.
|
||||
*
|
||||
* <p>This is an group item change event, not a structural change event. It indicates that any
|
||||
* reflection of the data at <code>groupPosition</code> is out of date and should be updated.
|
||||
* The item at <code>groupPosition</code> retains the same identity.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item which contains changed children
|
||||
*
|
||||
* @see #notifyGroupItemChanged(int)
|
||||
* @see #notifyChildrenOfGroupItemChanged(int)
|
||||
*/
|
||||
public void notifyGroupAndChildrenItemsChanged(int groupPosition) {
|
||||
mAdapter.notifyGroupAndChildrenItemsChanged(groupPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the children items contained in the group item at <code>groupPosition</code> have changed.
|
||||
*
|
||||
* <p>This is an group item change event, not a structural change event. It indicates that any
|
||||
* reflection of the data at <code>groupPosition</code> is out of date and should be updated.
|
||||
* The item at <code>groupPosition</code> retains the same identity.</p>
|
||||
*
|
||||
* <p>This method does not notify for the group item.
|
||||
* If the group has also changed, use {@link #notifyGroupAndChildrenItemsChanged(int)} instead.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item which contains changed children
|
||||
*
|
||||
* @see #notifyGroupAndChildrenItemsChanged(int)
|
||||
*/
|
||||
public void notifyChildrenOfGroupItemChanged(int groupPosition) {
|
||||
mAdapter.notifyChildrenOfGroupItemChanged(groupPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the child item at <code>{groupPosition, childPosition}</code> has changed.
|
||||
*
|
||||
* <p>This is an item change event, not a structural change event. It indicates that any
|
||||
* reflection of the data at <code>{groupPosition, childPosition}</code> is out of date and should be updated.
|
||||
* The item at <code>{groupPosition, childPosition}</code> retains the same identity.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item which contains the changed child
|
||||
* @param childPosition Position of the child item in the group that has changed
|
||||
*
|
||||
* @see #notifyChildItemRangeChanged(int, int, int)
|
||||
*/
|
||||
public void notifyChildItemChanged(int groupPosition, int childPosition) {
|
||||
mAdapter.notifyChildItemChanged(groupPosition, childPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the <code>itemCount</code> child items starting at
|
||||
* position <code>{groupPosition, childPosition}</code> have changed.
|
||||
*
|
||||
* <p>This is an item change event, not a structural change event. It indicates that
|
||||
* any reflection of the data in the given position range is out of date and should
|
||||
* be updated. The items in the given range retain the same identity.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item which contains the changed child
|
||||
* @param childPositionStart Position of the first child item in the group that has changed
|
||||
* @param itemCount Number of items that have changed
|
||||
*
|
||||
* @see #notifyChildItemChanged(int, int)
|
||||
*/
|
||||
public void notifyChildItemRangeChanged(int groupPosition, int childPositionStart, int itemCount) {
|
||||
mAdapter.notifyChildItemRangeChanged(groupPosition, childPositionStart, itemCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the group item reflected at <code>groupPosition</code>
|
||||
* has been newly inserted. The group item previously at <code>groupPosition</code> is now at
|
||||
* position <code>groupPosition + 1</code>.
|
||||
*
|
||||
* <p>This is a structural change event. Representations of other existing items in the
|
||||
* data set are still considered up to date and will not be rebound, though their
|
||||
* positions may be altered.</p>
|
||||
*
|
||||
* @param groupPosition Position of the newly inserted group item in the data set
|
||||
*
|
||||
* @see #notifyGroupItemRangeInserted(int, int)
|
||||
*/
|
||||
public void notifyGroupItemInserted(int groupPosition) {
|
||||
mAdapter.notifyGroupItemInserted(groupPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the currently reflected <code>itemCount</code>
|
||||
* group items starting at <code>groupPositionStart</code> have been newly inserted. The group items
|
||||
* previously located at <code>groupPositionStart</code> and beyond can now be found starting
|
||||
* at position <code>groupPositionStart + itemCount</code>.
|
||||
*
|
||||
* <p>This is a structural change event. Representations of other existing items in the
|
||||
* data set are still considered up to date and will not be rebound, though their positions
|
||||
* may be altered.</p>
|
||||
*
|
||||
* @param groupPositionStart Position of the first group item that was inserted
|
||||
* @param itemCount Number of group items inserted
|
||||
*
|
||||
* @see #notifyGroupItemInserted(int)
|
||||
*/
|
||||
public void notifyGroupItemRangeInserted(int groupPositionStart, int itemCount) {
|
||||
mAdapter.notifyGroupItemRangeInserted(groupPositionStart, itemCount);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the group item reflected at <code>groupPosition</code>
|
||||
* has been newly inserted. The group item previously at <code>groupPosition</code> is now at
|
||||
* position <code>groupPosition + 1</code>.
|
||||
*
|
||||
* <p>This is a structural change event. Representations of other existing items in the
|
||||
* data set are still considered up to date and will not be rebound, though their
|
||||
* positions may be altered.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item which contains the inserted child
|
||||
* @param childPosition Position of the newly inserted child item in the data set
|
||||
*
|
||||
* @see #notifyChildItemRangeInserted(int, int, int)
|
||||
*/
|
||||
public void notifyChildItemInserted(int groupPosition, int childPosition) {
|
||||
mAdapter.notifyChildItemInserted(groupPosition, childPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the currently reflected <code>itemCount</code>
|
||||
* child items starting at <code>childPositionStart</code> have been newly inserted. The child items
|
||||
* previously located at <code>childPositionStart</code> and beyond can now be found starting
|
||||
* at position <code>childPositionStart + itemCount</code>.
|
||||
*
|
||||
* <p>This is a structural change event. Representations of other existing items in the
|
||||
* data set are still considered up to date and will not be rebound, though their positions
|
||||
* may be altered.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item which contains the inserted child
|
||||
* @param childPositionStart Position of the first child item that was inserted
|
||||
* @param itemCount Number of child items inserted
|
||||
*
|
||||
* @see #notifyChildItemInserted(int, int)
|
||||
*/
|
||||
public void notifyChildItemRangeInserted(int groupPosition, int childPositionStart, int itemCount) {
|
||||
mAdapter.notifyChildItemRangeInserted(groupPosition, childPositionStart, itemCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the group item previously located at <code>groupPosition</code>
|
||||
* has been removed from the data set. The group items previously located at and after
|
||||
* <code>groupPosition</code> may now be found at <code>oldGroupPosition - 1</code>.
|
||||
*
|
||||
* <p>This is a structural change event. Representations of other existing items in the
|
||||
* data set are still considered up to date and will not be rebound, though their positions
|
||||
* may be altered.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item that has now been removed
|
||||
*
|
||||
* @see #notifyGroupItemRangeRemoved(int, int)
|
||||
*/
|
||||
public void notifyGroupItemRemoved(int groupPosition) {
|
||||
mAdapter.notifyGroupItemRemoved(groupPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the <code>itemCount</code> group items previously
|
||||
* located at <code>groupPositionStart</code> have been removed from the data set. The group items
|
||||
* previously located at and after <code>groupPositionStart + itemCount</code> may now be found
|
||||
* at <code>oldPosition - itemCount</code>.
|
||||
*
|
||||
* <p>This is a structural change event. Representations of other existing items in the data
|
||||
* set are still considered up to date and will not be rebound, though their positions
|
||||
* may be altered.</p>
|
||||
*
|
||||
* @param groupPositionStart Previous position of the first group item that was removed
|
||||
* @param itemCount Number of group items removed from the data set
|
||||
*/
|
||||
public void notifyGroupItemRangeRemoved(int groupPositionStart, int itemCount) {
|
||||
mAdapter.notifyGroupItemRangeRemoved(groupPositionStart, itemCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the child item previously located at <code>childPosition</code>
|
||||
* has been removed from the data set. The child items previously located at and after
|
||||
* <code>childPosition</code> may now be found at <code>oldGroupPosition - 1</code>.
|
||||
*
|
||||
* <p>This is a structural change event. Representations of other existing items in the
|
||||
* data set are still considered up to date and will not be rebound, though their positions
|
||||
* may be altered.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item which was the parent of the child item that was removed
|
||||
* @param childPosition Position of the child item that has now been removed
|
||||
*
|
||||
* @see #notifyGroupItemRangeRemoved(int, int)
|
||||
*/
|
||||
public void notifyChildItemRemoved(int groupPosition, int childPosition) {
|
||||
mAdapter.notifyChildItemRemoved(groupPosition, childPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any registered observers that the <code>itemCount</code> child items previously
|
||||
* located at <code>childPositionStart</code> have been removed from the data set. The child items
|
||||
* previously located at and after <code>childPositionStart + itemCount</code> may now be found
|
||||
* at <code>oldPosition - itemCount</code>.
|
||||
*
|
||||
* <p>This is a structural change event. Representations of other existing items in the data
|
||||
* set are still considered up to date and will not be rebound, though their positions
|
||||
* may be altered.</p>
|
||||
*
|
||||
* @param groupPosition Position of the group item which was the parent of the child item that was removed
|
||||
* @param childPositionStart Previous position of the first child item that was removed
|
||||
* @param itemCount Number of child items removed from the data set
|
||||
*/
|
||||
public void notifyChildItemRangeRemoved(int groupPosition, int childPositionStart, int itemCount) {
|
||||
mAdapter.notifyChildItemRangeRemoved(groupPosition, childPositionStart, itemCount);
|
||||
}
|
||||
|
||||
public static class SavedState implements Parcelable {
|
||||
final int [] adapterSavedState;
|
||||
|
||||
|
||||
Regular → Executable
+121
-8
@@ -32,6 +32,7 @@ import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -41,40 +42,62 @@ public class ItemSlidingAnimator {
|
||||
private Interpolator mSlideToDefaultPositionAnimationInterpolator = new AccelerateDecelerateInterpolator();
|
||||
private Interpolator mSlideToOutsideOfWindowAnimationInterpolator = new AccelerateInterpolator(0.8f);
|
||||
private List<RecyclerView.ViewHolder> mActive;
|
||||
private List<WeakReference<ViewHolderDeferredProcess>> mDeferredProcesses;
|
||||
private int[] mTmpLocation = new int[2];
|
||||
private Rect mTmpRect = new Rect();
|
||||
private int mImmediatelySetTranslationThreshold;
|
||||
|
||||
public ItemSlidingAnimator() {
|
||||
mActive = new ArrayList<>();
|
||||
mDeferredProcesses = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void slideToDefaultPosition(RecyclerView.ViewHolder holder, boolean shouldAnimate, long duration) {
|
||||
cancelDeferredProcess(holder);
|
||||
slideToSpecifiedPositionInternal(holder, 0, shouldAnimate, duration);
|
||||
}
|
||||
|
||||
public void slideToOutsideOfWindow(RecyclerView.ViewHolder holder, boolean toLeft, boolean shouldAnimate, long duration) {
|
||||
cancelDeferredProcess(holder);
|
||||
slideToOutsideOfWindowInternal(holder, toLeft, shouldAnimate, duration);
|
||||
}
|
||||
|
||||
public void slideToSpecifiedPosition(RecyclerView.ViewHolder holder, float position) {
|
||||
cancelDeferredProcess(holder);
|
||||
slideToSpecifiedPositionInternal(holder, position, false, 0);
|
||||
}
|
||||
|
||||
private boolean slideToSpecifiedPositionInternal(RecyclerView.ViewHolder holder, float position, boolean shouldAnimate, long duration) {
|
||||
final int translationX;
|
||||
private void cancelDeferredProcess(RecyclerView.ViewHolder holder) {
|
||||
int n = mDeferredProcesses.size();
|
||||
for (int i = n - 1; i >= 0; i--) {
|
||||
ViewHolderDeferredProcess dp = mDeferredProcesses.get(i).get();
|
||||
|
||||
if (dp == null || dp.hasTargetViewHolderOrLostReference(holder)) {
|
||||
mDeferredProcesses.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean slideToSpecifiedPositionInternal(final RecyclerView.ViewHolder holder, final float position, boolean shouldAnimate, long duration) {
|
||||
duration = (shouldAnimate) ? duration : 0;
|
||||
|
||||
if (position != 0.0f) {
|
||||
final View containerView = ((SwipeableItemViewHolder) holder).getSwipeableContainerView();
|
||||
final int width = containerView.getWidth();
|
||||
|
||||
translationX = (int) (containerView.getWidth() * position + 0.5f);
|
||||
if (width != 0) {
|
||||
final int translationX;
|
||||
translationX = (int) (width * position + 0.5f);
|
||||
return animateSlideInternalCompat(holder, translationX, duration, mSlideToDefaultPositionAnimationInterpolator);
|
||||
} else {
|
||||
final DeferredSlideProcess deferredProcess = new DeferredSlideProcess(holder, position);
|
||||
mDeferredProcesses.add(new WeakReference<ViewHolderDeferredProcess>(deferredProcess));
|
||||
containerView.post(deferredProcess);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
translationX = 0;
|
||||
return animateSlideInternalCompat(holder, 0, duration, mSlideToDefaultPositionAnimationInterpolator);
|
||||
}
|
||||
|
||||
return animateSlideInternalCompat(holder, translationX, duration, mSlideToDefaultPositionAnimationInterpolator);
|
||||
}
|
||||
|
||||
private boolean slideToOutsideOfWindowInternal(RecyclerView.ViewHolder holder, boolean toLeft, boolean shouldAnimate, long duration) {
|
||||
@@ -124,12 +147,20 @@ public class ItemSlidingAnimator {
|
||||
if (supportsViewPropertyAnimator()) {
|
||||
return animateSlideInternal(holder, translationX, duration, interpolator);
|
||||
} else {
|
||||
return animateSlideInternalPreHoneycomb(holder, translationX);
|
||||
return slideInternalPreHoneycomb(holder, translationX);
|
||||
}
|
||||
}
|
||||
|
||||
static void slideInternalCompat(RecyclerView.ViewHolder holder, int translationX) {
|
||||
if (supportsViewPropertyAnimator()) {
|
||||
slideInternal(holder, translationX);
|
||||
} else {
|
||||
slideInternalPreHoneycomb(holder, translationX);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
private boolean animateSlideInternalPreHoneycomb(RecyclerView.ViewHolder holder, int translationX) {
|
||||
private static boolean slideInternalPreHoneycomb(RecyclerView.ViewHolder holder, int translationX) {
|
||||
if (!(holder instanceof SwipeableItemViewHolder)) {
|
||||
return false;
|
||||
}
|
||||
@@ -153,6 +184,29 @@ public class ItemSlidingAnimator {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int getTranslationXPreHoneycomb(RecyclerView.ViewHolder holder) {
|
||||
final View containerView = ((SwipeableItemViewHolder) holder).getSwipeableContainerView();
|
||||
|
||||
final ViewGroup.LayoutParams lp = containerView.getLayoutParams();
|
||||
if (lp instanceof ViewGroup.MarginLayoutParams) {
|
||||
final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
|
||||
return mlp.leftMargin;
|
||||
} else {
|
||||
Log.w(TAG, "should use MarginLayoutParams supported view for compatibility on Android 2.3");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static void slideInternal(final RecyclerView.ViewHolder holder, int translationX) {
|
||||
if (!(holder instanceof SwipeableItemViewHolder)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final View containerView = ((SwipeableItemViewHolder) holder).getSwipeableContainerView();
|
||||
ViewCompat.animate(containerView).cancel();
|
||||
ViewCompat.setTranslationX(containerView, translationX);
|
||||
}
|
||||
|
||||
private boolean animateSlideInternal(final RecyclerView.ViewHolder holder, int translationX, long duration, Interpolator interpolator) {
|
||||
if (!(holder instanceof SwipeableItemViewHolder)) {
|
||||
return false;
|
||||
@@ -164,8 +218,13 @@ public class ItemSlidingAnimator {
|
||||
|
||||
endAnimation(holder);
|
||||
|
||||
final int curTranslationX = (int) (ViewCompat.getTranslationX(containerView) + 0.5f);
|
||||
final int toX = translationX;
|
||||
|
||||
if (curTranslationX == toX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (duration == 0 || Math.abs(toX - prevTranslationX) <= mImmediatelySetTranslationThreshold) {
|
||||
ViewCompat.setTranslationX(containerView, toX);
|
||||
return false;
|
||||
@@ -209,6 +268,8 @@ public class ItemSlidingAnimator {
|
||||
return;
|
||||
}
|
||||
|
||||
cancelDeferredProcess(holder);
|
||||
|
||||
final View containerView = ((SwipeableItemViewHolder) holder).getSwipeableContainerView();
|
||||
|
||||
ViewCompat.animate(containerView).cancel();
|
||||
@@ -244,4 +305,56 @@ public class ItemSlidingAnimator {
|
||||
private static boolean supportsViewPropertyAnimator() {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
}
|
||||
|
||||
public int getSwipeContainerViewTranslationX(RecyclerView.ViewHolder holder) {
|
||||
if (supportsViewPropertyAnimator()) {
|
||||
final View containerView = ((SwipeableItemViewHolder) holder).getSwipeableContainerView();
|
||||
return (int) (ViewCompat.getTranslationX(containerView) + 0.5f);
|
||||
} else {
|
||||
return getTranslationXPreHoneycomb(holder);
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class ViewHolderDeferredProcess implements Runnable {
|
||||
final WeakReference<RecyclerView.ViewHolder> mRefHolder;
|
||||
|
||||
public ViewHolderDeferredProcess(RecyclerView.ViewHolder holder) {
|
||||
mRefHolder = new WeakReference<RecyclerView.ViewHolder>(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
RecyclerView.ViewHolder holder = mRefHolder.get();
|
||||
|
||||
if (holder != null) {
|
||||
onProcess(holder);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasTargetViewHolderOrLostReference(RecyclerView.ViewHolder holder) {
|
||||
RecyclerView.ViewHolder holder2 = mRefHolder.get();
|
||||
return ((holder2 == null) || (holder2 == holder));
|
||||
}
|
||||
|
||||
protected abstract void onProcess(RecyclerView.ViewHolder holder);
|
||||
}
|
||||
|
||||
private static final class DeferredSlideProcess extends ViewHolderDeferredProcess {
|
||||
final float mPosition;
|
||||
|
||||
public DeferredSlideProcess(RecyclerView.ViewHolder holder, float position) {
|
||||
super(holder);
|
||||
mPosition = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProcess(RecyclerView.ViewHolder holder) {
|
||||
final View containerView = ((SwipeableItemViewHolder) holder).getSwipeableContainerView();
|
||||
final int width = containerView.getWidth();
|
||||
final int translationX;
|
||||
|
||||
translationX = (int) (width * mPosition + 0.5f);
|
||||
slideInternalCompat(holder, translationX);
|
||||
}
|
||||
}
|
||||
}
|
||||
Regular → Executable
+106
-25
@@ -40,7 +40,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Result code of swipe operation. Used for the second argument of the
|
||||
* {@link SwipeableItemAdapter#onPerformAfterSwipeReaction(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onPerformAfterSwipeReaction(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* None. (internal default value, this value is not used for the argument)
|
||||
*/
|
||||
@@ -48,7 +48,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Result code of swipe operation. Used for the second argument of the
|
||||
* {@link SwipeableItemAdapter#onPerformAfterSwipeReaction(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onPerformAfterSwipeReaction(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* Canceled.
|
||||
*/
|
||||
@@ -56,7 +56,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Result code of swipe operation. Used for the second argument of the
|
||||
* {@link SwipeableItemAdapter#onPerformAfterSwipeReaction(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onPerformAfterSwipeReaction(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* Swipe left performed.
|
||||
*/
|
||||
@@ -64,7 +64,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Result code of swipe operation. Used for the second argument of the
|
||||
* {@link SwipeableItemAdapter#onPerformAfterSwipeReaction(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onPerformAfterSwipeReaction(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* Swipe right performed.
|
||||
*/
|
||||
@@ -73,7 +73,7 @@ public class RecyclerViewSwipeManager {
|
||||
// ---
|
||||
/**
|
||||
* Reaction type to swipe operation. Used for the return value of the
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* Indicates "can not swipe left" (completely no reactions)
|
||||
*/
|
||||
@@ -81,7 +81,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Reaction type to swipe operation. Used for the return value of the
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* Indicates "can not swipe left" (not swipeable, but rubber-band effect applied)
|
||||
*/
|
||||
@@ -89,7 +89,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Reaction type to swipe operation. Used for the return value of the
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* Indicates "can swipe left"
|
||||
*/
|
||||
@@ -97,7 +97,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Reaction type to swipe operation. Used for the return value of the
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* Indicates "can not swipe right" (completely no reactions)
|
||||
*/
|
||||
@@ -105,7 +105,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Reaction type to swipe operation. Used for the return value of the
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* Indicates "can not swipe right" (not swipeable, but rubber-band effect applied)
|
||||
*/
|
||||
@@ -113,7 +113,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Reaction type to swipe operation. Used for the return value of the
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
* {@link SwipeableItemAdapter#onGetSwipeReactionType(android.support.v7.widget.RecyclerView.ViewHolder, int, int, int)} method.
|
||||
*
|
||||
* Indicates "can swipe right"
|
||||
*/
|
||||
@@ -141,7 +141,7 @@ public class RecyclerViewSwipeManager {
|
||||
// ---
|
||||
/**
|
||||
* Background drawable type used for the second argument of the
|
||||
* {@link SwipeableItemAdapter#onSetSwipeBackground(android.support.v7.widget.RecyclerView.ViewHolder, int)} method.
|
||||
* {@link SwipeableItemAdapter#onSetSwipeBackground(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
*
|
||||
* Background image for the neutral (= not swiping) item.
|
||||
*/
|
||||
@@ -149,7 +149,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Background drawable type used for the second argument of the
|
||||
* {@link SwipeableItemAdapter#onSetSwipeBackground(android.support.v7.widget.RecyclerView.ViewHolder, int)} method.
|
||||
* {@link SwipeableItemAdapter#onSetSwipeBackground(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
*
|
||||
* Background image for the swiping-left item.
|
||||
*/
|
||||
@@ -157,7 +157,7 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
/**
|
||||
* Background drawable type used for the second argument of the
|
||||
* {@link SwipeableItemAdapter#onSetSwipeBackground(android.support.v7.widget.RecyclerView.ViewHolder, int)} method.
|
||||
* {@link SwipeableItemAdapter#onSetSwipeBackground(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
*
|
||||
* Background image for the swiping-right item.
|
||||
*/
|
||||
@@ -217,6 +217,29 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
// ---
|
||||
|
||||
/**
|
||||
* Used for listening item swipe events
|
||||
*/
|
||||
public interface OnItemSwipeEventListener {
|
||||
/**
|
||||
* Callback method to be invoked when swiping is started.
|
||||
*
|
||||
* @param position The position of the item.
|
||||
*/
|
||||
void onItemSwipeStarted(int position);
|
||||
|
||||
/**
|
||||
* Callback method to be invoked when swiping is finished.
|
||||
*
|
||||
* @param position The position of the item.
|
||||
* @param result The result code of the swipe operation.
|
||||
* @param afterSwipeReaction The reaction type to the swipe operation.
|
||||
*/
|
||||
void onItemSwipeFinished(int position, int result, int afterSwipeReaction);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
private static final int MIN_DISTANCE_TOUCH_SLOP_MUL = 10;
|
||||
private static final int SLIDE_ITEM_IMMEDIATELY_SET_TRANSLATION_THRESHOLD_DP = 8;
|
||||
|
||||
@@ -239,12 +262,14 @@ public class RecyclerViewSwipeManager {
|
||||
private ItemSlidingAnimator mItemSlideAnimator;
|
||||
private SwipeableItemWrapperAdapter<RecyclerView.ViewHolder> mAdapter;
|
||||
private RecyclerView.ViewHolder mSwipingItem;
|
||||
private int mSwipingItemPosition = RecyclerView.NO_POSITION;
|
||||
private Rect mSwipingItemMargins = new Rect();
|
||||
private int mTouchedItemOffsetX;
|
||||
private int mLastTouchX;
|
||||
private int mSwipingItemReactionType;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
private SwipingItemOperator mSwipingItemOperator;
|
||||
private OnItemSwipeEventListener mItemSwipeEventListener;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -260,6 +285,10 @@ public class RecyclerViewSwipeManager {
|
||||
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
|
||||
RecyclerViewSwipeManager.this.onTouchEvent(rv, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
}
|
||||
};
|
||||
mItemSlideAnimator = new ItemSlidingAnimator();
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
@@ -437,7 +466,7 @@ public class RecyclerViewSwipeManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int itemPosition = holder.getPosition();
|
||||
final int itemPosition = CustomRecyclerViewUtils.getSynchronizedPosition(holder);
|
||||
|
||||
// verify the touched item is valid state
|
||||
if (!(itemPosition >= 0 && itemPosition < adapter.getItemCount())) {
|
||||
@@ -456,7 +485,7 @@ public class RecyclerViewSwipeManager {
|
||||
final int viewX = touchX - (view.getLeft() + translateX);
|
||||
final int viewY = touchY - (view.getTop() + translateY);
|
||||
|
||||
final int reactionType = mAdapter.getSwipeReactionType(holder, viewX, viewY);
|
||||
final int reactionType = mAdapter.getSwipeReactionType(holder, itemPosition, viewX, viewY);
|
||||
|
||||
if (reactionType == 0) {
|
||||
return false;
|
||||
@@ -538,11 +567,17 @@ public class RecyclerViewSwipeManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int itemPosition = CustomRecyclerViewUtils.getSynchronizedPosition(holder);
|
||||
|
||||
if (itemPosition == RecyclerView.NO_POSITION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LOCAL_LOGD) {
|
||||
Log.d(TAG, "swiping started");
|
||||
}
|
||||
|
||||
startSwiping(rv, e, holder);
|
||||
startSwiping(rv, e, holder, itemPosition);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -556,13 +591,14 @@ public class RecyclerViewSwipeManager {
|
||||
mSwipingItemOperator.update(swipeDistance);
|
||||
}
|
||||
|
||||
private void startSwiping(RecyclerView rv, MotionEvent e, RecyclerView.ViewHolder holder) {
|
||||
private void startSwiping(RecyclerView rv, MotionEvent e, RecyclerView.ViewHolder holder, int itemPosition) {
|
||||
mSwipingItem = holder;
|
||||
mSwipingItemPosition = itemPosition;
|
||||
mLastTouchX = (int) (e.getX() + 0.5f);
|
||||
mTouchedItemOffsetX = mLastTouchX;
|
||||
CustomRecyclerViewUtils.getLayoutMargins(holder.itemView, mSwipingItemMargins);
|
||||
|
||||
mSwipingItemOperator = new SwipingItemOperator(this, mSwipingItem, mSwipingItemReactionType);
|
||||
mSwipingItemOperator = new SwipingItemOperator(this, mSwipingItem, mSwipingItemPosition, mSwipingItemReactionType);
|
||||
mSwipingItemOperator.start();
|
||||
|
||||
mVelocityTracker.clear();
|
||||
@@ -570,8 +606,13 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
mRecyclerView.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
|
||||
// raise onItemSwipeStarted() event
|
||||
if (mItemSwipeEventListener != null) {
|
||||
mItemSwipeEventListener.onItemSwipeStarted(itemPosition);
|
||||
}
|
||||
|
||||
// raise onSwipeItemStarted() event
|
||||
mAdapter.onSwipeItemStarted(this, holder);
|
||||
mAdapter.onSwipeItemStarted(this, holder, itemPosition);
|
||||
}
|
||||
|
||||
private void finishSwiping(int result) {
|
||||
@@ -585,9 +626,12 @@ public class RecyclerViewSwipeManager {
|
||||
mRecyclerView.getParent().requestDisallowInterceptTouchEvent(false);
|
||||
}
|
||||
|
||||
final int itemPosition = mSwipingItemPosition;
|
||||
|
||||
mVelocityTracker.clear();
|
||||
|
||||
mSwipingItem = null;
|
||||
mSwipingItemPosition = RecyclerView.NO_POSITION;
|
||||
mLastTouchX = 0;
|
||||
mInitialTouchX = 0;
|
||||
mTouchedItemOffsetX = 0;
|
||||
@@ -603,7 +647,7 @@ public class RecyclerViewSwipeManager {
|
||||
int afterReaction = AFTER_SWIPE_REACTION_DEFAULT;
|
||||
|
||||
if (mAdapter != null) {
|
||||
afterReaction = mAdapter.onSwipeItemFinished(swipingItem, result);
|
||||
afterReaction = mAdapter.onSwipeItemFinished(swipingItem, itemPosition, result);
|
||||
}
|
||||
|
||||
afterReaction = correctAfterReaction(result, afterReaction);
|
||||
@@ -640,7 +684,12 @@ public class RecyclerViewSwipeManager {
|
||||
}
|
||||
|
||||
if (mAdapter != null) {
|
||||
mAdapter.onSwipeItemFinished2(swipingItem, result, afterReaction);
|
||||
mAdapter.onSwipeItemFinished2(swipingItem, itemPosition, result, afterReaction);
|
||||
}
|
||||
|
||||
// raise onItemSwipeFinished() event
|
||||
if (mItemSwipeEventListener != null) {
|
||||
mItemSwipeEventListener.onItemSwipeFinished(itemPosition, result, afterReaction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,7 +760,24 @@ public class RecyclerViewSwipeManager {
|
||||
mMoveToOutsideWindowAnimationDuration = duration;
|
||||
}
|
||||
|
||||
/*package*/ void applySlideItem(RecyclerView.ViewHolder holder, float prevAmount, float amount, boolean shouldAnimate) {
|
||||
/**
|
||||
* Gets OnItemSwipeEventListener listener
|
||||
* @return The listener object
|
||||
*/
|
||||
public OnItemSwipeEventListener getOnItemSwipeEventListener() {
|
||||
return mItemSwipeEventListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets OnItemSwipeEventListener listener
|
||||
*
|
||||
* @param listener The listener object
|
||||
*/
|
||||
public void setOnItemSwipeEventListener(OnItemSwipeEventListener listener) {
|
||||
mItemSwipeEventListener = listener;
|
||||
}
|
||||
|
||||
/*package*/ void applySlideItem(RecyclerView.ViewHolder holder, int itemPosition, float prevAmount, float amount, boolean shouldAnimate) {
|
||||
final SwipeableItemViewHolder holder2 = (SwipeableItemViewHolder) holder;
|
||||
final View containerView = holder2.getSwipeableContainerView();
|
||||
|
||||
@@ -737,13 +803,28 @@ public class RecyclerViewSwipeManager {
|
||||
|
||||
if (amount == 0.0f) {
|
||||
slideItem(holder, amount, shouldAnimate);
|
||||
mAdapter.setSwipeBackgroundDrawable(holder, reqBackgroundType);
|
||||
mAdapter.setSwipeBackgroundDrawable(holder, itemPosition, reqBackgroundType);
|
||||
} else {
|
||||
mAdapter.setSwipeBackgroundDrawable(holder, reqBackgroundType);
|
||||
slideItem(holder, amount, shouldAnimate);
|
||||
float adjustedAmount = amount;
|
||||
|
||||
adjustedAmount = Math.max(adjustedAmount, holder2.getMaxLeftSwipeAmount());
|
||||
adjustedAmount = Math.min(adjustedAmount, holder2.getMaxRightSwipeAmount());
|
||||
|
||||
mAdapter.setSwipeBackgroundDrawable(holder, itemPosition, reqBackgroundType);
|
||||
slideItem(holder, adjustedAmount, shouldAnimate);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void cancelPendingAnimations(RecyclerView.ViewHolder holder) {
|
||||
if (mItemSlideAnimator != null) {
|
||||
mItemSlideAnimator.endAnimation(holder);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ int getSwipeContainerViewTranslationX(RecyclerView.ViewHolder holder) {
|
||||
return mItemSlideAnimator.getSwipeContainerViewTranslationX(holder);
|
||||
}
|
||||
|
||||
private static boolean supportsViewPropertyAnimator() {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
}
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+9
-5
@@ -24,6 +24,7 @@ public interface SwipeableItemAdapter<T extends RecyclerView.ViewHolder> {
|
||||
* Called when user is attempt to swipe the item.
|
||||
*
|
||||
* @param holder The ViewHolder which is associated to item user is attempt to start swiping.
|
||||
* @param position The position of the item within the adapter's data set.
|
||||
* @param x Touched X position. Relative from the itemView's top-left.
|
||||
* @param y Touched Y position. Relative from the itemView's top-left.
|
||||
|
||||
@@ -35,18 +36,19 @@ public interface SwipeableItemAdapter<T extends RecyclerView.ViewHolder> {
|
||||
* - {@link RecyclerViewSwipeManager#REACTION_CAN_NOT_SWIPE_RIGHT_WITH_RUBBER_BAND_EFFECT}
|
||||
* - {@link RecyclerViewSwipeManager#REACTION_CAN_SWIPE_RIGHT}
|
||||
*/
|
||||
int onGetSwipeReactionType(T holder, int x, int y);
|
||||
int onGetSwipeReactionType(T holder, int position, int x, int y);
|
||||
|
||||
/**
|
||||
* Called when sets background of the swiping item.
|
||||
*
|
||||
* @param holder The ViewHolder which is associated to the swiping item.
|
||||
* @param position The position of the item within the adapter's data set.
|
||||
* @param type Background type. One of the
|
||||
* {@link RecyclerViewSwipeManager#DRAWABLE_SWIPE_NEUTRAL_BACKGROUND},
|
||||
* {@link RecyclerViewSwipeManager#DRAWABLE_SWIPE_LEFT_BACKGROUND} or
|
||||
* {@link RecyclerViewSwipeManager#DRAWABLE_SWIPE_RIGHT_BACKGROUND}.
|
||||
*/
|
||||
void onSetSwipeBackground(T holder, int type);
|
||||
void onSetSwipeBackground(T holder, int position, int type);
|
||||
|
||||
/**
|
||||
* Called when item is swiped.
|
||||
@@ -54,6 +56,7 @@ public interface SwipeableItemAdapter<T extends RecyclerView.ViewHolder> {
|
||||
* *Note that do not change data set and do not call notifyDataXXX() methods inside of this method.*
|
||||
*
|
||||
* @param holder The ViewHolder which is associated to the swiped item.
|
||||
* @param position The position of the item within the adapter's data set.
|
||||
* @param result The result code of user's swipe operation.
|
||||
* {@link RecyclerViewSwipeManager#RESULT_CANCELED},
|
||||
* {@link RecyclerViewSwipeManager#RESULT_SWIPED_LEFT} or
|
||||
@@ -64,14 +67,15 @@ public interface SwipeableItemAdapter<T extends RecyclerView.ViewHolder> {
|
||||
* {@link RecyclerViewSwipeManager#AFTER_SWIPE_REACTION_MOVE_TO_SWIPED_DIRECTION} or
|
||||
* {@link RecyclerViewSwipeManager#AFTER_SWIPE_REACTION_REMOVE_ITEM}.
|
||||
*/
|
||||
int onSwipeItem(T holder, int result);
|
||||
int onSwipeItem(T holder, int position, int result);
|
||||
|
||||
/**
|
||||
* Called after {@link #onSwipeItem(android.support.v7.widget.RecyclerView.ViewHolder, int)} method.
|
||||
* Called after {@link #onSwipeItem(android.support.v7.widget.RecyclerView.ViewHolder, int, int)} method.
|
||||
*
|
||||
* You can update data set and call notifyDataXXX() methods inside of this method.
|
||||
*
|
||||
* @param holder The ViewHolder which is associated to the swiped item.
|
||||
* @param position The position of the item within the adapter's data set.
|
||||
* @param result The result code of user's swipe operation.
|
||||
* {@link RecyclerViewSwipeManager#RESULT_CANCELED},
|
||||
* {@link RecyclerViewSwipeManager#RESULT_SWIPED_LEFT} or
|
||||
@@ -80,5 +84,5 @@ public interface SwipeableItemAdapter<T extends RecyclerView.ViewHolder> {
|
||||
* {@link RecyclerViewSwipeManager#AFTER_SWIPE_REACTION_MOVE_TO_SWIPED_DIRECTION} or
|
||||
* {@link RecyclerViewSwipeManager#AFTER_SWIPE_REACTION_REMOVE_ITEM}.
|
||||
*/
|
||||
void onPerformAfterSwipeReaction(T holder, int result, int reaction);
|
||||
void onPerformAfterSwipeReaction(T holder, int position, int result, int reaction);
|
||||
}
|
||||
Regular → Executable
+28
@@ -104,6 +104,34 @@ public interface SwipeableItemViewHolder {
|
||||
*/
|
||||
float getSwipeItemSlideAmount();
|
||||
|
||||
/**
|
||||
* Sets the maximum item right swipe amount.
|
||||
*
|
||||
* @param amount Item swipe amount. Generally the range is [-1.0 .. 1.0]
|
||||
*/
|
||||
void setMaxLeftSwipeAmount(float amount);
|
||||
|
||||
/**
|
||||
* Gets the maximum item left swipe amount.
|
||||
*
|
||||
* @return Item swipe amount. Generally the range is [-1.0 .. 1.0]
|
||||
*/
|
||||
float getMaxLeftSwipeAmount();
|
||||
|
||||
/**
|
||||
* Sets the maximum item right swipe amount.
|
||||
*
|
||||
* @param amount Item swipe amount. Generally the range is [-1.0 .. 1.0]
|
||||
*/
|
||||
void setMaxRightSwipeAmount(float amount);
|
||||
|
||||
/**
|
||||
* Gets the maximum item right swipe amount.
|
||||
*
|
||||
* @return Item swipe amount. Generally the range is [-1.0 .. 1.0]
|
||||
*/
|
||||
float getMaxRightSwipeAmount();
|
||||
|
||||
/**
|
||||
* Gets the container view for the swipeable area.
|
||||
*
|
||||
|
||||
Regular → Executable
+17
-15
@@ -67,6 +67,8 @@ class SwipeableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
|
||||
// reset SwipeableItemViewHolder state
|
||||
if (holder instanceof SwipeableItemViewHolder) {
|
||||
mSwipeManager.cancelPendingAnimations(holder);
|
||||
|
||||
((SwipeableItemViewHolder) holder).setSwipeItemSlideAmount(0.0f);
|
||||
|
||||
View containerView = ((SwipeableItemViewHolder) holder).getSwipeableContainerView();
|
||||
@@ -116,7 +118,7 @@ class SwipeableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
|
||||
if ((prevSwipeItemSlideAmount != swipeItemSlideAmount) ||
|
||||
!(mSwipeManager.isSwiping() || mSwipeManager.isAnimationRunning(holder))) {
|
||||
mSwipeManager.applySlideItem(holder, prevSwipeItemSlideAmount, swipeItemSlideAmount, true);
|
||||
mSwipeManager.applySlideItem(holder, position, prevSwipeItemSlideAmount, swipeItemSlideAmount, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,32 +177,32 @@ class SwipeableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
// NOTE: This method is called from RecyclerViewDragDropManager
|
||||
/*package*/
|
||||
@SuppressWarnings("unchecked")
|
||||
int getSwipeReactionType(RecyclerView.ViewHolder holder, int x, int y) {
|
||||
int getSwipeReactionType(RecyclerView.ViewHolder holder, int position, int x, int y) {
|
||||
if (LOCAL_LOGV) {
|
||||
Log.v(TAG, "getSwipeReactionType(holder = " + holder + ", x = " + x + ", y = " + y + ")");
|
||||
Log.v(TAG, "getSwipeReactionType(holder = " + holder + ", position = " + position + ", x = " + x + ", y = " + y + ")");
|
||||
}
|
||||
|
||||
return mSwipeableItemAdapter.onGetSwipeReactionType(holder, x, y);
|
||||
return mSwipeableItemAdapter.onGetSwipeReactionType(holder, position, x, y);
|
||||
}
|
||||
|
||||
// NOTE: This method is called from RecyclerViewDragDropManager
|
||||
/*package*/
|
||||
@SuppressWarnings("unchecked")
|
||||
void setSwipeBackgroundDrawable(RecyclerView.ViewHolder holder, int type) {
|
||||
void setSwipeBackgroundDrawable(RecyclerView.ViewHolder holder, int position, int type) {
|
||||
if (LOCAL_LOGV) {
|
||||
Log.v(TAG, "setSwipeBackgroundDrawable(holder = " + holder + ", type = " + type + ")");
|
||||
Log.v(TAG, "setSwipeBackgroundDrawable(holder = " + holder + ", position = " + position + ", type = " + type + ")");
|
||||
}
|
||||
|
||||
mSwipeableItemAdapter.onSetSwipeBackground(holder, type);
|
||||
mSwipeableItemAdapter.onSetSwipeBackground(holder, position, type);
|
||||
}
|
||||
|
||||
// NOTE: This method is called from RecyclerViewDragDropManager
|
||||
/*package*/ void onSwipeItemStarted(RecyclerViewSwipeManager manager, RecyclerView.ViewHolder holder) {
|
||||
/*package*/ void onSwipeItemStarted(RecyclerViewSwipeManager manager, RecyclerView.ViewHolder holder, int position) {
|
||||
if (LOCAL_LOGD) {
|
||||
Log.d(TAG, "onSwipeItemStarted(holder = " + holder + ")");
|
||||
Log.d(TAG, "onSwipeItemStarted(holder = " + holder + ", position = " + position + ")");
|
||||
}
|
||||
|
||||
mSwipingItemPosition = holder.getPosition();
|
||||
mSwipingItemPosition = position;
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
@@ -208,25 +210,25 @@ class SwipeableItemWrapperAdapter<VH extends RecyclerView.ViewHolder> extends Ba
|
||||
// NOTE: This method is called from RecyclerViewDragDropManager
|
||||
/*package*/
|
||||
@SuppressWarnings("unchecked")
|
||||
int onSwipeItemFinished(RecyclerView.ViewHolder holder, int result) {
|
||||
int onSwipeItemFinished(RecyclerView.ViewHolder holder, int position, int result) {
|
||||
if (LOCAL_LOGD) {
|
||||
Log.d(TAG, "onSwipeItemFinished(holder = " + holder + ", result = " + result + ")");
|
||||
Log.d(TAG, "onSwipeItemFinished(holder = " + holder + ", position = " + position + ", result = " + result + ")");
|
||||
}
|
||||
|
||||
mSwipingItemPosition = RecyclerView.NO_POSITION;
|
||||
|
||||
return mSwipeableItemAdapter.onSwipeItem(holder, result);
|
||||
return mSwipeableItemAdapter.onSwipeItem(holder, position, result);
|
||||
}
|
||||
|
||||
/*package*/
|
||||
@SuppressWarnings("unchecked")
|
||||
void onSwipeItemFinished2(RecyclerView.ViewHolder holder, int result, int afterReaction) {
|
||||
void onSwipeItemFinished2(RecyclerView.ViewHolder holder, int position, int result, int afterReaction) {
|
||||
|
||||
((SwipeableItemViewHolder) holder).setSwipeResult(result);
|
||||
((SwipeableItemViewHolder) holder).setAfterSwipeReaction(afterReaction);
|
||||
((SwipeableItemViewHolder) holder).setSwipeItemSlideAmount(getSwipeAmountFromAfterReaction(result, afterReaction));
|
||||
|
||||
mSwipeableItemAdapter.onPerformAfterSwipeReaction(holder, result, afterReaction);
|
||||
mSwipeableItemAdapter.onPerformAfterSwipeReaction(holder, position, result, afterReaction);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
Regular → Executable
+19
-8
@@ -29,11 +29,13 @@ class SwipingItemOperator {
|
||||
private static final int REACTION_CAN_SWIPE = SwipeReactionUtils.REACTION_CAN_SWIPE;
|
||||
|
||||
private static final float RUBBER_BAND_LIMIT = 0.15f;
|
||||
private static final int MIN_GRABBING_AREA_WIDTH = 48;
|
||||
|
||||
private static final Interpolator RUBBER_BAND_INTERPOLATOR = new RubberBandInterpolator(RUBBER_BAND_LIMIT);
|
||||
|
||||
private RecyclerViewSwipeManager mSwipeManager;
|
||||
private RecyclerView.ViewHolder mSwipingItem;
|
||||
private int mSwipingItemPosition;
|
||||
private View mSwipingItemContainerView;
|
||||
private int mLeftSwipeReactionType;
|
||||
private int mRightSwipeReactionType;
|
||||
@@ -41,10 +43,12 @@ class SwipingItemOperator {
|
||||
private float mInvSwipingItemWidth;
|
||||
private int mSwipeDistance;
|
||||
private float mPrevTranslateAmount;
|
||||
private int mInitialTranslateAmount;
|
||||
|
||||
public SwipingItemOperator(RecyclerViewSwipeManager manager, RecyclerView.ViewHolder swipingItem, int swipeReactionType) {
|
||||
public SwipingItemOperator(RecyclerViewSwipeManager manager, RecyclerView.ViewHolder swipingItem, int position, int swipeReactionType) {
|
||||
mSwipeManager = manager;
|
||||
mSwipingItem = swipingItem;
|
||||
mSwipingItemPosition = position;
|
||||
mLeftSwipeReactionType = SwipeReactionUtils.extractLeftReaction(swipeReactionType);
|
||||
mRightSwipeReactionType = SwipeReactionUtils.extractRightReaction(swipeReactionType);
|
||||
|
||||
@@ -53,9 +57,13 @@ class SwipingItemOperator {
|
||||
mInvSwipingItemWidth = (mSwipingItemWidth != 0) ? (1.0f / mSwipingItemWidth) : 0.0f;
|
||||
}
|
||||
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
public void start() {
|
||||
// nothing to do here.
|
||||
float density = mSwipingItem.itemView.getResources().getDisplayMetrics().density;
|
||||
int maxAmount = Math.max(0, mSwipingItemWidth - (int) (density * MIN_GRABBING_AREA_WIDTH));
|
||||
|
||||
mInitialTranslateAmount = mSwipeManager.getSwipeContainerViewTranslationX(mSwipingItem);
|
||||
mInitialTranslateAmount = Math.min(mInitialTranslateAmount, maxAmount);
|
||||
mInitialTranslateAmount = Math.max(mInitialTranslateAmount, -maxAmount);
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
@@ -67,6 +75,7 @@ class SwipingItemOperator {
|
||||
mLeftSwipeReactionType = REACTION_CAN_NOT_SWIPE;
|
||||
mRightSwipeReactionType = REACTION_CAN_NOT_SWIPE;
|
||||
mPrevTranslateAmount = 0;
|
||||
mInitialTranslateAmount = 0;
|
||||
mSwipingItemContainerView = null;
|
||||
}
|
||||
|
||||
@@ -77,7 +86,9 @@ class SwipingItemOperator {
|
||||
|
||||
mSwipeDistance = swipeDistance;
|
||||
|
||||
final int reactionType = (mSwipeDistance > 0) ? mRightSwipeReactionType : mLeftSwipeReactionType;
|
||||
int distance = mSwipeDistance + mInitialTranslateAmount;
|
||||
|
||||
final int reactionType = (distance > 0) ? mRightSwipeReactionType : mLeftSwipeReactionType;
|
||||
|
||||
float translateAmount = 0;
|
||||
|
||||
@@ -85,15 +96,15 @@ class SwipingItemOperator {
|
||||
case REACTION_CAN_NOT_SWIPE:
|
||||
break;
|
||||
case REACTION_CAN_NOT_SWIPE_WITH_RUBBER_EFFECT:
|
||||
float proportion = Math.min(Math.abs(mSwipeDistance), mSwipingItemWidth) * mInvSwipingItemWidth;
|
||||
translateAmount = Math.signum(mSwipeDistance) * RUBBER_BAND_INTERPOLATOR.getInterpolation(proportion);
|
||||
float proportion = Math.min(Math.abs(distance), mSwipingItemWidth) * mInvSwipingItemWidth;
|
||||
translateAmount = Math.signum(distance) * RUBBER_BAND_INTERPOLATOR.getInterpolation(proportion);
|
||||
break;
|
||||
case REACTION_CAN_SWIPE:
|
||||
translateAmount = Math.min(Math.max((mSwipeDistance * mInvSwipingItemWidth), -1.0f), 1.0f);
|
||||
translateAmount = Math.min(Math.max((distance * mInvSwipingItemWidth), -1.0f), 1.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
mSwipeManager.applySlideItem(mSwipingItem, mPrevTranslateAmount, translateAmount, false);
|
||||
mSwipeManager.applySlideItem(mSwipingItem, mSwipingItemPosition, mPrevTranslateAmount, translateAmount, false);
|
||||
|
||||
mPrevTranslateAmount = translateAmount;
|
||||
}
|
||||
|
||||
Regular → Executable
+47
-2
@@ -22,6 +22,9 @@ import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
/**
|
||||
* Hooks touch events to avoid unexpected scrolling.
|
||||
*/
|
||||
public class RecyclerViewTouchActionGuardManager {
|
||||
private static final String TAG = "ARVTouchActionGuardMgr";
|
||||
|
||||
@@ -37,6 +40,9 @@ public class RecyclerViewTouchActionGuardManager {
|
||||
private boolean mEnabled;
|
||||
private boolean mInterceptScrollingWhileAnimationRunning;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public RecyclerViewTouchActionGuardManager() {
|
||||
mInternalUseOnItemTouchListener = new RecyclerView.OnItemTouchListener() {
|
||||
@Override
|
||||
@@ -48,13 +54,27 @@ public class RecyclerViewTouchActionGuardManager {
|
||||
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
|
||||
RecyclerViewTouchActionGuardManager.this.onTouchEvent(rv, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates this manager instance has released or not.
|
||||
*
|
||||
* @return True if this manager instance has released
|
||||
*/
|
||||
public boolean isReleased() {
|
||||
return (mInternalUseOnItemTouchListener == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches {@link android.support.v7.widget.RecyclerView} instance.
|
||||
*
|
||||
* @param rv The {@link android.support.v7.widget.RecyclerView} instance
|
||||
*/
|
||||
public void attachRecyclerView(RecyclerView rv) {
|
||||
if (rv == null) {
|
||||
throw new IllegalArgumentException("RecyclerView cannot be null");
|
||||
@@ -74,6 +94,11 @@ public class RecyclerViewTouchActionGuardManager {
|
||||
mTouchSlop = ViewConfiguration.get(rv.getContext()).getScaledTouchSlop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach the {@link android.support.v7.widget.RecyclerView} instance and release internal field references.
|
||||
*
|
||||
* This method should be called in order to avoid memory leaks.
|
||||
*/
|
||||
public void release() {
|
||||
if (mRecyclerView != null && mInternalUseOnItemTouchListener != null) {
|
||||
mRecyclerView.removeOnItemTouchListener(mInternalUseOnItemTouchListener);
|
||||
@@ -163,6 +188,11 @@ public class RecyclerViewTouchActionGuardManager {
|
||||
mGuarding = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to use touch guard feature. If set false, all touch event interceptions will be disabled.
|
||||
*
|
||||
* @param enabled enabled / disabled
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (mEnabled == enabled) {
|
||||
return;
|
||||
@@ -174,14 +204,29 @@ public class RecyclerViewTouchActionGuardManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the touch guard feature is enabled.
|
||||
*
|
||||
* @return True for currently touch guard feature is enabled, otherwise false
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
public void setInterceptVerticalScrollingWhileAnimationRunning(boolean value) {
|
||||
mInterceptScrollingWhileAnimationRunning = value;
|
||||
/**
|
||||
* Sets whether to use interception of "vertical scroll while animation running".
|
||||
*
|
||||
* @param enabled enabled / disabled
|
||||
*/
|
||||
public void setInterceptVerticalScrollingWhileAnimationRunning(boolean enabled) {
|
||||
mInterceptScrollingWhileAnimationRunning = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the interception of "vertical scroll while animation running" is enabled.
|
||||
*
|
||||
* @return enabled / disabled
|
||||
*/
|
||||
public boolean isInterceptScrollingWhileAnimationRunning() {
|
||||
return mInterceptScrollingWhileAnimationRunning;
|
||||
}
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+21
@@ -29,6 +29,8 @@ public abstract class AbstractDraggableSwipeableItemViewHolder extends RecyclerV
|
||||
private int mSwipeResult = RecyclerViewSwipeManager.RESULT_NONE;
|
||||
private int mAfterSwipeReaction = RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_DEFAULT;
|
||||
private float mSwipeAmount;
|
||||
private float mMaxLeftSwipeAmount = RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_LEFT;
|
||||
private float mMaxRightSwipeAmount = RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_RIGHT;
|
||||
|
||||
public AbstractDraggableSwipeableItemViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
@@ -84,4 +86,23 @@ public abstract class AbstractDraggableSwipeableItemViewHolder extends RecyclerV
|
||||
mSwipeAmount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxLeftSwipeAmount(float amount) {
|
||||
mMaxLeftSwipeAmount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxLeftSwipeAmount() {
|
||||
return mMaxLeftSwipeAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRightSwipeAmount(float amount) {
|
||||
mMaxRightSwipeAmount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxRightSwipeAmount() {
|
||||
return mMaxRightSwipeAmount;
|
||||
}
|
||||
}
|
||||
Regular → Executable
+18
@@ -85,4 +85,22 @@ public abstract class AbstractExpandableItemAdapter<GVH extends RecyclerView.Vie
|
||||
@Override
|
||||
public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method if need to customize the behavior.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean onHookGroupExpand(int groupPosition, boolean fromUser) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method if need to customize the behavior.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean onHookGroupCollapse(int groupPosition, boolean fromUser) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+21
@@ -27,6 +27,8 @@ public abstract class AbstractSwipeableItemViewHolder extends RecyclerView.ViewH
|
||||
private int mSwipeResult = RecyclerViewSwipeManager.RESULT_NONE;
|
||||
private int mAfterSwipeReaction = RecyclerViewSwipeManager.AFTER_SWIPE_REACTION_DEFAULT;
|
||||
private float mSwipeAmount;
|
||||
private float mMaxLeftSwipeAmount = RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_LEFT;
|
||||
private float mMaxRightSwipeAmount = RecyclerViewSwipeManager.OUTSIDE_OF_THE_WINDOW_RIGHT;
|
||||
|
||||
public AbstractSwipeableItemViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
@@ -72,4 +74,23 @@ public abstract class AbstractSwipeableItemViewHolder extends RecyclerView.ViewH
|
||||
mSwipeAmount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxLeftSwipeAmount(float amount) {
|
||||
mMaxLeftSwipeAmount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxLeftSwipeAmount() {
|
||||
return mMaxLeftSwipeAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRightSwipeAmount(float amount) {
|
||||
mMaxRightSwipeAmount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxRightSwipeAmount() {
|
||||
return mMaxRightSwipeAmount;
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+11
@@ -118,4 +118,15 @@ public class CustomRecyclerViewUtils {
|
||||
return RecyclerView.NO_POSITION;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getSynchronizedPosition(RecyclerView.ViewHolder holder) {
|
||||
int pos1 = holder.getLayoutPosition();
|
||||
int pos2 = holder.getAdapterPosition();
|
||||
if (pos1 == pos2) {
|
||||
return pos1;
|
||||
} else {
|
||||
return RecyclerView.NO_POSITION;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Haruki Hasegawa
|
||||
*
|
||||
* 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.h6ah4i.android.widget.advrecyclerview.utils;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.view.ViewParent;
|
||||
|
||||
public class RecyclerViewAdapterUtils {
|
||||
private RecyclerViewAdapterUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets parent RecyclerView instance.
|
||||
* @param view Child view of the RecyclerView's item
|
||||
* @return Parent RecyclerView instance
|
||||
*/
|
||||
public static RecyclerView getParentRecyclerView(View view) {
|
||||
if (view == null) {
|
||||
return null;
|
||||
}
|
||||
ViewParent parent = view.getParent();
|
||||
if (parent instanceof RecyclerView) {
|
||||
return (RecyclerView) parent;
|
||||
} else if (parent instanceof View) {
|
||||
return getParentRecyclerView((View) parent);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets directly child of RecyclerView (== {@link android.support.v7.widget.RecyclerView.ViewHolder#itemView}})
|
||||
* @param view Child view of the RecyclerView's item
|
||||
* @return Item view
|
||||
*/
|
||||
public static View getParentViewHolderItemView(View view) {
|
||||
if (view == null) {
|
||||
return null;
|
||||
}
|
||||
ViewParent parent = view.getParent();
|
||||
if (parent instanceof RecyclerView) {
|
||||
return view;
|
||||
} else if (parent instanceof View) {
|
||||
return getParentViewHolderItemView((View) parent);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets {@link android.support.v7.widget.RecyclerView.ViewHolder}.
|
||||
* @param view Child view of the RecyclerView's item
|
||||
* @return ViewHolder
|
||||
*/
|
||||
public static RecyclerView.ViewHolder getViewHolder(View view) {
|
||||
RecyclerView rv = getParentRecyclerView(view);
|
||||
View rvChild = getParentViewHolderItemView(view);
|
||||
|
||||
if (rv != null && rvChild != null) {
|
||||
return rv.getChildViewHolder(rvChild);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/google-android-support-v4"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1 @@
|
||||
/bin/
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>google-android-support-v13</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,101 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
|
||||
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
|
||||
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
|
||||
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deadCode=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
+7
-5
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2014 The Android Open Source Project
|
||||
<!--
|
||||
Copyright (C) 2014 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.
|
||||
@@ -13,10 +14,11 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android.support.v13" >
|
||||
|
||||
<resources>
|
||||
<uses-sdk android:minSdkVersion="13" />
|
||||
|
||||
<!-- Since SwitchCompat can use optical insets on v18+, reset the manual padding -->
|
||||
<dimen name="abc_switch_padding">0px</dimen>
|
||||
<application />
|
||||
|
||||
</resources>
|
||||
</manifest>
|
||||
@@ -0,0 +1,15 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-22
|
||||
android.library=true
|
||||
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 android.support.v13.app;
|
||||
|
||||
import android.app.Fragment;
|
||||
|
||||
/**
|
||||
* Helper for accessing features in {@link Fragment} introduced after
|
||||
* API level 13 in a backwards compatible fashion.
|
||||
*/
|
||||
public class FragmentCompat {
|
||||
interface FragmentCompatImpl {
|
||||
void setMenuVisibility(Fragment f, boolean visible);
|
||||
void setUserVisibleHint(Fragment f, boolean deferStart);
|
||||
}
|
||||
|
||||
static class BaseFragmentCompatImpl implements FragmentCompatImpl {
|
||||
public void setMenuVisibility(Fragment f, boolean visible) {
|
||||
}
|
||||
public void setUserVisibleHint(Fragment f, boolean deferStart) {
|
||||
}
|
||||
}
|
||||
|
||||
static class ICSFragmentCompatImpl extends BaseFragmentCompatImpl {
|
||||
@Override
|
||||
public void setMenuVisibility(Fragment f, boolean visible) {
|
||||
FragmentCompatICS.setMenuVisibility(f, visible);
|
||||
}
|
||||
}
|
||||
|
||||
static class ICSMR1FragmentCompatImpl extends ICSFragmentCompatImpl {
|
||||
@Override
|
||||
public void setUserVisibleHint(Fragment f, boolean deferStart) {
|
||||
FragmentCompatICSMR1.setUserVisibleHint(f, deferStart);
|
||||
}
|
||||
}
|
||||
|
||||
static final FragmentCompatImpl IMPL;
|
||||
static {
|
||||
if (android.os.Build.VERSION.SDK_INT >= 15) {
|
||||
IMPL = new ICSMR1FragmentCompatImpl();
|
||||
} else if (android.os.Build.VERSION.SDK_INT >= 14) {
|
||||
IMPL = new ICSFragmentCompatImpl();
|
||||
} else {
|
||||
IMPL = new BaseFragmentCompatImpl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link Fragment#setMenuVisibility(boolean) Fragment.setMenuVisibility(boolean)}
|
||||
* if running on an appropriate version of the platform.
|
||||
*/
|
||||
public static void setMenuVisibility(Fragment f, boolean visible) {
|
||||
IMPL.setMenuVisibility(f, visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link Fragment#setUserVisibleHint(boolean) setUserVisibleHint(boolean)}
|
||||
* if running on an appropriate version of the platform.
|
||||
*/
|
||||
public static void setUserVisibleHint(Fragment f, boolean deferStart) {
|
||||
IMPL.setUserVisibleHint(f, deferStart);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 android.support.v13.app;
|
||||
|
||||
import android.app.Fragment;
|
||||
|
||||
class FragmentCompatICS {
|
||||
public static void setMenuVisibility(Fragment f, boolean visible) {
|
||||
f.setMenuVisibility(visible);
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 android.support.v13.app;
|
||||
|
||||
import android.app.Fragment;
|
||||
|
||||
class FragmentCompatICSMR1 {
|
||||
public static void setUserVisibleHint(Fragment f, boolean isVisible) {
|
||||
f.setUserVisibleHint(isVisible);
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 android.support.v13.app;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Implementation of {@link android.support.v4.view.PagerAdapter} that
|
||||
* represents each page as a {@link android.app.Fragment} that is persistently
|
||||
* kept in the fragment manager as long as the user can return to the page.
|
||||
*
|
||||
* <p>This version of the pager is best for use when there are a handful of
|
||||
* typically more static fragments to be paged through, such as a set of tabs.
|
||||
* The fragment of each page the user visits will be kept in memory, though its
|
||||
* view hierarchy may be destroyed when not visible. This can result in using
|
||||
* a significant amount of memory since fragment instances can hold on to an
|
||||
* arbitrary amount of state. For larger sets of pages, consider
|
||||
* {@link FragmentStatePagerAdapter}.
|
||||
*
|
||||
* <p>When using FragmentPagerAdapter the host ViewPager must have a
|
||||
* valid ID set.</p>
|
||||
*
|
||||
* <p>Subclasses only need to implement {@link #getItem(int)}
|
||||
* and {@link #getCount()} to have a working adapter.
|
||||
*
|
||||
* <p>Here is an example implementation of a pager containing fragments of
|
||||
* lists:
|
||||
*
|
||||
* {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/FragmentPagerSupport.java
|
||||
* complete}
|
||||
*
|
||||
* <p>The <code>R.layout.fragment_pager</code> resource of the top-level fragment is:
|
||||
*
|
||||
* {@sample development/samples/Support13Demos/res/layout/fragment_pager.xml
|
||||
* complete}
|
||||
*
|
||||
* <p>The <code>R.layout.fragment_pager_list</code> resource containing each
|
||||
* individual fragment's layout is:
|
||||
*
|
||||
* {@sample development/samples/Support13Demos/res/layout/fragment_pager_list.xml
|
||||
* complete}
|
||||
*/
|
||||
public abstract class FragmentPagerAdapter extends PagerAdapter {
|
||||
private static final String TAG = "FragmentPagerAdapter";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final FragmentManager mFragmentManager;
|
||||
private FragmentTransaction mCurTransaction = null;
|
||||
private Fragment mCurrentPrimaryItem = null;
|
||||
|
||||
public FragmentPagerAdapter(FragmentManager fm) {
|
||||
mFragmentManager = fm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Fragment associated with a specified position.
|
||||
*/
|
||||
public abstract Fragment getItem(int position);
|
||||
|
||||
@Override
|
||||
public void startUpdate(ViewGroup container) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
if (mCurTransaction == null) {
|
||||
mCurTransaction = mFragmentManager.beginTransaction();
|
||||
}
|
||||
|
||||
final long itemId = getItemId(position);
|
||||
|
||||
// Do we already have this fragment?
|
||||
String name = makeFragmentName(container.getId(), itemId);
|
||||
Fragment fragment = mFragmentManager.findFragmentByTag(name);
|
||||
if (fragment != null) {
|
||||
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
|
||||
mCurTransaction.attach(fragment);
|
||||
} else {
|
||||
fragment = getItem(position);
|
||||
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
|
||||
mCurTransaction.add(container.getId(), fragment,
|
||||
makeFragmentName(container.getId(), itemId));
|
||||
}
|
||||
if (fragment != mCurrentPrimaryItem) {
|
||||
FragmentCompat.setMenuVisibility(fragment, false);
|
||||
FragmentCompat.setUserVisibleHint(fragment, false);
|
||||
}
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
if (mCurTransaction == null) {
|
||||
mCurTransaction = mFragmentManager.beginTransaction();
|
||||
}
|
||||
if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
|
||||
+ " v=" + ((Fragment)object).getView());
|
||||
mCurTransaction.detach((Fragment)object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryItem(ViewGroup container, int position, Object object) {
|
||||
Fragment fragment = (Fragment)object;
|
||||
if (fragment != mCurrentPrimaryItem) {
|
||||
if (mCurrentPrimaryItem != null) {
|
||||
FragmentCompat.setMenuVisibility(mCurrentPrimaryItem, false);
|
||||
FragmentCompat.setUserVisibleHint(mCurrentPrimaryItem, false);
|
||||
}
|
||||
if (fragment != null) {
|
||||
FragmentCompat.setMenuVisibility(fragment, true);
|
||||
FragmentCompat.setUserVisibleHint(fragment, true);
|
||||
}
|
||||
mCurrentPrimaryItem = fragment;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishUpdate(ViewGroup container) {
|
||||
if (mCurTransaction != null) {
|
||||
mCurTransaction.commitAllowingStateLoss();
|
||||
mCurTransaction = null;
|
||||
mFragmentManager.executePendingTransactions();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
return ((Fragment)object).getView() == view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable saveState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState(Parcelable state, ClassLoader loader) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a unique identifier for the item at the given position.
|
||||
*
|
||||
* <p>The default implementation returns the given position.
|
||||
* Subclasses should override this method if the positions of items can change.</p>
|
||||
*
|
||||
* @param position Position within this adapter
|
||||
* @return Unique identifier for the item at position
|
||||
*/
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
private static String makeFragmentName(int viewId, long id) {
|
||||
return "android:switcher:" + viewId + ":" + id;
|
||||
}
|
||||
}
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 android.support.v13.app;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Implementation of {@link android.support.v4.view.PagerAdapter} that
|
||||
* uses a {@link Fragment} to manage each page. This class also handles
|
||||
* saving and restoring of fragment's state.
|
||||
*
|
||||
* <p>This version of the pager is more useful when there are a large number
|
||||
* of pages, working more like a list view. When pages are not visible to
|
||||
* the user, their entire fragment may be destroyed, only keeping the saved
|
||||
* state of that fragment. This allows the pager to hold on to much less
|
||||
* memory associated with each visited page as compared to
|
||||
* {@link FragmentPagerAdapter} at the cost of potentially more overhead when
|
||||
* switching between pages.
|
||||
*
|
||||
* <p>When using FragmentPagerAdapter the host ViewPager must have a
|
||||
* valid ID set.</p>
|
||||
*
|
||||
* <p>Subclasses only need to implement {@link #getItem(int)}
|
||||
* and {@link #getCount()} to have a working adapter.
|
||||
*
|
||||
* <p>Here is an example implementation of a pager containing fragments of
|
||||
* lists:
|
||||
*
|
||||
* {@sample development/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentStatePagerSupport.java
|
||||
* complete}
|
||||
*
|
||||
* <p>The <code>R.layout.fragment_pager</code> resource of the top-level fragment is:
|
||||
*
|
||||
* {@sample development/samples/Support4Demos/res/layout/fragment_pager.xml
|
||||
* complete}
|
||||
*
|
||||
* <p>The <code>R.layout.fragment_pager_list</code> resource containing each
|
||||
* individual fragment's layout is:
|
||||
*
|
||||
* {@sample development/samples/Support4Demos/res/layout/fragment_pager_list.xml
|
||||
* complete}
|
||||
*/
|
||||
public abstract class FragmentStatePagerAdapter extends PagerAdapter {
|
||||
private static final String TAG = "FragmentStatePagerAdapter";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final FragmentManager mFragmentManager;
|
||||
private FragmentTransaction mCurTransaction = null;
|
||||
|
||||
private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
|
||||
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
|
||||
private Fragment mCurrentPrimaryItem = null;
|
||||
|
||||
public FragmentStatePagerAdapter(FragmentManager fm) {
|
||||
mFragmentManager = fm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Fragment associated with a specified position.
|
||||
*/
|
||||
public abstract Fragment getItem(int position);
|
||||
|
||||
@Override
|
||||
public void startUpdate(ViewGroup container) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
// If we already have this item instantiated, there is nothing
|
||||
// to do. This can happen when we are restoring the entire pager
|
||||
// from its saved state, where the fragment manager has already
|
||||
// taken care of restoring the fragments we previously had instantiated.
|
||||
if (mFragments.size() > position) {
|
||||
Fragment f = mFragments.get(position);
|
||||
if (f != null) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
if (mCurTransaction == null) {
|
||||
mCurTransaction = mFragmentManager.beginTransaction();
|
||||
}
|
||||
|
||||
Fragment fragment = getItem(position);
|
||||
if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
|
||||
if (mSavedState.size() > position) {
|
||||
Fragment.SavedState fss = mSavedState.get(position);
|
||||
if (fss != null) {
|
||||
fragment.setInitialSavedState(fss);
|
||||
}
|
||||
}
|
||||
while (mFragments.size() <= position) {
|
||||
mFragments.add(null);
|
||||
}
|
||||
FragmentCompat.setMenuVisibility(fragment, false);
|
||||
FragmentCompat.setUserVisibleHint(fragment, false);
|
||||
mFragments.set(position, fragment);
|
||||
mCurTransaction.add(container.getId(), fragment);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
Fragment fragment = (Fragment)object;
|
||||
|
||||
if (mCurTransaction == null) {
|
||||
mCurTransaction = mFragmentManager.beginTransaction();
|
||||
}
|
||||
if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
|
||||
+ " v=" + ((Fragment)object).getView());
|
||||
while (mSavedState.size() <= position) {
|
||||
mSavedState.add(null);
|
||||
}
|
||||
mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
|
||||
mFragments.set(position, null);
|
||||
|
||||
mCurTransaction.remove(fragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryItem(ViewGroup container, int position, Object object) {
|
||||
Fragment fragment = (Fragment)object;
|
||||
if (fragment != mCurrentPrimaryItem) {
|
||||
if (mCurrentPrimaryItem != null) {
|
||||
FragmentCompat.setMenuVisibility(mCurrentPrimaryItem, false);
|
||||
FragmentCompat.setUserVisibleHint(mCurrentPrimaryItem, false);
|
||||
}
|
||||
if (fragment != null) {
|
||||
FragmentCompat.setMenuVisibility(fragment, true);
|
||||
FragmentCompat.setUserVisibleHint(fragment, true);
|
||||
}
|
||||
mCurrentPrimaryItem = fragment;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishUpdate(ViewGroup container) {
|
||||
if (mCurTransaction != null) {
|
||||
mCurTransaction.commitAllowingStateLoss();
|
||||
mCurTransaction = null;
|
||||
mFragmentManager.executePendingTransactions();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
return ((Fragment)object).getView() == view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable saveState() {
|
||||
Bundle state = null;
|
||||
if (mSavedState.size() > 0) {
|
||||
state = new Bundle();
|
||||
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
|
||||
mSavedState.toArray(fss);
|
||||
state.putParcelableArray("states", fss);
|
||||
}
|
||||
for (int i=0; i<mFragments.size(); i++) {
|
||||
Fragment f = mFragments.get(i);
|
||||
if (f != null && f.isAdded()) {
|
||||
if (state == null) {
|
||||
state = new Bundle();
|
||||
}
|
||||
String key = "f" + i;
|
||||
mFragmentManager.putFragment(state, key, f);
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState(Parcelable state, ClassLoader loader) {
|
||||
if (state != null) {
|
||||
Bundle bundle = (Bundle)state;
|
||||
bundle.setClassLoader(loader);
|
||||
Parcelable[] fss = bundle.getParcelableArray("states");
|
||||
mSavedState.clear();
|
||||
mFragments.clear();
|
||||
if (fss != null) {
|
||||
for (int i=0; i<fss.length; i++) {
|
||||
mSavedState.add((Fragment.SavedState)fss[i]);
|
||||
}
|
||||
}
|
||||
Iterable<String> keys = bundle.keySet();
|
||||
for (String key: keys) {
|
||||
if (key.startsWith("f")) {
|
||||
int index = Integer.parseInt(key.substring(1));
|
||||
Fragment f = mFragmentManager.getFragment(bundle, key);
|
||||
if (f != null) {
|
||||
while (mFragments.size() <= index) {
|
||||
mFragments.add(null);
|
||||
}
|
||||
FragmentCompat.setMenuVisibility(f, false);
|
||||
mFragments.set(index, f);
|
||||
} else {
|
||||
Log.w(TAG, "Bad fragment at key " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 android.support.v13.app;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TabHost;
|
||||
import android.widget.TabWidget;
|
||||
|
||||
/**
|
||||
* Version of {@link android.support.v4.app.FragmentTabHost} that can be
|
||||
* used with the platform {@link android.app.Fragment} APIs. You will not
|
||||
* normally use this, instead using action bar tabs.
|
||||
*/
|
||||
public class FragmentTabHost extends TabHost
|
||||
implements TabHost.OnTabChangeListener {
|
||||
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
|
||||
private FrameLayout mRealTabContent;
|
||||
private Context mContext;
|
||||
private FragmentManager mFragmentManager;
|
||||
private int mContainerId;
|
||||
private TabHost.OnTabChangeListener mOnTabChangeListener;
|
||||
private TabInfo mLastTab;
|
||||
private boolean mAttached;
|
||||
|
||||
static final class TabInfo {
|
||||
private final String tag;
|
||||
private final Class<?> clss;
|
||||
private final Bundle args;
|
||||
private Fragment fragment;
|
||||
|
||||
TabInfo(String _tag, Class<?> _class, Bundle _args) {
|
||||
tag = _tag;
|
||||
clss = _class;
|
||||
args = _args;
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyTabFactory implements TabHost.TabContentFactory {
|
||||
private final Context mContext;
|
||||
|
||||
public DummyTabFactory(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View createTabContent(String tag) {
|
||||
View v = new View(mContext);
|
||||
v.setMinimumWidth(0);
|
||||
v.setMinimumHeight(0);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
static class SavedState extends BaseSavedState {
|
||||
String curTab;
|
||||
|
||||
SavedState(Parcelable superState) {
|
||||
super(superState);
|
||||
}
|
||||
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
curTab = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeString(curTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FragmentTabHost.SavedState{"
|
||||
+ Integer.toHexString(System.identityHashCode(this))
|
||||
+ " curTab=" + curTab + "}";
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public FragmentTabHost(Context context) {
|
||||
// Note that we call through to the version that takes an AttributeSet,
|
||||
// because the simple Context construct can result in a broken object!
|
||||
super(context, null);
|
||||
initFragmentTabHost(context, null);
|
||||
}
|
||||
|
||||
public FragmentTabHost(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initFragmentTabHost(context, attrs);
|
||||
}
|
||||
|
||||
private void initFragmentTabHost(Context context, AttributeSet attrs) {
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
new int[] { android.R.attr.inflatedId }, 0, 0);
|
||||
mContainerId = a.getResourceId(0, 0);
|
||||
a.recycle();
|
||||
|
||||
super.setOnTabChangedListener(this);
|
||||
}
|
||||
|
||||
private void ensureHierarchy(Context context) {
|
||||
// If owner hasn't made its own view hierarchy, then as a convenience
|
||||
// we will construct a standard one here.
|
||||
if (findViewById(android.R.id.tabs) == null) {
|
||||
LinearLayout ll = new LinearLayout(context);
|
||||
ll.setOrientation(LinearLayout.VERTICAL);
|
||||
addView(ll, new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.FILL_PARENT));
|
||||
|
||||
TabWidget tw = new TabWidget(context);
|
||||
tw.setId(android.R.id.tabs);
|
||||
tw.setOrientation(TabWidget.HORIZONTAL);
|
||||
ll.addView(tw, new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, 0));
|
||||
|
||||
FrameLayout fl = new FrameLayout(context);
|
||||
fl.setId(android.R.id.tabcontent);
|
||||
ll.addView(fl, new LinearLayout.LayoutParams(0, 0, 0));
|
||||
|
||||
mRealTabContent = fl = new FrameLayout(context);
|
||||
mRealTabContent.setId(mContainerId);
|
||||
ll.addView(fl, new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.FILL_PARENT, 0, 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Don't call the original TabHost setup, you must instead
|
||||
* call {@link #setup(Context, FragmentManager)} or
|
||||
* {@link #setup(Context, FragmentManager, int)}.
|
||||
*/
|
||||
@Override @Deprecated
|
||||
public void setup() {
|
||||
throw new IllegalStateException(
|
||||
"Must call setup() that takes a Context and FragmentManager");
|
||||
}
|
||||
|
||||
public void setup(Context context, FragmentManager manager) {
|
||||
ensureHierarchy(context); // Ensure views required by super.setup()
|
||||
super.setup();
|
||||
mContext = context;
|
||||
mFragmentManager = manager;
|
||||
ensureContent();
|
||||
}
|
||||
|
||||
public void setup(Context context, FragmentManager manager, int containerId) {
|
||||
ensureHierarchy(context); // Ensure views required by super.setup()
|
||||
super.setup();
|
||||
mContext = context;
|
||||
mFragmentManager = manager;
|
||||
mContainerId = containerId;
|
||||
ensureContent();
|
||||
mRealTabContent.setId(containerId);
|
||||
|
||||
// We must have an ID to be able to save/restore our state. If
|
||||
// the owner hasn't set one at this point, we will set it ourself.
|
||||
if (getId() == View.NO_ID) {
|
||||
setId(android.R.id.tabhost);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureContent() {
|
||||
if (mRealTabContent == null) {
|
||||
mRealTabContent = (FrameLayout)findViewById(mContainerId);
|
||||
if (mRealTabContent == null) {
|
||||
throw new IllegalStateException(
|
||||
"No tab content FrameLayout found for id " + mContainerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnTabChangedListener(OnTabChangeListener l) {
|
||||
mOnTabChangeListener = l;
|
||||
}
|
||||
|
||||
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
|
||||
tabSpec.setContent(new DummyTabFactory(mContext));
|
||||
String tag = tabSpec.getTag();
|
||||
|
||||
TabInfo info = new TabInfo(tag, clss, args);
|
||||
|
||||
if (mAttached) {
|
||||
// If we are already attached to the window, then check to make
|
||||
// sure this tab's fragment is inactive if it exists. This shouldn't
|
||||
// normally happen.
|
||||
info.fragment = mFragmentManager.findFragmentByTag(tag);
|
||||
if (info.fragment != null && !info.fragment.isDetached()) {
|
||||
FragmentTransaction ft = mFragmentManager.beginTransaction();
|
||||
ft.detach(info.fragment);
|
||||
ft.commit();
|
||||
}
|
||||
}
|
||||
|
||||
mTabs.add(info);
|
||||
addTab(tabSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
String currentTab = getCurrentTabTag();
|
||||
|
||||
// Go through all tabs and make sure their fragments match
|
||||
// the correct state.
|
||||
FragmentTransaction ft = null;
|
||||
for (int i=0; i<mTabs.size(); i++) {
|
||||
TabInfo tab = mTabs.get(i);
|
||||
tab.fragment = mFragmentManager.findFragmentByTag(tab.tag);
|
||||
if (tab.fragment != null && !tab.fragment.isDetached()) {
|
||||
if (tab.tag.equals(currentTab)) {
|
||||
// The fragment for this tab is already there and
|
||||
// active, and it is what we really want to have
|
||||
// as the current tab. Nothing to do.
|
||||
mLastTab = tab;
|
||||
} else {
|
||||
// This fragment was restored in the active state,
|
||||
// but is not the current tab. Deactivate it.
|
||||
if (ft == null) {
|
||||
ft = mFragmentManager.beginTransaction();
|
||||
}
|
||||
ft.detach(tab.fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are now ready to go. Make sure we are switched to the
|
||||
// correct tab.
|
||||
mAttached = true;
|
||||
ft = doTabChanged(currentTab, ft);
|
||||
if (ft != null) {
|
||||
ft.commit();
|
||||
mFragmentManager.executePendingTransactions();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mAttached = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
SavedState ss = new SavedState(superState);
|
||||
ss.curTab = getCurrentTabTag();
|
||||
return ss;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState ss = (SavedState)state;
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
setCurrentTabByTag(ss.curTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabChanged(String tabId) {
|
||||
if (mAttached) {
|
||||
FragmentTransaction ft = doTabChanged(tabId, null);
|
||||
if (ft != null) {
|
||||
ft.commit();
|
||||
}
|
||||
}
|
||||
if (mOnTabChangeListener != null) {
|
||||
mOnTabChangeListener.onTabChanged(tabId);
|
||||
}
|
||||
}
|
||||
|
||||
private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
|
||||
TabInfo newTab = null;
|
||||
for (int i=0; i<mTabs.size(); i++) {
|
||||
TabInfo tab = mTabs.get(i);
|
||||
if (tab.tag.equals(tabId)) {
|
||||
newTab = tab;
|
||||
}
|
||||
}
|
||||
if (newTab == null) {
|
||||
throw new IllegalStateException("No tab known for tag " + tabId);
|
||||
}
|
||||
if (mLastTab != newTab) {
|
||||
if (ft == null) {
|
||||
ft = mFragmentManager.beginTransaction();
|
||||
}
|
||||
if (mLastTab != null) {
|
||||
if (mLastTab.fragment != null) {
|
||||
ft.detach(mLastTab.fragment);
|
||||
}
|
||||
}
|
||||
if (newTab != null) {
|
||||
if (newTab.fragment == null) {
|
||||
newTab.fragment = Fragment.instantiate(mContext,
|
||||
newTab.clss.getName(), newTab.args);
|
||||
ft.add(mContainerId, newTab.fragment, newTab.tag);
|
||||
} else {
|
||||
ft.attach(newTab.fragment);
|
||||
}
|
||||
}
|
||||
|
||||
mLastTab = newTab;
|
||||
}
|
||||
return ft;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<body>
|
||||
|
||||
Support classes to access some of the android.app package features introduced after API level 13 in a backwards compatible fashion.
|
||||
|
||||
</body>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="var" path="ANDROID_HOME/extras/android/m2repository/com/android/support/support-annotations/22.2.1/support-annotations-22.2.1.jar"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1 @@
|
||||
/bin/
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>google-android-support-v4</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,101 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
|
||||
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
|
||||
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
|
||||
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deadCode=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=ignore
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
||||
+7
-4
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2014 The Android Open Source Project
|
||||
<!--
|
||||
Copyright (C) 2014 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.
|
||||
@@ -13,9 +14,11 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android.support.v4" >
|
||||
|
||||
<resources>
|
||||
<uses-sdk android:minSdkVersion="4" />
|
||||
|
||||
<bool name="abc_action_bar_embed_tabs">false</bool>
|
||||
<application />
|
||||
|
||||
</resources>
|
||||
</manifest>
|
||||
+4
-11
@@ -1,7 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
** Copyright 2012, The Android Open Source Project
|
||||
/* Copyright 2014, 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.
|
||||
@@ -15,11 +12,7 @@
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!-- These resources are around just to allow their values to be customized
|
||||
for different hardware and product builds. -->
|
||||
<resources>
|
||||
<!-- see comment in values/config.xml -->
|
||||
<dimen name="abc_config_prefDialogWidth">580dp</dimen>
|
||||
</resources>
|
||||
package android.support.v4.media;
|
||||
|
||||
parcelable MediaMetadataCompat;
|
||||
@@ -0,0 +1,18 @@
|
||||
/* Copyright 2014, 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 android.support.v4.media;
|
||||
|
||||
parcelable RatingCompat;
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/* Copyright 2014, 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 android.support.v4.media.session;
|
||||
|
||||
parcelable MediaSessionCompat.Token;
|
||||
parcelable MediaSessionCompat.QueueItem;
|
||||
parcelable MediaSessionCompat.ResultReceiverWrapper;
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/* Copyright 2014, 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 android.support.v4.media.session;
|
||||
|
||||
parcelable ParcelableVolumeInfo;
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/* Copyright 2014, 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 android.support.v4.media.session;
|
||||
|
||||
parcelable PlaybackStateCompat;
|
||||
@@ -0,0 +1,15 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-22
|
||||
android.library=true
|
||||
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
+451
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 android.support.v4.accessibilityservice;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Helper for accessing features in {@link android.accessibilityservice.AccessibilityService}
|
||||
* introduced after API level 4 in a backwards compatible fashion.
|
||||
*/
|
||||
public class AccessibilityServiceInfoCompat {
|
||||
|
||||
static interface AccessibilityServiceInfoVersionImpl {
|
||||
public String getId(AccessibilityServiceInfo info);
|
||||
public ResolveInfo getResolveInfo(AccessibilityServiceInfo info);
|
||||
public boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info);
|
||||
public String getDescription(AccessibilityServiceInfo info);
|
||||
public String getSettingsActivityName(AccessibilityServiceInfo info);
|
||||
public int getCapabilities(AccessibilityServiceInfo info);
|
||||
}
|
||||
|
||||
static class AccessibilityServiceInfoStubImpl implements AccessibilityServiceInfoVersionImpl {
|
||||
|
||||
public boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getDescription(AccessibilityServiceInfo info) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getId(AccessibilityServiceInfo info) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ResolveInfo getResolveInfo(AccessibilityServiceInfo info) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getSettingsActivityName(AccessibilityServiceInfo info) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCapabilities(AccessibilityServiceInfo info) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static class AccessibilityServiceInfoIcsImpl extends AccessibilityServiceInfoStubImpl {
|
||||
|
||||
@Override
|
||||
public boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) {
|
||||
return AccessibilityServiceInfoCompatIcs.getCanRetrieveWindowContent(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(AccessibilityServiceInfo info) {
|
||||
return AccessibilityServiceInfoCompatIcs.getDescription(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId(AccessibilityServiceInfo info) {
|
||||
return AccessibilityServiceInfoCompatIcs.getId(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolveInfo getResolveInfo(AccessibilityServiceInfo info) {
|
||||
return AccessibilityServiceInfoCompatIcs.getResolveInfo(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSettingsActivityName(AccessibilityServiceInfo info) {
|
||||
return AccessibilityServiceInfoCompatIcs.getSettingsActivityName(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCapabilities(AccessibilityServiceInfo info) {
|
||||
if (getCanRetrieveWindowContent(info)) {
|
||||
return CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static class AccessibilityServiceInfoJellyBeanMr2 extends AccessibilityServiceInfoIcsImpl {
|
||||
@Override
|
||||
public int getCapabilities(AccessibilityServiceInfo info) {
|
||||
return AccessibilityServiceInfoCompatJellyBeanMr2.getCapabilities(info);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
if (Build.VERSION.SDK_INT >= 18) { // JellyBean MR2
|
||||
IMPL = new AccessibilityServiceInfoJellyBeanMr2();
|
||||
} else if (Build.VERSION.SDK_INT >= 14) { // ICS
|
||||
IMPL = new AccessibilityServiceInfoIcsImpl();
|
||||
} else {
|
||||
IMPL = new AccessibilityServiceInfoStubImpl();
|
||||
}
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
|
||||
private static final AccessibilityServiceInfoVersionImpl IMPL;
|
||||
|
||||
/**
|
||||
* Capability: This accessibility service can retrieve the active window content.
|
||||
*/
|
||||
public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001;
|
||||
|
||||
/**
|
||||
* Capability: This accessibility service can request touch exploration mode in which
|
||||
* touched items are spoken aloud and the UI can be explored via gestures.
|
||||
*/
|
||||
public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;
|
||||
|
||||
/**
|
||||
* Capability: This accessibility service can request enhanced web accessibility
|
||||
* enhancements. For example, installing scripts to make app content more accessible.
|
||||
*/
|
||||
public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
|
||||
|
||||
/**
|
||||
* Capability: This accessibility service can filter the key event stream.
|
||||
*/
|
||||
public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 0x00000008;
|
||||
|
||||
// Feedback types
|
||||
|
||||
/**
|
||||
* Denotes braille feedback.
|
||||
*/
|
||||
public static final int FEEDBACK_BRAILLE = 0x0000020;
|
||||
|
||||
/**
|
||||
* Mask for all feedback types.
|
||||
*
|
||||
* @see AccessibilityServiceInfo#FEEDBACK_SPOKEN
|
||||
* @see AccessibilityServiceInfo#FEEDBACK_HAPTIC
|
||||
* @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE
|
||||
* @see AccessibilityServiceInfo#FEEDBACK_VISUAL
|
||||
* @see AccessibilityServiceInfo#FEEDBACK_GENERIC
|
||||
* @see FEEDBACK_BRAILLE
|
||||
*/
|
||||
public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF;
|
||||
|
||||
// Flags
|
||||
|
||||
/**
|
||||
* If an {@link AccessibilityService} is the default for a given type.
|
||||
* Default service is invoked only if no package specific one exists. In case of
|
||||
* more than one package specific service only the earlier registered is notified.
|
||||
*/
|
||||
public static final int DEFAULT = 0x0000001;
|
||||
|
||||
/**
|
||||
* If this flag is set the system will regard views that are not important
|
||||
* for accessibility in addition to the ones that are important for accessibility.
|
||||
* That is, views that are marked as not important for accessibility via
|
||||
* {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO} or
|
||||
* {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS} and views that are
|
||||
* marked as potentially important for accessibility via
|
||||
* {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined
|
||||
* that are not important for accessibility, are both reported while querying the
|
||||
* window content and also the accessibility service will receive accessibility events
|
||||
* from them.
|
||||
* <p>
|
||||
* <strong>Note:</strong> For accessibility services targeting API version
|
||||
* {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly
|
||||
* set for the system to regard views that are not important for accessibility. For
|
||||
* accessibility services targeting API version lower than
|
||||
* {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are
|
||||
* regarded for accessibility purposes.
|
||||
* </p>
|
||||
* <p>
|
||||
* Usually views not important for accessibility are layout managers that do not
|
||||
* react to user actions, do not draw any content, and do not have any special
|
||||
* semantics in the context of the screen content. For example, a three by three
|
||||
* grid can be implemented as three horizontal linear layouts and one vertical,
|
||||
* or three vertical linear layouts and one horizontal, or one grid layout, etc.
|
||||
* In this context the actual layout mangers used to achieve the grid configuration
|
||||
* are not important, rather it is important that there are nine evenly distributed
|
||||
* elements.
|
||||
* </p>
|
||||
*/
|
||||
public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002;
|
||||
|
||||
/**
|
||||
* This flag requests that the system gets into touch exploration mode.
|
||||
* In this mode a single finger moving on the screen behaves as a mouse
|
||||
* pointer hovering over the user interface. The system will also detect
|
||||
* certain gestures performed on the touch screen and notify this service.
|
||||
* The system will enable touch exploration mode if there is at least one
|
||||
* accessibility service that has this flag set. Hence, clearing this
|
||||
* flag does not guarantee that the device will not be in touch exploration
|
||||
* mode since there may be another enabled service that requested it.
|
||||
* <p>
|
||||
* For accessibility services targeting API version higher than
|
||||
* {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
|
||||
* this flag have to declare this capability in their meta-data by setting
|
||||
* the attribute canRequestTouchExplorationMode to true, otherwise this flag
|
||||
* will be ignored. For how to declare the meta-data of a service refer to
|
||||
* {@value AccessibilityService#SERVICE_META_DATA}.
|
||||
* </p>
|
||||
* <p>
|
||||
* Services targeting API version equal to or lower than
|
||||
* {@link Build.VERSION_CODES#JELLY_BEAN_MR1} will work normally, i.e.
|
||||
* the first time they are run, if this flag is specified, a dialog is
|
||||
* shown to the user to confirm enabling explore by touch.
|
||||
* </p>
|
||||
*/
|
||||
public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004;
|
||||
|
||||
/**
|
||||
* This flag requests from the system to enable web accessibility enhancing
|
||||
* extensions. Such extensions aim to provide improved accessibility support
|
||||
* for content presented in a {@link android.webkit.WebView}. An example of such
|
||||
* an extension is injecting JavaScript from a secure source. The system will enable
|
||||
* enhanced web accessibility if there is at least one accessibility service
|
||||
* that has this flag set. Hence, clearing this flag does not guarantee that the
|
||||
* device will not have enhanced web accessibility enabled since there may be
|
||||
* another enabled service that requested it.
|
||||
* <p>
|
||||
* Services that want to set this flag have to declare this capability
|
||||
* in their meta-data by setting the attribute canRequestEnhancedWebAccessibility
|
||||
* to true, otherwise this flag will be ignored. For how to declare the meta-data
|
||||
* of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
|
||||
* </p>
|
||||
*/
|
||||
public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
|
||||
|
||||
/**
|
||||
* This flag requests that the AccessibilityNodeInfos obtained
|
||||
* by an {@link AccessibilityService} contain the id of the source view.
|
||||
* The source view id will be a fully qualified resource name of the
|
||||
* form "package:id/name", for example "foo.bar:id/my_list", and it is
|
||||
* useful for UI test automation. This flag is not set by default.
|
||||
*/
|
||||
public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
|
||||
|
||||
/**
|
||||
* This flag requests from the system to filter key events. If this flag
|
||||
* is set the accessibility service will receive the key events before
|
||||
* applications allowing it implement global shortcuts. Setting this flag
|
||||
* does not guarantee that this service will filter key events since only
|
||||
* one service can do so at any given time. This avoids user confusion due
|
||||
* to behavior change in case different key filtering services are enabled.
|
||||
* If there is already another key filtering service enabled, this one will
|
||||
* not receive key events.
|
||||
* <p>
|
||||
* Services that want to set this flag have to declare this capability
|
||||
* in their meta-data by setting the attribute canRequestFilterKeyEvents
|
||||
* to true, otherwise this flag will be ignored. For how to declare the meta
|
||||
* -data of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
|
||||
* </p>
|
||||
*/
|
||||
public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
|
||||
|
||||
/*
|
||||
* Hide constructor
|
||||
*/
|
||||
private AccessibilityServiceInfoCompat() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The accessibility service id.
|
||||
* <p>
|
||||
* <strong>Generated by the system.</strong>
|
||||
* </p>
|
||||
*
|
||||
* @return The id.
|
||||
*/
|
||||
public static String getId(AccessibilityServiceInfo info) {
|
||||
return IMPL.getId(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* The service {@link ResolveInfo}.
|
||||
* <p>
|
||||
* <strong>Generated by the system.</strong>
|
||||
* </p>
|
||||
*
|
||||
* @return The info.
|
||||
*/
|
||||
public static ResolveInfo getResolveInfo(AccessibilityServiceInfo info) {
|
||||
return IMPL.getResolveInfo(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* The settings activity name.
|
||||
* <p>
|
||||
* <strong>Statically set from {@link AccessibilityService#SERVICE_META_DATA
|
||||
* meta-data}.</strong>
|
||||
* </p>
|
||||
*
|
||||
* @return The settings activity name.
|
||||
*/
|
||||
public static String getSettingsActivityName(AccessibilityServiceInfo info) {
|
||||
return IMPL.getSettingsActivityName(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this service can retrieve the current window's content.
|
||||
* <p>
|
||||
* <strong>Statically set from {@link AccessibilityService#SERVICE_META_DATA
|
||||
* meta-data}.</strong>
|
||||
* </p>
|
||||
*
|
||||
* @return True window content can be retrieved.
|
||||
*/
|
||||
public static boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) {
|
||||
return IMPL.getCanRetrieveWindowContent(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of the accessibility service.
|
||||
* <p>
|
||||
* <strong>Statically set from {@link AccessibilityService#SERVICE_META_DATA
|
||||
* meta-data}.</strong>
|
||||
* </p>
|
||||
*
|
||||
* @return The description.
|
||||
*/
|
||||
public static String getDescription(AccessibilityServiceInfo info) {
|
||||
return IMPL.getDescription(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of a feedback type. For example,
|
||||
* {@link AccessibilityServiceInfo#FEEDBACK_SPOKEN} is represented by the
|
||||
* string FEEDBACK_SPOKEN.
|
||||
*
|
||||
* @param feedbackType The feedback type.
|
||||
* @return The string representation.
|
||||
*/
|
||||
public static String feedbackTypeToString(int feedbackType) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("[");
|
||||
while (feedbackType > 0) {
|
||||
final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType);
|
||||
feedbackType &= ~feedbackTypeFlag;
|
||||
if (builder.length() > 1) {
|
||||
builder.append(", ");
|
||||
}
|
||||
switch (feedbackTypeFlag) {
|
||||
case AccessibilityServiceInfo.FEEDBACK_AUDIBLE:
|
||||
builder.append("FEEDBACK_AUDIBLE");
|
||||
break;
|
||||
case AccessibilityServiceInfo.FEEDBACK_HAPTIC:
|
||||
builder.append("FEEDBACK_HAPTIC");
|
||||
break;
|
||||
case AccessibilityServiceInfo.FEEDBACK_GENERIC:
|
||||
builder.append("FEEDBACK_GENERIC");
|
||||
break;
|
||||
case AccessibilityServiceInfo.FEEDBACK_SPOKEN:
|
||||
builder.append("FEEDBACK_SPOKEN");
|
||||
break;
|
||||
case AccessibilityServiceInfo.FEEDBACK_VISUAL:
|
||||
builder.append("FEEDBACK_VISUAL");
|
||||
break;
|
||||
}
|
||||
}
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of a flag. For example,
|
||||
* {@link AccessibilityServiceInfo#DEFAULT} is represented by the
|
||||
* string DEFAULT.
|
||||
*
|
||||
* @param flag The flag.
|
||||
* @return The string representation.
|
||||
*/
|
||||
public static String flagToString(int flag) {
|
||||
switch (flag) {
|
||||
case DEFAULT:
|
||||
return "DEFAULT";
|
||||
case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:
|
||||
return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
|
||||
case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
|
||||
return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
|
||||
case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
|
||||
return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
|
||||
case FLAG_REPORT_VIEW_IDS:
|
||||
return "FLAG_REPORT_VIEW_IDS";
|
||||
case FLAG_REQUEST_FILTER_KEY_EVENTS:
|
||||
return "FLAG_REQUEST_FILTER_KEY_EVENTS";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit mask of capabilities this accessibility service has such as
|
||||
* being able to retrieve the active window content, etc.
|
||||
*
|
||||
* @param info The service info whose capabilities to get.
|
||||
* @return The capability bit mask.
|
||||
*
|
||||
* @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
|
||||
* @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
|
||||
* @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
|
||||
* @see #CAPABILITY_CAN_FILTER_KEY_EVENTS
|
||||
*/
|
||||
public static int getCapabilities(AccessibilityServiceInfo info) {
|
||||
return IMPL.getCapabilities(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of a capability. For example,
|
||||
* {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
|
||||
* by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
|
||||
*
|
||||
* @param capability The capability.
|
||||
* @return The string representation.
|
||||
*/
|
||||
public static String capabilityToString(int capability) {
|
||||
switch (capability) {
|
||||
case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
|
||||
return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
|
||||
case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
|
||||
return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
|
||||
case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
|
||||
return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
|
||||
case CAPABILITY_CAN_FILTER_KEY_EVENTS:
|
||||
return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 1072 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user