fix jumping input layout on keyboard appearing / disappearing

This commit is contained in:
cyberta
2020-06-15 12:56:31 +02:00
parent 0df0d5bc8e
commit 4a022cd865
@@ -27,7 +27,6 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.View;
import android.view.ViewTreeObserver;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ServiceUtil;
@@ -41,7 +40,7 @@ import java.util.Set;
* LinearLayout that, when a view container, will report back when it thinks a soft keyboard
* has been opened and what its height would be.
*/
public class KeyboardAwareLinearLayout extends LinearLayoutCompat implements ViewTreeObserver.OnGlobalLayoutListener {
public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
private static final String TAG = KeyboardAwareLinearLayout.class.getSimpleName();
private final Rect rect = new Rect();
@@ -50,12 +49,15 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat implements Vie
private final int minKeyboardSize;
private final int minCustomKeyboardSize;
private final int defaultCustomKeyboardSize;
private final int minCustomKeyboardTopMargin;
private final int minCustomKeyboardTopMarginPortrait;
private final int minCustomKeyboardTopMarginLandscape;
private final int statusBarHeight;
private int viewInset;
private boolean keyboardOpen = false;
private int rotation = -1;
private boolean isFullscreen = false;
public KeyboardAwareLinearLayout(Context context) {
this(context, null);
@@ -68,52 +70,49 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat implements Vie
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final int statusBarRes = getResources().getIdentifier("status_bar_height", "dimen", "android");
minKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_keyboard_size);
minCustomKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_size);
defaultCustomKeyboardSize = getResources().getDimensionPixelSize(R.dimen.default_custom_keyboard_size);
minCustomKeyboardTopMargin = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_top_margin);
statusBarHeight = statusBarRes > 0 ? getResources().getDimensionPixelSize(statusBarRes) : 0;
viewInset = getViewInset();
minKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_keyboard_size);
minCustomKeyboardSize = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_size);
defaultCustomKeyboardSize = getResources().getDimensionPixelSize(R.dimen.default_custom_keyboard_size);
minCustomKeyboardTopMarginPortrait = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_top_margin);
minCustomKeyboardTopMarginLandscape = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_top_margin);
statusBarHeight = statusBarRes > 0 ? getResources().getDimensionPixelSize(statusBarRes) : 0;
viewInset = getViewInset();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
ViewTreeObserver observer = this.getViewTreeObserver();
observer.addOnGlobalLayoutListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
ViewTreeObserver observer = this.getViewTreeObserver();
if (Build.VERSION.SDK_INT < 16) {
observer.removeGlobalOnLayoutListener(this);
} else {
observer.removeOnGlobalLayoutListener(this);
}
}
@Override
public void onGlobalLayout() {
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
updateRotation();
updateKeyboardState();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void updateKeyboardState() {
if (isLandscape()) {
if (keyboardOpen) onKeyboardClose();
return;
private void updateRotation() {
int oldRotation = rotation;
rotation = getDeviceRotation();
if (oldRotation != rotation) {
Log.i(TAG, "rotation changed");
onKeyboardClose();
}
}
private void updateKeyboardState() {
if (viewInset == 0 && Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) viewInset = getViewInset();
final int availableHeight = this.getRootView().getHeight() - statusBarHeight - viewInset;
getWindowVisibleDisplayFrame(rect);
final int keyboardHeight = availableHeight - (rect.bottom - rect.top);
final int availableHeight = getAvailableHeight();
final int keyboardHeight = availableHeight - (rect.bottom - rect.top);
if (keyboardHeight > minKeyboardSize) {
if (getKeyboardHeight() != keyboardHeight) setKeyboardPortraitHeight(keyboardHeight);
if (!keyboardOpen) onKeyboardOpen(keyboardHeight);
if (getKeyboardHeight() != keyboardHeight) {
if (isLandscape()) {
setKeyboardLandscapeHeight(keyboardHeight);
} else {
setKeyboardPortraitHeight(keyboardHeight);
}
}
if (!keyboardOpen) {
onKeyboardOpen(keyboardHeight);
}
} else if (keyboardOpen) {
onKeyboardClose();
}
@@ -139,15 +138,27 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat implements Vie
return 0;
}
private int getAvailableHeight() {
final int availableHeight = this.getRootView().getHeight() - viewInset - (!isFullscreen ? statusBarHeight : 0);
final int availableWidth = this.getRootView().getWidth() - (!isFullscreen ? statusBarHeight : 0);
if (isLandscape() && availableHeight > availableWidth) {
//noinspection SuspiciousNameCombination
return availableWidth;
}
return availableHeight;
}
protected void onKeyboardOpen(int keyboardHeight) {
Log.w(TAG, "onKeyboardOpen(" + keyboardHeight + ")");
Log.i(TAG, "onKeyboardOpen(" + keyboardHeight + ")");
keyboardOpen = true;
notifyShownListeners();
}
protected void onKeyboardClose() {
Log.w(TAG, "onKeyboardClose()");
Log.i(TAG, "onKeyboardClose()");
keyboardOpen = false;
notifyHiddenListeners();
}
@@ -169,18 +180,25 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat implements Vie
}
private int getKeyboardLandscapeHeight() {
return Math.max(getHeight(), getRootView().getHeight()) / 2;
int keyboardHeight = PreferenceManager.getDefaultSharedPreferences(getContext())
.getInt("keyboard_height_landscape", defaultCustomKeyboardSize);
return Util.clamp(keyboardHeight, minCustomKeyboardSize, getRootView().getHeight() - minCustomKeyboardTopMarginLandscape);
}
private int getKeyboardPortraitHeight() {
int keyboardHeight = PreferenceManager.getDefaultSharedPreferences(getContext())
.getInt("keyboard_height_portrait", defaultCustomKeyboardSize);
return Util.clamp(keyboardHeight, minCustomKeyboardSize, getRootView().getHeight() - minCustomKeyboardTopMargin);
.getInt("keyboard_height_portrait", defaultCustomKeyboardSize);
return Util.clamp(keyboardHeight, minCustomKeyboardSize, getRootView().getHeight() - minCustomKeyboardTopMarginPortrait);
}
private void setKeyboardPortraitHeight(int height) {
PreferenceManager.getDefaultSharedPreferences(getContext())
.edit().putInt("keyboard_height_portrait", height).apply();
.edit().putInt("keyboard_height_portrait", height).apply();
}
private void setKeyboardLandscapeHeight(int height) {
PreferenceManager.getDefaultSharedPreferences(getContext())
.edit().putInt("keyboard_height_landscape", height).apply();
}
public void postOnKeyboardClose(final Runnable runnable) {
@@ -225,6 +243,10 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat implements Vie
shownListeners.remove(listener);
}
public void setFullscreen(boolean isFullscreen) {
this.isFullscreen = isFullscreen;
}
private void notifyHiddenListeners() {
final Set<OnKeyboardHiddenListener> listeners = new HashSet<>(hiddenListeners);
for (OnKeyboardHiddenListener listener : listeners) {