diff --git a/quickstep/res/drawable/button_taskbar_edu_bordered.xml b/quickstep/res/drawable/button_taskbar_edu_bordered.xml
new file mode 100644
index 0000000000..47f8e8f8cd
--- /dev/null
+++ b/quickstep/res/drawable/button_taskbar_edu_bordered.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/button_taskbar_edu_colored.xml b/quickstep/res/drawable/button_taskbar_edu_colored.xml
new file mode 100644
index 0000000000..70bfc9f255
--- /dev/null
+++ b/quickstep/res/drawable/button_taskbar_edu_colored.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/taskbar_edu_splitscreen.webp b/quickstep/res/drawable/taskbar_edu_splitscreen.webp
new file mode 100644
index 0000000000..2f4402f69e
Binary files /dev/null and b/quickstep/res/drawable/taskbar_edu_splitscreen.webp differ
diff --git a/quickstep/res/layout/taskbar_edu.xml b/quickstep/res/layout/taskbar_edu.xml
new file mode 100644
index 0000000000..b7717b71be
--- /dev/null
+++ b/quickstep/res/layout/taskbar_edu.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 659ff9a06a..80d12aa450 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -165,4 +165,5 @@
24dp
220dp
6dp
+ 28dp
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 4aee2a9ccb..da19c95596 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -203,4 +203,13 @@
Cancel
Skip
+
+
+
+ Use 2 apps at once and switch apps with the taskbar
+
+ Next
+
+ Close
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 07c448df9e..c23a3a01a6 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -139,4 +139,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index d41590b10b..433ae3c0e5 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -670,6 +670,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
if (v instanceof BubbleTextView) {
((BubbleTextView) v).setStayPressed(false);
}
+ LauncherTaskbarUIController taskbarController = mLauncher.getTaskbarUIController();
+ if (taskbarController != null) {
+ taskbarController.showEdu();
+ }
openingTargets.release();
}
});
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 95c7d6292c..b2e33ebb37 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -32,6 +32,7 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.AnimatedFloat;
@@ -261,6 +262,28 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
mTaskbarOverrideBackgroundAlpha.updateValue(forceHide ? 0 : 1);
}
+ /**
+ * Starts the taskbar education flow, if the user hasn't seen it yet.
+ */
+ public void showEdu() {
+ if (!FeatureFlags.ENABLE_TASKBAR_EDU.get()) {
+ return;
+ }
+
+ mControllers.taskbarEduController.showEdu();
+ }
+
+ /**
+ * Manually ends the taskbar education flow.
+ */
+ public void hideEdu() {
+ if (!FeatureFlags.ENABLE_TASKBAR_EDU.get()) {
+ return;
+ }
+
+ mControllers.taskbarEduController.hideEdu();
+ }
+
private final class TaskBarRecentsAnimationListener implements RecentsAnimationListener {
private final RecentsAnimationCallbacks mCallbacks;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index dbe528f6af..ec0355b133 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -128,7 +128,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
new TaskbarViewController(this, taskbarView),
new TaskbarKeyguardController(this),
new StashedHandleViewController(this, stashedHandleView),
- new TaskbarStashController(this));
+ new TaskbarStashController(this),
+ new TaskbarEduController(this));
Display display = windowContext.getDisplay();
Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index be26913554..2927a6321e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -34,6 +34,7 @@ public class TaskbarControllers {
public final TaskbarKeyguardController taskbarKeyguardController;
public final StashedHandleViewController stashedHandleViewController;
public final TaskbarStashController taskbarStashController;
+ public final TaskbarEduController taskbarEduController;
/** Do not store this controller, as it may change at runtime. */
@NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT;
@@ -47,7 +48,8 @@ public class TaskbarControllers {
TaskbarViewController taskbarViewController,
TaskbarKeyguardController taskbarKeyguardController,
StashedHandleViewController stashedHandleViewController,
- TaskbarStashController taskbarStashController) {
+ TaskbarStashController taskbarStashController,
+ TaskbarEduController taskbarEduController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
this.navButtonController = navButtonController;
@@ -58,6 +60,7 @@ public class TaskbarControllers {
this.taskbarKeyguardController = taskbarKeyguardController;
this.stashedHandleViewController = stashedHandleViewController;
this.taskbarStashController = taskbarStashController;
+ this.taskbarEduController = taskbarEduController;
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
new file mode 100644
index 0000000000..c5a0fc1902
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
@@ -0,0 +1,47 @@
+/*
+ * 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 com.android.launcher3.R;
+
+/** Handles the Taskbar Education flow. */
+public class TaskbarEduController {
+
+ private final TaskbarActivityContext mActivity;
+ private TaskbarEduView mTaskbarEduView;
+
+ public TaskbarEduController(TaskbarActivityContext activity) {
+ mActivity = activity;
+ }
+
+ void showEdu() {
+ mActivity.setTaskbarWindowFullscreen(true);
+ mActivity.getDragLayer().post(() -> {
+ mTaskbarEduView = (TaskbarEduView) mActivity.getLayoutInflater().inflate(
+ R.layout.taskbar_edu, mActivity.getDragLayer(), false);
+ mTaskbarEduView.addOnCloseListener(() -> {
+ mTaskbarEduView = null;
+ });
+ mTaskbarEduView.show();
+ });
+ }
+
+ void hideEdu() {
+ if (mTaskbarEduView != null) {
+ mTaskbarEduView.close(true /* animate */);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
new file mode 100644
index 0000000000..b5dab7e770
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
@@ -0,0 +1,113 @@
+/*
+ * 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.anim.Interpolators.FAST_OUT_SLOW_IN;
+
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+
+import com.android.launcher3.Insettable;
+import com.android.launcher3.R;
+import com.android.launcher3.views.AbstractSlideInView;
+
+/** Education view about the Taskbar. */
+public class TaskbarEduView extends AbstractSlideInView
+ implements Insettable {
+
+ private static final int DEFAULT_CLOSE_DURATION = 200;
+
+ private final Rect mInsets = new Rect();
+
+ public TaskbarEduView(Context context, AttributeSet attr) {
+ this(context, attr, 0);
+ }
+
+ public TaskbarEduView(Context context, AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ handleClose(animate, DEFAULT_CLOSE_DURATION);
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_TASKBAR_EDUCATION_DIALOG) != 0;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mContent = findViewById(R.id.edu_view);
+ findViewById(R.id.edu_close_button).setOnClickListener(v -> close(true /* animate */));
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ mInsets.set(insets);
+ mContent.setPadding(mContent.getPaddingStart(),
+ mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
+ }
+
+ @Override
+ protected void attachToContainer() {
+ if (mColorScrim != null) {
+ getPopupContainer().addView(mColorScrim, 0);
+ }
+ getPopupContainer().addView(this, 1);
+ }
+
+ /** Show the Education flow. */
+ public void show() {
+ attachToContainer();
+ animateOpen();
+ }
+
+ @Override
+ protected int getScrimColor(Context context) {
+ return context.getResources().getColor(R.color.widgets_picker_scrim);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int width = r - l;
+ int height = b - t;
+
+ // Lay out the content as center bottom aligned.
+ int contentWidth = mContent.getMeasuredWidth();
+ int contentLeft = (width - contentWidth - mInsets.left - mInsets.right) / 2 + mInsets.left;
+ mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
+ contentLeft + contentWidth, height);
+
+ setTranslationShift(mTranslationShift);
+ }
+
+ private void animateOpen() {
+ if (mIsOpen || mOpenCloseAnimator.isRunning()) {
+ return;
+ }
+ mIsOpen = true;
+ mOpenCloseAnimator.setValues(
+ PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+ mOpenCloseAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+ mOpenCloseAnimator.start();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index d91d5b06f9..f84f377913 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -288,6 +288,10 @@ public final class LauncherActivityInterface extends
} else {
om.hideOverlay(150);
}
+ LauncherTaskbarUIController taskbarController = getTaskbarController();
+ if (taskbarController != null) {
+ taskbarController.hideEdu();
+ }
}
@Override
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 4979b40af5..e080537293 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -64,7 +64,8 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
TYPE_OPTIONS_POPUP,
TYPE_ICON_SURFACE,
TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP,
- TYPE_WIDGETS_EDUCATION_DIALOG
+ TYPE_WIDGETS_EDUCATION_DIALOG,
+ TYPE_TASKBAR_EDUCATION_DIALOG
})
@Retention(RetentionPolicy.SOURCE)
public @interface FloatingViewType {}
@@ -87,18 +88,20 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public static final int TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP = 1 << 14;
public static final int TYPE_WIDGETS_EDUCATION_DIALOG = 1 << 15;
+ public static final int TYPE_TASKBAR_EDUCATION_DIALOG = 1 << 16;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
| TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
| TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU
| TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
- | TYPE_WIDGETS_EDUCATION_DIALOG;
+ | TYPE_WIDGETS_EDUCATION_DIALOG | TYPE_TASKBAR_EDUCATION_DIALOG;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
- | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_WIDGETS_EDUCATION_DIALOG;
+ | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_WIDGETS_EDUCATION_DIALOG
+ | TYPE_TASKBAR_EDUCATION_DIALOG;
// Usually we show the back button when a floating view is open. Instead, hide for these types.
public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index da701a8cb1..38a957ddae 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -219,6 +219,9 @@ public final class FeatureFlags {
public static final BooleanFlag ENABLE_TASKBAR = getDebugFlag(
"ENABLE_TASKBAR", true, "Allows a system Taskbar to be shown on larger devices.");
+ public static final BooleanFlag ENABLE_TASKBAR_EDU = getDebugFlag("ENABLE_TASKBAR_EDU", false,
+ "Enables showing taskbar education the first time an app is opened.");
+
public static final BooleanFlag ENABLE_OVERVIEW_GRID = getDebugFlag(
"ENABLE_OVERVIEW_GRID", true, "Uses grid overview layout. "
+ "Only applicable on large screen devices.");