Files
lawnchair/src/com/android/launcher3/ExtendedEditText.java
Andy Wickham a601341ff5 Add a WindowInsetsAnimationCallback to listen to IME changes.
This handles cases that were previously ignored, such as dismissing
the IME with the back key/gesture.

Removed extraneous manual state updates that were used for specific
cases previously. The only remaining state updates are from our
controlled IME animation in KeyboardInsetsHandler, as that correctly
handles the case where you start closing the IME but end up keeping
it open (or vice versa).

Bug: 277738379
Fix: 320659754
Test: Manually go through various IME transitions on Launcher,
open and close apps, lock/unlock, etc to verify keyboard state
is correctly updated. And verify b/320659754 steps do not repro.
Flag: NA

Change-Id: I4787afbb37eed815b909a0215d8afeb3894ab985
2024-01-23 15:56:37 -08:00

200 lines
6.5 KiB
Java

/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
import android.content.Context;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import com.android.launcher3.views.ActivityContext;
import java.util.HashSet;
import java.util.Set;
/**
* The edit text that reports back when the back key has been pressed.
* Note: AppCompatEditText doesn't fully support #displayCompletions and #onCommitCompletion
*/
public class ExtendedEditText extends EditText {
private static final String TAG = "ExtendedEditText";
private final Set<OnFocusChangeListener> mOnFocusChangeListeners = new HashSet<>();
private boolean mForceDisableSuggestions = false;
/**
* Implemented by listeners of the back key.
*/
public interface OnBackKeyListener {
boolean onBackKey();
}
private OnBackKeyListener mBackKeyListener;
public ExtendedEditText(Context context) {
// ctor chaining breaks the touch handling
super(context);
}
public ExtendedEditText(Context context, AttributeSet attrs) {
// ctor chaining breaks the touch handling
super(context, attrs);
}
public ExtendedEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setOnBackKeyListener(OnBackKeyListener listener) {
mBackKeyListener = listener;
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
// If this is a back key, propagate the key back to the listener
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP
&& mBackKeyListener != null) {
return mBackKeyListener.onBackKey();
}
return super.onKeyPreIme(keyCode, event);
}
@Override
public boolean onDragEvent(DragEvent event) {
// We don't want this view to interfere with Launcher own drag and drop.
return false;
}
/**
* Synchronously shows the soft input method.
*
* @return true if the keyboard is shown correctly and focus is given to this view.
*/
public boolean showKeyboard() {
return requestFocus() && showSoftInputInternal();
}
/**
* Requests the framework to show the keyboard in order to ensure that an already registered
* controlled keyboard animation is triggered correctly.
* Must NEVER be called in any other case than to trigger a pre-registered controlled animation.
*/
public void requestShowKeyboardForControlledAnimation() {
// We don't log the keyboard state, as that must happen only after the controlled animation
// has completed.
// We also must not request focus, as this triggers unwanted side effects.
showSoftInputInternal();
}
public void hideKeyboard() {
hideKeyboard(/* clearFocus= */ true);
}
public void hideKeyboard(boolean clearFocus) {
ActivityContext.lookupContext(getContext()).hideKeyboard();
if (clearFocus) {
clearFocus();
}
}
private boolean showSoftInputInternal() {
boolean result = false;
InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
if (imm != null) {
result = imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
} else {
Log.w(TAG, "Failed to retrieve InputMethodManager from the system.");
}
return result;
}
public void dispatchBackKey() {
hideKeyboard();
if (mBackKeyListener != null) {
mBackKeyListener.onBackKey();
}
}
/**
* Set to true when you want isSuggestionsEnabled to return false.
* Use this to disable the red underlines that appear under typos when suggestions is enabled.
*/
public void forceDisableSuggestions(boolean forceDisableSuggestions) {
mForceDisableSuggestions = forceDisableSuggestions;
}
@Override
public boolean isSuggestionsEnabled() {
return !mForceDisableSuggestions && super.isSuggestionsEnabled();
}
public void reset() {
if (!TextUtils.isEmpty(getText())) {
setText("");
}
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
// With hardware keyboard, there is a possibility that the user types before edit
// text is visible during the transition.
// So move the cursor to the end of the text.
setSelection(getText().length());
}
/**
* This method should be preferred to {@link #setOnFocusChangeListener(OnFocusChangeListener)},
* as it allows for multiple listeners from different sources.
*/
public void addOnFocusChangeListener(OnFocusChangeListener listener) {
mOnFocusChangeListeners.add(listener);
}
/**
* Removes the given listener from the set of registered focus listeners, or does nothing if it
* wasn't registered in the first place.
*/
public void removeOnFocusChangeListener(OnFocusChangeListener listener) {
mOnFocusChangeListeners.remove(listener);
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
for (OnFocusChangeListener listener : mOnFocusChangeListeners) {
listener.onFocusChange(this, focused);
}
}
/**
* Save the input, suggestion, hint states when it's on focus, and set to unfocused states.
*/
public void saveFocusedStateAndUpdateToUnfocusedState() {}
/**
* Restore to the previous saved focused state.
*/
public void restoreToFocusedState() {}
}