Listen for changes to IME and show/hide nav bar

This feature is configurable and set to false as the default value. It
is overlayed as true for Automotive.

Bug: 138242566
Test: manual
Change-Id: I5dde8adc9d4ce749d895287ccf63017b284caec8
This commit is contained in:
Heemin Seog
2019-08-15 13:18:41 -07:00
parent 92bd450659
commit 26c830dd16
4 changed files with 99 additions and 16 deletions

View File

@@ -21,6 +21,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Debug; import android.os.Debug;
import android.os.IBinder; import android.os.IBinder;
@@ -50,6 +51,7 @@ public class SoftInputWindow extends Dialog {
final int mWindowType; final int mWindowType;
final int mGravity; final int mGravity;
final boolean mTakesFocus; final boolean mTakesFocus;
final boolean mAutomotiveHideNavBarForKeyboard;
private final Rect mBounds = new Rect(); private final Rect mBounds = new Rect();
@Retention(SOURCE) @Retention(SOURCE)
@@ -134,6 +136,8 @@ public class SoftInputWindow extends Dialog {
mWindowType = windowType; mWindowType = windowType;
mGravity = gravity; mGravity = gravity;
mTakesFocus = takesFocus; mTakesFocus = takesFocus;
mAutomotiveHideNavBarForKeyboard = context.getResources().getBoolean(
com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
initDockWindow(); initDockWindow();
} }
@@ -247,6 +251,11 @@ public class SoftInputWindow extends Dialog {
windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
} }
if (isAutomotive() && mAutomotiveHideNavBarForKeyboard) {
windowSetFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
windowModFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
}
getWindow().setFlags(windowSetFlags, windowModFlags); getWindow().setFlags(windowSetFlags, windowModFlags);
} }
@@ -338,6 +347,10 @@ public class SoftInputWindow extends Dialog {
mWindowState = newState; mWindowState = newState;
} }
private boolean isAutomotive() {
return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
private static String stateToString(@SoftInputWindowState int state) { private static String stateToString(@SoftInputWindowState int state) {
switch (state) { switch (state) {
case SoftInputWindowState.TOKEN_PENDING: case SoftInputWindowState.TOKEN_PENDING:

View File

@@ -4285,4 +4285,9 @@
<!-- The list of packages to automatically opt out of refresh rates higher than 60hz because <!-- The list of packages to automatically opt out of refresh rates higher than 60hz because
of known compatibility issues. --> of known compatibility issues. -->
<string-array name="config_highRefreshRateBlacklist"></string-array> <string-array name="config_highRefreshRateBlacklist"></string-array>
<!-- Whether or not to hide the navigation bar when the soft keyboard is visible in order to
create additional screen real estate outside beyond the keyboard. Note that the user needs
to have a confirmed way to dismiss the keyboard when desired. -->
<bool name="config_automotiveHideNavBarForKeyboard">false</bool>
</resources> </resources>

View File

@@ -3847,4 +3847,6 @@
<java-symbol type="string" name="config_factoryResetPackage" /> <java-symbol type="string" name="config_factoryResetPackage" />
<java-symbol type="array" name="config_highRefreshRateBlacklist" /> <java-symbol type="array" name="config_highRefreshRateBlacklist" />
<java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" />
</resources> </resources>

View File

@@ -31,7 +31,10 @@ import android.content.res.Configuration;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.util.Log; import android.util.Log;
import android.view.Display;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.Gravity; import android.view.Gravity;
import android.view.MotionEvent; import android.view.MotionEvent;
@@ -86,8 +89,7 @@ import java.util.Map;
/** /**
* A status bar (and navigation bar) tailored for the automotive use case. * A status bar (and navigation bar) tailored for the automotive use case.
*/ */
public class CarStatusBar extends StatusBar implements public class CarStatusBar extends StatusBar implements CarBatteryController.BatteryViewHandler {
CarBatteryController.BatteryViewHandler {
private static final String TAG = "CarStatusBar"; private static final String TAG = "CarStatusBar";
// used to calculate how fast to open or close the window // used to calculate how fast to open or close the window
private static final float DEFAULT_FLING_VELOCITY = 0; private static final float DEFAULT_FLING_VELOCITY = 0;
@@ -168,6 +170,9 @@ public class CarStatusBar extends StatusBar implements
private boolean mIsSwipingVerticallyToClose; private boolean mIsSwipingVerticallyToClose;
// Whether heads-up notifications should be shown when shade is open. // Whether heads-up notifications should be shown when shade is open.
private boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen; private boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
// If the nav bar should be hidden when the soft keyboard is visible.
private boolean mHideNavBarForKeyboard;
private boolean mBottomNavBarVisible;
private final CarPowerStateListener mCarPowerStateListener = private final CarPowerStateListener mCarPowerStateListener =
(int state) -> { (int state) -> {
@@ -189,6 +194,12 @@ public class CarStatusBar extends StatusBar implements
// builds the nav bar // builds the nav bar
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
mDeviceIsProvisioned = mDeviceProvisionedController.isDeviceProvisioned(); mDeviceIsProvisioned = mDeviceProvisionedController.isDeviceProvisioned();
// Keyboard related setup, before nav bars are created.
mHideNavBarForKeyboard = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
mBottomNavBarVisible = false;
super.start(); super.start();
mTaskStackListener = new TaskStackListenerImpl(); mTaskStackListener = new TaskStackListenerImpl();
mActivityManagerWrapper = ActivityManagerWrapper.getInstance(); mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
@@ -719,6 +730,13 @@ public class CarStatusBar extends StatusBar implements
buildNavBarContent(); buildNavBarContent();
attachNavBarWindows(); attachNavBarWindows();
// Try setting up the initial state of the nav bar if applicable.
if (result != null) {
setImeWindowStatus(Display.DEFAULT_DISPLAY, result.mImeToken,
result.mImeWindowVis, result.mImeBackDisposition,
result.mShowImeSwitcher);
}
// There has been a car customized nav bar on the default display, so just create nav bars // There has been a car customized nav bar on the default display, so just create nav bars
// on external displays. // on external displays.
mNavigationBarController.createNavigationBars(false /* includeDefaultDisplay */, result); mNavigationBarController.createNavigationBars(false /* includeDefaultDisplay */, result);
@@ -757,22 +775,33 @@ public class CarStatusBar extends StatusBar implements
} }
private void attachNavBarWindows() { /**
* We register for soft keyboard visibility events such that we can hide the navigation bar
if (mShowBottom) { * giving more screen space to the IME. Note: this is optional and controlled by
WindowManager.LayoutParams lp = new WindowManager.LayoutParams( * {@code com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard}.
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, */
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, @Override
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL boolean showImeSwitcher) {
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH if (!mHideNavBarForKeyboard) {
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, return;
PixelFormat.TRANSLUCENT);
lp.setTitle("CarNavigationBar");
lp.windowAnimations = 0;
mWindowManager.addView(mNavigationBarWindow, lp);
} }
if (mContext.getDisplay().getDisplayId() != displayId) {
return;
}
boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
if (!isKeyboardVisible) {
attachBottomNavBarWindow();
} else {
detachBottomNavBarWindow();
}
}
private void attachNavBarWindows() {
attachBottomNavBarWindow();
if (mShowLeft) { if (mShowLeft) {
int width = mContext.getResources().getDimensionPixelSize( int width = mContext.getResources().getDimensionPixelSize(
R.dimen.car_left_navigation_bar_width); R.dimen.car_left_navigation_bar_width);
@@ -807,7 +836,41 @@ public class CarStatusBar extends StatusBar implements
rightlp.gravity = Gravity.RIGHT; rightlp.gravity = Gravity.RIGHT;
mWindowManager.addView(mRightNavigationBarWindow, rightlp); mWindowManager.addView(mRightNavigationBarWindow, rightlp);
} }
}
private void attachBottomNavBarWindow() {
if (!mShowBottom) {
return;
}
if (mBottomNavBarVisible) {
return;
}
mBottomNavBarVisible = true;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
PixelFormat.TRANSLUCENT);
lp.setTitle("CarNavigationBar");
lp.windowAnimations = 0;
mWindowManager.addView(mNavigationBarWindow, lp);
}
private void detachBottomNavBarWindow() {
if (!mShowBottom) {
return;
}
if (!mBottomNavBarVisible) {
return;
}
mBottomNavBarVisible = false;
mWindowManager.removeView(mNavigationBarWindow);
} }
private void buildBottomBar(int layout) { private void buildBottomBar(int layout) {