package de.jeisfeld.augendiagnoselib.util; import android.app.Activity; import android.graphics.Rect; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; import android.view.ViewTreeObserver; import android.widget.FrameLayout; /** * Utility class that ensures that the activity is resized when the keyboard appears, in full screen mode. * * <p>android:windowSoftInputMode="adjustResize" does not work in full screen mode. * * <p>Thanks to Joseph Johnson for this class. * * <p>For more information, see https://code.google.com/p/android/issues/detail?id=5497 To use this class, simply invoke * assistActivity() on an Activity that already has its content view set. */ public final class AutoKeyboardLayoutUtility { /** * Assumed minimum portion that the keyboard fills vertically. */ private static final float MIN_KEYBOARD_SIZE = .1f; /** * Method to be called to apply the workaround to the activity. Should be called at the end of onCreate(). * * @param activity the activity which uses the workaround. */ @SuppressWarnings("unused") public static void assistActivity(@NonNull final Activity activity) { new AutoKeyboardLayoutUtility(activity); } /** * Method to be called to apply the workaround to the activity. Should be called at the end of onCreate(). * * @param activity the activity which uses the workaround. * @param callback a callback to be called if the kayboard is shown or hidden. * @param changeLayout Flag indicating if the layout should be changed by this tool, or if it is only used for the callback. */ public static void assistActivity(@NonNull final Activity activity, final OnKeyboardChangeListener callback, final boolean changeLayout) { AutoKeyboardLayoutUtility instance = new AutoKeyboardLayoutUtility(activity); instance.mCallback = callback; instance.mChangeLayout = changeLayout; } // JAVADOC:OFF private final View mChildOfContent; private int mUsableHeightPrevious; @NonNull private final FrameLayout.LayoutParams mFrameLayoutParams; @Nullable private ActivityWithExplicitLayoutTrigger mActivityWithLayoutTrigger = null; // JAVADOC:ON /** * A callback to be called if the kayboard is shown or hidden. */ @Nullable private OnKeyboardChangeListener mCallback = null; /** * Flag indicating if the layout should be changed by this tool, or if it is only used for the callback. */ private boolean mChangeLayout = true; /** * Constructor, adding a listener to change the global layout if required. * * @param activity the activity which uses the workaround. */ private AutoKeyboardLayoutUtility(@NonNull final Activity activity) { FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content); mChildOfContent = content.getChildAt(0); mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { possiblyResizeChildOfContent(); } }); mFrameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams(); if (activity instanceof ActivityWithExplicitLayoutTrigger) { mActivityWithLayoutTrigger = (ActivityWithExplicitLayoutTrigger) activity; } } /** * Resize the view, as the keyboard may have appeared or vanished. */ private void possiblyResizeChildOfContent() { int usableHeightNow = computeUsableHeight(); if (usableHeightNow != mUsableHeightPrevious) { int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight(); int heightDifference = usableHeightSansKeyboard - usableHeightNow; if (heightDifference > (usableHeightSansKeyboard * MIN_KEYBOARD_SIZE)) { // keyboard probably just became visible if (mChangeLayout) { mFrameLayoutParams.height = usableHeightSansKeyboard - heightDifference; } if (mCallback != null) { mCallback.onKeyboardChanged(true); } } else { // keyboard probably just became hidden if (mChangeLayout) { mFrameLayoutParams.height = usableHeightSansKeyboard; } if (mCallback != null) { mCallback.onKeyboardChanged(false); } } mChildOfContent.requestLayout(); mUsableHeightPrevious = usableHeightNow; if (mActivityWithLayoutTrigger != null) { mActivityWithLayoutTrigger.requestLayout(); } } } /** * Calculate the height that can be used for the view above keyboard. * * @return the usable height. */ private int computeUsableHeight() { Rect r = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(r); return r.bottom - r.top; } /** * Callback for activities to request layout. */ public interface ActivityWithExplicitLayoutTrigger { /** * Callback method to do request layout. */ void requestLayout(); } /** * Callback listener that will be informed if the keyboard is added or removed. */ public interface OnKeyboardChangeListener { /** * Callback method that will be called if the keyboard is added or removed. * * @param visible true if the keyboard is added, false if the keyboard is removed. */ void onKeyboardChanged(final boolean visible); } }