Initial checkin of AOSP Messaging app.
b/23110861 Change-Id: I9aa980d7569247d6b2ca78f5dcb4502e1eaadb8a
This commit is contained in:
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 com.android.messaging.ui.mediapicker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.messaging.R;
|
||||
import com.android.messaging.ui.PagingAwareViewPager;
|
||||
import com.android.messaging.util.Assert;
|
||||
import com.android.messaging.util.OsUtil;
|
||||
import com.android.messaging.util.UiUtils;
|
||||
|
||||
/**
|
||||
* Custom layout panel which makes the MediaPicker animations seamless and synchronized
|
||||
* Designed to be very specific to the MediaPicker's usage
|
||||
*/
|
||||
public class MediaPickerPanel extends ViewGroup {
|
||||
/**
|
||||
* The window of time in which we might to decide to reinterpret the intent of a gesture.
|
||||
*/
|
||||
private static final long TOUCH_RECAPTURE_WINDOW_MS = 500L;
|
||||
|
||||
// The two view components to layout
|
||||
private LinearLayout mTabStrip;
|
||||
private boolean mFullScreenOnly;
|
||||
private PagingAwareViewPager mViewPager;
|
||||
|
||||
/**
|
||||
* True if the MediaPicker is full screen or animating into it
|
||||
*/
|
||||
private boolean mFullScreen;
|
||||
|
||||
/**
|
||||
* True if the MediaPicker is open at all
|
||||
*/
|
||||
private boolean mExpanded;
|
||||
|
||||
/**
|
||||
* The current desired height of the MediaPicker. This property may be animated and the
|
||||
* measure pass uses it to determine what size the components are.
|
||||
*/
|
||||
private int mCurrentDesiredHeight;
|
||||
|
||||
private final Handler mHandler = new Handler();
|
||||
|
||||
/**
|
||||
* The media picker for dispatching events to the MediaPicker's listener
|
||||
*/
|
||||
private MediaPicker mMediaPicker;
|
||||
|
||||
/**
|
||||
* The computed default "half-screen" height of the view pager in px
|
||||
*/
|
||||
private final int mDefaultViewPagerHeight;
|
||||
|
||||
/**
|
||||
* The action bar height used to compute the padding on the view pager when it's full screen.
|
||||
*/
|
||||
private final int mActionBarHeight;
|
||||
|
||||
private TouchHandler mTouchHandler;
|
||||
|
||||
static final int PAGE_NOT_SET = -1;
|
||||
|
||||
public MediaPickerPanel(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
// Cache the computed dimension
|
||||
mDefaultViewPagerHeight = getResources().getDimensionPixelSize(
|
||||
R.dimen.mediapicker_default_chooser_height);
|
||||
mActionBarHeight = getResources().getDimensionPixelSize(R.dimen.action_bar_height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mTabStrip = (LinearLayout) findViewById(R.id.mediapicker_tabstrip);
|
||||
mViewPager = (PagingAwareViewPager) findViewById(R.id.mediapicker_view_pager);
|
||||
mTouchHandler = new TouchHandler();
|
||||
setOnTouchListener(mTouchHandler);
|
||||
mViewPager.setOnTouchListener(mTouchHandler);
|
||||
|
||||
// Make sure full screen mode is updated in landscape mode change when the panel is open.
|
||||
addOnLayoutChangeListener(new OnLayoutChangeListener() {
|
||||
private boolean mLandscapeMode = UiUtils.isLandscapeMode();
|
||||
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right, int bottom,
|
||||
int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||
final boolean newLandscapeMode = UiUtils.isLandscapeMode();
|
||||
if (mLandscapeMode != newLandscapeMode) {
|
||||
mLandscapeMode = newLandscapeMode;
|
||||
if (mExpanded) {
|
||||
setExpanded(mExpanded, false /* animate */, mViewPager.getCurrentItem(),
|
||||
true /* force */);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
|
||||
int requestedHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
if (mMediaPicker.getChooserShowsActionBarInFullScreen()) {
|
||||
requestedHeight -= mActionBarHeight;
|
||||
}
|
||||
int desiredHeight = Math.min(mCurrentDesiredHeight, requestedHeight);
|
||||
if (mExpanded && desiredHeight == 0) {
|
||||
// If we want to be shown, we have to have a non-0 height. Returning a height of 0 will
|
||||
// cause the framework to abort the animation from 0, so we must always have some
|
||||
// height once we start expanding
|
||||
desiredHeight = 1;
|
||||
} else if (!mExpanded && desiredHeight == 0) {
|
||||
mViewPager.setVisibility(View.GONE);
|
||||
mViewPager.setAdapter(null);
|
||||
}
|
||||
|
||||
measureChild(mTabStrip, widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
int tabStripHeight;
|
||||
if (requiresFullScreen()) {
|
||||
// Ensure that the tab strip is always visible, even in full screen.
|
||||
tabStripHeight = mTabStrip.getMeasuredHeight();
|
||||
} else {
|
||||
// Slide out the tab strip at the end of the animation to full screen.
|
||||
tabStripHeight = Math.min(mTabStrip.getMeasuredHeight(),
|
||||
requestedHeight - desiredHeight);
|
||||
}
|
||||
|
||||
// If we are animating and have an interim desired height, use the default height. We can't
|
||||
// take the max here as on some devices the mDefaultViewPagerHeight may be too big in
|
||||
// landscape mode after animation.
|
||||
final int tabAdjustedDesiredHeight = desiredHeight - tabStripHeight;
|
||||
final int viewPagerHeight =
|
||||
tabAdjustedDesiredHeight <= 1 ? mDefaultViewPagerHeight : tabAdjustedDesiredHeight;
|
||||
|
||||
int viewPagerHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
|
||||
viewPagerHeight, MeasureSpec.EXACTLY);
|
||||
measureChild(mViewPager, widthMeasureSpec, viewPagerHeightMeasureSpec);
|
||||
setMeasuredDimension(mViewPager.getMeasuredWidth(), desiredHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(final boolean changed, final int left, final int top, final int right,
|
||||
final int bottom) {
|
||||
int y = top;
|
||||
final int width = right - left;
|
||||
|
||||
final int viewPagerHeight = mViewPager.getMeasuredHeight();
|
||||
mViewPager.layout(0, y, width, y + viewPagerHeight);
|
||||
y += viewPagerHeight;
|
||||
|
||||
mTabStrip.layout(0, y, width, y + mTabStrip.getMeasuredHeight());
|
||||
}
|
||||
|
||||
void onChooserChanged() {
|
||||
if (mFullScreen) {
|
||||
setDesiredHeight(getDesiredHeight(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void setFullScreenOnly(boolean fullScreenOnly) {
|
||||
mFullScreenOnly = fullScreenOnly;
|
||||
}
|
||||
|
||||
boolean isFullScreen() {
|
||||
return mFullScreen;
|
||||
}
|
||||
|
||||
void setMediaPicker(final MediaPicker mediaPicker) {
|
||||
mMediaPicker = mediaPicker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the desired height of the media picker panel for when the panel is not in motion (i.e.
|
||||
* not being dragged by the user).
|
||||
*/
|
||||
private int getDesiredHeight() {
|
||||
if (mFullScreen) {
|
||||
int fullHeight = getContext().getResources().getDisplayMetrics().heightPixels;
|
||||
if (OsUtil.isAtLeastKLP() && isAttachedToWindow()) {
|
||||
// When we're attached to the window, we can get an accurate height, not necessary
|
||||
// on older API level devices because they don't include the action bar height
|
||||
View composeContainer =
|
||||
getRootView().findViewById(R.id.conversation_and_compose_container);
|
||||
if (composeContainer != null) {
|
||||
// protect against composeContainer having been unloaded already
|
||||
fullHeight -= UiUtils.getMeasuredBoundsOnScreen(composeContainer).top;
|
||||
}
|
||||
}
|
||||
if (mMediaPicker.getChooserShowsActionBarInFullScreen()) {
|
||||
return fullHeight - mActionBarHeight;
|
||||
} else {
|
||||
return fullHeight;
|
||||
}
|
||||
} else if (mExpanded) {
|
||||
return LayoutParams.WRAP_CONTENT;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupViewPager(final int startingPage) {
|
||||
mViewPager.setVisibility(View.VISIBLE);
|
||||
if (startingPage >= 0 && startingPage < mMediaPicker.getPagerAdapter().getCount()) {
|
||||
mViewPager.setAdapter(mMediaPicker.getPagerAdapter());
|
||||
mViewPager.setCurrentItem(startingPage);
|
||||
}
|
||||
updateViewPager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the media picker panel. Since we always set the pager adapter to null when the panel
|
||||
* is collapsed, we need to restore the adapter and the starting page.
|
||||
* @param expanded expanded or collapsed
|
||||
* @param animate need animation
|
||||
* @param startingPage the desired selected page to start
|
||||
*/
|
||||
void setExpanded(final boolean expanded, final boolean animate, final int startingPage) {
|
||||
setExpanded(expanded, animate, startingPage, false /* force */);
|
||||
}
|
||||
|
||||
private void setExpanded(final boolean expanded, final boolean animate, final int startingPage,
|
||||
final boolean force) {
|
||||
if (expanded == mExpanded && !force) {
|
||||
return;
|
||||
}
|
||||
mFullScreen = false;
|
||||
mExpanded = expanded;
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setDesiredHeight(getDesiredHeight(), animate);
|
||||
}
|
||||
});
|
||||
if (expanded) {
|
||||
setupViewPager(startingPage);
|
||||
mMediaPicker.dispatchOpened();
|
||||
} else {
|
||||
mMediaPicker.dispatchDismissed();
|
||||
}
|
||||
|
||||
// Call setFullScreenView() when we are in landscape mode so it can go full screen as
|
||||
// soon as it is expanded.
|
||||
if (expanded && requiresFullScreen()) {
|
||||
setFullScreenView(true, animate);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requiresFullScreen() {
|
||||
return mFullScreenOnly || UiUtils.isLandscapeMode();
|
||||
}
|
||||
|
||||
private void setDesiredHeight(int height, final boolean animate) {
|
||||
final int startHeight = mCurrentDesiredHeight;
|
||||
if (height == LayoutParams.WRAP_CONTENT) {
|
||||
height = measureHeight();
|
||||
}
|
||||
clearAnimation();
|
||||
if (animate) {
|
||||
final int deltaHeight = height - startHeight;
|
||||
final Animation animation = new Animation() {
|
||||
@Override
|
||||
protected void applyTransformation(final float interpolatedTime,
|
||||
final Transformation t) {
|
||||
mCurrentDesiredHeight = (int) (startHeight + deltaHeight * interpolatedTime);
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willChangeBounds() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
animation.setDuration(UiUtils.MEDIAPICKER_TRANSITION_DURATION);
|
||||
animation.setInterpolator(UiUtils.EASE_OUT_INTERPOLATOR);
|
||||
startAnimation(animation);
|
||||
} else {
|
||||
mCurrentDesiredHeight = height;
|
||||
}
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The minimum total height of the view
|
||||
*/
|
||||
private int measureHeight() {
|
||||
final int measureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE, MeasureSpec.AT_MOST);
|
||||
measureChild(mTabStrip, measureSpec, measureSpec);
|
||||
return mDefaultViewPagerHeight + mTabStrip.getMeasuredHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters or leaves full screen view
|
||||
*
|
||||
* @param fullScreen True to enter full screen view, false to leave
|
||||
* @param animate True to animate the transition
|
||||
*/
|
||||
void setFullScreenView(final boolean fullScreen, final boolean animate) {
|
||||
if (fullScreen == mFullScreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (requiresFullScreen() && !fullScreen) {
|
||||
setExpanded(false /* expanded */, true /* animate */, PAGE_NOT_SET);
|
||||
return;
|
||||
}
|
||||
mFullScreen = fullScreen;
|
||||
setDesiredHeight(getDesiredHeight(), animate);
|
||||
mMediaPicker.dispatchFullScreen(mFullScreen);
|
||||
updateViewPager();
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewPager should have its paging disabled when in full screen mode.
|
||||
*/
|
||||
private void updateViewPager() {
|
||||
mViewPager.setPagingEnabled(!mFullScreen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(final MotionEvent ev) {
|
||||
return mTouchHandler.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to handle touch events and swipe gestures
|
||||
*/
|
||||
private class TouchHandler implements OnTouchListener {
|
||||
/**
|
||||
* The height of the view when the touch press started
|
||||
*/
|
||||
private int mDownHeight = -1;
|
||||
|
||||
/**
|
||||
* True if the panel moved at all (changed height) during the drag
|
||||
*/
|
||||
private boolean mMoved = false;
|
||||
|
||||
// The threshold constants converted from DP to px
|
||||
private final float mFlingThresholdPx;
|
||||
private final float mBigFlingThresholdPx;
|
||||
|
||||
// The system defined pixel size to determine when a movement is considered a drag.
|
||||
private final int mTouchSlop;
|
||||
|
||||
/**
|
||||
* A copy of the MotionEvent that started the drag/swipe gesture
|
||||
*/
|
||||
private MotionEvent mDownEvent;
|
||||
|
||||
/**
|
||||
* Whether we are currently moving down. We may not be able to move down in full screen
|
||||
* mode when the child view can swipe down (such as a list view).
|
||||
*/
|
||||
private boolean mMovedDown = false;
|
||||
|
||||
/**
|
||||
* Indicates whether the child view contained in the panel can swipe down at the beginning
|
||||
* of the drag event (i.e. the initial down). The MediaPanel can contain
|
||||
* scrollable children such as a list view / grid view. If the child view can swipe down,
|
||||
* We want to let the child view handle the scroll first instead of handling it ourselves.
|
||||
*/
|
||||
private boolean mCanChildViewSwipeDown = false;
|
||||
|
||||
/**
|
||||
* Necessary direction ratio for a fling to be considered in one direction this prevents
|
||||
* horizontal swipes with small vertical components from triggering vertical swipe actions
|
||||
*/
|
||||
private static final float DIRECTION_RATIO = 1.1f;
|
||||
|
||||
TouchHandler() {
|
||||
final Resources resources = getContext().getResources();
|
||||
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
|
||||
mFlingThresholdPx = resources.getDimensionPixelSize(
|
||||
R.dimen.mediapicker_fling_threshold);
|
||||
mBigFlingThresholdPx = resources.getDimensionPixelSize(
|
||||
R.dimen.mediapicker_big_fling_threshold);
|
||||
mTouchSlop = configuration.getScaledTouchSlop();
|
||||
}
|
||||
|
||||
/**
|
||||
* The media picker panel may contain scrollable children such as a GridView, which eats
|
||||
* all touch events before we get to it. Therefore, we'd like to intercept these events
|
||||
* before the children to determine if we should handle swiping down in full screen mode.
|
||||
* In non-full screen mode, we should handle all vertical scrolling events and leave
|
||||
* horizontal scrolling to the view pager.
|
||||
*/
|
||||
public boolean onInterceptTouchEvent(final MotionEvent ev) {
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// Never capture the initial down, so that the children may handle it
|
||||
// as well. Let the touch handler know about the down event as well.
|
||||
mTouchHandler.onTouch(MediaPickerPanel.this, ev);
|
||||
|
||||
// Ask the MediaPicker whether the contained view can be swiped down.
|
||||
// We record the value at the start of the drag to decide the swiping mode
|
||||
// for the entire motion.
|
||||
mCanChildViewSwipeDown = mMediaPicker.canSwipeDownChooser();
|
||||
return false;
|
||||
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
if (mMediaPicker.isChooserHandlingTouch()) {
|
||||
if (shouldAllowRecaptureTouch(ev)) {
|
||||
mMediaPicker.stopChooserTouchHandling();
|
||||
mViewPager.setPagingEnabled(true);
|
||||
return false;
|
||||
}
|
||||
// If the chooser is claiming ownership on all touch events, then we
|
||||
// shouldn't try to handle them (neither should the view pager).
|
||||
mViewPager.setPagingEnabled(false);
|
||||
return false;
|
||||
} else if (mCanChildViewSwipeDown) {
|
||||
// Never capture event if the child view can swipe down.
|
||||
return false;
|
||||
} else if (!mFullScreen && mMoved) {
|
||||
// When we are not fullscreen, we own any vertical drag motion.
|
||||
return true;
|
||||
} else if (mMovedDown) {
|
||||
// We are currently handling the down swipe ourselves, so always
|
||||
// capture this event.
|
||||
return true;
|
||||
} else {
|
||||
// The current interaction mode is undetermined, so always let the
|
||||
// touch handler know about this event. However, don't capture this
|
||||
// event so the child may handle it as well.
|
||||
mTouchHandler.onTouch(MediaPickerPanel.this, ev);
|
||||
|
||||
// Capture the touch event from now on if we are handling the drag.
|
||||
return mFullScreen ? mMovedDown : mMoved;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether we think the user is actually trying to expand or slide despite the
|
||||
* fact that they touched first on a chooser that captured the input.
|
||||
*/
|
||||
private boolean shouldAllowRecaptureTouch(MotionEvent ev) {
|
||||
final long elapsedMs = ev.getEventTime() - ev.getDownTime();
|
||||
if (mDownEvent == null || elapsedMs == 0 || elapsedMs > TOUCH_RECAPTURE_WINDOW_MS) {
|
||||
// Either we don't have info to decide or it's been long enough that we no longer
|
||||
// want to reinterpret user intent.
|
||||
return false;
|
||||
}
|
||||
final float dx = ev.getRawX() - mDownEvent.getRawX();
|
||||
final float dy = ev.getRawY() - mDownEvent.getRawY();
|
||||
final float dt = elapsedMs / 1000.0f;
|
||||
final float maxAbsDelta = Math.max(Math.abs(dx), Math.abs(dy));
|
||||
final float velocity = maxAbsDelta / dt;
|
||||
return velocity > mFlingThresholdPx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(final View view, final MotionEvent motionEvent) {
|
||||
switch (motionEvent.getAction()) {
|
||||
case MotionEvent.ACTION_UP: {
|
||||
if (!mMoved || mDownEvent == null) {
|
||||
return false;
|
||||
}
|
||||
final float dx = motionEvent.getRawX() - mDownEvent.getRawX();
|
||||
final float dy = motionEvent.getRawY() - mDownEvent.getRawY();
|
||||
|
||||
final float dt =
|
||||
(motionEvent.getEventTime() - mDownEvent.getEventTime()) / 1000.0f;
|
||||
final float yVelocity = dy / dt;
|
||||
|
||||
boolean handled = false;
|
||||
|
||||
// Vertical swipe occurred if the direction is as least mostly in the y
|
||||
// component and has the required velocity (px/sec)
|
||||
if ((dx == 0 || (Math.abs(dy) / Math.abs(dx)) > DIRECTION_RATIO) &&
|
||||
Math.abs(yVelocity) > mFlingThresholdPx) {
|
||||
if (yVelocity < 0 && mExpanded) {
|
||||
setFullScreenView(true, true);
|
||||
handled = true;
|
||||
} else if (yVelocity > 0) {
|
||||
if (mFullScreen && yVelocity < mBigFlingThresholdPx) {
|
||||
setFullScreenView(false, true);
|
||||
} else {
|
||||
setExpanded(false, true, PAGE_NOT_SET);
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
// If they didn't swipe enough, animate back to resting state
|
||||
setDesiredHeight(getDesiredHeight(), true);
|
||||
}
|
||||
resetState();
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
mDownHeight = getHeight();
|
||||
mDownEvent = MotionEvent.obtain(motionEvent);
|
||||
// If we are here and care about the return value (i.e. this is not called
|
||||
// from onInterceptTouchEvent), then presumably no children view in the panel
|
||||
// handles the down event. We'd like to handle future ACTION_MOVE events, so
|
||||
// always claim ownership on this event so it doesn't fall through and gets
|
||||
// cancelled by the framework.
|
||||
return true;
|
||||
}
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
if (mDownEvent == null) {
|
||||
return mMoved;
|
||||
}
|
||||
|
||||
final float dx = mDownEvent.getRawX() - motionEvent.getRawX();
|
||||
final float dy = mDownEvent.getRawY() - motionEvent.getRawY();
|
||||
// Don't act if the move is mostly horizontal
|
||||
if (Math.abs(dy) > mTouchSlop &&
|
||||
(Math.abs(dy) / Math.abs(dx)) > DIRECTION_RATIO) {
|
||||
setDesiredHeight((int) (mDownHeight + dy), false);
|
||||
mMoved = true;
|
||||
if (dy < -mTouchSlop) {
|
||||
mMovedDown = true;
|
||||
}
|
||||
}
|
||||
return mMoved;
|
||||
}
|
||||
|
||||
}
|
||||
return mMoved;
|
||||
}
|
||||
|
||||
private void resetState() {
|
||||
mDownEvent = null;
|
||||
mDownHeight = -1;
|
||||
mMoved = false;
|
||||
mMovedDown = false;
|
||||
mCanChildViewSwipeDown = false;
|
||||
updateViewPager();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user