summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2016-12-19 09:11:38 -0800
committerJustin Klaassen <justinklaassen@google.com>2017-01-08 18:41:49 -0800
commit392977886711392c51b0727e9e10c96474794760 (patch)
tree12725995ee5999730f8cb354467ba8325b6fd064
parenta9395c92523f46caa90ebf94fbd96104b09f6d94 (diff)
downloadandroid_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.xml5
-rw-r--r--res/layout/fragment_history.xml4
-rw-r--r--res/layout/history_item.xml1
-rw-r--r--src/com/android/calculator2/Calculator.java74
-rw-r--r--src/com/android/calculator2/DragController.java94
-rw-r--r--src/com/android/calculator2/DragLayout.java165
-rw-r--r--src/com/android/calculator2/HistoryFragment.java68
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. */
}