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.logging.KeyboardStateManager.KeyboardState.SHOW; 19 20 import android.content.Context; 21 import android.graphics.Rect; 22 import android.text.TextUtils; 23 import android.util.AttributeSet; 24 import android.util.Log; 25 import android.view.DragEvent; 26 import android.view.KeyEvent; 27 import android.view.inputmethod.InputMethodManager; 28 import android.widget.EditText; 29 30 import com.android.launcher3.views.ActivityContext; 31 32 import java.util.HashSet; 33 import java.util.Set; 34 35 36 /** 37 * The edit text that reports back when the back key has been pressed. 38 * Note: AppCompatEditText doesn't fully support #displayCompletions and #onCommitCompletion 39 */ 40 public class ExtendedEditText extends EditText { 41 private static final String TAG = "ExtendedEditText"; 42 43 private final Set<OnFocusChangeListener> mOnFocusChangeListeners = new HashSet<>(); 44 45 private boolean mForceDisableSuggestions = false; 46 47 /** 48 * Implemented by listeners of the back key. 49 */ 50 public interface OnBackKeyListener { onBackKey()51 boolean onBackKey(); 52 } 53 54 private OnBackKeyListener mBackKeyListener; 55 ExtendedEditText(Context context)56 public ExtendedEditText(Context context) { 57 // ctor chaining breaks the touch handling 58 super(context); 59 } 60 ExtendedEditText(Context context, AttributeSet attrs)61 public ExtendedEditText(Context context, AttributeSet attrs) { 62 // ctor chaining breaks the touch handling 63 super(context, attrs); 64 } 65 ExtendedEditText(Context context, AttributeSet attrs, int defStyleAttr)66 public ExtendedEditText(Context context, AttributeSet attrs, int defStyleAttr) { 67 super(context, attrs, defStyleAttr); 68 } 69 setOnBackKeyListener(OnBackKeyListener listener)70 public void setOnBackKeyListener(OnBackKeyListener listener) { 71 mBackKeyListener = listener; 72 } 73 74 @Override onKeyPreIme(int keyCode, KeyEvent event)75 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 76 // If this is a back key, propagate the key back to the listener 77 if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP 78 && mBackKeyListener != null) { 79 return mBackKeyListener.onBackKey(); 80 } 81 return super.onKeyPreIme(keyCode, event); 82 } 83 84 @Override onDragEvent(DragEvent event)85 public boolean onDragEvent(DragEvent event) { 86 // We don't want this view to interfere with Launcher own drag and drop. 87 return false; 88 } 89 90 /** 91 * Synchronously shows the soft input method. 92 * 93 * @param shouldFocus whether this EditText should also request focus. 94 * @return true if the keyboard is shown correctly and focus is given to this view (if 95 * applicable). 96 */ showKeyboard(boolean shouldFocus)97 public boolean showKeyboard(boolean shouldFocus) { 98 onKeyboardShown(); 99 boolean focusResult = !shouldFocus || requestFocus(); 100 return focusResult && showSoftInputInternal(); 101 } 102 hideKeyboard()103 public void hideKeyboard() { 104 ActivityContext.lookupContext(getContext()).hideKeyboard(); 105 clearFocus(); 106 } 107 onKeyboardShown()108 protected void onKeyboardShown() { 109 ActivityContext.lookupContext(getContext()).getStatsLogManager() 110 .keyboardStateManager().setKeyboardState(SHOW); 111 } 112 showSoftInputInternal()113 private boolean showSoftInputInternal() { 114 boolean result = false; 115 InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); 116 if (imm != null) { 117 result = imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT); 118 } else { 119 Log.w(TAG, "Failed to retrieve InputMethodManager from the system."); 120 } 121 return result; 122 } 123 dispatchBackKey()124 public void dispatchBackKey() { 125 hideKeyboard(); 126 if (mBackKeyListener != null) { 127 mBackKeyListener.onBackKey(); 128 } 129 } 130 131 /** 132 * Set to true when you want isSuggestionsEnabled to return false. 133 * Use this to disable the red underlines that appear under typos when suggestions is enabled. 134 */ forceDisableSuggestions(boolean forceDisableSuggestions)135 public void forceDisableSuggestions(boolean forceDisableSuggestions) { 136 mForceDisableSuggestions = forceDisableSuggestions; 137 } 138 139 @Override isSuggestionsEnabled()140 public boolean isSuggestionsEnabled() { 141 return !mForceDisableSuggestions && super.isSuggestionsEnabled(); 142 } 143 reset()144 public void reset() { 145 if (!TextUtils.isEmpty(getText())) { 146 setText(""); 147 } 148 } 149 150 /** 151 * This method should be preferred to {@link #setOnFocusChangeListener(OnFocusChangeListener)}, 152 * as it allows for multiple listeners from different sources. 153 */ addOnFocusChangeListener(OnFocusChangeListener listener)154 public void addOnFocusChangeListener(OnFocusChangeListener listener) { 155 mOnFocusChangeListeners.add(listener); 156 } 157 158 /** 159 * Removes the given listener from the set of registered focus listeners, or does nothing if it 160 * wasn't registered in the first place. 161 */ removeOnFocusChangeListener(OnFocusChangeListener listener)162 public void removeOnFocusChangeListener(OnFocusChangeListener listener) { 163 mOnFocusChangeListeners.remove(listener); 164 } 165 166 @Override onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect)167 protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { 168 super.onFocusChanged(focused, direction, previouslyFocusedRect); 169 for (OnFocusChangeListener listener : mOnFocusChangeListeners) { 170 listener.onFocusChange(this, focused); 171 } 172 } 173 174 /** 175 * Save the input, suggestion, hint states when it's on focus, and set to unfocused states. 176 */ saveFocusedStateAndUpdateToUnfocusedState()177 public void saveFocusedStateAndUpdateToUnfocusedState() {} 178 179 /** 180 * Restore to the previous saved focused state. 181 */ restoreToFocusedState()182 public void restoreToFocusedState() {} 183 } 184