diff options
author | Justin Klaassen <justinklaassen@google.com> | 2016-12-19 09:11:38 -0800 |
---|---|---|
committer | Justin Klaassen <justinklaassen@google.com> | 2017-01-08 18:41:49 -0800 |
commit | 392977886711392c51b0727e9e10c96474794760 (patch) | |
tree | 12725995ee5999730f8cb354467ba8325b6fd064 | |
parent | a9395c92523f46caa90ebf94fbd96104b09f6d94 (diff) | |
download | android_packages_apps_ExactCalculator-392977886711392c51b0727e9e10c96474794760.tar.gz android_packages_apps_ExactCalculator-392977886711392c51b0727e9e10c96474794760.tar.bz2 android_packages_apps_ExactCalculator-392977886711392c51b0727e9e10c96474794760.zip |
Don't re-use mHistoryFragment
Make a new HistoryFragment every time we enter and exit history to work
around a bug on older platforms where a Fragment's internal state may
not be reset correctly when detached.
Also the HistoryFragment open/close transition is now properly animated
using a custom Animator returned by DragLayout.
Fixes: 33587141
Fixes: 33789131
Fixes: 33789337
Fixes: 34132294
Fixes: 34132998
Fixes: 34134349
Fixes: 34135442
Test: manually verified no crash occurs on API 22, 23, & 24 emulator
Change-Id: Iaefbe2bbf4ca186b6396397579887774ed5906d3
-rw-r--r-- | res/layout/activity_calculator_main.xml | 5 | ||||
-rw-r--r-- | res/layout/fragment_history.xml | 4 | ||||
-rw-r--r-- | res/layout/history_item.xml | 1 | ||||
-rw-r--r-- | src/com/android/calculator2/Calculator.java | 74 | ||||
-rw-r--r-- | src/com/android/calculator2/DragController.java | 94 | ||||
-rw-r--r-- | src/com/android/calculator2/DragLayout.java | 165 | ||||
-rw-r--r-- | src/com/android/calculator2/HistoryFragment.java | 68 |
7 files changed, 230 insertions, 181 deletions
diff --git a/res/layout/activity_calculator_main.xml b/res/layout/activity_calculator_main.xml index 4173d33..2e9d62d 100644 --- a/res/layout/activity_calculator_main.xml +++ b/res/layout/activity_calculator_main.xml @@ -28,6 +28,7 @@ <FrameLayout android:id="@+id/history_frame" android:layout_width="match_parent" - android:layout_height="match_parent" /> + android:layout_height="match_parent" + android:visibility="invisible" /> -</com.android.calculator2.DragLayout>
\ No newline at end of file +</com.android.calculator2.DragLayout> diff --git a/res/layout/fragment_history.xml b/res/layout/fragment_history.xml index 78ba4cc..e5fe50e 100644 --- a/res/layout/fragment_history.xml +++ b/res/layout/fragment_history.xml @@ -19,7 +19,6 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/display_background_color" android:clipChildren="false" android:orientation="vertical"> @@ -40,9 +39,12 @@ android:id="@+id/history_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="@color/display_background_color" android:clipChildren="false" android:clipToPadding="false" android:paddingBottom="@dimen/history_divider_padding" + android:visibility="invisible" app:layoutManager="LinearLayoutManager" app:reverseLayout="true" /> + </LinearLayout> diff --git a/res/layout/history_item.xml b/res/layout/history_item.xml index eaa95ad..cf8b6c0 100644 --- a/res/layout/history_item.xml +++ b/res/layout/history_item.xml @@ -22,6 +22,7 @@ android:paddingTop="@dimen/history_divider_padding" android:clipChildren="false" android:clipToPadding="false" + android:importantForAccessibility="no" android:orientation="vertical"> <View diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java index 970683b..5019fdf 100644 --- a/src/com/android/calculator2/Calculator.java +++ b/src/com/android/calculator2/Calculator.java @@ -34,6 +34,7 @@ import android.animation.PropertyValuesHolder; import android.app.ActionBar; import android.app.Activity; import android.app.FragmentManager; +import android.app.FragmentTransaction; import android.content.ClipData; import android.content.DialogInterface; import android.content.Intent; @@ -66,7 +67,6 @@ import android.view.ViewAnimationUtils; import android.view.ViewGroupOverlay; import android.view.ViewTreeObserver; import android.view.animation.AccelerateDecelerateInterpolator; -import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.TextView; import android.widget.Toolbar; @@ -252,7 +252,6 @@ public class Calculator extends Activity private CalculatorResult mResultText; private HorizontalScrollView mFormulaContainer; private DragLayout mDragLayout; - private FrameLayout mHistoryFrame; private ViewPager mPadViewPager; private View mDeleteButton; @@ -280,8 +279,6 @@ public class Calculator extends Activity // Whether the display is one line. private boolean mIsOneLine; - private HistoryFragment mHistoryFragment = new HistoryFragment(); - /** * Map the old saved state to a new state reflecting requested result reevaluation. */ @@ -421,8 +418,6 @@ public class Calculator extends Activity mDragLayout.addDragCallback(this); mDragLayout.setCloseCallback(this); - mHistoryFrame = (FrameLayout) findViewById(R.id.history_frame); - mFormulaText.setOnContextMenuClickListener(mOnFormulaContextMenuClickListener); mFormulaText.setOnDisplayMemoryOperationsListener(mOnDisplayMemoryOperationsListener); @@ -596,8 +591,10 @@ public class Calculator extends Activity public boolean dispatchTouchEvent(MotionEvent e) { if (e.getActionMasked() == MotionEvent.ACTION_DOWN) { stopActionModeOrContextMenu(); - if (mDragLayout.isOpen()) { - mHistoryFragment.stopActionModeOrContextMenu(); + + final HistoryFragment historyFragment = getHistoryFragment(); + if (mDragLayout.isOpen() && historyFragment != null) { + historyFragment.stopActionModeOrContextMenu(); } } return super.dispatchTouchEvent(e); @@ -606,9 +603,9 @@ public class Calculator extends Activity @Override public void onBackPressed() { if (!stopActionModeOrContextMenu()) { - if (mDragLayout.isOpen()) { - if (!mHistoryFragment.stopActionModeOrContextMenu()) { - mDragLayout.setClosed(); + final HistoryFragment historyFragment = getHistoryFragment(); + if (mDragLayout.isOpen() && historyFragment != null) { + if (!historyFragment.stopActionModeOrContextMenu()) { removeHistoryFragment(); } return; @@ -1278,8 +1275,7 @@ public class Calculator extends Activity public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_history: - showHistoryFragment(); - mDragLayout.setOpen(); + showHistoryFragment(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); return true; case R.id.menu_leading: displayFull(); @@ -1306,21 +1302,23 @@ public class Calculator extends Activity /* Begin override DragCallback methods */ - @Override public void onStartDraggingOpen() { - showHistoryFragment(); + mDisplayView.hideToolbar(); + showHistoryFragment(FragmentTransaction.TRANSIT_NONE); + } + + @Override + public void onInstanceStateRestored(boolean isOpen) { } @Override public void whileDragging(float yFraction) { - // no-op } @Override public boolean shouldCaptureView(View view, int x, int y) { - return mDragLayout.isMoving() - || mDragLayout.isOpen() - || mDragLayout.isViewUnder(mDisplayView, x, y); + return view.getId() == R.id.history_frame + && (mDragLayout.isMoving() || mDragLayout.isViewUnder(view, x, y)); } @Override @@ -1328,11 +1326,6 @@ public class Calculator extends Activity return mDisplayView.getMeasuredHeight(); } - @Override - public void onLayout(int translation) { - mHistoryFrame.setTranslationY(translation + mDisplayView.getBottom()); - } - /* End override DragCallback methods */ /** @@ -1358,27 +1351,34 @@ public class Calculator extends Activity return true; } - private void showHistoryFragment() { + private HistoryFragment getHistoryFragment() { + final FragmentManager manager = getFragmentManager(); + if (manager == null || manager.isDestroyed()) { + return null; + } + return (HistoryFragment) manager.findFragmentByTag(HistoryFragment.TAG); + } + + private void showHistoryFragment(int transit) { final FragmentManager manager = getFragmentManager(); if (manager == null || manager.isDestroyed()) { return; } - if (!prepareForHistory()) { + + if (getHistoryFragment() != null || !prepareForHistory()) { return; } - if (!mDragLayout.isOpen()) { - stopActionModeOrContextMenu(); - manager.beginTransaction() - .replace(R.id.history_frame, mHistoryFragment, HistoryFragment.TAG) - .addToBackStack(HistoryFragment.TAG) - .commit(); - manager.executePendingTransactions(); + stopActionModeOrContextMenu(); + manager.beginTransaction() + .replace(R.id.history_frame, new HistoryFragment(), HistoryFragment.TAG) + .setTransition(transit) + .addToBackStack(HistoryFragment.TAG) + .commit(); - // When HistoryFragment is visible, hide all descendants of the main Calculator view. - mMainCalculator.setImportantForAccessibility( - View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - } + // When HistoryFragment is visible, hide all descendants of the main Calculator view. + mMainCalculator.setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); // TODO: pass current scroll position of result } diff --git a/src/com/android/calculator2/DragController.java b/src/com/android/calculator2/DragController.java index e90d1b4..8810e7d 100644 --- a/src/com/android/calculator2/DragController.java +++ b/src/com/android/calculator2/DragController.java @@ -94,9 +94,17 @@ public final class DragController { } public void animateViews(float yFraction, RecyclerView recyclerView) { - final HistoryAdapter.ViewHolder vh = (HistoryAdapter.ViewHolder) - recyclerView.findViewHolderForAdapterPosition(0); - if (yFraction > 0) { + if (mDisplayFormula == null + || mDisplayResult == null + || mToolbar == null + || mEvaluator == null) { + // Bail if we aren't yet initialized. + return; + } + + final HistoryAdapter.ViewHolder vh = + (HistoryAdapter.ViewHolder) recyclerView.findViewHolderForAdapterPosition(0); + if (yFraction > 0 && vh != null) { recyclerView.setVisibility(View.VISIBLE); } if (vh != null && !EvaluatorStateUtils.isDisplayEmpty(mEvaluator)) { @@ -123,40 +131,37 @@ public final class DragController { mAnimationInitialized = true; } - if (mAnimationInitialized) { - result.setScaleX(mAnimationController.getResultScale(yFraction)); - result.setScaleY(mAnimationController.getResultScale(yFraction)); + result.setScaleX(mAnimationController.getResultScale(yFraction)); + result.setScaleY(mAnimationController.getResultScale(yFraction)); - formula.setScaleX(mAnimationController.getFormulaScale(yFraction)); - formula.setScaleY(mAnimationController.getFormulaScale(yFraction)); + formula.setScaleX(mAnimationController.getFormulaScale(yFraction)); + formula.setScaleY(mAnimationController.getFormulaScale(yFraction)); - formula.setPivotX(formula.getWidth() - formula.getPaddingEnd()); - formula.setPivotY(formula.getHeight() - formula.getPaddingBottom()); + formula.setPivotX(formula.getWidth() - formula.getPaddingEnd()); + formula.setPivotY(formula.getHeight() - formula.getPaddingBottom()); - result.setPivotX(result.getWidth() - result.getPaddingEnd()); - result.setPivotY(result.getHeight() - result.getPaddingBottom()); + result.setPivotX(result.getWidth() - result.getPaddingEnd()); + result.setPivotY(result.getHeight() - result.getPaddingBottom()); - formula.setTranslationX(mAnimationController.getFormulaTranslationX(yFraction)); - formula.setTranslationY(mAnimationController.getFormulaTranslationY(yFraction)); + formula.setTranslationX(mAnimationController.getFormulaTranslationX(yFraction)); + formula.setTranslationY(mAnimationController.getFormulaTranslationY(yFraction)); - result.setTranslationX(mAnimationController.getResultTranslationX(yFraction)); - result.setTranslationY(mAnimationController.getResultTranslationY(yFraction)); + result.setTranslationX(mAnimationController.getResultTranslationX(yFraction)); + result.setTranslationY(mAnimationController.getResultTranslationY(yFraction)); - formula.setTextColor((int) mColorEvaluator.evaluate(yFraction, mFormulaStartColor, - mFormulaEndColor)); + formula.setTextColor((int) mColorEvaluator.evaluate(yFraction, mFormulaStartColor, + mFormulaEndColor)); - result.setTextColor((int) mColorEvaluator.evaluate(yFraction, mResultStartColor, - mResultEndColor)); + result.setTextColor((int) mColorEvaluator.evaluate(yFraction, mResultStartColor, + mResultEndColor)); - date.setTranslationY(mAnimationController.getDateTranslationY(yFraction)); - divider.setTranslationY(mAnimationController.getDateTranslationY(yFraction)); - } + date.setTranslationY(mAnimationController.getDateTranslationY(yFraction)); + divider.setTranslationY(mAnimationController.getDateTranslationY(yFraction)); } else if (EvaluatorStateUtils.isDisplayEmpty(mEvaluator)) { // There is no current expression but we still need to collect information // to translate the other viewholders. if (!mAnimationInitialized) { mAnimationController.initializeDisplayHeight(); - mAnimationInitialized = true; } } @@ -180,11 +185,8 @@ public final class DragController { /** * Reset all initialized values. - * If the DragLayout is closed, set recyclerview to INVISIBLE to avoid flickering. */ - public void initializeAnimation(RecyclerView recyclerView, boolean isResult, - boolean oneLine, boolean isOpen) { - recyclerView.setVisibility(isOpen ? View.VISIBLE : View.INVISIBLE); + public void initializeAnimation(boolean isResult, boolean oneLine) { mAnimationInitialized = false; initializeController(isResult, oneLine); } @@ -245,7 +247,7 @@ public final class DragController { public void initializeScales(AlignedTextView formula, CalculatorResult result) { // Calculate the scale for the text - mFormulaScale = (mDisplayFormula.getTextSize() * 1.0f) / formula.getTextSize(); + mFormulaScale = mDisplayFormula.getTextSize() / formula.getTextSize(); } public void initializeFormulaTranslationY(AlignedTextView formula, @@ -281,38 +283,37 @@ public final class DragController { } public float getResultTranslationX(float yFraction) { - return (mResultTranslationX * yFraction) - mResultTranslationX; + return mResultTranslationX * (yFraction - 1f); } public float getResultTranslationY(float yFraction) { - return (mResultTranslationY * yFraction) - mResultTranslationY; + return mResultTranslationY * (yFraction - 1f); } public float getResultScale(float yFraction) { - return 1; + return 1f; } public float getFormulaScale(float yFraction) { - return mFormulaScale - (mFormulaScale * yFraction) + yFraction; + return mFormulaScale + (1f - mFormulaScale) * yFraction; } public float getFormulaTranslationX(float yFraction) { - return (mFormulaTranslationX * yFraction) - - mFormulaTranslationX; + return mFormulaTranslationX * (yFraction - 1f); } public float getFormulaTranslationY(float yFraction) { // Scale linearly between -FormulaTranslationY and 0. - return (mFormulaTranslationY * yFraction) - mFormulaTranslationY; + return mFormulaTranslationY * (yFraction - 1f); } public float getDateTranslationY(float yFraction) { // We also want the date to start out above the visible screen with // this distance decreasing as it's pulled down. // Account for the scaled formula height. - return -mToolbar.getHeight() * (1 - yFraction) + return -mToolbar.getHeight() * (1f - yFraction) + getFormulaTranslationY(yFraction) - - mDisplayFormula.getHeight() /getFormulaScale(yFraction) * (1 - yFraction); + - mDisplayFormula.getHeight() /getFormulaScale(yFraction) * (1f - yFraction); } public float getHistoryElementTranslationY(float yFraction) { @@ -331,8 +332,7 @@ public final class DragController { public void initializeScales(AlignedTextView formula, CalculatorResult result) { final float textSize = mDisplayResult.getTextSize() * mDisplayResult.getScaleX(); mResultScale = textSize / result.getTextSize(); - - mFormulaScale = 1; + mFormulaScale = 1f; } @Override @@ -392,14 +392,14 @@ public final class DragController { @Override public float getFormulaScale(float yFraction) { - return 1; + return 1f; } @Override public float getDateTranslationY(float yFraction) { // We also want the date to start out above the visible screen with // this distance decreasing as it's pulled down. - return -mToolbar.getHeight() * (1 - yFraction) + return -mToolbar.getHeight() * (1f - yFraction) + (mResultTranslationY * yFraction) - mResultTranslationY - mDisplayFormula.getPaddingTop() + (mDisplayFormula.getPaddingTop() * yFraction); @@ -448,27 +448,27 @@ public final class DragController { @Override public float getResultTranslationX(float yFraction) { - return 0; + return 0f; } @Override public float getResultTranslationY(float yFraction) { - return 0; + return 0f; } @Override public float getFormulaScale(float yFraction) { - return 1; + return 1f; } @Override public float getDateTranslationY(float yFraction) { - return 0; + return 0f; } @Override public float getHistoryElementTranslationY(float yFraction) { - return -mDisplayHeight * (1 - yFraction) - mBottomPaddingHeight; + return -mDisplayHeight * (1f - yFraction) - mBottomPaddingHeight; } @Override diff --git a/src/com/android/calculator2/DragLayout.java b/src/com/android/calculator2/DragLayout.java index 9e83aa1..1848e38 100644 --- a/src/com/android/calculator2/DragLayout.java +++ b/src/com/android/calculator2/DragLayout.java @@ -16,6 +16,9 @@ package com.android.calculator2; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.PointF; import android.graphics.Rect; @@ -26,18 +29,17 @@ import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.widget.FrameLayout; -import android.widget.RelativeLayout; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; -public class DragLayout extends RelativeLayout { +public class DragLayout extends ViewGroup { - private static final String TAG = "DragLayout"; - private static final double AUTO_OPEN_SPEED_LIMIT = 800.0; + private static final double AUTO_OPEN_SPEED_LIMIT = 600.0; private static final String KEY_IS_OPEN = "IS_OPEN"; private static final String KEY_SUPER_STATE = "SUPER_STATE"; @@ -51,8 +53,6 @@ public class DragLayout extends RelativeLayout { private final Map<Integer, PointF> mLastMotionPoints = new HashMap<>(); private final Rect mHitRect = new Rect(); - private int mDraggingState = ViewDragHelper.STATE_IDLE; - private int mDraggingBorder; private int mVerticalRange; private boolean mIsOpen; @@ -68,28 +68,30 @@ public class DragLayout extends RelativeLayout { } @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - if (changed) { - for (DragCallback c : mDragCallbacks) { - c.onLayout(t - b); - } - if (mIsOpen) { - setOpen(); - } else { - setClosed(); - } - } + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + measureChildren(widthMeasureSpec, heightMeasureSpec); } @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - int height = 0; + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int displayHeight = 0; for (DragCallback c : mDragCallbacks) { - height += c.getDisplayHeight(); + displayHeight = Math.max(displayHeight, c.getDisplayHeight()); + } + mVerticalRange = getHeight() - displayHeight; + + final int childCount = getChildCount(); + for (int i = 0; i < childCount; ++i) { + final View child = getChildAt(i); + + int top = 0; + if (child == mHistoryFrame) { + top = mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE + ? child.getTop() : (mIsOpen ? 0 : -mVerticalRange); + } + child.layout(0, top, child.getMeasuredWidth(), top + child.getMeasuredHeight()); } - mVerticalRange = h - height; - super.onSizeChanged(w, h, oldw, oldh); } @Override @@ -105,6 +107,11 @@ public class DragLayout extends RelativeLayout { if (state instanceof Bundle) { final Bundle bundle = (Bundle) state; mIsOpen = bundle.getBoolean(KEY_IS_OPEN); + mHistoryFrame.setVisibility(mIsOpen ? View.VISIBLE : View.INVISIBLE); + for (DragCallback c : mDragCallbacks) { + c.onInstanceStateRestored(mIsOpen); + } + state = bundle.getParcelable(KEY_SUPER_STATE); } super.onRestoreInstanceState(state); @@ -179,8 +186,9 @@ public class DragLayout extends RelativeLayout { } public boolean isMoving() { - return mDraggingState == ViewDragHelper.STATE_DRAGGING - || mDraggingState == ViewDragHelper.STATE_SETTLING; + final int draggingState = mDragHelper.getViewDragState(); + return draggingState == ViewDragHelper.STATE_DRAGGING + || draggingState == ViewDragHelper.STATE_SETTLING; } public boolean isOpen() { @@ -188,14 +196,54 @@ public class DragLayout extends RelativeLayout { } public void setOpen() { - mDragHelper.smoothSlideViewTo(mHistoryFrame, 0, mVerticalRange); - mHistoryFrame.setVisibility(VISIBLE); - mIsOpen = true; + if (!mIsOpen) { + mIsOpen = true; + mDragHelper.smoothSlideViewTo(mHistoryFrame, 0, 0); + mHistoryFrame.setVisibility(VISIBLE); + } } public void setClosed() { - mDragHelper.smoothSlideViewTo(mHistoryFrame, 0, 0); - mIsOpen = false; + if (mIsOpen) { + mIsOpen = false; + mDragHelper.smoothSlideViewTo(mHistoryFrame, 0, -mVerticalRange); + mHistoryFrame.setVisibility(View.INVISIBLE); + + if (mCloseCallback != null) { + mCloseCallback.onClose(); + } + } + } + + public Animator createAnimator(final boolean toOpen) { + mHistoryFrame.setVisibility(VISIBLE); + + final ValueAnimator animator = ValueAnimator.ofInt(mHistoryFrame.getTop(), + toOpen ? 0 : -mVerticalRange); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animator) { + final int top = (int) animator.getAnimatedValue(); + mHistoryFrame.offsetTopAndBottom(top - mHistoryFrame.getTop()); + + for (DragCallback c : mDragCallbacks) { + // Top is between [-mVerticalRange, 0]. + c.whileDragging(1f + (float) top / mVerticalRange); + } + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + if (toOpen) { + setOpen(); + } else { + setClosed(); + } + } + }); + + return animator; } public void setCloseCallback(CloseCallback callback) { @@ -228,6 +276,9 @@ public class DragLayout extends RelativeLayout { // Callback when a drag to open begins. void onStartDraggingOpen(); + // Callback in onRestoreInstanceState. + void onInstanceStateRestored(boolean isOpen); + // Animate the RecyclerView text. void whileDragging(float yFraction); @@ -235,43 +286,26 @@ public class DragLayout extends RelativeLayout { boolean shouldCaptureView(View view, int x, int y); int getDisplayHeight(); - - void onLayout(int translation); } public class DragHelperCallback extends ViewDragHelper.Callback { @Override public void onViewDragStateChanged(int state) { - if (state == mDraggingState) { - // No change. - return; - } - if ((mDraggingState == ViewDragHelper.STATE_DRAGGING - || mDraggingState == ViewDragHelper.STATE_SETTLING) - && state == ViewDragHelper.STATE_IDLE) { - // The view stopped moving. - if (mDraggingBorder == 0) { + // The view stopped moving. + if (state == ViewDragHelper.STATE_IDLE) { + if (mDragHelper.getCapturedView().getTop() < -(mVerticalRange / 2)) { setClosed(); - mHistoryFrame.setVisibility(GONE); - if (mCloseCallback != null) { - mCloseCallback.onClose(); - } - } else if (mDraggingBorder == mVerticalRange) { + } else { setOpen(); } - } else if (state == ViewDragHelper.STATE_DRAGGING && !mIsOpen) { - onStartDragging(); } - mDraggingState = state; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { - mDraggingBorder = top; - - // Animate RecyclerView text. for (DragCallback c : mDragCallbacks) { - c.whileDragging(top / (mVerticalRange * 1.0f)); + // Top is between [-mVerticalRange, 0]. + c.whileDragging(1f + (float) top / mVerticalRange); } } @@ -300,27 +334,32 @@ public class DragLayout extends RelativeLayout { @Override public int clampViewPositionVertical(View child, int top, int dy) { - final int topBound = getPaddingTop(); - final int bottomBound = mVerticalRange; - return Math.min(Math.max(top, topBound), bottomBound); + return Math.max(Math.min(top, 0), -mVerticalRange); + } + + @Override + public void onViewCaptured(View capturedChild, int activePointerId) { + super.onViewCaptured(capturedChild, activePointerId); + + if (!mIsOpen) { + mIsOpen = true; + onStartDragging(); + } } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { - boolean settleToOpen = false; - final float threshold = mVerticalRange / 2; + final boolean settleToOpen; if (yvel > AUTO_OPEN_SPEED_LIMIT) { // Speed has priority over position. settleToOpen = true; } else if (yvel < -AUTO_OPEN_SPEED_LIMIT) { settleToOpen = false; - } else if (mDraggingBorder > threshold) { - settleToOpen = true; - } else if (mDraggingBorder < threshold) { - settleToOpen = false; + } else { + settleToOpen = releasedChild.getTop() > -(mVerticalRange / 2); } - if (mDragHelper.settleCapturedViewAt(0, settleToOpen ? mVerticalRange : 0)) { + if (mDragHelper.settleCapturedViewAt(0, settleToOpen ? 0 : -mVerticalRange)) { ViewCompat.postInvalidateOnAnimation(DragLayout.this); } } diff --git a/src/com/android/calculator2/HistoryFragment.java b/src/com/android/calculator2/HistoryFragment.java index 883f229..64a94f9 100644 --- a/src/com/android/calculator2/HistoryFragment.java +++ b/src/com/android/calculator2/HistoryFragment.java @@ -16,8 +16,9 @@ package com.android.calculator2; +import android.animation.Animator; import android.app.Fragment; -import android.graphics.Color; +import android.app.FragmentTransaction; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; @@ -49,7 +50,6 @@ public class HistoryFragment extends Fragment implements DragLayout.DragCallback @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mAdapter = new HistoryAdapter(mDataSet); } @@ -59,6 +59,9 @@ public class HistoryFragment extends Fragment implements DragLayout.DragCallback final View view = inflater.inflate( R.layout.fragment_history, container, false /* attachToRoot */); + mDragLayout = (DragLayout) container.getRootView().findViewById(R.id.drag_layout); + mDragLayout.addDragCallback(this); + mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler_view); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override @@ -110,10 +113,6 @@ public class HistoryFragment extends Fragment implements DragLayout.DragCallback final boolean isResultLayout = activity.isResultLayout(); final boolean isOneLine = activity.isOneLine(); - mDragLayout = (DragLayout) activity.findViewById(R.id.drag_layout); - mDragLayout.removeDragCallback(this); - mDragLayout.addDragCallback(this); - if (mEvaluator != null) { initializeController(isResultLayout, isOneLine); @@ -135,9 +134,8 @@ public class HistoryFragment extends Fragment implements DragLayout.DragCallback newDataSet.add(null); } final boolean isEmpty = newDataSet.isEmpty(); - mRecyclerView.setBackgroundColor(isEmpty - ? ContextCompat.getColor(activity, R.color.empty_history_color) - : Color.TRANSPARENT); + mRecyclerView.setBackgroundColor(ContextCompat.getColor(activity, + isEmpty ? R.color.empty_history_color : R.color.display_background_color)); if (isEmpty) { newDataSet.add(new HistoryItem()); } @@ -153,37 +151,43 @@ public class HistoryFragment extends Fragment implements DragLayout.DragCallback @Override public void onStart() { super.onStart(); + final Calculator activity = (Calculator) getActivity(); - // The orientation may have changed. - mDragController.initializeAnimation(mRecyclerView, - activity.isResultLayout(), activity.isOneLine(), mDragLayout.isOpen()); + mDragController.initializeAnimation(activity.isResultLayout(), activity.isOneLine()); } @Override - public void onDestroyView() { - final DragLayout dragLayout = (DragLayout) getActivity().findViewById(R.id.drag_layout); - if (dragLayout != null) { - dragLayout.removeDragCallback(this); + public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) { + if (enter) { + if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) { + return mDragLayout.createAnimator(true /* toOpen */); + } else { + return null; + } + } + return mDragLayout.createAnimator(false /* toOpen */); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (mDragLayout != null) { + mDragLayout.removeDragCallback(this); } // Note that the view is destroyed when the fragment backstack is popped, so // these are essentially called when the DragLayout is closed. mEvaluator.cancelNonMain(); - - super.onDestroyView(); } private void initializeController(boolean isResult, boolean isOneLine) { mDragController.setDisplayFormula( (CalculatorFormula) getActivity().findViewById(R.id.formula)); - mDragController.setDisplayResult( (CalculatorResult) getActivity().findViewById(R.id.result)); - mDragController.setToolbar(getActivity().findViewById(R.id.toolbar)); - mDragController.setEvaluator(mEvaluator); - mDragController.initializeController(isResult, isOneLine); } @@ -211,15 +215,22 @@ public class HistoryFragment extends Fragment implements DragLayout.DragCallback } @Override + public void onInstanceStateRestored(boolean isOpen) { + if (isOpen) { + mRecyclerView.setVisibility(View.VISIBLE); + } + } + + @Override public void whileDragging(float yFraction) { - mDragController.animateViews(yFraction, mRecyclerView); + if (isVisible() || isRemoving()) { + mDragController.animateViews(yFraction, mRecyclerView); + } } @Override public boolean shouldCaptureView(View view, int x, int y) { - return view.getId() == R.id.history_frame - && mDragLayout.isViewUnder(view, x, y) - && !mRecyclerView.canScrollVertically(1 /* scrolling down */); + return !mRecyclerView.canScrollVertically(1 /* scrolling down */); } @Override @@ -227,10 +238,5 @@ public class HistoryFragment extends Fragment implements DragLayout.DragCallback return 0; } - @Override - public void onLayout(int translation) { - // no-op - } - /* End override DragCallback methods. */ } |