Adds ripple effect for successful Back gestures in tutorial.

Emanates from where the gesture was started.

Demo: https://drive.google.com/open?id=1oaXOSUiZP6Hi7J6W4H2NIFVVu0tQfKWm
Bug: 148542211
Change-Id: I38874b8b731864cbfdf963a5e44a59c8c3d30c51
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 6e36722..190290e 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -18,6 +18,12 @@
     android:layout_height="match_parent"
     android:background="@color/gesture_tutorial_background_color">
 
+    <View
+        android:id="@+id/gesture_tutorial_ripple_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/gesture_tutorial_ripple"/>
+
     <ImageView
         android:id="@+id/gesture_tutorial_fragment_hand_coaching"
         android:layout_width="match_parent"
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 91e8f68..fe95e83 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -113,8 +113,10 @@
     private void handleAttemptFromRight(BackGestureResult result) {
         switch (result) {
             case BACK_COMPLETED_FROM_RIGHT:
+                hideFeedback();
                 hideHandCoachingAnimation();
-                mTutorialFragment.changeController(LEFT_EDGE_BACK_NAVIGATION);
+                showRippleEffect(
+                        () -> mTutorialFragment.changeController(LEFT_EDGE_BACK_NAVIGATION));
                 break;
             case BACK_CANCELLED_FROM_RIGHT:
                 showFeedback(R.string.back_gesture_feedback_cancelled_right_edge);
@@ -133,8 +135,10 @@
     private void handleAttemptFromLeft(BackGestureResult result) {
         switch (result) {
             case BACK_COMPLETED_FROM_LEFT:
+                hideFeedback();
                 hideHandCoachingAnimation();
-                mTutorialFragment.changeController(BACK_NAVIGATION_COMPLETE);
+                showRippleEffect(
+                        () -> mTutorialFragment.changeController(BACK_NAVIGATION_COMPLETE));
                 break;
             case BACK_CANCELLED_FROM_LEFT:
                 showFeedback(R.string.back_gesture_feedback_cancelled_left_edge);
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
index 730e3ef..bef50ea 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
@@ -15,6 +15,9 @@
  */
 package com.android.quickstep.interaction;
 
+import android.view.MotionEvent;
+import android.view.View;
+
 import com.android.launcher3.R;
 import com.android.quickstep.interaction.TutorialController.TutorialType;
 
@@ -34,4 +37,12 @@
     Class<? extends TutorialController> getControllerClass() {
         return BackGestureTutorialController.class;
     }
+
+    @Override
+    public boolean onTouch(View view, MotionEvent motionEvent) {
+        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN && mTutorialController != null) {
+            mTutorialController.setRippleHotspot(motionEvent.getX(), motionEvent.getY());
+        }
+        return super.onTouch(view, motionEvent);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 8d68c76..1e29f44 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -15,6 +15,7 @@
  */
 package com.android.quickstep.interaction;
 
+import android.graphics.drawable.RippleDrawable;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
@@ -34,6 +35,7 @@
 
     private static final int FEEDBACK_VISIBLE_MS = 3000;
     private static final int FEEDBACK_ANIMATION_MS = 500;
+    private static final int RIPPLE_VISIBLE_MS = 300;
 
     final TutorialFragment mTutorialFragment;
     TutorialType mTutorialType;
@@ -42,6 +44,8 @@
     final TextView mTitleTextView;
     final TextView mSubtitleTextView;
     final TextView mFeedbackView;
+    final View mRippleView;
+    final RippleDrawable mRippleDrawable;
     final TutorialHandAnimation mHandCoachingAnimation;
     final ImageView mHandCoachingView;
     final Button mActionTextButton;
@@ -58,6 +62,8 @@
         mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view);
         mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view);
         mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
+        mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
+        mRippleDrawable = (RippleDrawable) mRippleView.getBackground();
         mHandCoachingAnimation = tutorialFragment.getHandAnimation();
         mHandCoachingView = rootView.findViewById(R.id.gesture_tutorial_fragment_hand_coaching);
         mHandCoachingView.bringToFront();
@@ -109,6 +115,21 @@
         mFeedbackView.setAlpha(0);
     }
 
+    void setRippleHotspot(float x, float y) {
+        mRippleDrawable.setHotspot(x, y);
+    }
+
+    void showRippleEffect(@Nullable Runnable onCompleteRunnable) {
+        mRippleDrawable.setState(
+                new int[] {android.R.attr.state_pressed, android.R.attr.state_enabled});
+        mRippleView.postDelayed(() -> {
+            mRippleDrawable.setState(new int[] {});
+            if (onCompleteRunnable != null) {
+                onCompleteRunnable.run();
+            }
+        }, RIPPLE_VISIBLE_MS);
+    }
+
     void onActionButtonClicked(View button) {}
 
     void onActionTextButtonClicked(View button) {}
diff --git a/res/drawable/gesture_tutorial_ripple.xml b/res/drawable/gesture_tutorial_ripple.xml
new file mode 100644
index 0000000..ca45662
--- /dev/null
+++ b/res/drawable/gesture_tutorial_ripple.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ripple android:color="@color/gesture_tutorial_ripple_color"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/mask"
+        android:drawable="@color/gesture_tutorial_background_color" />
+</ripple>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index a99c644..c9c893e 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -42,6 +42,7 @@
     <color name="gesture_tutorial_title_color">#FF000000</color>
     <color name="gesture_tutorial_subtitle_color">#99000000</color> <!-- 60% black -->
     <color name="gesture_tutorial_feedback_color">#FF000000</color>
+    <color name="gesture_tutorial_ripple_color">#A0C2F9</color> <!-- Light Blue -->
     <color name="gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
     <color name="gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->