Home | History | Annotate | Download | only in input
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package android.support.car.input;
     17 
     18 import android.content.Context;
     19 import android.text.InputType;
     20 import android.util.AttributeSet;
     21 import android.view.ActionMode;
     22 import android.view.KeyEvent;
     23 import android.view.inputmethod.EditorInfo;
     24 import android.view.inputmethod.InputConnection;
     25 import android.view.inputmethod.InputConnectionWrapper;
     26 import android.widget.EditText;
     27 import android.widget.TextView;
     28 
     29 /**
     30  * A special EditText for use in-car. This EditText:
     31  * <ul>
     32  *     <li>Disables selection</li>
     33  *     <li>Disables Cut/Copy/Paste</li>
     34  *     <li>Force-disables suggestions</li>
     35  * </ul>
     36  * @hide
     37  */
     38 public class CarRestrictedEditText extends EditText implements CarEditable {
     39 
     40     private static final boolean SELECTION_CLAMPING_ENABLED = false;
     41 
     42     private int mLastSelEnd = 0;
     43     private int mLastSelStart = 0;
     44     private boolean mCursorClamped;
     45 
     46     private CarEditableListener mCarEditableListener;
     47     private KeyListener mListener;
     48 
     49     public interface KeyListener {
     50         void onKeyDown(int keyCode);
     51         void onKeyUp(int keyCode);
     52         void onCommitText(String input);
     53         void onCloseKeyboard();
     54         void onDelete();
     55     }
     56 
     57     public CarRestrictedEditText(Context context, AttributeSet attrs) {
     58         super(context, attrs);
     59         setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
     60         setTextIsSelectable(false);
     61         setSelection(getText().length());
     62         mCursorClamped = true;
     63         setOnEditorActionListener(new OnEditorActionListener() {
     64             @Override
     65             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
     66                 if (mListener != null && actionId == EditorInfo.IME_ACTION_DONE) {
     67                     mListener.onCloseKeyboard();
     68                 }
     69                 // Return false because we don't want to hijack the default behavior.
     70                 return false;
     71             }
     72         });
     73     }
     74 
     75     public void setKeyListener(KeyListener listener) {
     76         mListener = listener;
     77     }
     78 
     79     @SuppressWarnings("unused")
     80     @Override
     81     protected void onSelectionChanged(int selStart, int selEnd) {
     82         if (mCursorClamped && SELECTION_CLAMPING_ENABLED) {
     83             setSelection(mLastSelStart, mLastSelEnd);
     84             return;
     85         }
     86         if (mCarEditableListener != null) {
     87             mCarEditableListener.onUpdateSelection(mLastSelStart, mLastSelEnd, selStart, selEnd);
     88         }
     89         mLastSelStart = selStart;
     90         mLastSelEnd = selEnd;
     91     }
     92 
     93     @Override
     94     public ActionMode startActionMode(ActionMode.Callback callback) {
     95         return null;
     96     }
     97 
     98     @Override
     99     public void setCarEditableListener(CarEditableListener listener) {
    100         mCarEditableListener = listener;
    101     }
    102 
    103     @Override
    104     public void setInputEnabled(boolean enabled) {
    105         mCursorClamped = !enabled;
    106     }
    107 
    108     @Override
    109     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
    110         InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
    111         return new InputConnectionWrapper(inputConnection, false) {
    112             @Override
    113             public boolean sendKeyEvent(android.view.KeyEvent event) {
    114                 if (mListener != null) {
    115                     if (event.getAction() == KeyEvent.ACTION_DOWN) {
    116                         mListener.onKeyDown(event.getKeyCode());
    117                     } else if (event.getAction() == KeyEvent.ACTION_UP) {
    118                         mListener.onKeyUp(event.getKeyCode());
    119 
    120                         // InputMethodService#sendKeyChar doesn't call
    121                         // InputConnection#commitText for digit chars.
    122                         // TODO: fix projected IME to be in coherence with system IME.
    123                         char unicodeChar = (char) event.getUnicodeChar();
    124                         if (Character.isDigit(unicodeChar)) {
    125                             commitText(String.valueOf(unicodeChar), 1);
    126                         }
    127                     }
    128                     return true;
    129                 } else {
    130                     return super.sendKeyEvent(event);
    131                 }
    132             }
    133 
    134             @Override
    135             public boolean commitText(java.lang.CharSequence charSequence, int i) {
    136                 if (mListener != null) {
    137                     mListener.onCommitText(charSequence.toString());
    138                     return true;
    139                 }
    140                 return super.commitText(charSequence, i);
    141             }
    142 
    143             @Override
    144             public boolean deleteSurroundingText(int i, int i1) {
    145                 if (mListener != null) {
    146                     mListener.onDelete();
    147                     return true;
    148                 }
    149                 return super.deleteSurroundingText(i, i1);
    150             }
    151         };
    152     }
    153 }
    154