Merge "Add event tracking to the gesture navigation tutorial." into tm-dev
diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
index b797f0c..b3f2354 100644
--- a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
@@ -15,13 +15,21 @@
*/
package com.android.quickstep.interaction;
+import android.content.SharedPreferences;
import android.view.MotionEvent;
import android.view.View;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Home gesture interactive tutorial. */
public class AssistantGestureTutorialFragment extends TutorialFragment {
+
+ protected AssistantGestureTutorialFragment(
+ SharedPreferences sharedPrefs, StatsLogManager statsLogManager) {
+ super(sharedPrefs, statsLogManager);
+ }
+
@Override
TutorialController createController(TutorialType type) {
return new AssistantGestureTutorialController(this, type);
@@ -39,4 +47,14 @@
}
return super.onTouch(view, motionEvent);
}
+
+ @Override
+ void logTutorialStepShown() {
+ // No-Op: tutorial step not currently shown to users
+ }
+
+ @Override
+ void logTutorialStepCompleted() {
+ // No-Op: tutorial step not currently shown to users
+ }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
index f54734d..e7ed0b4 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
@@ -19,12 +19,14 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.content.SharedPreferences;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.interaction.TutorialController.TutorialType;
import java.util.ArrayList;
@@ -32,6 +34,11 @@
/** Shows the Back gesture interactive tutorial. */
public class BackGestureTutorialFragment extends TutorialFragment {
+ protected BackGestureTutorialFragment(
+ SharedPreferences sharedPrefs, StatsLogManager statsLogManager) {
+ super(sharedPrefs, statsLogManager);
+ }
+
@Nullable
@Override
Integer getEdgeAnimationResId() {
@@ -117,4 +124,16 @@
}
return super.onTouch(view, motionEvent);
}
+
+ @Override
+ void logTutorialStepShown() {
+ mStatsLogManager.logger().log(
+ StatsLogManager.LauncherEvent.LAUNCHER_GESTURE_TUTORIAL_BACK_STEP_SHOWN);
+ }
+
+ @Override
+ void logTutorialStepCompleted() {
+ mStatsLogManager.logger().log(
+ StatsLogManager.LauncherEvent.LAUNCHER_GESTURE_TUTORIAL_BACK_STEP_COMPLETED);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index c2524b1..002e8b7 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.interaction;
+import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
@@ -28,6 +29,8 @@
import androidx.fragment.app.FragmentActivity;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.interaction.TutorialController.TutorialType;
import java.util.List;
@@ -46,17 +49,26 @@
private int mCurrentStep;
private int mNumSteps;
+ private SharedPreferences mSharedPrefs;
+ private StatsLogManager mStatsLogManager;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.gesture_tutorial_activity);
+ mSharedPrefs = Utilities.getPrefs(this);
+ mStatsLogManager = StatsLogManager.newInstance(getApplicationContext());
+
Bundle args = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState;
mTutorialSteps = getTutorialSteps(args);
mCurrentTutorialStep = mTutorialSteps[mCurrentStep - 1];
mFragment = TutorialFragment.newInstance(
- mCurrentTutorialStep, args.getBoolean(KEY_GESTURE_COMPLETE, false));
+ mCurrentTutorialStep,
+ args.getBoolean(KEY_GESTURE_COMPLETE, false),
+ mSharedPrefs,
+ mStatsLogManager);
getSupportFragmentManager().beginTransaction()
.add(R.id.gesture_tutorial_fragment_container, mFragment)
.commit();
@@ -105,13 +117,6 @@
}
/**
- * Closes the tutorial and this activity.
- */
- public void closeTutorial() {
- mFragment.closeTutorial();
- }
-
- /**
* Replaces the current TutorialFragment, continuing to the next tutorial step if there is one.
*
* If there is no following step, the tutorial is closed.
@@ -122,7 +127,8 @@
return;
}
mCurrentTutorialStep = mTutorialSteps[mCurrentStep];
- mFragment = TutorialFragment.newInstance(mCurrentTutorialStep, false);
+ mFragment = TutorialFragment.newInstance(
+ mCurrentTutorialStep, /* gestureComplete= */ false, mSharedPrefs, mStatsLogManager);
getSupportFragmentManager().beginTransaction()
.replace(R.id.gesture_tutorial_fragment_container, mFragment)
.runOnCommit(() -> mFragment.onAttachedToWindow())
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
index 423e66f..e987d5a 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
@@ -18,12 +18,14 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.content.SharedPreferences;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.interaction.TutorialController.TutorialType;
import java.util.ArrayList;
@@ -31,6 +33,11 @@
/** Shows the Home gesture interactive tutorial. */
public class HomeGestureTutorialFragment extends TutorialFragment {
+ protected HomeGestureTutorialFragment(
+ SharedPreferences sharedPrefs, StatsLogManager statsLogManager) {
+ super(sharedPrefs, statsLogManager);
+ }
+
@Nullable
@Override
Integer getEdgeAnimationResId() {
@@ -99,4 +106,16 @@
releaseFeedbackAnimation();
return super.onTouch(view, motionEvent);
}
+
+ @Override
+ void logTutorialStepShown() {
+ mStatsLogManager.logger().log(
+ StatsLogManager.LauncherEvent.LAUNCHER_GESTURE_TUTORIAL_HOME_STEP_SHOWN);
+ }
+
+ @Override
+ void logTutorialStepCompleted() {
+ mStatsLogManager.logger().log(
+ StatsLogManager.LauncherEvent.LAUNCHER_GESTURE_TUTORIAL_HOME_STEP_COMPLETED);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
index f63a945..c7e24db 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
@@ -18,12 +18,14 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.content.SharedPreferences;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.interaction.TutorialController.TutorialType;
import java.util.ArrayList;
@@ -31,6 +33,11 @@
/** Shows the Overview gesture interactive tutorial. */
public class OverviewGestureTutorialFragment extends TutorialFragment {
+ protected OverviewGestureTutorialFragment(
+ SharedPreferences sharedPrefs, StatsLogManager statsLogManager) {
+ super(sharedPrefs, statsLogManager);
+ }
+
@Nullable
@Override
Integer getEdgeAnimationResId() {
@@ -111,4 +118,16 @@
releaseFeedbackAnimation();
return super.onTouch(view, motionEvent);
}
+
+ @Override
+ void logTutorialStepShown() {
+ mStatsLogManager.logger().log(
+ StatsLogManager.LauncherEvent.LAUNCHER_GESTURE_TUTORIAL_OVERVIEW_STEP_SHOWN);
+ }
+
+ @Override
+ void logTutorialStepCompleted() {
+ mStatsLogManager.logger().log(
+ StatsLogManager.LauncherEvent.LAUNCHER_GESTURE_TUTORIAL_OVERVIEW_STEP_COMPLETED);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java
index 955a2f7..92a2731 100644
--- a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java
@@ -15,14 +15,21 @@
*/
package com.android.quickstep.interaction;
+import android.content.SharedPreferences;
import android.view.MotionEvent;
import android.view.View;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the general navigation gesture sandbox environment. */
public class SandboxModeTutorialFragment extends TutorialFragment {
+ protected SandboxModeTutorialFragment(
+ SharedPreferences sharedPrefs, StatsLogManager statsLogManager) {
+ super(sharedPrefs, statsLogManager);
+ }
+
@Override
TutorialController createController(TutorialType type) {
return new SandboxModeTutorialController(this, type);
@@ -40,4 +47,14 @@
}
return super.onTouch(view, motionEvent);
}
+
+ @Override
+ void logTutorialStepShown() {
+ // No-Op: tutorial step not currently shown to users
+ }
+
+ @Override
+ void logTutorialStepCompleted() {
+ // No-Op: tutorial step not currently shown to users
+ }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 3c88988..6a8894e 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -81,7 +81,8 @@
TutorialType mTutorialType;
final Context mContext;
- final TextView mCloseButton;
+ final TextView mSkipButton;
+ final Button mDoneButton;
final ViewGroup mFeedbackView;
final TextView mFeedbackTitleView;
final ImageView mEdgeGestureVideoView;
@@ -94,7 +95,6 @@
final AnimatedTaskView mFakePreviousTaskView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
- final Button mActionButton;
final TutorialStepIndicator mTutorialStepView;
final ImageView mFingerDotView;
private final AlertDialog mSkipTutorialDialog;
@@ -115,8 +115,8 @@
mContext = mTutorialFragment.getContext();
RootSandboxLayout rootView = tutorialFragment.getRootView();
- mCloseButton = rootView.findViewById(R.id.gesture_tutorial_fragment_close_button);
- mCloseButton.setOnClickListener(button -> showSkipTutorialDialog());
+ mSkipButton = rootView.findViewById(R.id.gesture_tutorial_fragment_close_button);
+ mSkipButton.setOnClickListener(button -> showSkipTutorialDialog());
mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
mFeedbackTitleView = mFeedbackView.findViewById(
R.id.gesture_tutorial_fragment_feedback_title);
@@ -130,7 +130,7 @@
rootView.findViewById(R.id.gesture_tutorial_fake_previous_task_view);
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
mRippleDrawable = (RippleDrawable) mRippleView.getBackground();
- mActionButton = rootView.findViewById(R.id.gesture_tutorial_fragment_action_button);
+ mDoneButton = rootView.findViewById(R.id.gesture_tutorial_fragment_action_button);
mTutorialStepView =
rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_tutorial_step);
mFingerDotView = rootView.findViewById(R.id.gesture_tutorial_finger_dot);
@@ -431,22 +431,22 @@
}
void updateCloseButton() {
- mCloseButton.setTextAppearance(Utilities.isDarkTheme(mContext)
+ mSkipButton.setTextAppearance(Utilities.isDarkTheme(mContext)
? R.style.TextAppearance_GestureTutorial_Feedback_Subtext
: R.style.TextAppearance_GestureTutorial_Feedback_Subtext_Dark);
}
void hideActionButton() {
- mCloseButton.setVisibility(View.VISIBLE);
+ mSkipButton.setVisibility(View.VISIBLE);
// Invisible to maintain the layout.
- mActionButton.setVisibility(View.INVISIBLE);
- mActionButton.setOnClickListener(null);
+ mDoneButton.setVisibility(View.INVISIBLE);
+ mDoneButton.setOnClickListener(null);
}
void showActionButton() {
- mCloseButton.setVisibility(GONE);
- mActionButton.setVisibility(View.VISIBLE);
- mActionButton.setOnClickListener(this::onActionButtonClicked);
+ mSkipButton.setVisibility(GONE);
+ mDoneButton.setVisibility(View.VISIBLE);
+ mDoneButton.setOnClickListener(this::onActionButtonClicked);
}
void hideFakeTaskbar(boolean animateToHotseat) {
@@ -609,7 +609,7 @@
R.id.gesture_tutorial_dialog_confirm_button);
if (confirmButton != null) {
confirmButton.setOnClickListener(v -> {
- sandboxActivity.closeTutorial();
+ mTutorialFragment.closeTutorial(true);
tutorialDialog.dismiss();
});
} else {
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 4b836e3..d79b946 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -20,11 +20,13 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.graphics.Insets;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.util.ArraySet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -43,14 +45,24 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.interaction.TutorialController.TutorialType;
+import java.util.Set;
+
abstract class TutorialFragment extends Fragment implements OnTouchListener {
private static final String LOG_TAG = "TutorialFragment";
static final String KEY_TUTORIAL_TYPE = "tutorial_type";
static final String KEY_GESTURE_COMPLETE = "gesture_complete";
+ private static final String TUTORIAL_SKIPPED_PREFERENCE_KEY = "pref_gestureTutorialSkipped";
+ private static final String COMPLETED_TUTORIAL_STEPS_PREFERENCE_KEY =
+ "pref_completedTutorialSteps";
+
+ private final SharedPreferences mSharedPrefs;
+ protected final StatsLogManager mStatsLogManager;
+
TutorialType mTutorialType;
boolean mGestureComplete = false;
@Nullable TutorialController mTutorialController = null;
@@ -71,10 +83,15 @@
private boolean mIsLargeScreen;
private boolean mIsFoldable;
- public static TutorialFragment newInstance(TutorialType tutorialType, boolean gestureComplete) {
- TutorialFragment fragment = getFragmentForTutorialType(tutorialType);
+ public static TutorialFragment newInstance(
+ TutorialType tutorialType,
+ boolean gestureComplete,
+ SharedPreferences sharedPrefs,
+ StatsLogManager statsLogManager) {
+ TutorialFragment fragment =
+ getFragmentForTutorialType(tutorialType, sharedPrefs, statsLogManager);
if (fragment == null) {
- fragment = new BackGestureTutorialFragment();
+ fragment = new BackGestureTutorialFragment(sharedPrefs, statsLogManager);
tutorialType = TutorialType.BACK_NAVIGATION;
}
@@ -86,28 +103,36 @@
}
@Nullable
- private static TutorialFragment getFragmentForTutorialType(TutorialType tutorialType) {
+ private static TutorialFragment getFragmentForTutorialType(
+ TutorialType tutorialType,
+ SharedPreferences sharedPrefs,
+ StatsLogManager statsLogManager) {
switch (tutorialType) {
case BACK_NAVIGATION:
case BACK_NAVIGATION_COMPLETE:
- return new BackGestureTutorialFragment();
+ return new BackGestureTutorialFragment(sharedPrefs, statsLogManager);
case HOME_NAVIGATION:
case HOME_NAVIGATION_COMPLETE:
- return new HomeGestureTutorialFragment();
+ return new HomeGestureTutorialFragment(sharedPrefs, statsLogManager);
case OVERVIEW_NAVIGATION:
case OVERVIEW_NAVIGATION_COMPLETE:
- return new OverviewGestureTutorialFragment();
+ return new OverviewGestureTutorialFragment(sharedPrefs, statsLogManager);
case ASSISTANT:
case ASSISTANT_COMPLETE:
- return new AssistantGestureTutorialFragment();
+ return new AssistantGestureTutorialFragment(sharedPrefs, statsLogManager);
case SANDBOX_MODE:
- return new SandboxModeTutorialFragment();
+ return new SandboxModeTutorialFragment(sharedPrefs, statsLogManager);
default:
Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name());
}
return null;
}
+ protected TutorialFragment(SharedPreferences sharedPrefs, StatsLogManager statsLogManager) {
+ mSharedPrefs = sharedPrefs;
+ mStatsLogManager = statsLogManager;
+ }
+
@Nullable Integer getEdgeAnimationResId() {
return null;
}
@@ -315,6 +340,7 @@
}
void onAttachedToWindow() {
+ logTutorialStepShown();
mEdgeBackGestureHandler.setViewGroupParent(getRootView());
}
@@ -348,8 +374,16 @@
}
void continueTutorial() {
- GestureSandboxActivity gestureSandboxActivity = getGestureSandboxActivity();
+ Set<String> updatedCompletedSteps = new ArraySet<>(mSharedPrefs.getStringSet(
+ COMPLETED_TUTORIAL_STEPS_PREFERENCE_KEY, new ArraySet<>()));
+ updatedCompletedSteps.add(mTutorialType.toString());
+
+ mSharedPrefs.edit().putStringSet(
+ COMPLETED_TUTORIAL_STEPS_PREFERENCE_KEY, updatedCompletedSteps).apply();
+ logTutorialStepCompleted();
+
+ GestureSandboxActivity gestureSandboxActivity = getGestureSandboxActivity();
if (gestureSandboxActivity == null) {
closeTutorial();
return;
@@ -358,6 +392,15 @@
}
void closeTutorial() {
+ closeTutorial(false);
+ }
+
+ void closeTutorial(boolean tutorialSkipped) {
+ if (tutorialSkipped) {
+ mSharedPrefs.edit().putBoolean(TUTORIAL_SKIPPED_PREFERENCE_KEY, true).apply();
+ mStatsLogManager.logger().log(
+ StatsLogManager.LauncherEvent.LAUNCHER_GESTURE_TUTORIAL_SKIPPED);
+ }
FragmentActivity activity = getActivity();
if (activity != null) {
activity.setResult(Activity.RESULT_OK);
@@ -390,6 +433,10 @@
|| (mTutorialController != null && mTutorialController.isGestureCompleted());
}
+ abstract void logTutorialStepShown();
+
+ abstract void logTutorialStepCompleted();
+
@Nullable
private GestureSandboxActivity getGestureSandboxActivity() {
Context context = getContext();
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index f392e95..e6dc21e 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -529,6 +529,27 @@
@UiEvent(doc = "User clicks on the search icon on header to launch search in app.")
LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH(913),
+ @UiEvent(doc = "User is shown the back gesture navigation tutorial step.")
+ LAUNCHER_GESTURE_TUTORIAL_BACK_STEP_SHOWN(959),
+
+ @UiEvent(doc = "User is shown the home gesture navigation tutorial step.")
+ LAUNCHER_GESTURE_TUTORIAL_HOME_STEP_SHOWN(960),
+
+ @UiEvent(doc = "User is shown the overview gesture navigation tutorial step.")
+ LAUNCHER_GESTURE_TUTORIAL_OVERVIEW_STEP_SHOWN(961),
+
+ @UiEvent(doc = "User completed the back gesture navigation tutorial step.")
+ LAUNCHER_GESTURE_TUTORIAL_BACK_STEP_COMPLETED(962),
+
+ @UiEvent(doc = "User completed the home gesture navigation tutorial step.")
+ LAUNCHER_GESTURE_TUTORIAL_HOME_STEP_COMPLETED(963),
+
+ @UiEvent(doc = "User completed the overview gesture navigation tutorial step.")
+ LAUNCHER_GESTURE_TUTORIAL_OVERVIEW_STEP_COMPLETED(964),
+
+ @UiEvent(doc = "User skips the gesture navigation tutorial.")
+ LAUNCHER_GESTURE_TUTORIAL_SKIPPED(965),
+
@UiEvent(doc = "User scrolled on one of the all apps surfaces such as A-Z list, search "
+ "result page etc.")
LAUNCHER_ALLAPPS_SCROLLED(985);