diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml
index d32c11514f..d61a8952a7 100644
--- a/quickstep/res/layout/taskbar.xml
+++ b/quickstep/res/layout/taskbar.xml
@@ -13,12 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+ android:layout_height="wrap_content"
+ android:clipChildren="false">
+
+
+ android:gravity="center_vertical"
+ android:layout_gravity="start"/>
-
-
-
-
-
-
-
+ android:gravity="center_vertical"
+ android:layout_gravity="end"/>
+
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_nav_button.xml b/quickstep/res/layout/taskbar_nav_button.xml
new file mode 100644
index 0000000000..985f928ca7
--- /dev/null
+++ b/quickstep/res/layout/taskbar_nav_button.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index d9c33aeeee..d8899a6e8e 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -148,11 +148,9 @@
60dp
- 44dp
48dp
54dp
-
- 8dp
16dp
16dp
+ 48dp
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 2a86e81f8b..8a7d01b71e 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -350,14 +350,6 @@ public abstract class BaseQuickstepLauncher extends Launcher
? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET};
}
- @Override
- public float getNormalTaskbarScale() {
- if (mTaskbarUIController != null) {
- return mTaskbarUIController.getTaskbarScaleOnHome();
- }
- return super.getNormalTaskbarScale();
- }
-
@Override
public void onDragLayerHierarchyChanged() {
onLauncherStateOrFocusChanged();
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index 14b0c5dd62..c7c25670ce 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -85,7 +85,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements I
mSampleHotseat = findViewById(R.id.sample_prediction);
DeviceProfile grid = mActivityContext.getDeviceProfile();
- Rect padding = grid.getHotseatLayoutPadding();
+ Rect padding = grid.getHotseatLayoutPadding(getContext());
mSampleHotseat.getLayoutParams().height = grid.cellHeightPx;
mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1);
diff --git a/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java b/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java
deleted file mode 100644
index 86ac39f5a2..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2021 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;
-
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
-
-import android.annotation.DrawableRes;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.android.launcher3.R;
-import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
-import com.android.launcher3.taskbar.contextual.RotationContextButton;
-
-/**
- * Creates Buttons for Taskbar for 3 button nav.
- * Can add animations and state management for buttons in this class as things progress.
- */
-public class ButtonProvider {
-
- private final int mMarginLeftRight;
- private final TaskbarActivityContext mContext;
-
- public ButtonProvider(TaskbarActivityContext context) {
- mContext = context;
- mMarginLeftRight = context.getResources()
- .getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
- }
-
- public View getBack() {
- // Back button
- return getButtonForDrawable(R.drawable.ic_sysbar_back, BUTTON_BACK);
- }
-
- public View getDown() {
- // Ime down button
- return getButtonForDrawable(R.drawable.ic_sysbar_back, BUTTON_BACK);
- }
-
- public View getHome() {
- // Home button
- return getButtonForDrawable(R.drawable.ic_sysbar_home, BUTTON_HOME);
- }
-
- public View getRecents() {
- // Recents button
- return getButtonForDrawable(R.drawable.ic_sysbar_recent, BUTTON_RECENTS);
- }
-
- public View getImeSwitcher() {
- // IME Switcher Button
- return getButtonForDrawable(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH);
- }
-
- public RotationContextButton getContextualRotation() {
- // Rotation suggestion button
- return new RotationContextButton(mContext);
- }
-
- private View getButtonForDrawable(@DrawableRes int drawableId, @TaskbarButton int buttonType) {
- ImageView buttonView = new ImageView(mContext);
- buttonView.setImageResource(drawableId);
- buttonView.setBackgroundResource(R.drawable.taskbar_icon_click_feedback_roundrect);
- buttonView.setPadding(mMarginLeftRight, 0, mMarginLeftRight, 0);
- buttonView.setOnClickListener(view -> mContext.onNavigationButtonClick(buttonType));
- return buttonView;
- }
-
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java b/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java
deleted file mode 100644
index d581302e62..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2021 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;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.RelativeLayout;
-
-import com.android.launcher3.views.ActivityContext;
-
-public class ImeBarView extends RelativeLayout {
-
- private View mImeView;
-
- public ImeBarView(Context context) {
- this(context, null);
- }
-
- public ImeBarView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ImeBarView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public void init(ButtonProvider buttonProvider) {
- // TODO (b/187966005), maybe need to replace ime switcher button with
- // RotationContextButton when device rotates
- ActivityContext context = getActivityContext();
- RelativeLayout.LayoutParams imeParams = new RelativeLayout.LayoutParams(
- context.getDeviceProfile().iconSizePx,
- context.getDeviceProfile().iconSizePx
- );
- RelativeLayout.LayoutParams downParams = new RelativeLayout.LayoutParams(imeParams);
-
- imeParams.addRule(ALIGN_PARENT_END);
- imeParams.setMarginEnd(context.getDeviceProfile().iconSizePx);
- downParams.setMarginStart(context.getDeviceProfile().iconSizePx);
- downParams.addRule(ALIGN_PARENT_START);
-
- // Down Arrow
- View downView = buttonProvider.getDown();
- downView.setLayoutParams(downParams);
- downView.setRotation(-90);
- addView(downView);
-
- // IME switcher button
- mImeView = buttonProvider.getImeSwitcher();
- mImeView.setLayoutParams(imeParams);
- addView(mImeView);
- }
-
- public void setImeSwitcherVisibility(boolean show) {
- mImeView.setVisibility(show ? VISIBLE : GONE);
- }
-
- private T getActivityContext() {
- return ActivityContext.lookupContext(getContext());
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index f124de79ba..79af7cc5dd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -15,42 +15,42 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.graphics.Rect;
-import android.graphics.RectF;
import android.view.MotionEvent;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.quickstep.AnimatedFloat;
+
/**
* A data source which integrates with a Launcher instance
- * TODO: Rename to have Launcher prefix
*/
-
public class LauncherTaskbarUIController extends TaskbarUIController {
private final BaseQuickstepLauncher mLauncher;
private final TaskbarStateHandler mTaskbarStateHandler;
- private final TaskbarAnimationController mTaskbarAnimationController;
private final TaskbarHotseatController mHotseatController;
private final TaskbarActivityContext mContext;
final TaskbarDragLayer mTaskbarDragLayer;
final TaskbarView mTaskbarView;
+ private AnimatedFloat mTaskBarAlpha;
+ private AlphaProperty mIconAlphaForHome;
private @Nullable Animator mAnimator;
private boolean mIsAnimatingToLauncher;
- private ContextualRotationNotifier mContextualRotationNotifier;
public LauncherTaskbarUIController(
BaseQuickstepLauncher launcher, TaskbarActivityContext context) {
@@ -60,20 +60,19 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
mLauncher = launcher;
mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
- mTaskbarAnimationController = new TaskbarAnimationController(mLauncher,
- createTaskbarAnimationControllerCallbacks());
mHotseatController = new TaskbarHotseatController(
mLauncher, mTaskbarView::updateHotseatItems);
+
}
@Override
- protected void onCreate(ContextualRotationNotifier notifier) {
- mContextualRotationNotifier = notifier;
- mTaskbarStateHandler.setAnimationController(mTaskbarAnimationController);
- mTaskbarAnimationController.init();
+ protected void init(AnimatedFloat taskBarAlpha, AlphaProperty iconAlphaForLauncherState,
+ AlphaProperty iconAlphaForHome) {
+ mTaskBarAlpha = taskBarAlpha;
+ mIconAlphaForHome = iconAlphaForHome;
+ mTaskbarStateHandler.setAnimationController(iconAlphaForLauncherState);
mHotseatController.init();
setTaskbarViewVisible(!mLauncher.hasBeenResumed());
- alignRealHotseatWithTaskbar();
mLauncher.setTaskbarUIController(this);
}
@@ -83,9 +82,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
// End this first, in case it relies on properties that are about to be cleaned up.
mAnimator.end();
}
- mContextualRotationNotifier = null;
mTaskbarStateHandler.setAnimationController(null);
- mTaskbarAnimationController.cleanup();
mHotseatController.cleanup();
setTaskbarViewVisible(true);
mLauncher.getHotseat().setIconsAlpha(1f);
@@ -97,46 +94,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
return !mIsAnimatingToLauncher;
}
- private TaskbarAnimationControllerCallbacks createTaskbarAnimationControllerCallbacks() {
- return new TaskbarAnimationControllerCallbacks() {
- @Override
- public void updateTaskbarBackgroundAlpha(float alpha) {
- mTaskbarDragLayer.setTaskbarBackgroundAlpha(alpha);
- }
-
- @Override
- public void updateTaskbarVisibilityAlpha(float alpha) {
- mTaskbarView.setAlpha(alpha);
- if (mContextualRotationNotifier != null) {
- mContextualRotationNotifier.onTaskbarVisibilityChanged(alpha == 1);
- }
- }
-
- @Override
- public void updateImeBarVisibilityAlpha(float alpha) {
- mTaskbarDragLayer.updateImeBarVisibilityAlpha(alpha);
- }
-
- @Override
- public void updateTaskbarScale(float scale) {
- mTaskbarView.setScaleX(scale);
- mTaskbarView.setScaleY(scale);
- }
-
- @Override
- public void updateTaskbarTranslationY(float translationY) {
- if (translationY < 0) {
- // Resize to accommodate the max translation we'll reach.
- mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize
- + mLauncher.getHotseat().getTaskbarOffsetY());
- } else {
- mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize);
- }
- mTaskbarView.setTranslationY(translationY);
- }
- };
- }
-
/**
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
@@ -146,7 +103,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
mAnimator.cancel();
}
if (isResumed) {
- mAnimator = createAnimToLauncher(null, duration);
+ mAnimator = createAnimToLauncher(mLauncher.getStateManager().getState(), duration);
} else {
mAnimator = createAnimToApp(duration);
}
@@ -162,20 +119,19 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
/**
* Create Taskbar animation when going from an app to Launcher.
* @param toState If known, the state we will end up in when reaching Launcher.
+ * TODO: Move this and createAnimToApp to TaskbarStateHandler using the BACKGROUND state
*/
- public Animator createAnimToLauncher(@Nullable LauncherState toState, long duration) {
+ public Animator createAnimToLauncher(@NonNull LauncherState toState, long duration) {
PendingAnimation anim = new PendingAnimation(duration);
- anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(0, duration));
- if (toState != null) {
- mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim);
- }
+ mTaskbarStateHandler.setState(toState, anim);
+
+ anim.setFloat(mTaskBarAlpha, AnimatedFloat.VALUE, 0, LINEAR);
+ mTaskbarView.alignIconsWithLauncher(mLauncher.getDeviceProfile(), anim);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mIsAnimatingToLauncher = true;
- mTaskbarView.setHolesAllowedInLayout(true);
- mTaskbarView.updateHotseatItemsVisibility();
}
@Override
@@ -190,27 +146,17 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
private Animator createAnimToApp(long duration) {
PendingAnimation anim = new PendingAnimation(duration);
- anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(1, duration));
+ anim.setFloat(mTaskBarAlpha, AnimatedFloat.VALUE, 1, LINEAR);
+ anim.addListener(AnimatorListeners.forEndCallback(mTaskbarView.resetIconPosition(anim)));
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- mTaskbarView.updateHotseatItemsVisibility();
setTaskbarViewVisible(true);
}
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mTaskbarView.setHolesAllowedInLayout(false);
- }
});
return anim.buildAnim();
}
- @Override
- protected void onImeVisible(TaskbarDragLayer containerView, boolean isVisible) {
- mTaskbarAnimationController.animateToVisibilityForIme(isVisible ? 0 : 1);
- }
-
/**
* Should be called when one or more items in the Hotseat have changed.
*/
@@ -230,55 +176,8 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
return mContext.getDragController().isDragging();
}
- /**
- * Pads the Hotseat to line up exactly with Taskbar's copy of the Hotseat.
- */
- @Override
- public void alignRealHotseatWithTaskbar() {
- Rect hotseatBounds = new Rect();
- DeviceProfile grid = mLauncher.getDeviceProfile();
- int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize;
- int taskbarOffset = mLauncher.getHotseat().getTaskbarOffsetY();
- int hotseatTopDiff = hotseatHeight - grid.taskbarSize - taskbarOffset;
- int hotseatBottomDiff = taskbarOffset;
-
- RectF hotseatBoundsF = mTaskbarView.getHotseatBounds();
- Utilities.scaleRectFAboutPivot(hotseatBoundsF, getTaskbarScaleOnHome(),
- mTaskbarView.getPivotX(), mTaskbarView.getPivotY());
- hotseatBoundsF.round(hotseatBounds);
- mLauncher.getHotseat().setPadding(hotseatBounds.left,
- hotseatBounds.top + hotseatTopDiff,
- mTaskbarView.getWidth() - hotseatBounds.right,
- mTaskbarView.getHeight() - hotseatBounds.bottom + hotseatBottomDiff);
- }
-
- /**
- * Returns the ratio of the taskbar icon size on home vs in an app.
- */
- public float getTaskbarScaleOnHome() {
- DeviceProfile inAppDp = mContext.getDeviceProfile();
- DeviceProfile onHomeDp = mLauncher.getDeviceProfile();
- return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx;
- }
-
void setTaskbarViewVisible(boolean isVisible) {
- mTaskbarView.setIconsVisibility(isVisible);
+ mIconAlphaForHome.setValue(isVisible ? 1 : 0);
mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f);
}
-
- /**
- * Contains methods that TaskbarAnimationController can call to interface with
- * TaskbarController.
- */
- protected interface TaskbarAnimationControllerCallbacks {
- void updateTaskbarBackgroundAlpha(float alpha);
- void updateTaskbarVisibilityAlpha(float alpha);
- void updateImeBarVisibilityAlpha(float alpha);
- void updateTaskbarScale(float scale);
- void updateTaskbarTranslationY(float translationY);
- }
-
- public interface ContextualRotationNotifier {
- void onTaskbarVisibilityChanged(boolean showing);
- }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonUIController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonUIController.java
new file mode 100644
index 0000000000..1281b2e38f
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonUIController.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
+
+import android.animation.ObjectAnimator;
+import android.annotation.DrawableRes;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Region.Op;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.util.Property;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnHoverListener;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.launcher3.LauncherAnimUtils;
+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.contextual.RotationButton;
+import com.android.launcher3.taskbar.contextual.RotationButtonController;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.quickstep.AnimatedFloat;
+
+import java.util.ArrayList;
+import java.util.function.IntPredicate;
+
+/**
+ * Controller for managing nav bar buttons in taskbar
+ */
+public class NavbarButtonUIController {
+
+ private final Rect mTempRect = new Rect();
+
+ private static final int FLAG_SWITCHER_SUPPORTED = 1 << 0;
+ private static final int FLAG_IME_VISIBLE = 1 << 1;
+ private static final int FLAG_ROTATION_BUTTON_VISIBLE = 1 << 2;
+
+ private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
+
+ private final ArrayList mPropertyHolders = new ArrayList<>();
+ private final ArrayList mAllButtons = new ArrayList<>();
+ private int mState;
+
+ private final TaskbarActivityContext mContext;
+
+ public NavbarButtonUIController(TaskbarActivityContext context) {
+ mContext = context;
+ }
+
+ /**
+ * Initializes the controller
+ */
+ public void init(TaskbarDragLayer dragLayer,
+ TaskbarNavButtonController navButtonController,
+ RotationButtonController rotationButtonController,
+ AnimatedFloat taskbarBackgroundAlpha, AlphaProperty taskbarIconAlpha) {
+ FrameLayout buttonController = dragLayer.findViewById(R.id.navbuttons_view);
+ buttonController.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
+
+ if (mContext.canShowNavButtons()) {
+ ViewGroup startContainer = buttonController.findViewById(R.id.start_nav_buttons);
+ ViewGroup endContainer = buttonController.findViewById(R.id.end_nav_buttons);
+
+ initButtons(startContainer, endContainer, navButtonController);
+
+ // Animate taskbar background when IME shows
+ mPropertyHolders.add(new StatePropertyHolder(taskbarBackgroundAlpha,
+ flags -> (flags & FLAG_IME_VISIBLE) == 0,
+ AnimatedFloat.VALUE, 0, 1));
+ mPropertyHolders.add(new StatePropertyHolder(
+ taskbarIconAlpha, flags -> (flags & FLAG_IME_VISIBLE) == 0,
+ MultiValueAlpha.VALUE, 1, 0));
+
+ // Rotation button
+ RotationButton rotationButton = new RotationButtonImpl(addButton(endContainer));
+ rotationButton.hide();
+ rotationButtonController.setRotationButton(rotationButton);
+ } else {
+ rotationButtonController.setRotationButton(new RotationButton() { });
+ }
+
+ applyState();
+ mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
+ }
+
+ private void initButtons(ViewGroup startContainer, ViewGroup endContainer,
+ TaskbarNavButtonController navButtonController) {
+
+ View backButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
+ startContainer, navButtonController);
+ // Rotate when Ime visible
+ mPropertyHolders.add(new StatePropertyHolder(backButton,
+ flags -> (flags & FLAG_IME_VISIBLE) == 0, View.ROTATION, 0,
+ Utilities.isRtl(mContext.getResources()) ? 90 : -90));
+
+ // home and recents buttons
+ View homeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, startContainer,
+ navButtonController);
+ mPropertyHolders.add(new StatePropertyHolder(homeButton,
+ flags -> (flags & FLAG_IME_VISIBLE) == 0));
+ View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
+ startContainer, navButtonController);
+ mPropertyHolders.add(new StatePropertyHolder(recentsButton,
+ flags -> (flags & FLAG_IME_VISIBLE) == 0));
+
+ // IME switcher
+ View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
+ endContainer, navButtonController);
+ mPropertyHolders.add(new StatePropertyHolder(imeSwitcherButton,
+ flags -> ((flags & MASK_IME_SWITCHER_VISIBLE) == MASK_IME_SWITCHER_VISIBLE)
+ && ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0)));
+ }
+
+ /**
+ * Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
+ */
+ public void setImeIsVisible(boolean isImeVisible) {
+ if (isImeVisible) {
+ mState |= FLAG_IME_VISIBLE;
+ } else {
+ mState &= ~FLAG_IME_VISIBLE;
+ }
+ applyState();
+ }
+
+ /**
+ * Returns true if IME bar is visible
+ */
+ public boolean isImeVisible() {
+ return (mState & FLAG_IME_VISIBLE) != 0;
+ }
+
+ /**
+ * Adds the bounds corresponding to all visible buttons to provided region
+ */
+ public void addVisibleButtonsRegion(TaskbarDragLayer parent, Region outRegion) {
+ int count = mAllButtons.size();
+ for (int i = 0; i < count; i++) {
+ View button = mAllButtons.get(i);
+ if (button.getVisibility() == View.VISIBLE) {
+ parent.getDescendantRectRelativeToSelf(button, mTempRect);
+ outRegion.op(mTempRect, Op.UNION);
+ }
+ }
+ }
+
+ /**
+ * Sets if ime switcher is visible or not when ime is visible
+ */
+ public void setImeSwitcherVisible(boolean imeSwitcherVisible) {
+ if (imeSwitcherVisible) {
+ mState |= FLAG_SWITCHER_SUPPORTED;
+ } else {
+ mState &= ~FLAG_SWITCHER_SUPPORTED;
+ }
+ applyState();
+ }
+
+ private void applyState() {
+ int count = mPropertyHolders.size();
+ for (int i = 0; i < count; i++) {
+ mPropertyHolders.get(i).setState(mState);
+ }
+ }
+
+ private ImageView addButton(@DrawableRes int drawableId, @TaskbarButton int buttonType,
+ ViewGroup parent, TaskbarNavButtonController navButtonController) {
+ ImageView buttonView = addButton(parent);
+ buttonView.setImageResource(drawableId);
+ buttonView.setOnClickListener(view -> navButtonController.onButtonClick(buttonType));
+ return buttonView;
+ }
+
+ private ImageView addButton(ViewGroup parent) {
+ ImageView buttonView = (ImageView) mContext.getLayoutInflater()
+ .inflate(R.layout.taskbar_nav_button, parent, false);
+ parent.addView(buttonView);
+ mAllButtons.add(buttonView);
+ return buttonView;
+ }
+
+ private class RotationButtonImpl implements RotationButton {
+
+ private final ImageView mButton;
+ private AnimatedVectorDrawable mImageDrawable;
+
+ RotationButtonImpl(ImageView button) {
+ mButton = button;
+ }
+
+ @Override
+ public void setRotationButtonController(RotationButtonController rotationButtonController) {
+ // TODO(b/187754252) UI polish, different icons based on light/dark context, etc
+ mImageDrawable = (AnimatedVectorDrawable) mButton.getContext()
+ .getDrawable(rotationButtonController.getIconResId());
+ mButton.setImageDrawable(mImageDrawable);
+ mImageDrawable.setCallback(mButton);
+ }
+
+ @Override
+ public View getCurrentView() {
+ return mButton;
+ }
+
+ @Override
+ public void show() {
+ mButton.setVisibility(View.VISIBLE);
+ mState |= FLAG_ROTATION_BUTTON_VISIBLE;
+ applyState();
+ }
+
+ @Override
+ public void hide() {
+ mButton.setVisibility(View.GONE);
+ mState &= ~FLAG_ROTATION_BUTTON_VISIBLE;
+ applyState();
+ }
+
+ @Override
+ public boolean isVisible() {
+ return mButton.getVisibility() == View.VISIBLE;
+ }
+
+ @Override
+ public void updateIcon(int lightIconColor, int darkIconColor) {
+ // TODO(b/187754252): UI Polish
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener onClickListener) {
+ mButton.setOnClickListener(onClickListener);
+ }
+
+ @Override
+ public void setOnHoverListener(OnHoverListener onHoverListener) {
+ mButton.setOnHoverListener(onHoverListener);
+ }
+
+ @Override
+ public AnimatedVectorDrawable getImageDrawable() {
+ return mImageDrawable;
+ }
+
+ @Override
+ public void setDarkIntensity(float darkIntensity) {
+ // TODO(b/187754252) UI polish
+ }
+
+ @Override
+ public boolean acceptRotationProposal() {
+ return mButton.isAttachedToWindow();
+ }
+ }
+
+ private static class StatePropertyHolder {
+
+ private final float mEnabledValue, mDisabledValue;
+ private final ObjectAnimator mAnimator;
+ private final IntPredicate mEnableCondition;
+
+ private boolean mIsEnabled = true;
+
+ StatePropertyHolder(View view, IntPredicate enableCondition) {
+ this(view, enableCondition, LauncherAnimUtils.VIEW_ALPHA, 1, 0);
+ mAnimator.addListener(new AlphaUpdateListener(view));
+ }
+
+ StatePropertyHolder(T target, IntPredicate enabledCondition,
+ Property property, float enabledValue, float disabledValue) {
+ mEnableCondition = enabledCondition;
+ mEnabledValue = enabledValue;
+ mDisabledValue = disabledValue;
+ mAnimator = ObjectAnimator.ofFloat(target, property, enabledValue, disabledValue);
+ }
+
+ public void setState(int flags) {
+ boolean isEnabled = mEnableCondition.test(flags);
+ if (mIsEnabled != isEnabled) {
+ mIsEnabled = isEnabled;
+ mAnimator.cancel();
+ mAnimator.setFloatValues(mIsEnabled ? mEnabledValue : mDisabledValue);
+ mAnimator.start();
+ }
+ }
+
+ public void endAnimation() {
+ if (mAnimator.isRunning()) {
+ mAnimator.end();
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index d51506cd6c..5f7dce5fac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -29,6 +29,7 @@ import android.content.Intent;
import android.content.pm.LauncherApps;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.inputmethodservice.InputMethodService;
import android.os.Process;
import android.os.SystemProperties;
import android.util.Log;
@@ -53,10 +54,12 @@ import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
import com.android.launcher3.taskbar.contextual.RotationButtonController;
import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.systemui.shared.recents.model.Task;
@@ -76,11 +79,16 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
private static final String WINDOW_TITLE = "Taskbar";
+ private static final int ALPHA_INDEX_HOME = 0;
+ private static final int ALPHA_INDEX_LAUNCHER_STATE = 1;
+ private static final int ALPHA_INDEX_IME = 2;
+
private final DeviceProfile mDeviceProfile;
private final LayoutInflater mLayoutInflater;
private final TaskbarDragLayer mDragLayer;
private final TaskbarIconController mIconController;
private final TaskbarDragController mDragController;
+ private final NavbarButtonUIController mNavbarButtonUIController;
private final WindowManager mWindowManager;
private WindowManager.LayoutParams mWindowLayoutParams;
@@ -89,7 +97,6 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
private int mLastRequestedNonFullscreenHeight;
private final SysUINavigationMode.Mode mNavMode;
- private final SystemTaskbarNotificationManager mSystemTaskbarNotificationManager;
private final TaskbarNavButtonController mNavButtonController;
private final RotationButtonController mRotationButtonController;
@@ -101,43 +108,18 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
private final View.OnClickListener mOnTaskbarIconClickListener;
private final View.OnLongClickListener mOnTaskbarIconLongClickListener;
- private final TaskbarManager.SystemTaskbarNotifier mSystemTaskbarNotifier =
- new TaskbarManager.SystemTaskbarNotifier() {
- @Override
- public void updateImeStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
- /*
- * When in 3 button nav, sysui flags don't get called since we prevent
- * sysui nav bar from instantiating at all, which is what's responsible for
- * sending sysui state flags over.
- */
- mIconController.updateImeStatus(displayId, vis, showImeSwitcher);
- }
+ // Alpha property for task bar
+ private final AnimatedFloat mBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
+ private final AnimatedFloat mBgNavbar = new AnimatedFloat(this::updateBackgroundAlpha);
- @Override
- public void onRotationProposal(int rotation, boolean isValid) {
- mRotationButtonController.onRotationProposal(rotation, isValid);
- }
-
- @Override
- public void disable(int displayId, int state1, int state2, boolean animate) {
- mRotationButtonController.onDisable2FlagChanged(state2);
- }
-
- @Override
- public void onSystemBarAttributesChanged(int displayId, int behavior) {
- mRotationButtonController.onBehaviorChanged(displayId, behavior);
- }
- };
+ private final MultiValueAlpha mTaskbarIconAlpha;
public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
- TaskbarNavButtonController buttonController,
- SystemTaskbarNotificationManager systemTaskbarNotificationManager) {
+ TaskbarNavButtonController buttonController) {
super(windowContext, Themes.getActivityThemeRes(windowContext));
mDeviceProfile = dp;
mNavButtonController = buttonController;
mNavMode = SysUINavigationMode.getMode(windowContext);
- mSystemTaskbarNotificationManager = systemTaskbarNotificationManager;
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
() -> getPackageManager().isSafeMode());
@@ -146,23 +128,26 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
mOnTaskbarIconClickListener = this::onTaskbarIconClicked;
float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size);
+ mDeviceProfile.updateIconSize(1, getResources());
float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
mDeviceProfile.updateIconSize(iconScale, getResources());
mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
mDragLayer = (TaskbarDragLayer) mLayoutInflater
.inflate(R.layout.taskbar, null, false);
-
mRotationButtonController = new RotationButtonController(this,
R.color.popup_color_primary_light, R.color.popup_color_primary_light);
- mIconController = new TaskbarIconController(this, mDragLayer,
- mRotationButtonController);
+ mNavbarButtonUIController = new NavbarButtonUIController(this);
+ mIconController = new TaskbarIconController(this, mDragLayer, mNavbarButtonUIController);
Display display = windowContext.getDisplay();
Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
? windowContext.getApplicationContext()
: windowContext.getApplicationContext().createDisplayContext(display);
mWindowManager = c.getSystemService(WindowManager.class);
+
+ mTaskbarIconAlpha = new MultiValueAlpha(mDragLayer.findViewById(R.id.taskbar_view), 3);
+ mTaskbarIconAlpha.setUpdateVisibility(true);
}
public void init() {
@@ -187,12 +172,12 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
new int[] { ITYPE_EXTRA_NAVIGATION_BAR, ITYPE_BOTTOM_TAPPABLE_ELEMENT }
);
- mIconController.init(mOnTaskbarIconClickListener, mOnTaskbarIconLongClickListener,
- mNavMode);
+ mIconController.init(mOnTaskbarIconClickListener, mOnTaskbarIconLongClickListener);
+ mNavbarButtonUIController.init(mDragLayer, mNavButtonController, mRotationButtonController,
+ mBgNavbar, mTaskbarIconAlpha.getProperty(ALPHA_INDEX_IME));
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
- if (mNavMode == Mode.THREE_BUTTONS) {
- mSystemTaskbarNotificationManager
- .registerSystemTaskbarNotifications(mSystemTaskbarNotifier);
+ if (canShowNavButtons()) {
+ mRotationButtonController.init();
}
}
@@ -232,10 +217,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
mUIController.onDestroy();
mUIController = uiController;
mIconController.setUIController(mUIController);
- mUIController.onCreate(mRotationButtonController::onTaskBarVisibilityChange);
- if (mNavMode == Mode.THREE_BUTTONS) {
- mRotationButtonController.init();
- }
+ mUIController.init(mBgTaskbar, mTaskbarIconAlpha.getProperty(ALPHA_INDEX_LAUNCHER_STATE),
+ mTaskbarIconAlpha.getProperty(ALPHA_INDEX_HOME));
}
/**
@@ -244,12 +227,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
public void onDestroy() {
setUIController(TaskbarUIController.DEFAULT);
mIconController.onDestroy();
+ mRotationButtonController.onDestroy();
mWindowManager.removeViewImmediate(mDragLayer);
- if (mNavMode == Mode.THREE_BUTTONS) {
- mSystemTaskbarNotificationManager.removeSystemTaskbarNotifications(
- mSystemTaskbarNotifier);
- mRotationButtonController.cleanup();
- }
}
void onNavigationButtonClick(@TaskbarButton int buttonType) {
@@ -261,6 +240,36 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
*/
public void setImeIsVisible(boolean isImeVisible) {
mIconController.setImeIsVisible(isImeVisible);
+ mNavbarButtonUIController.setImeIsVisible(isImeVisible);
+ }
+
+ /**
+ * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from
+ * instantiating at all, which is what's responsible for sending sysui state flags over.
+ *
+ * @param vis IME visibility flag
+ */
+ public void updateImeStatus(int displayId, int vis, boolean showImeSwitcher) {
+ if (displayId != getDisplayId() || !canShowNavButtons()) {
+ return;
+ }
+ mNavbarButtonUIController.setImeSwitcherVisible(showImeSwitcher);
+ setImeIsVisible((vis & InputMethodService.IME_VISIBLE) != 0);
+ }
+
+ public void onRotationProposal(int rotation, boolean isValid) {
+ mRotationButtonController.onRotationProposal(rotation, isValid);
+ }
+
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != getDisplayId()) {
+ return;
+ }
+ mRotationButtonController.onDisable2FlagChanged(state2);
+ }
+
+ public void onSystemBarAttributesChanged(int displayId, int behavior) {
+ mRotationButtonController.onBehaviorChanged(displayId, behavior);
}
/**
@@ -316,7 +325,9 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
});
} else if (tag instanceof WorkspaceItemInfo) {
WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
- if (!(info.isDisabled() && ItemClickHandler.handleDisabledItemClicked(info, this))) {
+ if (info.isDisabled()) {
+ ItemClickHandler.handleDisabledItemClicked(info, this);
+ } else {
Intent intent = new Intent(info.getIntent())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
@@ -352,4 +363,9 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
AbstractFloatingView.closeAllOpenViews(this);
}
+
+ private void updateBackgroundAlpha() {
+ mDragLayer.setTaskbarBackgroundAlpha(Math.max(mBgNavbar.value, mBgTaskbar.value));
+ }
+
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java
deleted file mode 100644
index e20ddf88ce..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2021 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;
-
-import static com.android.launcher3.LauncherState.TASKBAR;
-
-import android.animation.Animator;
-
-import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.taskbar.LauncherTaskbarUIController.TaskbarAnimationControllerCallbacks;
-import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.SystemUiProxy;
-import com.android.systemui.shared.system.QuickStepContract;
-
-/**
- * Works with TaskbarController to update the TaskbarView's visual properties based on factors such
- * as LauncherState, whether Launcher is in the foreground, etc.
- */
-public class TaskbarAnimationController {
-
- private static final long IME_VISIBILITY_ALPHA_DURATION = 120;
-
- private final BaseQuickstepLauncher mLauncher;
- private final TaskbarAnimationControllerCallbacks mTaskbarCallbacks;
-
- // Background alpha.
- private final AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat(
- this::onTaskbarBackgroundAlphaChanged);
-
- // Overall visibility.
- private final AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat(
- this::updateVisibilityAlpha);
- private final AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat(
- this::updateVisibilityAlphaForIme);
-
- // Scale.
- private final AnimatedFloat mTaskbarScaleForLauncherState = new AnimatedFloat(
- this::updateScale);
-
- // TranslationY.
- private final AnimatedFloat mTaskbarTranslationYForLauncherState = new AnimatedFloat(
- this::updateTranslationY);
-
- public TaskbarAnimationController(BaseQuickstepLauncher launcher,
- TaskbarAnimationControllerCallbacks taskbarCallbacks) {
- mLauncher = launcher;
- mTaskbarCallbacks = taskbarCallbacks;
- }
-
- protected void init() {
- mTaskbarBackgroundAlpha.updateValue(mLauncher.hasBeenResumed() ? 0f : 1f);
- boolean isVisibleForLauncherState = (mLauncher.getStateManager().getState()
- .getVisibleElements(mLauncher) & TASKBAR) != 0;
- mTaskbarVisibilityAlphaForLauncherState.updateValue(isVisibleForLauncherState ? 1f : 0f);
- boolean isImeVisible = (SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags()
- & QuickStepContract.SYSUI_STATE_IME_SHOWING) != 0;
- mTaskbarVisibilityAlphaForIme.updateValue(isImeVisible ? 0f : 1f);
-
- onTaskbarBackgroundAlphaChanged();
- updateVisibilityAlpha();
- }
-
- protected void cleanup() {
- setNavBarButtonAlpha(1f);
- }
-
- protected AnimatedFloat getTaskbarVisibilityForLauncherState() {
- return mTaskbarVisibilityAlphaForLauncherState;
- }
-
- protected AnimatedFloat getTaskbarScaleForLauncherState() {
- return mTaskbarScaleForLauncherState;
- }
-
- protected AnimatedFloat getTaskbarTranslationYForLauncherState() {
- return mTaskbarTranslationYForLauncherState;
- }
-
- protected Animator createAnimToBackgroundAlpha(float toAlpha, long duration) {
- return mTaskbarBackgroundAlpha.animateToValue(mTaskbarBackgroundAlpha.value, toAlpha)
- .setDuration(duration);
- }
-
- protected void animateToVisibilityForIme(float toAlpha) {
- mTaskbarVisibilityAlphaForIme.animateToValue(mTaskbarVisibilityAlphaForIme.value, toAlpha)
- .setDuration(IME_VISIBILITY_ALPHA_DURATION).start();
- }
-
- private void onTaskbarBackgroundAlphaChanged() {
- mTaskbarCallbacks.updateTaskbarBackgroundAlpha(mTaskbarBackgroundAlpha.value);
- updateVisibilityAlpha();
- updateScale();
- updateTranslationY();
- }
-
- private void updateVisibilityAlpha() {
- // We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
- // assumption being that Taskbar should always be visible regardless of the current
- // LauncherState if Launcher is paused.
- float alphaDueToIme = mTaskbarVisibilityAlphaForIme.value;
- float alphaDueToLauncher = Math.max(mTaskbarBackgroundAlpha.value,
- mTaskbarVisibilityAlphaForLauncherState.value);
- float taskbarAlpha = alphaDueToLauncher * alphaDueToIme;
- mTaskbarCallbacks.updateTaskbarVisibilityAlpha(taskbarAlpha);
-
- // Make the nav bar invisible if taskbar is visible.
- setNavBarButtonAlpha(1f - taskbarAlpha);
- }
-
- private void updateVisibilityAlphaForIme() {
- updateVisibilityAlpha();
- float taskbarAlphaDueToIme = mTaskbarVisibilityAlphaForIme.value;
- mTaskbarCallbacks.updateImeBarVisibilityAlpha(1f - taskbarAlphaDueToIme);
- }
-
- private void updateScale() {
- // We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
- // assumption being that Taskbar should always be at scale 1f regardless of the current
- // LauncherState if Launcher is paused.
- float scale = mTaskbarScaleForLauncherState.value;
- scale = Utilities.mapRange(mTaskbarBackgroundAlpha.value, scale, 1f);
- mTaskbarCallbacks.updateTaskbarScale(scale);
- }
-
- private void updateTranslationY() {
- // We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
- // assumption being that Taskbar should always be at translationY 0f regardless of the
- // current LauncherState if Launcher is paused.
- float translationY = mTaskbarTranslationYForLauncherState.value;
- translationY = Utilities.mapRange(mTaskbarBackgroundAlpha.value, translationY, 0f);
- mTaskbarCallbacks.updateTaskbarTranslationY(translationY);
- }
-
- private void setNavBarButtonAlpha(float navBarAlpha) {
- SystemUiProxy.INSTANCE.get(mLauncher).setNavBarButtonAlpha(navBarAlpha, false);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 855c50728b..4294eb565f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.taskbar;
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
-
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Intent;
@@ -89,7 +86,7 @@ public class TaskbarDragController extends DragController {
startInternalDrag(btv);
- btv.setVisibility(INVISIBLE);
+ btv.setAlpha(0);
});
return true;
}
@@ -294,16 +291,9 @@ public class TaskbarDragController extends DragController {
mFolderMargin = getResources().getDimensionPixelSize(R.dimen.taskbar_folder_margin);
mTaskbarBackgroundPaint = new Paint();
mTaskbarBackgroundPaint.setColor(getResources().getColor(R.color.taskbar_background));
+ mTaskbarBackgroundPaint.setAlpha(0);
recreateControllers();
}
@@ -109,12 +110,6 @@ public class TaskbarDragLayer extends BaseDragLayer {
return true;
}
- public void updateImeBarVisibilityAlpha(float alpha) {
- if (mControllerCallbacks != null) {
- mControllerCallbacks.updateImeBarVisibilityAlpha(alpha);
- }
- }
-
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
@@ -139,7 +134,6 @@ public class TaskbarDragLayer extends BaseDragLayer {
return boundingBox;
}
-
/**
* Sets the alpha of the background color behind all the Taskbar contents.
* @param alpha 0 is fully transparent, 1 is fully opaque.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java
index 549e26cb22..b36b829b7a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java
@@ -15,14 +15,9 @@
*/
package com.android.launcher3.taskbar;
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME;
import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
-import android.graphics.Rect;
-import android.inputmethodservice.InputMethodService;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
@@ -31,8 +26,6 @@ import androidx.annotation.NonNull;
import com.android.launcher3.R;
import com.android.launcher3.anim.AlphaUpdateListener;
-import com.android.launcher3.taskbar.contextual.RotationButtonController;
-import com.android.quickstep.SysUINavigationMode;
import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo;
/**
@@ -40,42 +33,28 @@ import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo;
*/
public class TaskbarIconController {
- private final Rect mTempRect = new Rect();
-
private final TaskbarActivityContext mActivity;
private final TaskbarDragLayer mDragLayer;
+ private final NavbarButtonUIController mNavbarButtonUIController;
private final TaskbarView mTaskbarView;
- private final ImeBarView mImeBarView;
- private final RotationButtonController mRotationButtonController;
@NonNull
private TaskbarUIController mUIController = TaskbarUIController.DEFAULT;
TaskbarIconController(TaskbarActivityContext activity, TaskbarDragLayer dragLayer,
- RotationButtonController rotationButtonController) {
+ NavbarButtonUIController navbarButtonUIController) {
mActivity = activity;
mDragLayer = dragLayer;
+ mNavbarButtonUIController = navbarButtonUIController;
mTaskbarView = mDragLayer.findViewById(R.id.taskbar_view);
- mImeBarView = mDragLayer.findViewById(R.id.ime_bar_view);
- mRotationButtonController = rotationButtonController;
}
- public void init(OnClickListener clickListener, OnLongClickListener longClickListener,
- SysUINavigationMode.Mode navMode) {
- mDragLayer.addOnLayoutChangeListener((v, a, b, c, d, e, f, g, h) ->
- mUIController.alignRealHotseatWithTaskbar());
-
- ButtonProvider buttonProvider = new ButtonProvider(mActivity);
- mImeBarView.init(buttonProvider);
- mTaskbarView.init(new TaskbarViewCallbacks(), clickListener, longClickListener,
- buttonProvider);
+ public void init(OnClickListener clickListener, OnLongClickListener longClickListener) {
+ mTaskbarView.init(clickListener, longClickListener);
mTaskbarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize;
mDragLayer.init(new TaskbarDragLayerCallbacks(), mTaskbarView);
- if (mActivity.canShowNavButtons()) {
- mRotationButtonController.setRotationButton(mTaskbarView.getContextualRotationButton());
- }
}
public void onDestroy() {
@@ -86,27 +65,11 @@ public class TaskbarIconController {
mUIController = uiController;
}
- /**
- * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from
- * instantiating at all, which is what's responsible for sending sysui state flags over.
- *
- * @param vis IME visibility flag
- */
- public void updateImeStatus(int displayId, int vis, boolean showImeSwitcher) {
- if (displayId != mActivity.getDisplayId() || !mActivity.canShowNavButtons()) {
- return;
- }
-
- mImeBarView.setImeSwitcherVisibility(showImeSwitcher);
- setImeIsVisible((vis & InputMethodService.IME_VISIBLE) != 0);
- }
-
/**
* Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
*/
public void setImeIsVisible(boolean isImeVisible) {
mTaskbarView.setTouchesEnabled(!isImeVisible);
- mUIController.onImeVisible(mDragLayer, isImeVisible);
}
/**
@@ -122,7 +85,7 @@ public class TaskbarIconController {
if (mDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- } else if (mImeBarView.getVisibility() == VISIBLE) {
+ } else if (mNavbarButtonUIController.isImeVisible()) {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
} else if (!mUIController.isTaskbarTouchable()) {
// Let touches pass through us.
@@ -131,17 +94,8 @@ public class TaskbarIconController {
// Buttons are visible, take over the full taskbar area
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
} else {
- if (mTaskbarView.mSystemButtonContainer.getVisibility() == VISIBLE) {
- mDragLayer.getDescendantRectRelativeToSelf(
- mTaskbarView.mSystemButtonContainer, mTempRect);
- insetsInfo.touchableRegion.set(mTempRect);
- }
- if (mTaskbarView.mContextualButtonContainer.getVisibility() == VISIBLE) {
- mDragLayer.getDescendantRectRelativeToSelf(
- mTaskbarView.mContextualButtonContainer, mTempRect);
- insetsInfo.touchableRegion.union(mTempRect);
- }
-
+ mNavbarButtonUIController.addVisibleButtonsRegion(
+ mDragLayer, insetsInfo.touchableRegion);
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
}
@@ -160,32 +114,11 @@ public class TaskbarIconController {
// Ensure no other children present (like Folders, etc)
for (int i = 0; i < count; i++) {
View v = mDragLayer.getChildAt(i);
- if (!((v instanceof TaskbarView) || (v instanceof ImeBarView))) {
+ if (!(v instanceof TaskbarView)) {
return;
}
}
mActivity.setTaskbarWindowFullscreen(false);
}
-
- public void updateImeBarVisibilityAlpha(float alpha) {
- if (!mActivity.canShowNavButtons()) {
- // TODO Remove sysui IME bar for gesture nav as well
- return;
- }
- mImeBarView.setAlpha(alpha);
- mImeBarView.setVisibility(alpha == 0 ? GONE : VISIBLE);
- }
- }
-
- /**
- * Callbacks for {@link TaskbarView} to interact with the icon controller
- */
- public class TaskbarViewCallbacks {
- /**
- * Returns whether no other controller is currently handling the given View's visibility.
- */
- public boolean canUpdateViewVisibility(View child) {
- return !mActivity.getDragController().isDraggingView(child);
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index b9acee8160..36bccee464 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -40,14 +40,11 @@ import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.TouchInteractionService;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Class to manage taskbar lifecycle
*/
public class TaskbarManager implements DisplayController.DisplayInfoChangeListener,
- SysUINavigationMode.NavigationModeChangeListener, SystemTaskbarNotificationManager {
+ SysUINavigationMode.NavigationModeChangeListener {
private final Context mContext;
private final DisplayController mDisplayController;
@@ -62,8 +59,6 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
private boolean mUserUnlocked = false;
- private List mSystemTaskbarNotifiers = new ArrayList<>();
-
public TaskbarManager(TouchInteractionService service) {
mDisplayController = DisplayController.INSTANCE.get(service);
mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service);
@@ -129,7 +124,7 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
return;
}
mTaskbarActivityContext = new TaskbarActivityContext(
- mContext, dp.copy(mContext), mNavButtonController, this);
+ mContext, dp.copy(mContext), mNavButtonController);
mTaskbarActivityContext.init();
if (mLauncher != null) {
mTaskbarActivityContext.setUIController(
@@ -137,9 +132,6 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
}
}
- // TODO - I don't think this is the best place for these pass through methods,
- // maybe directly in TaskbarIconController?
-
/**
* See {@link com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags}
* @param systemUiStateFlags The latest SystemUiStateFlags
@@ -151,16 +143,6 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
}
}
- public void registerSystemTaskbarNotifications(SystemTaskbarNotifier notifier) {
- if (!mSystemTaskbarNotifiers.contains(notifier)) {
- mSystemTaskbarNotifiers.add(notifier);
- }
- }
-
- public void removeSystemTaskbarNotifications(SystemTaskbarNotifier notifier) {
- mSystemTaskbarNotifiers.remove(notifier);
- }
-
/**
* When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from
* instantiating at all, which is what's responsible for sending sysui state flags over.
@@ -171,26 +153,26 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
*/
public void updateImeStatus(int displayId, int vis, int backDisposition,
boolean showImeSwitcher) {
- for (SystemTaskbarNotifier notifier : mSystemTaskbarNotifiers) {
- notifier.updateImeStatus(displayId, vis, backDisposition, showImeSwitcher);
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.updateImeStatus(displayId, vis, showImeSwitcher);
}
}
public void onRotationProposal(int rotation, boolean isValid) {
- for (SystemTaskbarNotifier notifier : mSystemTaskbarNotifiers) {
- notifier.onRotationProposal(rotation, isValid);
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onRotationProposal(rotation, isValid);
}
}
public void disable(int displayId, int state1, int state2, boolean animate) {
- for (SystemTaskbarNotifier notifier : mSystemTaskbarNotifiers) {
- notifier.disable(displayId, state1, state2, animate);
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.disable(displayId, state1, state2, animate);
}
}
public void onSystemBarAttributesChanged(int displayId, int behavior) {
- for (SystemTaskbarNotifier notifier : mSystemTaskbarNotifiers) {
- notifier.onSystemBarAttributesChanged(displayId, behavior);
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onSystemBarAttributesChanged(displayId, behavior);
}
}
@@ -202,18 +184,4 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
mDisplayController.removeChangeListener(this);
mSysUINavigationMode.removeModeChangeListener(this);
}
-
- public interface SystemTaskbarNotifier {
- void updateImeStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher);
- void onRotationProposal(int rotation, boolean isValid);
- void disable(int displayId, int state1, int state2, boolean animate);
- void onSystemBarAttributesChanged(int displayId, int behavior);
-
- }
}
-
-interface SystemTaskbarNotificationManager {
- void registerSystemTaskbarNotifications(TaskbarManager.SystemTaskbarNotifier notifier);
- void removeSystemTaskbarNotifications(TaskbarManager.SystemTaskbarNotifier notifier);
-}
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
index a701aae088..e56ee8710b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.LauncherState.TASKBAR;
-import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import androidx.annotation.Nullable;
@@ -27,7 +26,7 @@ import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.quickstep.AnimatedFloat;
+import com.android.launcher3.util.MultiValueAlpha;
/**
* StateHandler to animate Taskbar according to Launcher's state machine. Does nothing if Taskbar
@@ -37,15 +36,15 @@ public class TaskbarStateHandler implements StateManager.StateHandler mActivityContext.setTaskbarWindowHeight(
+ mActivityContext.getDeviceProfile().taskbarSize);
}
/**
@@ -168,9 +158,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
*/
protected void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
for (int i = 0; i < hotseatItemInfos.length; i++) {
- ItemInfo hotseatItemInfo = hotseatItemInfos[
- !mIsRtl ? i : hotseatItemInfos.length - i - 1];
- View hotseatView = mHotseatIconsContainer.getChildAt(i);
+ ItemInfo hotseatItemInfo = hotseatItemInfos[i];
+ View hotseatView = getChildAt(i);
// Replace any Hotseat views with the appropriate type if it's not already that type.
final int expectedLayoutResId;
@@ -191,7 +180,7 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
if (hotseatView == null
|| hotseatView.getSourceLayoutResId() != expectedLayoutResId
|| needsReinflate) {
- mHotseatIconsContainer.removeView(hotseatView);
+ removeView(hotseatView);
if (isFolder) {
FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId,
@@ -201,10 +190,9 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
} else {
hotseatView = inflate(expectedLayoutResId);
}
- int iconSize = mActivityContext.getDeviceProfile().iconSizePx;
- LayoutParams lp = new LayoutParams(iconSize, iconSize);
- lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0);
- mHotseatIconsContainer.addView(hotseatView, i, lp);
+ LayoutParams lp = new LayoutParams(mIconTouchSize, mIconTouchSize);
+ hotseatView.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+ addView(hotseatView, i, lp);
}
// Apply the Hotseat ItemInfos, or hide the view if there is none for a given index.
@@ -222,22 +210,42 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
hotseatView.setOnLongClickListener(null);
hotseatView.setTag(null);
}
- updateHotseatItemVisibility(hotseatView);
+ hotseatView.setVisibility(hotseatView.getTag() != null ? VISIBLE : INVISIBLE);
}
}
- protected void updateHotseatItemsVisibility() {
- for (int i = mHotseatIconsContainer.getChildCount() - 1; i >= 0; i--) {
- updateHotseatItemVisibility(mHotseatIconsContainer.getChildAt(i));
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ int count = getChildCount();
+ // Find total visible children
+ int visibleChildren = 0;
+ for (int i = 0; i < count; i++) {
+ if (getChildAt(i).getVisibility() == VISIBLE) {
+ visibleChildren++;
+ }
}
- }
- private void updateHotseatItemVisibility(View hotseatView) {
- if (!mControllerCallbacks.canUpdateViewVisibility(hotseatView)) {
- return;
+ int spaceNeeded = visibleChildren * (mItemMarginLeftRight * 2 + mIconTouchSize);
+ int iconStart = (right - left - spaceNeeded) / 2;
+ int startOffset = ApiWrapper.getHotseatStartOffset(getContext());
+ if (startOffset > iconStart) {
+ int diff = startOffset - iconStart;
+ iconStart = isLayoutRtl() ? (iconStart - diff) : iconStart + diff;
}
- hotseatView.setVisibility(
- hotseatView.getTag() != null ? VISIBLE : (mAreHolesAllowed ? INVISIBLE : GONE));
+ // Layout the children
+ mIconLayoutBounds.left = iconStart;
+ mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2;
+ mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize;
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() == VISIBLE) {
+ iconStart += mItemMarginLeftRight;
+ int iconEnd = iconStart + mIconTouchSize;
+ child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
+ iconStart = iconEnd + mItemMarginLeftRight;
+ }
+ }
+ mIconLayoutBounds.right = iconStart;
}
@Override
@@ -248,154 +256,21 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
return super.dispatchTouchEvent(ev);
}
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- boolean handled = delegateTouchIfNecessary(event);
- return super.onTouchEvent(event) || handled;
- }
-
public void setTouchesEnabled(boolean touchEnabled) {
this.mTouchEnabled = touchEnabled;
}
- /**
- * User touched the Taskbar background. Determine whether the touch is close enough to a view
- * that we should forward the touches to it.
- * @return Whether a delegate view was chosen and it handled the touch event.
- */
- private boolean delegateTouchIfNecessary(MotionEvent event) {
- final float x = event.getX();
- final float y = event.getY();
- if (mDelegateView == null && event.getAction() == MotionEvent.ACTION_DOWN) {
- View delegateView = findDelegateView(x, y);
- if (delegateView != null) {
- mDelegateTargeted = true;
- mDelegateView = delegateView;
- mDelegateSlopBounds.set(mTempDelegateBounds);
- mDelegateSlopBounds.inset(-mTouchSlop, -mTouchSlop);
- }
- }
-
- boolean sendToDelegate = mDelegateTargeted;
- boolean inBounds = true;
- switch (event.getAction()) {
- case MotionEvent.ACTION_MOVE:
- inBounds = mDelegateSlopBounds.contains(x, y);
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mDelegateTargeted = false;
- break;
- }
-
- boolean handled = false;
- if (sendToDelegate) {
- if (inBounds) {
- // Offset event coordinates to be inside the target view
- event.setLocation(mDelegateView.getWidth() / 2f, mDelegateView.getHeight() / 2f);
- } else {
- // Offset event coordinates to be outside the target view (in case it does
- // something like tracking pressed state)
- event.setLocation(-mTouchSlop * 2, -mTouchSlop * 2);
- }
- handled = mDelegateView.dispatchTouchEvent(event);
- // Cleanup if this was the last event to send to the delegate.
- if (!mDelegateTargeted) {
- mDelegateView = null;
- }
- }
- return handled;
- }
-
- /**
- * Return an item whose touch bounds contain the given coordinates,
- * or null if no such item exists.
- *
- * Also sets {@link #mTempDelegateBounds} to be the touch bounds of the chosen delegate view.
- */
- private @Nullable View findDelegateView(float x, float y) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (!child.isShown() || !child.isClickable()) {
- continue;
- }
- int childCenterX = child.getLeft() + child.getWidth() / 2;
- int childCenterY = child.getTop() + child.getHeight() / 2;
- mTempDelegateBounds.set(
- childCenterX - mIconTouchSize / 2f,
- childCenterY - mIconTouchSize / 2f,
- childCenterX + mIconTouchSize / 2f,
- childCenterY + mIconTouchSize / 2f);
- if (mTempDelegateBounds.contains(x, y)) {
- return child;
- }
- }
- return null;
- }
-
/**
* Returns whether the given MotionEvent, *in screen coorindates*, is within any Taskbar item's
* touch bounds.
*/
public boolean isEventOverAnyItem(MotionEvent ev) {
getLocationOnScreen(mTempOutLocation);
- float xInOurCoordinates = ev.getX() - mTempOutLocation[0];
- float yInOurCoorindates = ev.getY() - mTempOutLocation[1];
- return findDelegateView(xInOurCoordinates, yInOurCoorindates) != null;
+ int xInOurCoordinates = (int) ev.getX() - mTempOutLocation[0];
+ int yInOurCoorindates = (int) ev.getY() - mTempOutLocation[1];
+ return isShown() && mIconLayoutBounds.contains(xInOurCoordinates, yInOurCoorindates);
}
- /**
- * Add back/home/recents buttons into a single ViewGroup that will be inserted at
- * {@param navButtonStartIndex}
- */
- private void createNavButtons() {
- LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(
- mActivityContext.getDeviceProfile().iconSizePx,
- mActivityContext.getDeviceProfile().iconSizePx
- );
- buttonParams.gravity = Gravity.CENTER;
-
- mSystemButtonContainer.addView(mButtonProvider.getBack(), buttonParams);
- mSystemButtonContainer.addView(mButtonProvider.getHome(), buttonParams);
- mSystemButtonContainer.addView(mButtonProvider.getRecents(), buttonParams);
- }
-
- /**
- * @return The bounding box of where the hotseat elements are relative to this TaskbarView.
- */
- protected RectF getHotseatBounds() {
- RectF result;
- mDisableRelayout = true;
- boolean wereHolesAllowed = mAreHolesAllowed;
- setHolesAllowedInLayoutNoAnimation(true);
- result = new RectF(
- mHotseatIconsContainer.getLeft(),
- mHotseatIconsContainer.getTop(),
- mHotseatIconsContainer.getRight(),
- mHotseatIconsContainer.getBottom());
- setHolesAllowedInLayoutNoAnimation(wereHolesAllowed);
- mDisableRelayout = false;
-
- return result;
- }
-
- @Override
- public void requestLayout() {
- if (!mDisableRelayout) {
- super.requestLayout();
- }
- }
-
- private void createContextualRegion() {
- mContextualRotationButton = mButtonProvider.getContextualRotation();
- mContextualRotationButton.setVisibility(GONE);
- mContextualButtonContainer.addView(mContextualRotationButton);
- }
-
- @Nullable
- public RotationContextButton getContextualRotationButton() {
- return mContextualRotationButton;
- }
// FolderIconParent implemented methods.
@Override
@@ -432,11 +307,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
// Ignore, we just implement Insettable to draw behind system insets.
}
- public void setIconsVisibility(boolean isVisible) {
- mHotseatIconsContainer.setVisibility(isVisible ? VISIBLE : INVISIBLE);
- }
-
public boolean areIconsVisible() {
- return mHotseatIconsContainer.getVisibility() == VISIBLE;
+ // Consider the overall visibility
+ return getVisibility() == VISIBLE;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java
index d42107742e..40930972d1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java
+++ b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java
@@ -30,16 +30,24 @@ import android.view.View;
* * Directly use AnimatedVectorDrawable instead of KeyButtonDrawable
*/
public interface RotationButton {
- void setRotationButtonController(RotationButtonController rotationButtonController);
- View getCurrentView();
- boolean show();
- boolean hide();
- boolean isVisible();
- void updateIcon(int lightIconColor, int darkIconColor);
- void setOnClickListener(View.OnClickListener onClickListener);
- void setOnHoverListener(View.OnHoverListener onHoverListener);
- AnimatedVectorDrawable getImageDrawable();
- void setDarkIntensity(float darkIntensity);
+ default void setRotationButtonController(RotationButtonController rotationButtonController) { }
+
+ default View getCurrentView() {
+ return null;
+ }
+ default void show() { }
+ default void hide() { }
+ default boolean isVisible() {
+ return false;
+ }
+
+ default void updateIcon(int lightIconColor, int darkIconColor) { }
+ default void setOnClickListener(View.OnClickListener onClickListener) { }
+ default void setOnHoverListener(View.OnHoverListener onHoverListener) { }
+ default AnimatedVectorDrawable getImageDrawable() {
+ return null;
+ }
+ default void setDarkIntensity(float darkIntensity) { }
default boolean acceptRotationProposal() {
return getCurrentView() != null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java
index 6f6abc2533..99dc2828ea 100644
--- a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java
@@ -104,7 +104,7 @@ public class RotationButtonController {
private final IRotationWatcher.Stub mRotationWatcher = new IRotationWatcher.Stub() {
@Override
- public void onRotationChanged(final int rotation) throws RemoteException {
+ public void onRotationChanged(final int rotation) {
// We need this to be scheduled as early as possible to beat the redrawing of
// window in response to the orientation change.
mMainThreadHandler.postAtFrontOfQueue(() -> {
@@ -137,7 +137,7 @@ public class RotationButtonController {
mAccessibilityManager = AccessibilityManager.getInstance(context);
mTaskStackListener = new TaskStackListenerImpl();
- mDisplayController = DisplayController.INSTANCE.getNoCreate();
+ mDisplayController = DisplayController.INSTANCE.get(context);
}
public void setRotationButton(RotationButton rotationButton) {
@@ -156,7 +156,7 @@ public class RotationButtonController {
}
}
- public void cleanup() {
+ public void onDestroy() {
unregisterListeners();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationContextButton.java b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationContextButton.java
deleted file mode 100644
index 7ad3191c49..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationContextButton.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2021 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.contextual;
-
-import android.content.Context;
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.android.launcher3.R;
-
-/** Containing logic for the rotation button in nav bar. */
-public class RotationContextButton extends ImageView implements RotationButton {
-
- private AnimatedVectorDrawable mImageDrawable;
-
- public RotationContextButton(Context context) {
- super(context);
- setBackgroundResource(R.drawable.taskbar_icon_click_feedback_roundrect);
- }
-
- @Override
- public void setRotationButtonController(RotationButtonController rotationButtonController) {
- // TODO(b/187754252) UI polish, different icons based on light/dark context, etc
- mImageDrawable = (AnimatedVectorDrawable) getContext()
- .getDrawable(rotationButtonController.getIconResId());
- setImageDrawable(mImageDrawable);
- mImageDrawable.setCallback(this);
- }
-
- @Override
- public View getCurrentView() {
- return this;
- }
-
- @Override
- public boolean show() {
- setVisibility(VISIBLE);
- return true;
- }
-
- @Override
- public boolean hide() {
- setVisibility(GONE);
- return true;
- }
-
- @Override
- public boolean isVisible() {
- return getVisibility() == VISIBLE;
- }
-
- @Override
- public void updateIcon(int lightIconColor, int darkIconColor) {
- // TODO(b/187754252): UI Polish
- }
-
- @Override
- public void setOnClickListener(View.OnClickListener onClickListener) {
- super.setOnClickListener(onClickListener);
- }
-
- @Override
- public void setOnHoverListener(View.OnHoverListener onHoverListener) {
- super.setOnHoverListener(onHoverListener);
- }
-
- @Override
- public AnimatedVectorDrawable getImageDrawable() {
- return mImageDrawable;
- }
-
- @Override
- public void setDarkIntensity(float darkIntensity) {
- // TODO(b/187754252) UI polish
- }
-
- @Override
- public void setVisibility(int visibility) {
- super.setVisibility(visibility);
-
- if (visibility != View.VISIBLE && mImageDrawable != null) {
- mImageDrawable.clearAnimationCallbacks();
- mImageDrawable.reset();
- }
-
- // Start the rotation animation once it becomes visible
- if (visibility == View.VISIBLE && mImageDrawable != null) {
- mImageDrawable.reset();
- mImageDrawable.start();
- }
- }
-
- @Override
- public boolean acceptRotationProposal() {
- return isAttachedToWindow();
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 76a5782d11..a595f54322 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -17,10 +17,15 @@
package com.android.launcher3.uioverrides;
import android.app.Person;
+import android.content.Context;
import android.content.pm.ShortcutInfo;
+import android.content.res.Resources;
import android.view.Display;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.SysUINavigationMode.Mode;
public class ApiWrapper {
@@ -37,4 +42,18 @@ public class ApiWrapper {
public static boolean isInternalDisplay(Display display) {
return display.getType() == Display.TYPE_INTERNAL;
}
+
+ /**
+ * Returns the minimum space that should be left empty at the start of hotseat
+ */
+ public static int getHotseatStartOffset(Context context) {
+ if (SysUINavigationMode.INSTANCE.get(context).getMode() == Mode.THREE_BUTTONS) {
+ Resources res = context.getResources();
+ return 2 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_spacing)
+ + 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size);
+ } else {
+ return 0;
+ }
+
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 8c128c8e08..90e17c0276 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -82,16 +82,6 @@ public class OverviewState extends LauncherState {
return new float[] {NO_SCALE, NO_OFFSET};
}
- @Override
- public float getTaskbarScale(Launcher launcher) {
- return 1f;
- }
-
- @Override
- public float getTaskbarTranslationY(Launcher launcher) {
- return 0f;
- }
-
@Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d6a6f43803..584ecb7c79 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -295,6 +295,10 @@
0dp
+ 0dp
+ 44dp
+
+ 8dp
16dp
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index e9245b0819..2da7ac39e0 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -44,6 +44,7 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.IconNormalizer;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.WindowBounds;
@@ -54,6 +55,8 @@ import java.io.PrintWriter;
public class DeviceProfile {
private static final int DEFAULT_DOT_SIZE = 100;
+ // Ratio of empty space, qsb should take up to appear visually centered.
+ private static final float QSB_CENTER_FACTOR = .325f;
public final InvariantDeviceProfile inv;
private final Info mInfo;
@@ -156,6 +159,7 @@ public class DeviceProfile {
// Start is the side next to the nav bar, end is the side next to the workspace
public final int hotseatBarSidePaddingStartPx;
public final int hotseatBarSidePaddingEndPx;
+ public final int hotseatQsbHeight;
// All apps
public int allAppsOpenVerticalTranslate;
@@ -240,6 +244,7 @@ public class DeviceProfile {
mMetrics = context.getResources().getDisplayMetrics();
final Resources res = context.getResources();
+ hotseatQsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height);
isTaskbarPresent = isTablet && FeatureFlags.ENABLE_TASKBAR.get();
if (isTaskbarPresent) {
// Taskbar will be added later, but provides bottom insets that we should subtract
@@ -740,7 +745,10 @@ public class DeviceProfile {
}
}
- public Rect getHotseatLayoutPadding() {
+ /**
+ * Returns the padding for hotseat view
+ */
+ public Rect getHotseatLayoutPadding(Context context) {
if (isVerticalBarLayout()) {
if (isSeascape()) {
mHotseatPadding.set(mInsets.left + hotseatBarSidePaddingStartPx,
@@ -749,6 +757,30 @@ public class DeviceProfile {
mHotseatPadding.set(hotseatBarSidePaddingEndPx, mInsets.top,
mInsets.right + hotseatBarSidePaddingStartPx, mInsets.bottom);
}
+ } else if (isTaskbarPresent) {
+ int hotseatHeight = workspacePadding.bottom + taskbarSize;
+ int taskbarOffset = getTaskbarOffsetY();
+ int hotseatTopDiff = hotseatHeight - taskbarSize - taskbarOffset;
+
+ int startOffset = ApiWrapper.getHotseatStartOffset(context);
+ int requiredWidth = iconSizePx * numShownHotseatIcons;
+
+ Resources res = context.getResources();
+ float taskbarIconSize = res.getDimension(R.dimen.taskbar_icon_size);
+ float taskbarIconSpacing = 2 * res.getDimension(R.dimen.taskbar_icon_spacing);
+ int maxSize = (int) (requiredWidth
+ * (taskbarIconSize + taskbarIconSpacing) / taskbarIconSize);
+ int hotseatSize = Math.min(maxSize, availableWidthPx - startOffset);
+ int sideSpacing = (availableWidthPx - hotseatSize) / 2;
+ mHotseatPadding.set(sideSpacing, hotseatTopDiff, sideSpacing, taskbarOffset);
+
+ if (startOffset > sideSpacing) {
+ int diff = Utilities.isRtl(context.getResources())
+ ? sideSpacing - startOffset
+ : startOffset - sideSpacing;
+ mHotseatPadding.left += diff;
+ mHotseatPadding.right -= diff;
+ }
} else {
// We want the edges of the hotseat to line up with the edges of the workspace, but the
// icons in the hotseat are a different size, and so don't line up perfectly. To account
@@ -768,6 +800,24 @@ public class DeviceProfile {
return mHotseatPadding;
}
+ /**
+ * Returns the number of pixels the QSB is translated from the bottom of the screen.
+ */
+ public int getQsbOffsetY() {
+ int freeSpace = isTaskbarPresent
+ ? workspacePadding.bottom
+ : hotseatBarSizePx - hotseatCellHeightPx - hotseatQsbHeight;
+ return (int) (freeSpace * QSB_CENTER_FACTOR)
+ + (isTaskbarPresent ? taskbarSize : getInsets().bottom);
+ }
+
+ /**
+ * Returns the number of pixels the taskbar is translated from the bottom of the screen.
+ */
+ public int getTaskbarOffsetY() {
+ return (getQsbOffsetY() - taskbarSize) / 2;
+ }
+
/**
* @return the bounds for which the open folders should be contained within
*/
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index ff380ce1ae..b3ae15ed4d 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -49,8 +49,6 @@ public class Hotseat extends CellLayout implements Insettable {
private final View mQsb;
private final int mQsbHeight;
- private final int mTaskbarViewHeight;
-
public Hotseat(Context context) {
this(context, null);
}
@@ -63,10 +61,9 @@ public class Hotseat extends CellLayout implements Insettable {
super(context, attrs, defStyle);
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
- mQsbHeight = mQsb.getLayoutParams().height;
addView(mQsb);
- mTaskbarViewHeight = context.getResources().getDimensionPixelSize(R.dimen.taskbar_size);
+ mQsbHeight = getResources().getDimensionPixelSize(R.dimen.qsb_widget_height);
}
/**
@@ -114,18 +111,13 @@ public class Hotseat extends CellLayout implements Insettable {
lp.gravity = Gravity.BOTTOM;
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
lp.height = (grid.isTaskbarPresent
- ? grid.workspacePadding.bottom
+ ? grid.workspacePadding.bottom
: grid.hotseatBarSizePx)
+ (grid.isTaskbarPresent ? grid.taskbarSize : insets.bottom);
}
- if (!grid.isTaskbarPresent) {
- // When taskbar is present, we set the padding separately to ensure a seamless visual
- // handoff between taskbar and hotseat during drag and drop.
- Rect padding = grid.getHotseatLayoutPadding();
- setPadding(padding.left, padding.top, padding.right, padding.bottom);
- }
-
+ Rect padding = grid.getHotseatLayoutPadding(getContext());
+ setPadding(padding.left, padding.top, padding.right, padding.bottom);
setLayoutParams(lp);
InsettableFrameLayout.dispatchInsets(this, insets);
}
@@ -193,30 +185,11 @@ public class Hotseat extends CellLayout implements Insettable {
int left = (r - l - qsbWidth) / 2;
int right = left + qsbWidth;
- int bottom = b - t - getQsbOffsetY();
+ int bottom = b - t - mActivity.getDeviceProfile().getQsbOffsetY();
int top = bottom - mQsbHeight;
mQsb.layout(left, top, right, bottom);
}
- /**
- * Returns the number of pixels the QSB is translated from the bottom of the screen.
- */
- private int getQsbOffsetY() {
- DeviceProfile dp = mActivity.getDeviceProfile();
- int freeSpace = dp.isTaskbarPresent
- ? dp.workspacePadding.bottom
- : dp.hotseatBarSizePx - dp.hotseatCellHeightPx - mQsbHeight;
- return (int) (freeSpace * QSB_CENTER_FACTOR)
- + (dp.isTaskbarPresent ? dp.taskbarSize : dp.getInsets().bottom);
- }
-
- /**
- * Returns the number of pixels the taskbar is translated from the bottom of the screen.
- */
- public int getTaskbarOffsetY() {
- return (getQsbOffsetY() - mTaskbarViewHeight) / 2;
- }
-
/**
* Sets the alpha value of just our ShortcutAndWidgetContainer.
*/
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 892fb6d6f0..fc8d65c85c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2801,13 +2801,6 @@ public class Launcher extends StatefulActivity implements Launche
return new float[] {NO_SCALE, NO_OFFSET};
}
- /**
- * @see LauncherState#getTaskbarScale(Launcher)
- */
- public float getNormalTaskbarScale() {
- return 1f;
- }
-
public static Launcher getLauncher(Context context) {
return fromContext(context);
}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 3399ce9cd6..7985ab5ad3 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -181,14 +181,6 @@ public abstract class LauncherState implements BaseState {
return launcher.getNormalOverviewScaleAndOffset();
}
- public float getTaskbarScale(Launcher launcher) {
- return launcher.getNormalTaskbarScale();
- }
-
- public float getTaskbarTranslationY(Launcher launcher) {
- return -launcher.getHotseat().getTaskbarOffsetY();
- }
-
public float getOverviewFullscreenProgress() {
return 0;
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
index 4407fe1149..c606861cd8 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -17,6 +17,7 @@
package com.android.launcher3.uioverrides;
import android.app.Person;
+import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.view.Display;
@@ -36,4 +37,11 @@ public class ApiWrapper {
public static boolean isInternalDisplay(Display display) {
return display.getDisplayId() == Display.DEFAULT_DISPLAY;
}
+
+ /**
+ * Returns the minimum space that should be left empty at the start of hotseat
+ */
+ public static int getHotseatStartOffset(Context context) {
+ return 0;
+ }
}