18a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk/*
28a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * Copyright 2017 The Android Open Source Project
38a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk *
48a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * Licensed under the Apache License, Version 2.0 (the "License");
58a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * you may not use this file except in compliance with the License.
68a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * You may obtain a copy of the License at
78a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk *
88a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
98a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk *
108a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * Unless required by applicable law or agreed to in writing, software
118a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * distributed under the License is distributed on an "AS IS" BASIS,
128a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * See the License for the specific language governing permissions and
148a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * limitations under the License.
158a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk */
168a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1785ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikaspackage androidx.slice.widget;
188a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
198a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.animation.Animator;
208a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.app.PendingIntent;
218a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.app.RemoteInput;
228a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.content.Context;
238a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.content.Intent;
248a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.graphics.Rect;
258a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.graphics.drawable.Drawable;
26f68dde011de8fb4d616a09292524869f56d94110Jason Monkimport android.os.Build;
278a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.os.Bundle;
288a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.text.Editable;
298a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.text.TextWatcher;
308a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.util.AttributeSet;
318a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.util.Log;
328a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.KeyEvent;
338a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.LayoutInflater;
348a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.MotionEvent;
358a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.View;
368a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.ViewAnimationUtils;
378a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.ViewGroup;
388a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.accessibility.AccessibilityEvent;
398a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.inputmethod.CompletionInfo;
408a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.inputmethod.EditorInfo;
418a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.inputmethod.InputConnection;
428a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.view.inputmethod.InputMethodManager;
438a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.widget.EditText;
448a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.widget.ImageButton;
458a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.widget.LinearLayout;
468a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.widget.ProgressBar;
478a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.widget.TextView;
488a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkimport android.widget.Toast;
498a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
50f68dde011de8fb4d616a09292524869f56d94110Jason Monkimport androidx.annotation.RequiresApi;
51f68dde011de8fb4d616a09292524869f56d94110Jason Monkimport androidx.annotation.RestrictTo;
52f68dde011de8fb4d616a09292524869f56d94110Jason Monkimport androidx.core.content.ContextCompat;
5307a4a56611cc044fd48b052db05aea332201216eJason Monkimport androidx.slice.SliceItem;
5485ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.view.R;
558a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
568a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk/**
578a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * Host for the remote input.
588a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk *
598a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk * @hide
608a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk */
618a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk// TODO this should be unified with SystemUI RemoteInputView (b/67527720)
628a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk@RestrictTo(RestrictTo.Scope.LIBRARY)
63f68dde011de8fb4d616a09292524869f56d94110Jason Monk@RequiresApi(21)
648a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monkpublic class RemoteInputView extends LinearLayout implements View.OnClickListener, TextWatcher {
658a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
668a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private static final String TAG = "RemoteInput";
678a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
688a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    /**
698a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     * A marker object that let's us easily find views of this class.
708a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     */
718a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public static final Object VIEW_TAG = new Object();
728a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
738a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private RemoteEditText mEditText;
748a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private ImageButton mSendButton;
758a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private ProgressBar mProgressBar;
7607a4a56611cc044fd48b052db05aea332201216eJason Monk    private SliceItem mAction;
778a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private RemoteInput[] mRemoteInputs;
788a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private RemoteInput mRemoteInput;
798a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
808a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private int mRevealCx;
818a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private int mRevealCy;
828a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private int mRevealR;
838a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private boolean mResetting;
848a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
858a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public RemoteInputView(Context context, AttributeSet attrs) {
868a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        super(context, attrs);
878a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
888a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
898a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @Override
908a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    protected void onFinishInflate() {
918a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        super.onFinishInflate();
928a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
938a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mProgressBar = findViewById(R.id.remote_input_progress);
948a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mSendButton = findViewById(R.id.remote_input_send);
958a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mSendButton.setOnClickListener(this);
968a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
978a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText = (RemoteEditText) getChildAt(0);
988a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
998a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            @Override
1008a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
1018a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                final boolean isSoftImeEvent = event == null
1028a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                        && (actionId == EditorInfo.IME_ACTION_DONE
1038a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                                || actionId == EditorInfo.IME_ACTION_NEXT
1048a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                                || actionId == EditorInfo.IME_ACTION_SEND);
1058a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                final boolean isKeyboardEnterKey = event != null
1068a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                        && isConfirmKey(event.getKeyCode())
1078a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                        && event.getAction() == KeyEvent.ACTION_DOWN;
1088a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1098a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                if (isSoftImeEvent || isKeyboardEnterKey) {
1108a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    if (mEditText.length() > 0) {
1118a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                        sendRemoteInput();
1128a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    }
1138a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    // Consume action to prevent IME from closing.
1148a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    return true;
1158a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                }
1168a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                return false;
1178a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            }
1188a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        });
1198a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.addTextChangedListener(this);
1208a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.setInnerFocusable(false);
1218a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.mRemoteInputView = this;
1228a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
1238a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1248a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private void sendRemoteInput() {
1258a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        Bundle results = new Bundle();
1268a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
1278a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
1288a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
1298a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                results);
1308a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1318a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.setEnabled(false);
1328a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mSendButton.setVisibility(INVISIBLE);
1338a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mProgressBar.setVisibility(VISIBLE);
1348a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.mShowImeOnInputConnection = false;
1358a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1368a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        // TODO: Figure out API for telling the system about slice interaction.
1378a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        // Tell ShortcutManager that this package has been "activated".  ShortcutManager
1388a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        // will reset the throttling for this package.
1398a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        // Strictly speaking, the intent receiver may be different from the intent creator,
1408a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        // but that's an edge case, and also because we can't always know which package will receive
1418a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        // an intent, so we just reset for the creator.
1428a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        //getContext().getSystemService(ShortcutManager.class).onApplicationActive(
14307a4a56611cc044fd48b052db05aea332201216eJason Monk        //        mAction.getCreatorPackage(),
1448a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        //        getContext().getUserId());
1458a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1468a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        try {
14707a4a56611cc044fd48b052db05aea332201216eJason Monk            mAction.fireAction(getContext(), fillInIntent);
1488a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            reset();
1498a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        } catch (PendingIntent.CanceledException e) {
1508a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            Log.i(TAG, "Unable to send remote input result", e);
1518a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            Toast.makeText(getContext(), "Failure sending pending intent for inline reply :(",
1528a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    Toast.LENGTH_SHORT).show();
1538a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            reset();
1548a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
1558a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
1568a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1578a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    /**
1588a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     * Creates a remote input view.
1598a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     */
1608a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public static RemoteInputView inflate(Context context, ViewGroup root) {
1618a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        RemoteInputView v = (RemoteInputView) LayoutInflater.from(context).inflate(
1628a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                R.layout.abc_slice_remote_input, root, false);
1638a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        v.setTag(VIEW_TAG);
1648a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        return v;
1658a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
1668a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1678a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @Override
1688a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public void onClick(View v) {
1698a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        if (v == mSendButton) {
1708a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            sendRemoteInput();
1718a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
1728a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
1738a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1748a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @Override
1758a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public boolean onTouchEvent(MotionEvent event) {
1768a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        super.onTouchEvent(event);
1778a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1788a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        // We never want for a touch to escape to an outer view or one we covered.
1798a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        return true;
1808a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
1818a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1828a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private void onDefocus() {
1838a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        setVisibility(INVISIBLE);
1848a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
1858a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1868a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    /**
1878a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     * Set the pending intent for remote input.
1888a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     */
18907a4a56611cc044fd48b052db05aea332201216eJason Monk    public void setAction(SliceItem action) {
19007a4a56611cc044fd48b052db05aea332201216eJason Monk        mAction = action;
1918a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
1928a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
1938a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    /**
1948a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     * Set the remote inputs for this view.
1958a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     */
1968a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public void setRemoteInput(RemoteInput[] remoteInputs, RemoteInput remoteInput) {
1978a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mRemoteInputs = remoteInputs;
1988a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mRemoteInput = remoteInput;
1998a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.setHint(mRemoteInput.getLabel());
2008a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2018a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2028a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    /**
2038a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     * Focuses the remote input view.
2048a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     */
2058a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public void focusAnimated() {
2068a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        if (getVisibility() != VISIBLE) {
2078a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            Animator animator = ViewAnimationUtils.createCircularReveal(
2088a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    this, mRevealCx, mRevealCy, 0, mRevealR);
2098a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            animator.setDuration(200);
2108a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            animator.start();
2118a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
2128a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        focus();
2138a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2148a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2158a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private void focus() {
2168a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        setVisibility(VISIBLE);
2178a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.setInnerFocusable(true);
2188a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.mShowImeOnInputConnection = true;
2198a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.setSelection(mEditText.getText().length());
2208a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.requestFocus();
2218a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        updateSendButton();
2228a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2238a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2248a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private void reset() {
2258a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mResetting = true;
2268a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2278a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.getText().clear();
2288a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mEditText.setEnabled(true);
2298a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mSendButton.setVisibility(VISIBLE);
2308a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mProgressBar.setVisibility(INVISIBLE);
2318a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        updateSendButton();
2328a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        onDefocus();
2338a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2348a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mResetting = false;
2358a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2368a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2378a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @Override
2388a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
2398a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        if (mResetting && child == mEditText) {
2408a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            // Suppress text events if it happens during resetting. Ideally this would be
2418a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            // suppressed by the text view not being shown, but that doesn't work here because it
2428a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            // needs to stay visible for the animation.
2438a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            return false;
2448a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
2458a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        return super.onRequestSendAccessibilityEvent(child, event);
2468a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2478a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2488a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    private void updateSendButton() {
2498a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mSendButton.setEnabled(mEditText.getText().length() != 0);
2508a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2518a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2528a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @Override
2538a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
2548a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2558a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2568a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @Override
2578a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public void onTextChanged(CharSequence s, int start, int before, int count) {
2588a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2598a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2608a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @Override
2618a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public void afterTextChanged(Editable s) {
2628a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        updateSendButton();
2638a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2648a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2658a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    /**
2668a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     * @hide
2678a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     */
2688a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @RestrictTo(RestrictTo.Scope.LIBRARY)
2698a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public void setRevealParameters(int cx, int cy, int r) {
2708a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mRevealCx = cx;
2718a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mRevealCy = cy;
2728a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        mRevealR = r;
2738a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2748a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2758a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @Override
2768a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public void dispatchStartTemporaryDetach() {
2778a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        super.dispatchStartTemporaryDetach();
2788a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        // Detach the EditText temporarily such that it doesn't get onDetachedFromWindow and
2798a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        // won't lose IME focus.
2808a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        detachViewFromParent(mEditText);
2818a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2828a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2838a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @Override
2848a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public void dispatchFinishTemporaryDetach() {
2858a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        if (isAttachedToWindow()) {
2868a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            attachViewToParent(mEditText, 0, mEditText.getLayoutParams());
2878a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        } else {
2888a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            removeDetachedView(mEditText, false /* animate */);
2898a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
2908a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        super.dispatchFinishTemporaryDetach();
2918a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
2928a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2938a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    /**
2948a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     * An EditText that changes appearance based on whether it's focusable and becomes un-focusable
2958a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     * whenever the user navigates away from it or it becomes invisible.
2968a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     */
2978a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public static class RemoteEditText extends EditText {
2988a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
2998a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        private final Drawable mBackground;
3008a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        private RemoteInputView mRemoteInputView;
3018a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        boolean mShowImeOnInputConnection;
3028a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3038a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        public RemoteEditText(Context context, AttributeSet attrs) {
3048a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            super(context, attrs);
3058a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            mBackground = getBackground();
3068a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
3078a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3088a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        private void defocusIfNeeded(boolean animate) {
309f68dde011de8fb4d616a09292524869f56d94110Jason Monk            if (mRemoteInputView != null || isTemporarilyDetachedCompat()) {
310f68dde011de8fb4d616a09292524869f56d94110Jason Monk                if (isTemporarilyDetachedCompat()) {
3118a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    // We might get reattached but then the other one of HUN / expanded might steal
3128a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    // our focus, so we'll need to save our text here.
3138a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                }
3148a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                return;
3158a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            }
3168a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            if (isFocusable() && isEnabled()) {
3178a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                setInnerFocusable(false);
3188a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                if (mRemoteInputView != null) {
3198a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    mRemoteInputView.onDefocus();
3208a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                }
3218a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                mShowImeOnInputConnection = false;
3228a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            }
3238a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
3248a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
325f68dde011de8fb4d616a09292524869f56d94110Jason Monk        private boolean isTemporarilyDetachedCompat() {
326f68dde011de8fb4d616a09292524869f56d94110Jason Monk            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
327f68dde011de8fb4d616a09292524869f56d94110Jason Monk                return isTemporarilyDetached();
328f68dde011de8fb4d616a09292524869f56d94110Jason Monk            }
329f68dde011de8fb4d616a09292524869f56d94110Jason Monk            return false;
330f68dde011de8fb4d616a09292524869f56d94110Jason Monk        }
331f68dde011de8fb4d616a09292524869f56d94110Jason Monk
3328a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        @Override
3338a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        protected void onVisibilityChanged(View changedView, int visibility) {
3348a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            super.onVisibilityChanged(changedView, visibility);
3358a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3368a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            if (!isShown()) {
3378a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                defocusIfNeeded(false /* animate */);
3388a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            }
3398a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
3408a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3418a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        @Override
3428a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
3438a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            super.onFocusChanged(focused, direction, previouslyFocusedRect);
3448a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            if (!focused) {
3458a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                defocusIfNeeded(true /* animate */);
3468a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            }
3478a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
3488a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3498a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        @Override
3508a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        public void getFocusedRect(Rect r) {
3518a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            super.getFocusedRect(r);
3528a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            r.top = getScrollY();
3538a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            r.bottom = getScrollY() + (getBottom() - getTop());
3548a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
3558a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3568a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        @Override
3578a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        public boolean onKeyDown(int keyCode, KeyEvent event) {
3588a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            if (keyCode == KeyEvent.KEYCODE_BACK) {
3598a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                // Eat the DOWN event here to prevent any default behavior.
3608a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                return true;
3618a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            }
3628a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            return super.onKeyDown(keyCode, event);
3638a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
3648a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3658a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        @Override
3668a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        public boolean onKeyUp(int keyCode, KeyEvent event) {
3678a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            if (keyCode == KeyEvent.KEYCODE_BACK) {
3688a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                defocusIfNeeded(true /* animate */);
3698a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                return true;
3708a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            }
3718a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            return super.onKeyUp(keyCode, event);
3728a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
3738a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3748a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        @Override
3758a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
3768a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
3778a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3788a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            if (mShowImeOnInputConnection && inputConnection != null) {
37906ab4aa38f82b8e2d9af769f7c777253f2497f93Jake Wharton                final InputMethodManager imm = ContextCompat.getSystemService(getContext(),
3808a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                        InputMethodManager.class);
3818a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                if (imm != null) {
3828a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    // onCreateInputConnection is called by InputMethodManager in the middle of
3838a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    // setting up the connection to the IME; wait with requesting the IME until that
3848a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    // work has completed.
3858a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    post(new Runnable() {
3868a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                        @Override
3878a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                        public void run() {
3888a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                            imm.viewClicked(RemoteEditText.this);
3898a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                            imm.showSoftInput(RemoteEditText.this, 0);
3908a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                        }
3918a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                    });
3928a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                }
3938a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            }
3948a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3958a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            return inputConnection;
3968a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
3978a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
3988a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        @Override
3998a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        public void onCommitCompletion(CompletionInfo text) {
4008a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            clearComposingText();
4018a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            setText(text.getText());
4028a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            setSelection(getText().length());
4038a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
4048a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
4058a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        void setInnerFocusable(boolean focusable) {
4068a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            setFocusableInTouchMode(focusable);
4078a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            setFocusable(focusable);
4088a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            setCursorVisible(focusable);
4098a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
4108a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            if (focusable) {
4118a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                requestFocus();
4128a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                setBackground(mBackground);
4138a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            } else {
4148a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                setBackground(null);
4158a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            }
4168a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
4178a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
4188a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
4198a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk
4208a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    /** Whether key will, by default, trigger a click on the focused view.
4218a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     * @hide
4228a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk     */
4238a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    @RestrictTo(RestrictTo.Scope.LIBRARY)
4248a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    public static final boolean isConfirmKey(int keyCode) {
4258a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        switch (keyCode) {
4268a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            case KeyEvent.KEYCODE_DPAD_CENTER:
4278a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            case KeyEvent.KEYCODE_ENTER:
4288a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            case KeyEvent.KEYCODE_SPACE:
4298a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            case KeyEvent.KEYCODE_NUMPAD_ENTER:
4308a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                return true;
4318a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk            default:
4328a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk                return false;
4338a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk        }
4348a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk    }
4358a452e96e2308fe9515aa91b8e5b369eeefc25e7Jason Monk}
436