Direct Reply: Fix circular reveal origin

Makes sure the circular reveal origin matches the bounds of the
text. This is necessairy because the TextView for the last action
spans the full remaining width and is usually much larger than the
text, which makes the reveal look uncentered.

Also adds an animation for closing the direct reply view.

Bug: 29876991
Change-Id: Ib0ae8a12423f0ecfc573928a39634404c8232e40
This commit is contained in:
Adrian Roos
2016-07-15 12:26:49 -07:00
parent f8bc27d968
commit af06bf225a
3 changed files with 64 additions and 14 deletions

View File

@@ -472,20 +472,28 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
riv.setVisibility(View.VISIBLE);
int cx = view.getLeft() + view.getWidth() / 2;
int width = view.getWidth();
if (view instanceof TextView) {
// Center the reveal on the text which might be off-center from the TextView
TextView tv = (TextView) view;
if (tv.getLayout() != null) {
int innerWidth = (int) tv.getLayout().getLineWidth(0);
innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
width = Math.min(width, innerWidth);
}
}
int cx = view.getLeft() + width / 2;
int cy = view.getTop() + view.getHeight() / 2;
int w = riv.getWidth();
int h = riv.getHeight();
int r = Math.max(
Math.max(cx + cy, cx + (h - cy)),
Math.max((w - cx) + cy, (w - cx) + (h - cy)));
ViewAnimationUtils.createCircularReveal(riv, cx, cy, 0, r)
.start();
riv.setRevealParameters(cx, cy, r);
riv.setPendingIntent(pendingIntent);
riv.setRemoteInput(inputs, input);
riv.focus();
riv.focusAnimated();
return true;
}

View File

@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.policy;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
@@ -33,6 +35,7 @@ import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.inputmethod.CompletionInfo;
@@ -47,11 +50,13 @@ import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.stack.ScrollContainer;
import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
* Host for the remote input.
@@ -77,6 +82,10 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private View mScrollContainerChild;
private boolean mRemoved;
private int mRevealCx;
private int mRevealCy;
private int mRevealR;
public RemoteInputView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -180,14 +189,28 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
return true;
}
public void onDefocus() {
private void onDefocus(boolean animate) {
mController.removeRemoteInput(mEntry);
mEntry.remoteInputText = mEditText.getText();
// During removal, we get reattached and lose focus. Not hiding in that
// case to prevent flicker.
if (!mRemoved) {
setVisibility(INVISIBLE);
if (animate && mRevealR > 0) {
Animator reveal = ViewAnimationUtils.createCircularReveal(
this, mRevealCx, mRevealCy, mRevealR, 0);
reveal.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
reveal.setDuration(StackStateAnimator.ANIMATION_DURATION_CLOSE_REMOTE_INPUT);
reveal.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
setVisibility(INVISIBLE);
}
});
reveal.start();
} else {
setVisibility(INVISIBLE);
}
}
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_CLOSE,
mEntry.notification.getPackageName());
@@ -223,6 +246,17 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mEditText.setHint(mRemoteInput.getLabel());
}
public void focusAnimated() {
if (getVisibility() != VISIBLE) {
Animator animator = ViewAnimationUtils.createCircularReveal(
this, mRevealCx, mRevealCy, 0, mRevealR);
animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
animator.start();
}
focus();
}
public void focus() {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_OPEN,
mEntry.notification.getPackageName());
@@ -253,7 +287,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mProgressBar.setVisibility(INVISIBLE);
mController.removeSpinning(mEntry.key);
updateSendButton();
onDefocus();
onDefocus(false /* animate */);
}
private void updateSendButton() {
@@ -272,7 +306,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
public void close() {
mEditText.defocusIfNeeded();
mEditText.defocusIfNeeded(false /* animated */);
}
@Override
@@ -321,6 +355,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
other.close();
setPendingIntent(other.mPendingIntent);
setRemoteInput(other.mRemoteInputs, other.mRemoteInput);
setRevealParameters(other.mRevealCx, other.mRevealCy, other.mRevealR);
focus();
}
@@ -374,6 +409,12 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mRemoved = true;
}
public void setRevealParameters(int cx, int cy, int r) {
mRevealCx = cx;
mRevealCy = cy;
mRevealR = r;
}
/**
* An EditText that changes appearance based on whether it's focusable and becomes
* un-focusable whenever the user navigates away from it or it becomes invisible.
@@ -389,14 +430,14 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mBackground = getBackground();
}
private void defocusIfNeeded() {
private void defocusIfNeeded(boolean animate) {
if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()) {
return;
}
if (isFocusable() && isEnabled()) {
setInnerFocusable(false);
if (mRemoteInputView != null) {
mRemoteInputView.onDefocus();
mRemoteInputView.onDefocus(animate);
}
mShowImeOnInputConnection = false;
}
@@ -407,7 +448,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
super.onVisibilityChanged(changedView, visibility);
if (!isShown()) {
defocusIfNeeded();
defocusIfNeeded(false /* animate */);
}
}
@@ -415,7 +456,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (!focused) {
defocusIfNeeded();
defocusIfNeeded(true /* animate */);
}
}
@@ -434,7 +475,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
defocusIfNeeded();
defocusIfNeeded(true /* animate */);
final InputMethodManager imm = InputMethodManager.getInstance();
imm.hideSoftInputFromWindow(getWindowToken(), 0);
return true;

View File

@@ -44,6 +44,7 @@ public class StackStateAnimator {
public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448;
public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464;
public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
public static final int ANIMATION_DURATION_CLOSE_REMOTE_INPUT = 150;
public static final int ANIMATION_DURATION_HEADS_UP_APPEAR = 650;
public static final int ANIMATION_DURATION_HEADS_UP_DISAPPEAR = 230;
public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80;