Refactors Sandbox to more easily add new tutorials.
- Extracts abstract classes for common functionality
- Renames some layouts, etc. to not be back-specific
- Consolidates more logic in the controllers rather
than classes like BackGestureTutorialTypeInfo
- Removes redundant TutorialStep enum (combining it
with TutorialType)
Still considering removing additional layers of
abstraction like the Fragment itself (instead
keeping UI within the Activity, which would still
be controlled by a TutorialController).
Test: Built and went through the Back tutorial to
confirm existing funcitonality was not disrupted.
Bug: 148542211
Merged-In: Id893869cb59609141dcdbdca01744d0f5952b546
Change-Id: Id893869cb59609141dcdbdca01744d0f5952b546
diff --git a/quickstep/res/drawable-v28/back_gesture_tutorial_action_button_background.xml b/quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml
similarity index 91%
rename from quickstep/res/drawable-v28/back_gesture_tutorial_action_button_background.xml
rename to quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml
index cd30ef7..57423c2 100644
--- a/quickstep/res/drawable-v28/back_gesture_tutorial_action_button_background.xml
+++ b/quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml
@@ -16,5 +16,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?android:attr/dialogCornerRadius"/>
- <solid android:color="@color/back_gesture_tutorial_primary_color"/>
+ <solid android:color="@color/gesture_tutorial_primary_color"/>
</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/back_gesture_tutorial_action_button_background.xml b/quickstep/res/drawable/gesture_tutorial_action_button_background.xml
similarity index 91%
rename from quickstep/res/drawable/back_gesture_tutorial_action_button_background.xml
rename to quickstep/res/drawable/gesture_tutorial_action_button_background.xml
index d7b9102..3f3b288 100644
--- a/quickstep/res/drawable/back_gesture_tutorial_action_button_background.xml
+++ b/quickstep/res/drawable/gesture_tutorial_action_button_background.xml
@@ -16,5 +16,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/default_dialog_corner_radius"/>
- <solid android:color="@color/back_gesture_tutorial_primary_color"/>
+ <solid android:color="@color/gesture_tutorial_primary_color"/>
</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/back_gesture_tutorial_close_button.xml b/quickstep/res/drawable/gesture_tutorial_close_button.xml
similarity index 100%
rename from quickstep/res/drawable/back_gesture_tutorial_close_button.xml
rename to quickstep/res/drawable/gesture_tutorial_close_button.xml
diff --git a/quickstep/res/layout/back_gesture_tutorial_activity.xml b/quickstep/res/layout/gesture_tutorial_activity.xml
similarity index 92%
rename from quickstep/res/layout/back_gesture_tutorial_activity.xml
rename to quickstep/res/layout/gesture_tutorial_activity.xml
index e894e89..4dc8913 100644
--- a/quickstep/res/layout/back_gesture_tutorial_activity.xml
+++ b/quickstep/res/layout/gesture_tutorial_activity.xml
@@ -14,6 +14,6 @@
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/back_gesture_tutorial_fragment_container"
+ android:id="@+id/gesture_tutorial_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/quickstep/res/layout/back_gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
similarity index 71%
rename from quickstep/res/layout/back_gesture_tutorial_fragment.xml
rename to quickstep/res/layout/gesture_tutorial_fragment.xml
index d8c25bd..0bc062a 100644
--- a/quickstep/res/layout/back_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -16,27 +16,27 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/back_gesture_tutorial_background_color">
+ android:background="@color/gesture_tutorial_background_color">
<ImageView
- android:id="@+id/back_gesture_tutorial_fragment_hand_coaching"
+ android:id="@+id/gesture_tutorial_fragment_hand_coaching"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
<ImageButton
- android:id="@+id/back_gesture_tutorial_fragment_close_button"
+ android:id="@+id/gesture_tutorial_fragment_close_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="18dp"
android:layout_marginTop="30dp"
android:layout_marginStart="4dp"
- android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="@android:color/transparent"
- android:accessibilityTraversalAfter="@id/back_gesture_tutorial_fragment_titles_container"
- android:contentDescription="@string/back_gesture_tutorial_close_button_content_description"
- android:src="@drawable/back_gesture_tutorial_close_button"/>
+ android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_titles_container"
+ android:contentDescription="@string/gesture_tutorial_close_button_content_description"
+ android:src="@drawable/gesture_tutorial_close_button"/>
<LinearLayout
android:layout_width="match_parent"
@@ -45,29 +45,29 @@
android:orientation="vertical">
<LinearLayout
- android:id="@+id/back_gesture_tutorial_fragment_titles_container"
+ android:id="@+id/gesture_tutorial_fragment_titles_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusable="true">
<TextView
- android:id="@+id/back_gesture_tutorial_fragment_title_view"
+ android:id="@+id/gesture_tutorial_fragment_title_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
- android:layout_marginStart="@dimen/back_gesture_tutorial_title_margin_start_end"
- android:layout_marginEnd="@dimen/back_gesture_tutorial_title_margin_start_end"
+ android:layout_marginStart="@dimen/gesture_tutorial_title_margin_start_end"
+ android:layout_marginEnd="@dimen/gesture_tutorial_title_margin_start_end"
style="@style/TextAppearance.BackGestureTutorial.Title"/>
<TextView
- android:id="@+id/back_gesture_tutorial_fragment_subtitle_view"
+ android:id="@+id/gesture_tutorial_fragment_subtitle_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
- android:layout_marginStart="@dimen/back_gesture_tutorial_subtitle_margin_start_end"
- android:layout_marginEnd="@dimen/back_gesture_tutorial_subtitle_margin_start_end"
+ android:layout_marginStart="@dimen/gesture_tutorial_subtitle_margin_start_end"
+ android:layout_marginEnd="@dimen/gesture_tutorial_subtitle_margin_start_end"
style="@style/TextAppearance.BackGestureTutorial.Subtitle"/>
</LinearLayout>
@@ -91,21 +91,21 @@
android:layout_gravity="center_horizontal">
<Button
- android:id="@+id/back_gesture_tutorial_fragment_action_button"
+ android:id="@+id/gesture_tutorial_fragment_action_button"
android:layout_width="142dp"
android:layout_height="49dp"
- android:layout_marginEnd="@dimen/back_gesture_tutorial_button_margin_start_end"
+ android:layout_marginEnd="@dimen/gesture_tutorial_button_margin_start_end"
android:layout_alignParentEnd="true"
android:stateListAnimator="@null"
- android:background="@drawable/back_gesture_tutorial_action_button_background"
+ android:background="@drawable/gesture_tutorial_action_button_background"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
style="@style/TextAppearance.BackGestureTutorial.ButtonLabel"/>
<Button
- android:id="@+id/back_gesture_tutorial_fragment_action_text_button"
+ android:id="@+id/gesture_tutorial_fragment_action_text_button"
android:layout_width="142dp"
android:layout_height="49dp"
- android:layout_marginStart="@dimen/back_gesture_tutorial_button_margin_start_end"
+ android:layout_marginStart="@dimen/gesture_tutorial_button_margin_start_end"
android:layout_alignParentStart="true"
android:stateListAnimator="@null"
android:background="@null"
@@ -113,7 +113,5 @@
style="@style/TextAppearance.BackGestureTutorial.TextButtonLabel"/>
</RelativeLayout>
-
</LinearLayout>
-
</RelativeLayout>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9a61165..18dc19c 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -81,7 +81,7 @@
<dimen name="gestures_overscroll_fling_threshold">40dp</dimen>
<!-- Tips Gesture Tutorial -->
- <dimen name="back_gesture_tutorial_title_margin_start_end">40dp</dimen>
- <dimen name="back_gesture_tutorial_subtitle_margin_start_end">16dp</dimen>
- <dimen name="back_gesture_tutorial_button_margin_start_end">18dp</dimen>
+ <dimen name="gesture_tutorial_title_margin_start_end">40dp</dimen>
+ <dimen name="gesture_tutorial_subtitle_margin_start_end">16dp</dimen>
+ <dimen name="gesture_tutorial_button_margin_start_end">18dp</dimen>
</resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index c6b1477..d7c976d 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -61,7 +61,7 @@
<string name="all_apps_prediction_tip">Your predicted apps</string>
<!-- Content description for a close button. [CHAR LIMIT=NONE] -->
- <string name="back_gesture_tutorial_close_button_content_description" translatable="false">Close</string>
+ <string name="gesture_tutorial_close_button_content_description" translatable="false">Close</string>
<!-- Hotseat migration notification title -->
@@ -110,9 +110,9 @@
<string name="back_gesture_tutorial_confirm_subtitle" translatable="false">To change the sensitivity of the back gesture, go to Settings</string>
<!-- Button text shown on a button on the confirm screen. [CHAR LIMIT=14] -->
- <string name="back_gesture_tutorial_action_button_label" translatable="false">Done</string>
+ <string name="gesture_tutorial_action_button_label" translatable="false">Done</string>
<!-- Button text shown on a text button on the confirm screen. [CHAR LIMIT=14] -->
- <string name="back_gesture_tutorial_action_text_button_label" translatable="false">Settings</string>
+ <string name="gesture_tutorial_action_text_button_label" translatable="false">Settings</string>
<!-- ******* Overview ******* -->
<!-- Label for a button that causes the current overview app to be shared. [CHAR_LIMIT=40] -->
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index bf107fb..14e054e 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -35,14 +35,14 @@
<style name="TextAppearance.BackGestureTutorial.Title"
parent="TextAppearance.BackGestureTutorial">
<item name="android:gravity">center</item>
- <item name="android:textColor">@color/back_gesture_tutorial_title_color</item>
+ <item name="android:textColor">@color/gesture_tutorial_title_color</item>
<item name="android:textSize">28sp</item>
</style>
<style name="TextAppearance.BackGestureTutorial.Subtitle"
parent="TextAppearance.BackGestureTutorial">
<item name="android:gravity">center</item>
- <item name="android:textColor">@color/back_gesture_tutorial_subtitle_color</item>
+ <item name="android:textColor">@color/gesture_tutorial_subtitle_color</item>
<item name="android:letterSpacing">0.03</item>
<item name="android:textSize">21sp</item>
</style>
@@ -50,7 +50,7 @@
<style name="TextAppearance.BackGestureTutorial.ButtonLabel"
parent="TextAppearance.BackGestureTutorial.CallToAction">
<item name="android:gravity">center</item>
- <item name="android:textColor">@color/back_gesture_tutorial_action_button_label_color</item>
+ <item name="android:textColor">@color/gesture_tutorial_action_button_label_color</item>
<item name="android:letterSpacing">0.02</item>
<item name="android:textSize">16sp</item>
<item name="android:textAllCaps">false</item>
@@ -58,7 +58,7 @@
<style name="TextAppearance.BackGestureTutorial.TextButtonLabel"
parent="TextAppearance.BackGestureTutorial.ButtonLabel">
- <item name="android:textColor">@color/back_gesture_tutorial_primary_color</item>
+ <item name="android:textColor">@color/gesture_tutorial_primary_color</item>
</style>
<style name="OverviewActionButton"
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialConfirmController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialConfirmController.java
deleted file mode 100644
index 486d676..0000000
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialConfirmController.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2020 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.quickstep.interaction;
-
-import android.view.View;
-
-import com.android.launcher3.R;
-import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialStep;
-
-import java.util.Optional;
-
-/**
- * An implementation of {@link BackGestureTutorialController} that defines the behavior of the
- * {@link TutorialStep#CONFIRM}.
- */
-final class BackGestureTutorialConfirmController extends BackGestureTutorialController {
-
- BackGestureTutorialConfirmController(BackGestureTutorialFragment fragment,
- BackGestureTutorialTypeInfo tutorialTypeInfo) {
- super(fragment, TutorialStep.CONFIRM, Optional.of(tutorialTypeInfo));
- }
-
- @Override
- Optional<Integer> getTitleStringId() {
- return Optional.of(mTutorialTypeInfo.get().getTutorialConfirmTitleId());
- }
-
- @Override
- Optional<Integer> getSubtitleStringId() {
- return Optional.of(mTutorialTypeInfo.get().getTutorialConfirmSubtitleId());
- }
-
- @Override
- Optional<Integer> getActionButtonStringId() {
- return Optional.of(R.string.back_gesture_tutorial_action_button_label);
- }
-
- @Override
- Optional<Integer> getActionTextButtonStringId() {
- return Optional.of(R.string.back_gesture_tutorial_action_text_button_label);
- }
-
- @Override
- void onActionButtonClicked(View button) {
- hideHandCoachingAnimation();
- if (button == mActionTextButton) {
- mFragment.startSystemNavigationSetting();
- }
- mFragment.closeTutorial();
- }
-}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 5c2e992..640ae76 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -15,164 +15,101 @@
*/
package com.android.quickstep.interaction;
+import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION_COMPLETE;
+import static com.android.quickstep.interaction.TutorialController.TutorialType.LEFT_EDGE_BACK_NAVIGATION;
+
import android.view.View;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
import com.android.launcher3.R;
-import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialStep;
-import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialType;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
-import java.util.Optional;
+/** A {@link TutorialController} for the Back tutorial. */
+final class BackGestureTutorialController extends TutorialController {
-/**
- * Defines the behavior of the particular {@link TutorialStep} and implements the transition to it.
- */
-abstract class BackGestureTutorialController {
-
- final BackGestureTutorialFragment mFragment;
- final TutorialStep mTutorialStep;
- final Optional<BackGestureTutorialTypeInfo> mTutorialTypeInfo;
- final Button mActionTextButton;
- final Button mActionButton;
- final TextView mSubtitleTextView;
- final ImageButton mCloseButton;
- final BackGestureTutorialHandAnimation mHandCoachingAnimation;
- final LinearLayout mTitlesContainer;
-
- private final TextView mTitleTextView;
- private final ImageView mHandCoachingView;
-
- BackGestureTutorialController(
- BackGestureTutorialFragment fragment,
- TutorialStep tutorialStep,
- Optional<BackGestureTutorialTypeInfo> tutorialTypeInfo) {
- mFragment = fragment;
- mTutorialStep = tutorialStep;
- mTutorialTypeInfo = tutorialTypeInfo;
-
- View rootView = fragment.getRootView();
- mActionTextButton = rootView.findViewById(
- R.id.back_gesture_tutorial_fragment_action_text_button);
- mActionButton = rootView.findViewById(R.id.back_gesture_tutorial_fragment_action_button);
- mSubtitleTextView = rootView.findViewById(
- R.id.back_gesture_tutorial_fragment_subtitle_view);
- mTitleTextView = rootView.findViewById(R.id.back_gesture_tutorial_fragment_title_view);
- mHandCoachingView = rootView.findViewById(
- R.id.back_gesture_tutorial_fragment_hand_coaching);
- mHandCoachingAnimation = mFragment.getHandAnimation();
- mHandCoachingView.bringToFront();
- mCloseButton = rootView.findViewById(R.id.back_gesture_tutorial_fragment_close_button);
- mTitlesContainer = rootView.findViewById(
- R.id.back_gesture_tutorial_fragment_titles_container);
+ BackGestureTutorialController(BackGestureTutorialFragment fragment, TutorialType tutorialType) {
+ super(fragment, tutorialType);
}
+ @Override
void transitToController() {
- updateTitles();
- updateActionButtons();
+ super.transitToController();
+ if (mTutorialType != BACK_NAVIGATION_COMPLETE) {
+ mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
+ }
}
- void hideHandCoachingAnimation() {
- mHandCoachingAnimation.stop();
+ @Override
+ Integer getTitleStringId() {
+ switch (mTutorialType) {
+ case RIGHT_EDGE_BACK_NAVIGATION:
+ return R.string.back_gesture_tutorial_playground_title_swipe_inward_right_edge;
+ case LEFT_EDGE_BACK_NAVIGATION:
+ return R.string.back_gesture_tutorial_playground_title_swipe_inward_left_edge;
+ case BACK_NAVIGATION_COMPLETE:
+ return R.string.back_gesture_tutorial_confirm_title;
+ }
+ return null;
}
- void onGestureAttempted(BackGestureResult result) {
- if (mTutorialStep == TutorialStep.CONFIRM
- && (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
- || result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT)) {
- mFragment.closeTutorial();
- return;
+ @Override
+ Integer getSubtitleStringId() {
+ switch (mTutorialType) {
+ case RIGHT_EDGE_BACK_NAVIGATION:
+ return R.string.back_gesture_tutorial_engaged_subtitle_swipe_inward_right_edge;
+ case LEFT_EDGE_BACK_NAVIGATION:
+ return R.string.back_gesture_tutorial_engaged_subtitle_swipe_inward_left_edge;
+ case BACK_NAVIGATION_COMPLETE:
+ return R.string.back_gesture_tutorial_confirm_subtitle;
}
+ return null;
+ }
- if (!mTutorialTypeInfo.isPresent()) {
- return;
+ @Override
+ Integer getActionButtonStringId() {
+ if (mTutorialType == BACK_NAVIGATION_COMPLETE) {
+ return R.string.gesture_tutorial_action_button_label;
}
+ return null;
+ }
- switch (mTutorialTypeInfo.get().getTutorialType()) {
+ @Override
+ Integer getActionTextButtonStringId() {
+ if (mTutorialType == BACK_NAVIGATION_COMPLETE) {
+ return R.string.gesture_tutorial_action_text_button_label;
+ }
+ return null;
+ }
+
+ @Override
+ void onActionButtonClicked(View button) {
+ hideHandCoachingAnimation();
+ if (button == mActionTextButton) {
+ mTutorialFragment.startSystemNavigationSetting();
+ }
+ mTutorialFragment.closeTutorial();
+ }
+
+ @Override
+ public void onBackGestureAttempted(BackGestureResult result) {
+ switch (mTutorialType) {
case RIGHT_EDGE_BACK_NAVIGATION:
if (result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) {
hideHandCoachingAnimation();
- mFragment.changeController(
- TutorialStep.ENGAGED, TutorialType.LEFT_EDGE_BACK_NAVIGATION);
+ mTutorialFragment.changeController(LEFT_EDGE_BACK_NAVIGATION);
}
break;
case LEFT_EDGE_BACK_NAVIGATION:
if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT) {
hideHandCoachingAnimation();
- mFragment.changeController(TutorialStep.CONFIRM);
+ mTutorialFragment.changeController(BACK_NAVIGATION_COMPLETE);
}
break;
- }
- }
-
- abstract Optional<Integer> getTitleStringId();
-
- abstract Optional<Integer> getSubtitleStringId();
-
- abstract Optional<Integer> getActionButtonStringId();
-
- abstract Optional<Integer> getActionTextButtonStringId();
-
- abstract void onActionButtonClicked(View button);
-
- private void updateActionButtons() {
- updateButton(mActionButton, getActionButtonStringId(), this::onActionButtonClicked);
- updateButton(mActionTextButton, getActionTextButtonStringId(), this::onActionButtonClicked);
- }
-
- private static void updateButton(Button button, Optional<Integer> stringId,
- View.OnClickListener listener) {
- if (!stringId.isPresent()) {
- button.setVisibility(View.INVISIBLE);
- return;
- }
-
- button.setVisibility(View.VISIBLE);
- button.setText(stringId.get());
- button.setOnClickListener(listener);
- }
-
- private void updateTitles() {
- updateTitleView(mTitleTextView, getTitleStringId(),
- R.style.TextAppearance_BackGestureTutorial_Title);
- updateTitleView(mSubtitleTextView, getSubtitleStringId(),
- R.style.TextAppearance_BackGestureTutorial_Subtitle);
- }
-
- private static void updateTitleView(TextView textView, Optional<Integer> stringId,
- int styleId) {
- if (!stringId.isPresent()) {
- textView.setVisibility(View.GONE);
- return;
- }
-
- textView.setVisibility(View.VISIBLE);
- textView.setText(stringId.get());
- textView.setTextAppearance(styleId);
- }
-
- /**
- * Constructs {@link BackGestureTutorialController} for providing {@link TutorialType} and
- * {@link TutorialStep}.
- */
- static Optional<BackGestureTutorialController> getTutorialController(
- BackGestureTutorialFragment fragment, TutorialStep tutorialStep,
- TutorialType tutorialType) {
- BackGestureTutorialTypeInfo tutorialTypeInfo =
- BackGestureTutorialTypeInfoProvider.getTutorialTypeInfo(tutorialType);
- switch (tutorialStep) {
- case ENGAGED:
- return Optional.of(
- new BackGestureTutorialEngagedController(fragment, tutorialTypeInfo));
- case CONFIRM:
- return Optional.of(
- new BackGestureTutorialConfirmController(fragment, tutorialTypeInfo));
- default:
- throw new AssertionError("Unexpected tutorial step: " + tutorialStep);
+ case BACK_NAVIGATION_COMPLETE:
+ if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
+ || result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) {
+ mTutorialFragment.closeTutorial();
+ }
+ break;
}
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialEngagedController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialEngagedController.java
deleted file mode 100644
index 297c287..0000000
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialEngagedController.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2020 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.quickstep.interaction;
-
-import android.view.View;
-
-import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialStep;
-
-import java.util.Optional;
-
-/**
- * An implementation of {@link BackGestureTutorialController} that defines the behavior of the
- * {@link TutorialStep#ENGAGED}.
- */
-final class BackGestureTutorialEngagedController extends BackGestureTutorialController {
-
- BackGestureTutorialEngagedController(
- BackGestureTutorialFragment fragment, BackGestureTutorialTypeInfo tutorialTypeInfo) {
- super(fragment, TutorialStep.ENGAGED, Optional.of(tutorialTypeInfo));
- }
-
- @Override
- void transitToController() {
- super.transitToController();
- mHandCoachingAnimation.startLoopedAnimation(mTutorialTypeInfo.get().getTutorialType());
- }
-
- @Override
- Optional<Integer> getTitleStringId() {
- return Optional.of(mTutorialTypeInfo.get().getTutorialPlaygroundTitleId());
- }
-
- @Override
- Optional<Integer> getSubtitleStringId() {
- return Optional.of(mTutorialTypeInfo.get().getTutorialEngagedSubtitleId());
- }
-
- @Override
- Optional<Integer> getActionButtonStringId() {
- return Optional.empty();
- }
-
- @Override
- Optional<Integer> getActionTextButtonStringId() {
- return Optional.empty();
- }
-
- @Override
- void onActionButtonClicked(View button) {
- }
-}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
index aeb718d..ddf1cda 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
@@ -15,172 +15,43 @@
*/
package com.android.quickstep.interaction;
-import android.content.ActivityNotFoundException;
-import android.content.Intent;
-import android.graphics.Insets;
import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
import com.android.launcher3.R;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureAttemptCallback;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
-
-import java.net.URISyntaxException;
-import java.util.Optional;
+import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Back gesture interactive tutorial. */
-public class BackGestureTutorialFragment extends Fragment implements BackGestureAttemptCallback {
-
- private static final String LOG_TAG = "TutorialFragment";
- private static final String KEY_TUTORIAL_STEP = "tutorialStep";
- private static final String KEY_TUTORIAL_TYPE = "tutorialType";
- private static final String SYSTEM_NAVIGATION_SETTING_INTENT =
- "#Intent;action=com.android.settings.SEARCH_RESULT_TRAMPOLINE;S"
- + ".:settings:fragment_args_key=gesture_system_navigation_input_summary;S"
- + ".:settings:show_fragment=com.android.settings.gestures"
- + ".SystemNavigationGestureSettings;end";
-
- private TutorialStep mTutorialStep;
- private TutorialType mTutorialType;
- private Optional<BackGestureTutorialController> mTutorialController = Optional.empty();
- private View mRootView;
- private BackGestureTutorialHandAnimation mHandCoachingAnimation;
- private EdgeBackGestureHandler mEdgeBackGestureHandler;
-
- public static BackGestureTutorialFragment newInstance(
- TutorialStep tutorialStep, TutorialType tutorialType) {
- BackGestureTutorialFragment fragment = new BackGestureTutorialFragment();
- Bundle args = new Bundle();
- args.putSerializable(KEY_TUTORIAL_STEP, tutorialStep);
- args.putSerializable(KEY_TUTORIAL_TYPE, tutorialType);
- fragment.setArguments(args);
- return fragment;
- }
+public class BackGestureTutorialFragment extends TutorialFragment
+ implements BackGestureAttemptCallback {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
- mTutorialStep = (TutorialStep) args.getSerializable(KEY_TUTORIAL_STEP);
- mTutorialType = (TutorialType) args.getSerializable(KEY_TUTORIAL_TYPE);
- mEdgeBackGestureHandler = new EdgeBackGestureHandler(getContext());
mEdgeBackGestureHandler.registerBackGestureAttemptCallback(this);
}
@Override
- public View onCreateView(
- @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- super.onCreateView(inflater, container, savedInstanceState);
-
- mRootView = inflater.inflate(R.layout.back_gesture_tutorial_fragment,
- container, /* attachToRoot= */ false);
- mRootView.findViewById(R.id.back_gesture_tutorial_fragment_close_button)
- .setOnClickListener(this::onCloseButtonClicked);
- mRootView.setOnApplyWindowInsetsListener((view, insets) -> {
- Insets systemInsets = insets.getInsets(WindowInsets.Type.systemBars());
- mEdgeBackGestureHandler.setInsets(systemInsets.left, systemInsets.right);
- return insets;
- });
- mRootView.setOnTouchListener(mEdgeBackGestureHandler);
- mHandCoachingAnimation = new BackGestureTutorialHandAnimation(getContext(), mRootView);
-
- return mRootView;
+ public void onDestroy() {
+ super.onDestroy();
+ mEdgeBackGestureHandler.unregisterBackGestureAttemptCallback();
}
@Override
- public void onResume() {
- super.onResume();
- changeController(mTutorialStep, mTutorialType);
+ int getHandAnimationResId() {
+ return R.drawable.back_gesture;
}
@Override
- public void onPause() {
- super.onPause();
- mHandCoachingAnimation.stop();
- }
-
- void onAttachedToWindow() {
- mEdgeBackGestureHandler.setViewGroupParent((ViewGroup) getRootView());
- }
-
- void onDetachedFromWindow() {
- mEdgeBackGestureHandler.setViewGroupParent(null);
- }
-
- @Override
- public void onSaveInstanceState(Bundle savedInstanceState) {
- savedInstanceState.putSerializable(KEY_TUTORIAL_STEP, mTutorialStep);
- savedInstanceState.putSerializable(KEY_TUTORIAL_TYPE, mTutorialType);
- super.onSaveInstanceState(savedInstanceState);
- }
-
- View getRootView() {
- return mRootView;
- }
-
- BackGestureTutorialHandAnimation getHandAnimation() {
- return mHandCoachingAnimation;
- }
-
- void changeController(TutorialStep tutorialStep) {
- changeController(tutorialStep, mTutorialType);
- }
-
- void changeController(TutorialStep tutorialStep, TutorialType tutorialType) {
- Optional<BackGestureTutorialController> tutorialController =
- BackGestureTutorialController.getTutorialController(/* fragment= */ this,
- tutorialStep, tutorialType);
- if (!tutorialController.isPresent()) {
- return;
- }
-
- mTutorialController = tutorialController;
- mTutorialController.get().transitToController();
- this.mTutorialStep = mTutorialController.get().mTutorialStep;
- this.mTutorialType = tutorialType;
+ TutorialController createController(TutorialType type) {
+ return new BackGestureTutorialController(this, type);
}
@Override
public void onBackGestureAttempted(BackGestureResult result) {
- mTutorialController.ifPresent(controller -> controller.onGestureAttempted(result));
- }
-
- void closeTutorial() {
- getActivity().finish();
- }
-
- void startSystemNavigationSetting() {
- try {
- startActivityForResult(
- Intent.parseUri(SYSTEM_NAVIGATION_SETTING_INTENT, /* flags= */ 0),
- /* requestCode= */ 0);
- } catch (URISyntaxException e) {
- Log.e(LOG_TAG, "The launch Intent Uri is wrong syntax: " + e);
- } catch (ActivityNotFoundException e) {
- Log.e(LOG_TAG, "The launch Activity not found: " + e);
+ if (mTutorialController != null) {
+ mTutorialController.onBackGestureAttempted(result);
}
}
-
- private void onCloseButtonClicked(View button) {
- closeTutorial();
- }
-
- /** Denotes the step of the tutorial. */
- enum TutorialStep {
- ENGAGED,
- CONFIRM,
- }
-
- /** Denotes the type of the tutorial. */
- enum TutorialType {
- RIGHT_EDGE_BACK_NAVIGATION,
- LEFT_EDGE_BACK_NAVIGATION,
- }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialTypeInfo.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialTypeInfo.java
deleted file mode 100644
index ac8443d..0000000
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialTypeInfo.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2020 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.quickstep.interaction;
-
-import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialType;
-
-/** Defines the UI element identifiers for the particular {@link TutorialType}. */
-final class BackGestureTutorialTypeInfo {
-
- private final TutorialType mTutorialType;
- private final int mTutorialPlaygroundTitleId;
- private final int mTutorialEngagedSubtitleId;
- private final int mTutorialConfirmTitleId;
- private final int mTutorialConfirmSubtitleId;
-
- TutorialType getTutorialType() {
- return mTutorialType;
- }
-
- int getTutorialPlaygroundTitleId() {
- return mTutorialPlaygroundTitleId;
- }
-
- int getTutorialEngagedSubtitleId() {
- return mTutorialEngagedSubtitleId;
- }
-
- int getTutorialConfirmTitleId() {
- return mTutorialConfirmTitleId;
- }
-
- int getTutorialConfirmSubtitleId() {
- return mTutorialConfirmSubtitleId;
- }
-
- static Builder builder() {
- return new Builder();
- }
-
- private BackGestureTutorialTypeInfo(
- TutorialType tutorialType,
- int tutorialPlaygroundTitleId,
- int tutorialEngagedSubtitleId,
- int tutorialConfirmTitleId,
- int tutorialConfirmSubtitleId) {
- mTutorialType = tutorialType;
- mTutorialPlaygroundTitleId = tutorialPlaygroundTitleId;
- mTutorialEngagedSubtitleId = tutorialEngagedSubtitleId;
- mTutorialConfirmTitleId = tutorialConfirmTitleId;
- mTutorialConfirmSubtitleId = tutorialConfirmSubtitleId;
- }
-
- /** Builder for producing {@link BackGestureTutorialTypeInfo} objects. */
- static class Builder {
-
- private TutorialType mTutorialType;
- private Integer mTutorialPlaygroundTitleId;
- private Integer mTutorialEngagedSubtitleId;
- private Integer mTutorialConfirmTitleId;
- private Integer mTutorialConfirmSubtitleId;
-
- Builder setTutorialType(TutorialType tutorialType) {
- mTutorialType = tutorialType;
- return this;
- }
-
- Builder setTutorialPlaygroundTitleId(int stringId) {
- mTutorialPlaygroundTitleId = stringId;
- return this;
- }
-
- Builder setTutorialEngagedSubtitleId(int stringId) {
- mTutorialEngagedSubtitleId = stringId;
- return this;
- }
-
- Builder setTutorialConfirmTitleId(int stringId) {
- mTutorialConfirmTitleId = stringId;
- return this;
- }
-
- Builder setTutorialConfirmSubtitleId(int stringId) {
- mTutorialConfirmSubtitleId = stringId;
- return this;
- }
-
- BackGestureTutorialTypeInfo build() {
- return new BackGestureTutorialTypeInfo(
- mTutorialType,
- mTutorialPlaygroundTitleId,
- mTutorialEngagedSubtitleId,
- mTutorialConfirmTitleId,
- mTutorialConfirmSubtitleId);
- }
- }
-}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialTypeInfoProvider.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialTypeInfoProvider.java
deleted file mode 100644
index 9575d83..0000000
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialTypeInfoProvider.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2020 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.quickstep.interaction;
-
-import com.android.launcher3.R;
-import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialType;
-
-/** Provides instances of {@link BackGestureTutorialTypeInfo} for each {@link TutorialType}. */
-final class BackGestureTutorialTypeInfoProvider {
-
- private static final BackGestureTutorialTypeInfo RIGHT_EDGE_BACK_NAV_TUTORIAL_INFO =
- BackGestureTutorialTypeInfo.builder()
- .setTutorialType(TutorialType.RIGHT_EDGE_BACK_NAVIGATION)
- .setTutorialPlaygroundTitleId(
- R.string.back_gesture_tutorial_playground_title_swipe_inward_right_edge)
- .setTutorialEngagedSubtitleId(
- R.string.back_gesture_tutorial_engaged_subtitle_swipe_inward_right_edge)
- .setTutorialConfirmTitleId(R.string.back_gesture_tutorial_confirm_title)
- .setTutorialConfirmSubtitleId(R.string.back_gesture_tutorial_confirm_subtitle)
- .build();
-
- private static final BackGestureTutorialTypeInfo LEFT_EDGE_BACK_NAV_TUTORIAL_INFO =
- BackGestureTutorialTypeInfo.builder()
- .setTutorialType(TutorialType.LEFT_EDGE_BACK_NAVIGATION)
- .setTutorialPlaygroundTitleId(
- R.string.back_gesture_tutorial_playground_title_swipe_inward_left_edge)
- .setTutorialEngagedSubtitleId(
- R.string.back_gesture_tutorial_engaged_subtitle_swipe_inward_left_edge)
- .setTutorialConfirmTitleId(R.string.back_gesture_tutorial_confirm_title)
- .setTutorialConfirmSubtitleId(R.string.back_gesture_tutorial_confirm_subtitle)
- .build();
-
- static BackGestureTutorialTypeInfo getTutorialTypeInfo(TutorialType tutorialType) {
- switch (tutorialType) {
- case RIGHT_EDGE_BACK_NAVIGATION:
- return RIGHT_EDGE_BACK_NAV_TUTORIAL_INFO;
- case LEFT_EDGE_BACK_NAVIGATION:
- return LEFT_EDGE_BACK_NAV_TUTORIAL_INFO;
- default:
- throw new AssertionError("Unexpected tutorial type: " + tutorialType);
- }
- }
-
- private BackGestureTutorialTypeInfoProvider() {
- }
-}
diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
index f34530e..89c57a0 100644
--- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
@@ -20,7 +20,6 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.os.SystemProperties;
-import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
@@ -46,7 +45,6 @@
private final Context mContext;
private final Point mDisplaySize = new Point();
- private final int mDisplayId;
// The edge width where touch down is allowed
private int mEdgeWidth;
@@ -91,8 +89,6 @@
EdgeBackGestureHandler(Context context) {
final Resources res = context.getResources();
mContext = context;
- mDisplayId = context.getDisplay() == null
- ? Display.DEFAULT_DISPLAY : context.getDisplay().getDisplayId();
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT,
@@ -126,6 +122,10 @@
mGestureCallback = callback;
}
+ void unregisterBackGestureAttemptCallback() {
+ mGestureCallback = null;
+ }
+
private LayoutParams createLayoutParams() {
Resources resources = mContext.getResources();
return new LayoutParams(
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 4815366..414ddfa 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -19,6 +19,7 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.Window;
@@ -26,26 +27,32 @@
import androidx.fragment.app.FragmentActivity;
import com.android.launcher3.R;
-import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialStep;
-import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialType;
+import com.android.quickstep.interaction.TutorialController.TutorialType;
import java.util.List;
/** Shows the gesture interactive sandbox in full screen mode. */
public class GestureSandboxActivity extends FragmentActivity {
- private BackGestureTutorialFragment mFragment;
+ private static final String LOG_TAG = "GestureSandboxActivity";
+
+ private TutorialFragment mFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.back_gesture_tutorial_activity);
+ setContentView(R.layout.gesture_tutorial_activity);
- mFragment = BackGestureTutorialFragment.newInstance(
- TutorialStep.ENGAGED, TutorialType.RIGHT_EDGE_BACK_NAVIGATION);
+ try {
+ mFragment = TutorialFragment.newInstance(BackGestureTutorialFragment.class,
+ TutorialType.RIGHT_EDGE_BACK_NAVIGATION);
+ } catch (InstantiationException | IllegalAccessException e) {
+ Log.wtf(LOG_TAG, "Failed to create tutorial fragment!", e);
+ mFragment = new BackGestureTutorialFragment();
+ }
getSupportFragmentManager().beginTransaction()
- .add(R.id.back_gesture_tutorial_fragment_container, mFragment)
+ .add(R.id.gesture_tutorial_fragment_container, mFragment)
.commit();
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
new file mode 100644
index 0000000..cd4d0d8
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 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.quickstep.interaction;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.CallSuper;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
+
+abstract class TutorialController {
+
+ final TutorialFragment mTutorialFragment;
+ final TutorialType mTutorialType;
+
+ final ImageButton mCloseButton;
+ final TextView mTitleTextView;
+ final TextView mSubtitleTextView;
+ final TutorialHandAnimation mHandCoachingAnimation;
+ final ImageView mHandCoachingView;
+ final Button mActionTextButton;
+ final Button mActionButton;
+
+ TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
+ mTutorialFragment = tutorialFragment;
+ mTutorialType = tutorialType;
+
+ View rootView = tutorialFragment.getRootView();
+ mCloseButton = rootView.findViewById(R.id.gesture_tutorial_fragment_close_button);
+ mCloseButton.setOnClickListener(button -> mTutorialFragment.closeTutorial());
+ mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view);
+ mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view);
+ mHandCoachingAnimation = tutorialFragment.getHandAnimation();
+ mHandCoachingView = rootView.findViewById(R.id.gesture_tutorial_fragment_hand_coaching);
+ mHandCoachingView.bringToFront();
+ mActionTextButton =
+ rootView.findViewById(R.id.gesture_tutorial_fragment_action_text_button);
+ mActionButton = rootView.findViewById(R.id.gesture_tutorial_fragment_action_button);
+ }
+
+ abstract void onBackGestureAttempted(BackGestureResult result);
+
+ @Nullable
+ Integer getTitleStringId() {
+ return null;
+ }
+
+ @Nullable
+ Integer getSubtitleStringId() {
+ return null;
+ }
+
+ @Nullable
+ Integer getActionButtonStringId() {
+ return null;
+ }
+
+ @Nullable
+ Integer getActionTextButtonStringId() {
+ return null;
+ }
+
+ void onActionButtonClicked(View button) {}
+
+ void hideHandCoachingAnimation() {
+ mHandCoachingAnimation.stop();
+ }
+
+ @CallSuper
+ void transitToController() {
+ updateTitles();
+ updateActionButtons();
+ }
+
+ private void updateTitles() {
+ updateTitleView(mTitleTextView, getTitleStringId(),
+ R.style.TextAppearance_BackGestureTutorial_Title);
+ updateTitleView(mSubtitleTextView, getSubtitleStringId(),
+ R.style.TextAppearance_BackGestureTutorial_Subtitle);
+ }
+
+ private void updateTitleView(TextView textView, @Nullable Integer stringId, int styleId) {
+ if (stringId == null) {
+ textView.setVisibility(View.GONE);
+ return;
+ }
+
+ textView.setVisibility(View.VISIBLE);
+ textView.setText(stringId);
+ textView.setTextAppearance(styleId);
+ }
+
+ private void updateActionButtons() {
+ updateButton(mActionButton, getActionButtonStringId(), this::onActionButtonClicked);
+ updateButton(mActionTextButton, getActionTextButtonStringId(), this::onActionButtonClicked);
+ }
+
+ private void updateButton(Button button, @Nullable Integer stringId, OnClickListener listener) {
+ if (stringId == null) {
+ button.setVisibility(View.INVISIBLE);
+ return;
+ }
+
+ button.setVisibility(View.VISIBLE);
+ button.setText(stringId);
+ button.setOnClickListener(listener);
+ }
+
+ /** Denotes the type of the tutorial. */
+ enum TutorialType {
+ RIGHT_EDGE_BACK_NAVIGATION,
+ LEFT_EDGE_BACK_NAVIGATION,
+ BACK_NAVIGATION_COMPLETE,
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
new file mode 100644
index 0000000..09ea8d6
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2020 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.quickstep.interaction;
+
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.graphics.Insets;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.TutorialController.TutorialType;
+
+import java.net.URISyntaxException;
+
+abstract class TutorialFragment extends Fragment {
+
+ private static final String LOG_TAG = "TutorialFragment";
+ private static final String SYSTEM_NAVIGATION_SETTING_INTENT =
+ "#Intent;action=com.android.settings.SEARCH_RESULT_TRAMPOLINE;S"
+ + ".:settings:fragment_args_key=gesture_system_navigation_input_summary;S"
+ + ".:settings:show_fragment=com.android.settings.gestures"
+ + ".SystemNavigationGestureSettings;end";
+ private static final String KEY_TUTORIAL_TYPE = "tutorialType";
+
+ TutorialType mTutorialType;
+ @Nullable TutorialController mTutorialController = null;
+ View mRootView;
+ TutorialHandAnimation mHandCoachingAnimation;
+ EdgeBackGestureHandler mEdgeBackGestureHandler;
+
+ public static TutorialFragment newInstance(
+ Class<? extends TutorialFragment> fragmentClass, TutorialType tutorialType)
+ throws java.lang.InstantiationException, IllegalAccessException {
+ TutorialFragment fragment = fragmentClass.newInstance();
+ Bundle args = new Bundle();
+ args.putSerializable(KEY_TUTORIAL_TYPE, tutorialType);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ abstract int getHandAnimationResId();
+
+ abstract TutorialController createController(TutorialType type);
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
+ mTutorialType = (TutorialType) args.getSerializable(KEY_TUTORIAL_TYPE);
+ mEdgeBackGestureHandler = new EdgeBackGestureHandler(getContext());
+ }
+
+ @Override
+ public View onCreateView(
+ @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+
+ mRootView = inflater.inflate(R.layout.gesture_tutorial_fragment,
+ container, /* attachToRoot= */ false);
+ mRootView.setOnApplyWindowInsetsListener((view, insets) -> {
+ Insets systemInsets = insets.getInsets(WindowInsets.Type.systemBars());
+ mEdgeBackGestureHandler.setInsets(systemInsets.left, systemInsets.right);
+ return insets;
+ });
+ mRootView.setOnTouchListener(mEdgeBackGestureHandler);
+ mHandCoachingAnimation = new TutorialHandAnimation(getContext(), mRootView,
+ getHandAnimationResId());
+ return mRootView;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ changeController(mTutorialType);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mHandCoachingAnimation.stop();
+ }
+
+ void onAttachedToWindow() {
+ mEdgeBackGestureHandler.setViewGroupParent((ViewGroup) getRootView());
+ }
+
+ void onDetachedFromWindow() {
+ mEdgeBackGestureHandler.setViewGroupParent(null);
+ }
+
+ void changeController(TutorialType tutorialType) {
+ mTutorialController = createController(tutorialType);
+ mTutorialController.transitToController();
+ mTutorialType = tutorialType;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ savedInstanceState.putSerializable(KEY_TUTORIAL_TYPE, mTutorialType);
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ View getRootView() {
+ return mRootView;
+ }
+
+ TutorialHandAnimation getHandAnimation() {
+ return mHandCoachingAnimation;
+ }
+
+ void closeTutorial() {
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ activity.finish();
+ }
+ }
+
+ void startSystemNavigationSetting() {
+ try {
+ startActivityForResult(
+ Intent.parseUri(SYSTEM_NAVIGATION_SETTING_INTENT, /* flags= */ 0),
+ /* requestCode= */ 0);
+ } catch (URISyntaxException e) {
+ Log.e(LOG_TAG, "The launch Intent Uri is wrong syntax: " + e);
+ } catch (ActivityNotFoundException e) {
+ Log.e(LOG_TAG, "The launch Activity not found: " + e);
+ }
+ }
+
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialHandAnimation.java b/quickstep/src/com/android/quickstep/interaction/TutorialHandAnimation.java
similarity index 85%
rename from quickstep/src/com/android/quickstep/interaction/BackGestureTutorialHandAnimation.java
rename to quickstep/src/com/android/quickstep/interaction/TutorialHandAnimation.java
index d7c10b0..5362aaf 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialHandAnimation.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialHandAnimation.java
@@ -25,12 +25,12 @@
import androidx.core.content.ContextCompat;
import com.android.launcher3.R;
-import com.android.quickstep.interaction.BackGestureTutorialFragment.TutorialType;
+import com.android.quickstep.interaction.TutorialController.TutorialType;
import java.time.Duration;
/** Hand coaching animation. */
-final class BackGestureTutorialHandAnimation {
+final class TutorialHandAnimation {
// A delay for waiting the Activity fully launches.
private static final Duration ANIMATION_START_DELAY = Duration.ofMillis(300L);
@@ -38,16 +38,12 @@
private final ImageView mHandCoachingView;
private final AnimatedVectorDrawable mGestureAnimation;
- BackGestureTutorialHandAnimation(Context context, View rootView) {
- mHandCoachingView = rootView.findViewById(
- R.id.back_gesture_tutorial_fragment_hand_coaching);
- mGestureAnimation = (AnimatedVectorDrawable) ContextCompat.getDrawable(context,
- R.drawable.back_gesture);
+ TutorialHandAnimation(Context context, View rootView, int resId) {
+ mHandCoachingView = rootView.findViewById(R.id.gesture_tutorial_fragment_hand_coaching);
+ mGestureAnimation = (AnimatedVectorDrawable) ContextCompat.getDrawable(context, resId);
}
- /**
- * [Re]starts animation for the given tutorial.
- */
+ /** [Re]starts animation for the given tutorial. */
void startLoopedAnimation(TutorialType tutorialType) {
if (mGestureAnimation.isRunning()) {
stop();
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 194ef2c..adcff9a 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -38,11 +38,11 @@
<color name="all_apps_bg_hand_fill">#E5E5E5</color>
<color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
- <color name="back_gesture_tutorial_background_color">#FFFFFFFF</color>
- <color name="back_gesture_tutorial_subtitle_color">#99000000</color> <!-- 60% black -->
- <color name="back_gesture_tutorial_title_color">#FF000000</color>
- <color name="back_gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
- <color name="back_gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
+ <color name="gesture_tutorial_background_color">#FFFFFFFF</color>
+ <color name="gesture_tutorial_subtitle_color">#99000000</color> <!-- 60% black -->
+ <color name="gesture_tutorial_title_color">#FF000000</color>
+ <color name="gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
+ <color name="gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
</resources>