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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user