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 com.android.launcher3;
17 
18 import static com.android.launcher3.util.UiThreadHelper.hideKeyboardAsync;
19 
20 import android.content.Context;
21 import android.text.TextUtils;
22 import android.util.AttributeSet;
23 import android.view.DragEvent;
24 import android.view.KeyEvent;
25 import android.view.inputmethod.InputMethodManager;
26 import android.widget.EditText;
27 
28 import com.android.launcher3.views.ActivityContext;
29 
30 
31 /**
32  * The edit text that reports back when the back key has been pressed.
33  * Note: AppCompatEditText doesn't fully support #displayCompletions and #onCommitCompletion
34  */
35 public class ExtendedEditText extends EditText {
36 
37     private boolean mShowImeAfterFirstLayout;
38     private boolean mForceDisableSuggestions = false;
39 
40     /**
41      * Implemented by listeners of the back key.
42      */
43     public interface OnBackKeyListener {
onBackKey()44         boolean onBackKey();
45     }
46 
47     private OnBackKeyListener mBackKeyListener;
48 
ExtendedEditText(Context context)49     public ExtendedEditText(Context context) {
50         // ctor chaining breaks the touch handling
51         super(context);
52     }
53 
ExtendedEditText(Context context, AttributeSet attrs)54     public ExtendedEditText(Context context, AttributeSet attrs) {
55         // ctor chaining breaks the touch handling
56         super(context, attrs);
57     }
58 
ExtendedEditText(Context context, AttributeSet attrs, int defStyleAttr)59     public ExtendedEditText(Context context, AttributeSet attrs, int defStyleAttr) {
60         super(context, attrs, defStyleAttr);
61     }
62 
setOnBackKeyListener(OnBackKeyListener listener)63     public void setOnBackKeyListener(OnBackKeyListener listener) {
64         mBackKeyListener = listener;
65     }
66 
67     @Override
onKeyPreIme(int keyCode, KeyEvent event)68     public boolean onKeyPreIme(int keyCode, KeyEvent event) {
69         // If this is a back key, propagate the key back to the listener
70         if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
71             if (TextUtils.isEmpty(getText())) {
72                 hideKeyboard();
73             }
74             if (mBackKeyListener != null) {
75                 return mBackKeyListener.onBackKey();
76             }
77             return false;
78         }
79         return super.onKeyPreIme(keyCode, event);
80     }
81 
82     @Override
onDragEvent(DragEvent event)83     public boolean onDragEvent(DragEvent event) {
84         // We don't want this view to interfere with Launcher own drag and drop.
85         return false;
86     }
87 
88     @Override
onLayout(boolean changed, int left, int top, int right, int bottom)89     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
90         super.onLayout(changed, left, top, right, bottom);
91         if (mShowImeAfterFirstLayout) {
92             // soft input only shows one frame after the layout of the EditText happens,
93             post(() -> {
94                 showSoftInput();
95                 mShowImeAfterFirstLayout = false;
96             });
97         }
98     }
99 
100 
showKeyboard()101     public void showKeyboard() {
102         mShowImeAfterFirstLayout = !showSoftInput();
103     }
104 
hideKeyboard()105     public void hideKeyboard() {
106         hideKeyboardAsync(ActivityContext.lookupContext(getContext()), getWindowToken());
107     }
108 
showSoftInput()109     private boolean showSoftInput() {
110         return requestFocus() &&
111                 getContext().getSystemService(InputMethodManager.class)
112                     .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
113     }
114 
dispatchBackKey()115     public void dispatchBackKey() {
116         hideKeyboard();
117         if (mBackKeyListener != null) {
118             mBackKeyListener.onBackKey();
119         }
120     }
121 
122     /**
123      * Set to true when you want isSuggestionsEnabled to return false.
124      * Use this to disable the red underlines that appear under typos when suggestions is enabled.
125      */
forceDisableSuggestions(boolean forceDisableSuggestions)126     public void forceDisableSuggestions(boolean forceDisableSuggestions) {
127         mForceDisableSuggestions = forceDisableSuggestions;
128     }
129 
130     @Override
isSuggestionsEnabled()131     public boolean isSuggestionsEnabled() {
132         return !mForceDisableSuggestions && super.isSuggestionsEnabled();
133     }
134 
reset()135     public void reset() {
136         if (!TextUtils.isEmpty(getText())) {
137             setText("");
138         }
139     }
140 }
141