• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
onKeyDown(int keyCode)50         void onKeyDown(int keyCode);
onKeyUp(int keyCode)51         void onKeyUp(int keyCode);
onCommitText(String input)52         void onCommitText(String input);
onCloseKeyboard()53         void onCloseKeyboard();
onDelete()54         void onDelete();
55     }
56 
CarRestrictedEditText(Context context, AttributeSet attrs)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 
setKeyListener(KeyListener listener)75     public void setKeyListener(KeyListener listener) {
76         mListener = listener;
77     }
78 
79     @SuppressWarnings("unused")
80     @Override
onSelectionChanged(int selStart, int selEnd)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
startActionMode(ActionMode.Callback callback)94     public ActionMode startActionMode(ActionMode.Callback callback) {
95         return null;
96     }
97 
98     @Override
setCarEditableListener(CarEditableListener listener)99     public void setCarEditableListener(CarEditableListener listener) {
100         mCarEditableListener = listener;
101     }
102 
103     @Override
setInputEnabled(boolean enabled)104     public void setInputEnabled(boolean enabled) {
105         mCursorClamped = !enabled;
106     }
107 
108     @Override
onCreateInputConnection(EditorInfo outAttrs)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