Merge "Landscape 3 button nav on taskbar phone supported" into tm-qpr-dev
This commit is contained in:
@@ -23,7 +23,6 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
||||
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
|
||||
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.SYSUI_SURFACE_PROGRESS_INDEX;
|
||||
import static com.android.launcher3.taskbar.TaskbarManager.isPhoneButtonNavMode;
|
||||
import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
|
||||
@@ -54,6 +53,7 @@ import android.content.res.ColorStateList;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.Region.Op;
|
||||
@@ -81,6 +81,9 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AlphaUpdateListener;
|
||||
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
|
||||
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory;
|
||||
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter;
|
||||
import com.android.launcher3.util.DimensionUtils;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
@@ -181,6 +184,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
|
||||
private final ViewTreeObserver.OnComputeInternalInsetsListener mSeparateWindowInsetsComputer =
|
||||
this::onComputeInsetsForSeparateWindow;
|
||||
private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
|
||||
private View mRecentsButton;
|
||||
|
||||
public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
|
||||
mContext = context;
|
||||
@@ -203,11 +207,11 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
|
||||
boolean isThreeButtonNav = mContext.isThreeButtonNav();
|
||||
DeviceProfile deviceProfile = mContext.getDeviceProfile();
|
||||
Resources resources = mContext.getResources();
|
||||
mNavButtonsView.getLayoutParams().height = !isPhoneMode(deviceProfile) ?
|
||||
mContext.isUserSetupComplete()
|
||||
? deviceProfile.taskbarSize
|
||||
: resources.getDimensionPixelSize(R.dimen.taskbar_suw_frame)
|
||||
: resources.getDimensionPixelSize(R.dimen.taskbar_size);
|
||||
Point p = !mContext.isUserSetupComplete()
|
||||
? new Point(0, resources.getDimensionPixelSize(R.dimen.taskbar_suw_frame))
|
||||
: DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
|
||||
TaskbarManager.isPhoneMode(deviceProfile));
|
||||
mNavButtonsView.getLayoutParams().height = p.y;
|
||||
|
||||
mIsImeRenderingNavButtons =
|
||||
InputMethodService.canImeRenderGesturalNavButtons() && mContext.imeDrawsImeNavBar();
|
||||
@@ -268,81 +272,6 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
|
||||
mControllers.navButtonController);
|
||||
updateButtonLayoutSpacing();
|
||||
updateStateForFlag(FLAG_SMALL_SCREEN, isPhoneButtonNavMode(mContext));
|
||||
if (isInSetup) {
|
||||
handleSetupUi();
|
||||
|
||||
// Hide back button in SUW if keyboard is showing (IME draws its own back).
|
||||
mPropertyHolders.add(new StatePropertyHolder(
|
||||
mBackButtonAlpha.getProperty(ALPHA_INDEX_SUW),
|
||||
flags -> (flags & FLAG_IME_VISIBLE) == 0));
|
||||
|
||||
// TODO(b/210906568) Dark intensity is currently not propagated during setup, so set
|
||||
// it based on dark theme for now.
|
||||
int mode = resources.getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_MASK;
|
||||
boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES;
|
||||
mTaskbarNavButtonDarkIntensity.updateValue(isDarkTheme ? 0 : 1);
|
||||
} else if (isInKidsMode) {
|
||||
int iconSize = resources.getDimensionPixelSize(
|
||||
R.dimen.taskbar_icon_size_kids);
|
||||
int buttonWidth = resources.getDimensionPixelSize(
|
||||
R.dimen.taskbar_nav_buttons_width_kids);
|
||||
int buttonHeight = resources.getDimensionPixelSize(
|
||||
R.dimen.taskbar_nav_buttons_height_kids);
|
||||
int buttonRadius = resources.getDimensionPixelSize(
|
||||
R.dimen.taskbar_nav_buttons_corner_radius_kids);
|
||||
int paddingleft = (buttonWidth - iconSize) / 2;
|
||||
int paddingRight = paddingleft;
|
||||
int paddingTop = (buttonHeight - iconSize) / 2;
|
||||
int paddingBottom = paddingTop;
|
||||
|
||||
// Update icons
|
||||
((ImageView) mBackButton).setImageDrawable(
|
||||
mBackButton.getContext().getDrawable(R.drawable.ic_sysbar_back_kids));
|
||||
((ImageView) mBackButton).setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
mBackButton.setPadding(paddingleft, paddingTop, paddingRight, paddingBottom);
|
||||
((ImageView) mHomeButton).setImageDrawable(
|
||||
mHomeButton.getContext().getDrawable(R.drawable.ic_sysbar_home_kids));
|
||||
((ImageView) mHomeButton).setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
mHomeButton.setPadding(paddingleft, paddingTop, paddingRight, paddingBottom);
|
||||
|
||||
// Home button layout
|
||||
LinearLayout.LayoutParams homeLayoutparams = new LinearLayout.LayoutParams(
|
||||
buttonWidth,
|
||||
buttonHeight
|
||||
);
|
||||
int homeButtonLeftMargin = resources.getDimensionPixelSize(
|
||||
R.dimen.taskbar_home_button_left_margin_kids);
|
||||
homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0);
|
||||
mHomeButton.setLayoutParams(homeLayoutparams);
|
||||
|
||||
// Back button layout
|
||||
LinearLayout.LayoutParams backLayoutParams = new LinearLayout.LayoutParams(
|
||||
buttonWidth,
|
||||
buttonHeight
|
||||
);
|
||||
int backButtonLeftMargin = resources.getDimensionPixelSize(
|
||||
R.dimen.taskbar_back_button_left_margin_kids);
|
||||
backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0);
|
||||
mBackButton.setLayoutParams(backLayoutParams);
|
||||
|
||||
// Button backgrounds
|
||||
int whiteWith10PctAlpha = Color.argb(0.1f, 1, 1, 1);
|
||||
PaintDrawable buttonBackground = new PaintDrawable(whiteWith10PctAlpha);
|
||||
buttonBackground.setCornerRadius(buttonRadius);
|
||||
mHomeButton.setBackground(buttonBackground);
|
||||
mBackButton.setBackground(buttonBackground);
|
||||
|
||||
// Update alignment within taskbar
|
||||
FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams)
|
||||
mNavButtonContainer.getLayoutParams();
|
||||
navButtonsLayoutParams.setMarginStart(navButtonsLayoutParams.getMarginEnd() / 2);
|
||||
navButtonsLayoutParams.setMarginEnd(navButtonsLayoutParams.getMarginStart());
|
||||
navButtonsLayoutParams.gravity = Gravity.CENTER;
|
||||
mNavButtonContainer.requestLayout();
|
||||
|
||||
mHomeButton.setOnLongClickListener(null);
|
||||
}
|
||||
|
||||
// Animate taskbar background when either..
|
||||
// notification shade expanded AND not on keyguard
|
||||
@@ -445,20 +374,20 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
|
||||
(flags & FLAG_DISABLE_HOME) == 0));
|
||||
|
||||
// Recents button
|
||||
View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
|
||||
mRecentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
|
||||
navContainer, navButtonController, R.id.recent_apps);
|
||||
mHitboxExtender.init(recentsButton, mNavButtonsView, mContext.getDeviceProfile(),
|
||||
mHitboxExtender.init(mRecentsButton, mNavButtonsView, mContext.getDeviceProfile(),
|
||||
() -> {
|
||||
float[] recentsCoords = new float[2];
|
||||
getDescendantCoordRelativeToAncestor(recentsButton, mNavButtonsView,
|
||||
getDescendantCoordRelativeToAncestor(mRecentsButton, mNavButtonsView,
|
||||
recentsCoords, false);
|
||||
return recentsCoords;
|
||||
}, new Handler());
|
||||
recentsButton.setOnClickListener(v -> {
|
||||
mRecentsButton.setOnClickListener(v -> {
|
||||
navButtonController.onButtonClick(BUTTON_RECENTS, v);
|
||||
mHitboxExtender.onRecentsButtonClicked();
|
||||
});
|
||||
mPropertyHolders.add(new StatePropertyHolder(recentsButton,
|
||||
mPropertyHolders.add(new StatePropertyHolder(mRecentsButton,
|
||||
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_RECENTS) == 0
|
||||
&& !mContext.isNavBarKidsModeActive()));
|
||||
|
||||
@@ -773,14 +702,22 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
|
||||
|| !mContext.isUserSetupComplete()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPhoneButtonNavMode(mContext)) {
|
||||
updatePhoneButtonSpacing();
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceProfile dp = mContext.getDeviceProfile();
|
||||
Resources res = mContext.getResources();
|
||||
boolean isInSetup = !mContext.isUserSetupComplete();
|
||||
// TODO(b/244231596) we're getting the incorrect kidsMode value in small-screen
|
||||
boolean isInKidsMode = mContext.isNavBarKidsModeActive();
|
||||
|
||||
if (TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) {
|
||||
boolean isThreeButtonNav = mContext.isThreeButtonNav();
|
||||
|
||||
NavButtonLayoutter navButtonLayoutter =
|
||||
NavButtonLayoutFactory.Companion.getUiLayoutter(
|
||||
dp, mNavButtonsView, res, isInKidsMode, isInSetup, isThreeButtonNav,
|
||||
TaskbarManager.isPhoneMode(dp));
|
||||
navButtonLayoutter.layoutButtons(dp, isContextualButtonShowing());
|
||||
return;
|
||||
}
|
||||
|
||||
// Add spacing after the end of the last nav button
|
||||
FrameLayout.LayoutParams navButtonParams =
|
||||
@@ -816,38 +753,84 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
|
||||
buttonLayoutParams.setMarginEnd(spaceInBetween / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Uniformly spaces out the 3 button nav for smaller phone screens */
|
||||
private void updatePhoneButtonSpacing() {
|
||||
DeviceProfile dp = mContext.getDeviceProfile();
|
||||
Resources res = mContext.getResources();
|
||||
if (isInSetup) {
|
||||
handleSetupUi();
|
||||
|
||||
// TODO: Polish pending, this is just to make it usable
|
||||
FrameLayout.LayoutParams navContainerParams =
|
||||
(FrameLayout.LayoutParams) mNavButtonContainer.getLayoutParams();
|
||||
int endStartMargins = res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size);
|
||||
navContainerParams.gravity = Gravity.CENTER;
|
||||
navContainerParams.setMarginEnd(endStartMargins);
|
||||
navContainerParams.setMarginStart(endStartMargins);
|
||||
mNavButtonContainer.setLayoutParams(navContainerParams);
|
||||
// Hide back button in SUW if keyboard is showing (IME draws its own back).
|
||||
mPropertyHolders.add(new StatePropertyHolder(
|
||||
mBackButtonAlpha.getProperty(ALPHA_INDEX_SUW),
|
||||
flags -> (flags & FLAG_IME_VISIBLE) == 0));
|
||||
|
||||
// Add the spaces in between the nav buttons
|
||||
int spaceInBetween = res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone);
|
||||
for (int i = 0; i < mNavButtonContainer.getChildCount(); i++) {
|
||||
View navButton = mNavButtonContainer.getChildAt(i);
|
||||
LinearLayout.LayoutParams buttonLayoutParams =
|
||||
(LinearLayout.LayoutParams) navButton.getLayoutParams();
|
||||
buttonLayoutParams.weight = 1;
|
||||
if (i == 0) {
|
||||
buttonLayoutParams.setMarginEnd(spaceInBetween / 2);
|
||||
} else if (i == mNavButtonContainer.getChildCount() - 1) {
|
||||
buttonLayoutParams.setMarginStart(spaceInBetween / 2);
|
||||
} else {
|
||||
buttonLayoutParams.setMarginStart(spaceInBetween / 2);
|
||||
buttonLayoutParams.setMarginEnd(spaceInBetween / 2);
|
||||
}
|
||||
// TODO(b/210906568) Dark intensity is currently not propagated during setup, so set
|
||||
// it based on dark theme for now.
|
||||
int mode = res.getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_MASK;
|
||||
boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES;
|
||||
mTaskbarNavButtonDarkIntensity.updateValue(isDarkTheme ? 0 : 1);
|
||||
} else if (isInKidsMode) {
|
||||
int iconSize = res.getDimensionPixelSize(
|
||||
R.dimen.taskbar_icon_size_kids);
|
||||
int buttonWidth = res.getDimensionPixelSize(
|
||||
R.dimen.taskbar_nav_buttons_width_kids);
|
||||
int buttonHeight = res.getDimensionPixelSize(
|
||||
R.dimen.taskbar_nav_buttons_height_kids);
|
||||
int buttonRadius = res.getDimensionPixelSize(
|
||||
R.dimen.taskbar_nav_buttons_corner_radius_kids);
|
||||
int paddingleft = (buttonWidth - iconSize) / 2;
|
||||
int paddingRight = paddingleft;
|
||||
int paddingTop = (buttonHeight - iconSize) / 2;
|
||||
int paddingBottom = paddingTop;
|
||||
|
||||
// Update icons
|
||||
((ImageView) mBackButton).setImageDrawable(
|
||||
mBackButton.getContext().getDrawable(R.drawable.ic_sysbar_back_kids));
|
||||
((ImageView) mBackButton).setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
mBackButton.setPadding(paddingleft, paddingTop, paddingRight, paddingBottom);
|
||||
((ImageView) mHomeButton).setImageDrawable(
|
||||
mHomeButton.getContext().getDrawable(R.drawable.ic_sysbar_home_kids));
|
||||
((ImageView) mHomeButton).setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
mHomeButton.setPadding(paddingleft, paddingTop, paddingRight, paddingBottom);
|
||||
|
||||
// Home button layout
|
||||
LinearLayout.LayoutParams homeLayoutparams = new LinearLayout.LayoutParams(
|
||||
buttonWidth,
|
||||
buttonHeight
|
||||
);
|
||||
int homeButtonLeftMargin = res.getDimensionPixelSize(
|
||||
R.dimen.taskbar_home_button_left_margin_kids);
|
||||
homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0);
|
||||
mHomeButton.setLayoutParams(homeLayoutparams);
|
||||
|
||||
// Back button layout
|
||||
LinearLayout.LayoutParams backLayoutParams = new LinearLayout.LayoutParams(
|
||||
buttonWidth,
|
||||
buttonHeight
|
||||
);
|
||||
int backButtonLeftMargin = res.getDimensionPixelSize(
|
||||
R.dimen.taskbar_back_button_left_margin_kids);
|
||||
backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0);
|
||||
mBackButton.setLayoutParams(backLayoutParams);
|
||||
|
||||
// Button backgrounds
|
||||
int whiteWith10PctAlpha = Color.argb(0.1f, 1, 1, 1);
|
||||
PaintDrawable buttonBackground = new PaintDrawable(whiteWith10PctAlpha);
|
||||
buttonBackground.setCornerRadius(buttonRadius);
|
||||
mHomeButton.setBackground(buttonBackground);
|
||||
mBackButton.setBackground(buttonBackground);
|
||||
|
||||
// Update alignment within taskbar
|
||||
FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams)
|
||||
mNavButtonContainer.getLayoutParams();
|
||||
navButtonsLayoutParams.setMarginStart(
|
||||
navButtonsLayoutParams.getMarginEnd() / 2);
|
||||
navButtonsLayoutParams.setMarginEnd(navButtonsLayoutParams.getMarginStart());
|
||||
navButtonsLayoutParams.gravity = Gravity.CENTER;
|
||||
mNavButtonContainer.requestLayout();
|
||||
|
||||
mHomeButton.setOnLongClickListener(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
@@ -859,6 +842,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
|
||||
|
||||
moveNavButtonsBackToTaskbarWindow();
|
||||
mNavButtonContainer.removeAllViews();
|
||||
mEndContextualContainer.removeAllViews();
|
||||
mStartContextualContainer.removeAllViews();
|
||||
mAllButtons.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -101,8 +101,8 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen);
|
||||
} else {
|
||||
mStashedHandleView.getLayoutParams().height = deviceProfile.taskbarSize;
|
||||
mStashedHandleWidth =
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width);
|
||||
mStashedHandleWidth = resources
|
||||
.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width);
|
||||
}
|
||||
|
||||
mTaskbarStashedHandleAlpha.getProperty(ALPHA_INDEX_STASHED).setValue(
|
||||
|
||||
@@ -154,6 +154,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
|
||||
mIsNavBarForceVisible = settingsCache.getValue(
|
||||
Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
|
||||
// TODO(b/244231596) For shared Taskbar window, update this value in init() instead so
|
||||
// to get correct value when recreating the taskbar
|
||||
mIsNavBarKidsMode = settingsCache.getValue(
|
||||
Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
|
||||
|
||||
@@ -276,9 +278,13 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
* @param type The window type to pass to the created WindowManager.LayoutParams.
|
||||
*/
|
||||
public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type) {
|
||||
DeviceProfile deviceProfile = getDeviceProfile();
|
||||
// Taskbar is on the logical bottom of the screen
|
||||
boolean isVerticalBarLayout = TaskbarManager.isPhoneMode(deviceProfile) &&
|
||||
deviceProfile.isLandscape;
|
||||
WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(
|
||||
MATCH_PARENT,
|
||||
mLastRequestedNonFullscreenHeight,
|
||||
isVerticalBarLayout ? mLastRequestedNonFullscreenHeight : MATCH_PARENT,
|
||||
isVerticalBarLayout ? MATCH_PARENT : mLastRequestedNonFullscreenHeight,
|
||||
type,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
| WindowManager.LayoutParams.FLAG_SLIPPERY
|
||||
@@ -286,7 +292,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
PixelFormat.TRANSLUCENT);
|
||||
windowLayoutParams.setTitle(WINDOW_TITLE);
|
||||
windowLayoutParams.packageName = getPackageName();
|
||||
windowLayoutParams.gravity = Gravity.BOTTOM;
|
||||
windowLayoutParams.gravity = !isVerticalBarLayout ?
|
||||
Gravity.BOTTOM :
|
||||
Gravity.END; // TODO(b/230394142): seascape
|
||||
|
||||
windowLayoutParams.setFitInsetsTypes(0);
|
||||
windowLayoutParams.receiveInsetsIgnoringZOrder = true;
|
||||
windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
|
||||
@@ -803,7 +812,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
return mIsUserSetupComplete;
|
||||
}
|
||||
|
||||
protected boolean isNavBarKidsModeActive() {
|
||||
public boolean isNavBarKidsModeActive() {
|
||||
return mIsNavBarKidsMode && isThreeButtonNav();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.DimensionUtils;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.quickstep.AnimatedFloat;
|
||||
|
||||
@@ -177,9 +179,12 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
|
||||
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
|
||||
if (TaskbarManager.isPhoneMode(deviceProfile)) {
|
||||
Resources resources = mActivity.getResources();
|
||||
return mActivity.isThreeButtonNav() ?
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_size) :
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
|
||||
Point taskbarDimensions =
|
||||
DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
|
||||
TaskbarManager.isPhoneMode(deviceProfile));
|
||||
return taskbarDimensions.y == -1 ?
|
||||
deviceProfile.getDisplayInfo().currentSize.y :
|
||||
taskbarDimensions.y;
|
||||
} else {
|
||||
return deviceProfile.taskbarSize;
|
||||
}
|
||||
|
||||
@@ -84,16 +84,16 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask
|
||||
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
|
||||
for (provider in windowLayoutParams.providedInsets) {
|
||||
if (provider.type == ITYPE_EXTRA_NAVIGATION_BAR) {
|
||||
provider.insetsSize = Insets.of(0, 0, 0, contentHeight)
|
||||
provider.insetsSize = getInsetsByNavMode(contentHeight)
|
||||
} else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT
|
||||
|| provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES) {
|
||||
provider.insetsSize = Insets.of(0, 0, 0, tappableHeight)
|
||||
provider.insetsSize = getInsetsByNavMode(tappableHeight)
|
||||
}
|
||||
}
|
||||
|
||||
val imeInsetsSize = Insets.of(0, 0, 0, taskbarHeightForIme)
|
||||
val imeInsetsSize = getInsetsByNavMode(taskbarHeightForIme)
|
||||
// Use 0 insets for the VoiceInteractionWindow (assistant) when gesture nav is enabled.
|
||||
val visInsetsSize = Insets.of(0, 0, 0, if (context.isGestureNav) 0 else tappableHeight)
|
||||
val visInsetsSize = getInsetsByNavMode(if (context.isGestureNav) 0 else tappableHeight)
|
||||
val insetsSizeOverride = arrayOf(
|
||||
InsetsFrameProvider.InsetsSizeOverride(
|
||||
TYPE_INPUT_METHOD,
|
||||
@@ -109,6 +109,21 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return [Insets] where the [bottomInset] is either used as a bottom inset or
|
||||
* right/left inset if using 3 button nav
|
||||
*/
|
||||
private fun getInsetsByNavMode(bottomInset: Int) : Insets {
|
||||
val devicePortrait = !context.deviceProfile.isLandscape
|
||||
if (!TaskbarManager.isPhoneButtonNavMode(context) || devicePortrait) {
|
||||
// Taskbar or portrait phone mode
|
||||
return Insets.of(0, 0, 0, bottomInset)
|
||||
}
|
||||
|
||||
// TODO(b/230394142): seascape
|
||||
return Insets.of(0, 0, bottomInset, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@param providesInsetsTypes} as the inset types provided by {@param params}.
|
||||
* @param params The window layout params.
|
||||
|
||||
@@ -715,8 +715,16 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
|
||||
applyState(skipAnim ? 0 : animDuration, skipAnim ? 0 : startDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* We stash when IME or IME switcher is showing AND NOT
|
||||
* * in small screen AND
|
||||
* * 3 button nav AND
|
||||
* * landscape (or seascape)
|
||||
*/
|
||||
private boolean shouldStashForIme() {
|
||||
return mIsImeShowing || mIsImeSwitcherShowing;
|
||||
return (mIsImeShowing || mIsImeSwitcherShowing) &&
|
||||
!(isPhoneMode() && mActivity.isThreeButtonNav()
|
||||
&& mActivity.getDeviceProfile().isLandscape);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.taskbar.navbutton
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
|
||||
|
||||
/**
|
||||
* Meant to be a simple container for data subclasses will need
|
||||
*
|
||||
* Assumes that the 3 navigation buttons (back/home/recents) have already been added to
|
||||
* [navButtonContainer]
|
||||
*
|
||||
* @property navButtonContainer ViewGroup that holds the 3 navigation buttons.
|
||||
* @property endContextualContainer ViewGroup that holds the end contextual button (ex, IME dismiss).
|
||||
* @property startContextualContainer ViewGroup that holds the start contextual button (ex, A11y).
|
||||
*/
|
||||
abstract class AbstractNavButtonLayoutter(
|
||||
val resources: Resources,
|
||||
val navButtonContainer: LinearLayout,
|
||||
protected val endContextualContainer: ViewGroup,
|
||||
protected val startContextualContainer: ViewGroup
|
||||
) : NavButtonLayoutter {
|
||||
protected val homeButton: ImageView = navButtonContainer
|
||||
.findViewById(R.id.home)
|
||||
protected val recentsButton: ImageView = navButtonContainer
|
||||
.findViewById(R.id.recent_apps)
|
||||
protected val backButton: ImageView = navButtonContainer
|
||||
.findViewById(R.id.back)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.taskbar.navbutton
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.PaintDrawable
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_ICON_SIZE_KIDS
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DRAWABLE_SYSBAR_BACK_KIDS
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DRAWABLE_SYSBAR_HOME_KIDS
|
||||
|
||||
class KidsNavLayoutter(
|
||||
resources: Resources,
|
||||
navBarContainer: LinearLayout,
|
||||
endContextualContainer: ViewGroup,
|
||||
startContextualContainer: ViewGroup
|
||||
) : AbstractNavButtonLayoutter(
|
||||
resources,
|
||||
navBarContainer,
|
||||
endContextualContainer,
|
||||
startContextualContainer
|
||||
) {
|
||||
|
||||
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
|
||||
val iconSize: Int = resources.getDimensionPixelSize(
|
||||
DIMEN_TASKBAR_ICON_SIZE_KIDS)
|
||||
val buttonWidth: Int = resources.getDimensionPixelSize(
|
||||
DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS)
|
||||
val buttonHeight: Int = resources.getDimensionPixelSize(
|
||||
DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS)
|
||||
val buttonRadius: Int = resources.getDimensionPixelSize(
|
||||
DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS)
|
||||
val paddingLeft = (buttonWidth - iconSize) / 2
|
||||
val paddingTop = (buttonHeight - iconSize) / 2
|
||||
|
||||
// Update icons
|
||||
backButton.setImageDrawable(
|
||||
backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS))
|
||||
backButton.scaleType = ImageView.ScaleType.FIT_CENTER
|
||||
backButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
|
||||
homeButton.setImageDrawable(
|
||||
homeButton.getContext().getDrawable(DRAWABLE_SYSBAR_HOME_KIDS))
|
||||
homeButton.scaleType = ImageView.ScaleType.FIT_CENTER
|
||||
homeButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
|
||||
|
||||
// Home button layout
|
||||
val homeLayoutparams = LinearLayout.LayoutParams(
|
||||
buttonWidth,
|
||||
buttonHeight
|
||||
)
|
||||
val homeButtonLeftMargin: Int = resources.getDimensionPixelSize(
|
||||
DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS)
|
||||
homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0)
|
||||
homeButton.layoutParams = homeLayoutparams
|
||||
|
||||
// Back button layout
|
||||
val backLayoutParams = LinearLayout.LayoutParams(
|
||||
buttonWidth,
|
||||
buttonHeight
|
||||
)
|
||||
val backButtonLeftMargin: Int = resources.getDimensionPixelSize(
|
||||
DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS)
|
||||
backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0)
|
||||
backButton.layoutParams = backLayoutParams
|
||||
|
||||
// Button backgrounds
|
||||
val whiteWith10PctAlpha = Color.argb(0.1f, 1f, 1f, 1f)
|
||||
val buttonBackground = PaintDrawable(whiteWith10PctAlpha)
|
||||
buttonBackground.setCornerRadius(buttonRadius.toFloat())
|
||||
homeButton.background = buttonBackground
|
||||
backButton.background = buttonBackground
|
||||
|
||||
// Update alignment within taskbar
|
||||
val navButtonsLayoutParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
|
||||
navButtonsLayoutParams.apply {
|
||||
marginStart = navButtonsLayoutParams.marginEnd / 2
|
||||
marginEnd = navButtonsLayoutParams.marginStart
|
||||
gravity = Gravity.CENTER
|
||||
}
|
||||
navButtonContainer.requestLayout()
|
||||
|
||||
homeButton.onLongClickListener = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.taskbar.navbutton;
|
||||
|
||||
import android.annotation.DimenRes;
|
||||
import android.annotation.DrawableRes;
|
||||
import android.annotation.IdRes;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
|
||||
/**
|
||||
* A class for retrieving resources in Kotlin.
|
||||
*
|
||||
* This class should be removed once the build system supports resources loading in Kotlin.
|
||||
*/
|
||||
public final class LayoutResourceHelper {
|
||||
|
||||
// --------------------------
|
||||
// Kids Nav Layout
|
||||
@DimenRes
|
||||
public static final int DIMEN_TASKBAR_ICON_SIZE_KIDS = R.dimen.taskbar_icon_size_kids;
|
||||
@DrawableRes
|
||||
public static final int DRAWABLE_SYSBAR_BACK_KIDS = R.drawable.ic_sysbar_back_kids;
|
||||
@DrawableRes
|
||||
public static final int DRAWABLE_SYSBAR_HOME_KIDS = R.drawable.ic_sysbar_home_kids;
|
||||
@DimenRes
|
||||
public static final int DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS =
|
||||
R.dimen.taskbar_home_button_left_margin_kids;
|
||||
@DimenRes
|
||||
public static final int DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS =
|
||||
R.dimen.taskbar_back_button_left_margin_kids;
|
||||
@DimenRes
|
||||
public static final int DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS =
|
||||
R.dimen.taskbar_nav_buttons_width_kids;
|
||||
@DimenRes
|
||||
public static final int DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS =
|
||||
R.dimen.taskbar_nav_buttons_height_kids;
|
||||
@DimenRes
|
||||
public static final int DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS =
|
||||
R.dimen.taskbar_nav_buttons_corner_radius_kids;
|
||||
|
||||
// --------------------------
|
||||
// Nav Layout Factory
|
||||
@IdRes
|
||||
public static final int ID_START_CONTEXTUAL_BUTTONS = R.id.start_contextual_buttons;
|
||||
@IdRes
|
||||
public static final int ID_END_CONTEXTUAL_BUTTONS = R.id.end_contextual_buttons;
|
||||
@IdRes
|
||||
public static final int ID_END_NAV_BUTTONS = R.id.end_nav_buttons;
|
||||
|
||||
private LayoutResourceHelper() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.taskbar.navbutton
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
|
||||
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
|
||||
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.Companion
|
||||
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
|
||||
|
||||
/**
|
||||
* Select the correct layout for nav buttons
|
||||
*
|
||||
* Since layouts are done dynamically for the nav buttons on Taskbar, this
|
||||
* class returns a corresponding [NavButtonLayoutter] via
|
||||
* [Companion.getUiLayoutter]
|
||||
* that can help position the buttons based on the current [DeviceProfile]
|
||||
*/
|
||||
class NavButtonLayoutFactory {
|
||||
companion object {
|
||||
/**
|
||||
* Get the correct instance of [NavButtonLayoutter]
|
||||
*
|
||||
* No layouts supported for configurations where:
|
||||
* * taskbar isn't showing AND
|
||||
* * the device is not in [phoneMode]
|
||||
* OR
|
||||
* * phone is showing
|
||||
* * device is using gesture navigation
|
||||
*
|
||||
* @param navButtonsView ViewGroup that contains start, end, nav button ViewGroups
|
||||
* @param isKidsMode no-op when taskbar is hidden/not showing
|
||||
* @param isInSetup no-op when taskbar is hidden/not showing
|
||||
* @param phoneMode refers to the device using the taskbar window on phones
|
||||
* @param isThreeButtonNav are no-ops when taskbar is present/showing
|
||||
*/
|
||||
fun getUiLayoutter(deviceProfile: DeviceProfile,
|
||||
navButtonsView: FrameLayout,
|
||||
resources: Resources,
|
||||
isKidsMode: Boolean,
|
||||
isInSetup: Boolean,
|
||||
isThreeButtonNav: Boolean,
|
||||
phoneMode: Boolean):
|
||||
NavButtonLayoutter {
|
||||
val navButtonContainer =
|
||||
navButtonsView.findViewById<LinearLayout>(ID_END_NAV_BUTTONS)
|
||||
val endContextualContainer =
|
||||
navButtonsView.findViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS)
|
||||
val startContextualContainer =
|
||||
navButtonsView.findViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS)
|
||||
val isPhoneNavMode = phoneMode && isThreeButtonNav
|
||||
return when {
|
||||
isPhoneNavMode -> {
|
||||
if (!deviceProfile.isLandscape) {
|
||||
PhonePortraitNavLayoutter(resources, navButtonContainer,
|
||||
endContextualContainer, startContextualContainer)
|
||||
} else {
|
||||
PhoneLandscapeNavLayoutter(resources, navButtonContainer,
|
||||
endContextualContainer, startContextualContainer)
|
||||
}
|
||||
}
|
||||
deviceProfile.isTaskbarPresent -> {
|
||||
return when {
|
||||
isInSetup -> {
|
||||
SetupNavLayoutter(resources, navButtonContainer, endContextualContainer,
|
||||
startContextualContainer)
|
||||
}
|
||||
isKidsMode -> {
|
||||
KidsNavLayoutter(resources, navButtonContainer, endContextualContainer,
|
||||
startContextualContainer)
|
||||
}
|
||||
else ->
|
||||
TaskbarNavLayoutter(resources, navButtonContainer, endContextualContainer,
|
||||
startContextualContainer)
|
||||
}
|
||||
}
|
||||
else -> error("No layoutter found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Lays out and provides access to the home, recents, and back buttons for various mischief */
|
||||
interface NavButtonLayoutter {
|
||||
fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.taskbar.navbutton
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.children
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.taskbar.TaskbarManager
|
||||
import com.android.launcher3.util.DimensionUtils
|
||||
|
||||
class PhoneLandscapeNavLayoutter(
|
||||
resources: Resources,
|
||||
navBarContainer: LinearLayout,
|
||||
endContextualContainer: ViewGroup,
|
||||
startContextualContainer: ViewGroup
|
||||
) : AbstractNavButtonLayoutter(
|
||||
resources,
|
||||
navBarContainer,
|
||||
endContextualContainer,
|
||||
startContextualContainer
|
||||
) {
|
||||
|
||||
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
|
||||
// TODO(b/230395757): Polish pending, this is just to make it usable
|
||||
val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
|
||||
val endStartMargins =
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
|
||||
val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
|
||||
TaskbarManager.isPhoneMode(dp))
|
||||
navButtonContainer.removeAllViews()
|
||||
navButtonContainer.orientation = LinearLayout.VERTICAL
|
||||
|
||||
navContainerParams.apply {
|
||||
width = taskbarDimensions.x
|
||||
height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
gravity = Gravity.CENTER
|
||||
topMargin = endStartMargins
|
||||
bottomMargin = endStartMargins
|
||||
marginEnd = 0
|
||||
marginStart = 0
|
||||
}
|
||||
|
||||
// Swap recents and back button
|
||||
navButtonContainer.addView(recentsButton)
|
||||
navButtonContainer.addView(homeButton)
|
||||
navButtonContainer.addView(backButton)
|
||||
|
||||
navButtonContainer.layoutParams = navContainerParams
|
||||
|
||||
// Add the spaces in between the nav buttons
|
||||
val spaceInBetween: Int =
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
|
||||
navButtonContainer.children.forEachIndexed { i, navButton ->
|
||||
val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
|
||||
buttonLayoutParams.weight = 1f
|
||||
when (i) {
|
||||
0 -> {
|
||||
buttonLayoutParams.bottomMargin = spaceInBetween / 2
|
||||
}
|
||||
navButtonContainer.childCount - 1 -> {
|
||||
buttonLayoutParams.topMargin = spaceInBetween / 2
|
||||
}
|
||||
else -> {
|
||||
buttonLayoutParams.bottomMargin = spaceInBetween / 2
|
||||
buttonLayoutParams.topMargin = spaceInBetween / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.taskbar.navbutton
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.taskbar.TaskbarManager
|
||||
import com.android.launcher3.util.DimensionUtils
|
||||
|
||||
class PhonePortraitNavLayoutter(resources: Resources, navBarContainer: LinearLayout,
|
||||
endContextualContainer: ViewGroup,
|
||||
startContextualContainer: ViewGroup) :
|
||||
AbstractNavButtonLayoutter(resources, navBarContainer, endContextualContainer,
|
||||
startContextualContainer) {
|
||||
|
||||
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
|
||||
// TODO(b/230395757): Polish pending, this is just to make it usable
|
||||
val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
|
||||
val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
|
||||
TaskbarManager.isPhoneMode(dp))
|
||||
val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
|
||||
navContainerParams.width = taskbarDimensions.x
|
||||
navContainerParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
navContainerParams.gravity = Gravity.CENTER_VERTICAL
|
||||
|
||||
// Ensure order of buttons is correct
|
||||
navButtonContainer.removeAllViews()
|
||||
navButtonContainer.orientation = LinearLayout.HORIZONTAL
|
||||
navContainerParams.topMargin = 0
|
||||
navContainerParams.bottomMargin = 0
|
||||
navContainerParams.marginEnd = endStartMargins
|
||||
navContainerParams.marginStart = endStartMargins
|
||||
// Swap recents and back button in case we were landscape prior to this
|
||||
navButtonContainer.addView(backButton)
|
||||
navButtonContainer.addView(homeButton)
|
||||
navButtonContainer.addView(recentsButton)
|
||||
|
||||
navButtonContainer.layoutParams = navContainerParams
|
||||
|
||||
// Add the spaces in between the nav buttons
|
||||
val spaceInBetween =
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
|
||||
for (i in 0 until navButtonContainer.childCount) {
|
||||
val navButton = navButtonContainer.getChildAt(i)
|
||||
val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
|
||||
buttonLayoutParams.weight = 1f
|
||||
when (i) {
|
||||
0 -> {
|
||||
// First button
|
||||
buttonLayoutParams.marginEnd = spaceInBetween / 2
|
||||
}
|
||||
navButtonContainer.childCount - 1 -> {
|
||||
// Last button
|
||||
buttonLayoutParams.marginStart = spaceInBetween / 2
|
||||
}
|
||||
else -> {
|
||||
// other buttons
|
||||
buttonLayoutParams.marginStart = spaceInBetween / 2
|
||||
buttonLayoutParams.marginEnd = spaceInBetween / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.taskbar.navbutton
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import com.android.launcher3.DeviceProfile
|
||||
|
||||
class SetupNavLayoutter(
|
||||
resources: Resources,
|
||||
navButtonContainer: LinearLayout,
|
||||
endContextualContainer: ViewGroup,
|
||||
startContextualContainer: ViewGroup
|
||||
) : AbstractNavButtonLayoutter(
|
||||
resources,
|
||||
navButtonContainer,
|
||||
endContextualContainer,
|
||||
startContextualContainer
|
||||
) {
|
||||
|
||||
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
|
||||
// Since setup wizard only has back button enabled, it looks strange to be
|
||||
// end-aligned, so start-align instead.
|
||||
val navButtonsLayoutParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
|
||||
navButtonsLayoutParams.apply {
|
||||
marginStart = navButtonsLayoutParams.marginEnd
|
||||
marginEnd = 0
|
||||
gravity = Gravity.START
|
||||
}
|
||||
navButtonContainer.requestLayout()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.taskbar.navbutton
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.R
|
||||
|
||||
/**
|
||||
* Layoutter for showing 3 button navigation on large screen
|
||||
*/
|
||||
class TaskbarNavLayoutter(
|
||||
resources: Resources,
|
||||
navBarContainer: LinearLayout,
|
||||
endContextualContainer: ViewGroup,
|
||||
startContextualContainer: ViewGroup
|
||||
) : AbstractNavButtonLayoutter(
|
||||
resources,
|
||||
navBarContainer,
|
||||
endContextualContainer,
|
||||
startContextualContainer
|
||||
) {
|
||||
|
||||
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
|
||||
// Add spacing after the end of the last nav button
|
||||
val navButtonParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
|
||||
var navMarginEnd = resources.getDimension(dp.inv.inlineNavButtonsEndSpacing).toInt()
|
||||
val contextualWidth = endContextualContainer.width
|
||||
// If contextual buttons are showing, we check if the end margin is enough for the
|
||||
// contextual button to be showing - if not, move the nav buttons over a smidge
|
||||
if (isContextualButtonShowing && navMarginEnd < contextualWidth) {
|
||||
// Additional spacing, eat up half of space between last icon and nav button
|
||||
navMarginEnd += resources.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing) / 2
|
||||
}
|
||||
|
||||
navButtonParams.apply {
|
||||
gravity = Gravity.END
|
||||
width = FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
marginEnd = navMarginEnd
|
||||
}
|
||||
navButtonContainer.orientation = LinearLayout.HORIZONTAL
|
||||
navButtonContainer.layoutParams = navButtonParams
|
||||
|
||||
// Add the spaces in between the nav buttons
|
||||
val spaceInBetween = resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween)
|
||||
for (i in 0 until navButtonContainer.childCount) {
|
||||
val navButton = navButtonContainer.getChildAt(i)
|
||||
val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
|
||||
buttonLayoutParams.weight = 0f
|
||||
when (i) {
|
||||
0 -> {
|
||||
buttonLayoutParams.marginEnd = spaceInBetween / 2
|
||||
}
|
||||
navButtonContainer.childCount - 1 -> {
|
||||
buttonLayoutParams.marginStart = spaceInBetween / 2
|
||||
}
|
||||
else -> {
|
||||
buttonLayoutParams.marginStart = spaceInBetween / 2
|
||||
buttonLayoutParams.marginEnd = spaceInBetween / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package com.android.launcher3.taskbar.navbutton
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.test.runner.AndroidJUnit4
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.taskbar.TaskbarManager
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import com.android.launcher3.R
|
||||
import org.junit.Assume.assumeTrue
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class NavButtonLayoutFactoryTest {
|
||||
|
||||
@Mock
|
||||
lateinit var mockDeviceProfile: DeviceProfile
|
||||
@Mock
|
||||
lateinit var mockParentButtonContainer: FrameLayout
|
||||
@Mock
|
||||
lateinit var mockNavLayout: LinearLayout
|
||||
@Mock
|
||||
lateinit var mockStartContextualLayout: ViewGroup
|
||||
@Mock
|
||||
lateinit var mockEndContextualLayout: ViewGroup
|
||||
@Mock
|
||||
lateinit var mockResources: Resources
|
||||
@Mock
|
||||
lateinit var mockBackButton: ImageView
|
||||
@Mock
|
||||
lateinit var mockRecentsButton: ImageView
|
||||
@Mock
|
||||
lateinit var mockHomeButton: ImageView
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
// Init end nav buttons
|
||||
whenever(mockNavLayout.childCount).thenReturn(3)
|
||||
whenever(mockNavLayout.findViewById<View>(R.id.back)).thenReturn(mockBackButton)
|
||||
whenever(mockNavLayout.findViewById<View>(R.id.home)).thenReturn(mockHomeButton)
|
||||
whenever(mockNavLayout.findViewById<View>(R.id.recent_apps)).thenReturn(mockRecentsButton)
|
||||
|
||||
// Init top level layout
|
||||
whenever(mockParentButtonContainer.findViewById<LinearLayout>(R.id.end_nav_buttons))
|
||||
.thenReturn(mockNavLayout)
|
||||
whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.end_contextual_buttons))
|
||||
.thenReturn(mockEndContextualLayout)
|
||||
whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.start_contextual_buttons))
|
||||
.thenReturn(mockStartContextualLayout)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getKidsLayoutter() {
|
||||
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
|
||||
mockDeviceProfile.isTaskbarPresent = true
|
||||
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
|
||||
getLayoutter(isKidsMode = true, isInSetup = false, isThreeButtonNav = false,
|
||||
phoneMode = false)
|
||||
assert(layoutter is KidsNavLayoutter)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getSetupLayoutter() {
|
||||
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
|
||||
mockDeviceProfile.isTaskbarPresent = true
|
||||
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
|
||||
getLayoutter(isKidsMode = false, isInSetup = true, isThreeButtonNav = false,
|
||||
phoneMode = false)
|
||||
assert(layoutter is SetupNavLayoutter)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getTaskbarNavLayoutter() {
|
||||
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
|
||||
mockDeviceProfile.isTaskbarPresent = true
|
||||
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
|
||||
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
|
||||
phoneMode = false)
|
||||
assert(layoutter is TaskbarNavLayoutter)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun noValidLayoutForLargeScreenTaskbarNotPresent() {
|
||||
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
|
||||
mockDeviceProfile.isTaskbarPresent = false
|
||||
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
|
||||
phoneMode = false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getTaskbarPortraitLayoutter() {
|
||||
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
|
||||
mockDeviceProfile.isTaskbarPresent = false
|
||||
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
|
||||
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true,
|
||||
phoneMode = true)
|
||||
assert(layoutter is PhonePortraitNavLayoutter)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getTaskbarLandscapeLayoutter() {
|
||||
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
|
||||
mockDeviceProfile.isTaskbarPresent = false
|
||||
setDeviceProfileLandscape()
|
||||
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
|
||||
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true,
|
||||
phoneMode = true)
|
||||
assert(layoutter is PhoneLandscapeNavLayoutter)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun noValidLayoutForPhoneGestureNav() {
|
||||
assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
|
||||
mockDeviceProfile.isTaskbarPresent = false
|
||||
getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
|
||||
phoneMode = true)
|
||||
}
|
||||
|
||||
private fun setDeviceProfileLandscape() {
|
||||
// Use reflection to modify landscape field
|
||||
val landscapeField = mockDeviceProfile.javaClass.getDeclaredField("isLandscape")
|
||||
landscapeField.isAccessible = true
|
||||
landscapeField.set(mockDeviceProfile, true)
|
||||
}
|
||||
|
||||
private fun getLayoutter(isKidsMode: Boolean, isInSetup: Boolean,
|
||||
isThreeButtonNav: Boolean, phoneMode: Boolean):
|
||||
NavButtonLayoutFactory.NavButtonLayoutter {
|
||||
return NavButtonLayoutFactory.getUiLayoutter(
|
||||
deviceProfile = mockDeviceProfile,
|
||||
navButtonsView = mockParentButtonContainer,
|
||||
resources = mockResources,
|
||||
isKidsMode = isKidsMode, isInSetup = isInSetup,
|
||||
isThreeButtonNav = isThreeButtonNav, phoneMode = phoneMode
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -368,6 +368,7 @@
|
||||
<dimen name="taskbar_hotseat_nav_spacing">0dp</dimen>
|
||||
<dimen name="taskbar_button_margin_default">0dp</dimen>
|
||||
<dimen name="taskbar_button_space_inbetween">0dp</dimen>
|
||||
<dimen name="taskbar_button_space_inbetween_phone">0dp</dimen>
|
||||
<dimen name="taskbar_button_margin_5_5">0dp</dimen>
|
||||
<dimen name="taskbar_button_margin_6_5">0dp</dimen>
|
||||
<dimen name="taskbar_button_margin_4_5">0dp</dimen>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.util
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Point
|
||||
import android.view.ViewGroup
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.R
|
||||
|
||||
object DimensionUtils {
|
||||
/**
|
||||
* Point where x is width, and y is height of taskbar based on provided [deviceProfile]
|
||||
* x or y could also be -1 to indicate there is no dimension specified
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getTaskbarPhoneDimensions(deviceProfile: DeviceProfile, res: Resources,
|
||||
isPhoneMode: Boolean): Point {
|
||||
val p = Point()
|
||||
// Taskbar for large screen
|
||||
if (!isPhoneMode) {
|
||||
p.x = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
p.y = deviceProfile.taskbarSize
|
||||
return p
|
||||
}
|
||||
|
||||
// Taskbar on phone using gesture nav, it will always be stashed
|
||||
if (deviceProfile.isGestureMode) {
|
||||
p.x = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
p.y = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size)
|
||||
return p
|
||||
}
|
||||
|
||||
// Taskbar on phone, portrait
|
||||
if (!deviceProfile.isLandscape) {
|
||||
p.x = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
p.y = res.getDimensionPixelSize(R.dimen.taskbar_size)
|
||||
return p
|
||||
}
|
||||
|
||||
// Taskbar on phone, landscape
|
||||
p.x = res.getDimensionPixelSize(R.dimen.taskbar_size)
|
||||
p.y = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
return p
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user