Merge changes I38874b8b,I627ed7c6 into ub-launcher3-rvc-dev am: a29a69943a

Change-Id: I324727deb4c83401e9c1ed13d2c8b0add146ac7e
This commit is contained in:
TreeHugger Robot 2020-04-24 20:15:50 +00:00 committed by Automerger Merge Worker
commit 3176077614
13 changed files with 209 additions and 22 deletions

View File

@ -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"
@ -66,6 +72,17 @@
style="@style/TextAppearance.GestureTutorial.Subtitle"/>
</LinearLayout>
<TextView
android:id="@+id/gesture_tutorial_fragment_feedback_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_centerHorizontal="true"
android:layout_above="@id/gesture_tutorial_fragment_action_button"
android:layout_marginStart="@dimen/gesture_tutorial_feedback_margin_start_end"
android:layout_marginEnd="@dimen/gesture_tutorial_feedback_margin_start_end"
style="@style/TextAppearance.GestureTutorial.Feedback"/>
<!-- android:stateListAnimator="@null" removes shadow and normal on click behavior (increase
of elevation and shadow) which is replaced by ripple effect in android:foreground -->
<Button

View File

@ -83,5 +83,6 @@
<!-- Tips Gesture Tutorial -->
<dimen name="gesture_tutorial_title_margin_start_end">40dp</dimen>
<dimen name="gesture_tutorial_subtitle_margin_start_end">16dp</dimen>
<dimen name="gesture_tutorial_feedback_margin_start_end">24dp</dimen>
<dimen name="gesture_tutorial_button_margin_start_end">18dp</dimen>
</resources>

View File

@ -98,12 +98,22 @@
<string name="back_gesture_tutorial_playground_title_swipe_inward_right_edge" translatable="false">Try the back gesture</string>
<!-- Subtitle shown during interactive parts of Back gesture tutorial for right edge. [CHAR LIMIT=60] -->
<string name="back_gesture_tutorial_engaged_subtitle_swipe_inward_right_edge" translatable="false">Start at the right edge and swipe toward the middle</string>
<!-- Feedback shown during interactive parts of Back gesture tutorial for right edge when the gesture is too far from the edge. [CHAR LIMIT=100] -->
<string name="back_gesture_feedback_swipe_too_far_from_right_edge" translatable="false">Make sure you swipe from the far right edge</string>
<!-- Feedback shown during interactive parts of Back gesture tutorial for right edge when the gesture is cancelled. [CHAR LIMIT=100] -->
<string name="back_gesture_feedback_cancelled_right_edge" translatable="false">Make sure you swipe straight to the left and let go</string>
<!-- Title shown during interactive part of Back gesture tutorial for left edge. [CHAR LIMIT=30] -->
<string name="back_gesture_tutorial_playground_title_swipe_inward_left_edge" translatable="false">Try the other side</string>
<!-- Subtitle shown during interactive parts of Back gesture tutorial for left edge. [CHAR LIMIT=60] -->
<string name="back_gesture_tutorial_engaged_subtitle_swipe_inward_left_edge" translatable="false">That\'s it! Now try swiping from the left edge.</string>
<!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is too far from the edge. [CHAR LIMIT=100] -->
<string name="back_gesture_feedback_swipe_too_far_from_left_edge" translatable="false">Make sure you swipe from the far left edge</string>
<!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is cancelled. [CHAR LIMIT=100] -->
<string name="back_gesture_feedback_cancelled_left_edge" translatable="false">Make sure you swipe straight to the right and let go</string>
<!-- Feedback shown during interactive parts of Back gesture tutorial when the gesture is within the nav bar region. [CHAR LIMIT=100] -->
<string name="back_gesture_feedback_swipe_in_nav_bar" translatable="false">Make sure you don\'t swipe too close to the bottom of the screen</string>
<!-- Subtitle shown on the confirmation screen after successful gesture. [CHAR LIMIT=60] -->
<string name="back_gesture_tutorial_confirm_subtitle" translatable="false">To change the sensitivity of the back gesture, go to Settings</string>
@ -112,6 +122,12 @@
<string name="home_gesture_tutorial_playground_title" translatable="false">Tutorial: Go Home</string>
<!-- Subtitle shown during interactive parts of Home gesture tutorial. [CHAR LIMIT=60] -->
<string name="home_gesture_tutorial_playground_subtitle" translatable="false">Try swiping upward from the bottom edge of the screen</string>
<!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is started too far from the edge. [CHAR LIMIT=100] -->
<string name="home_gesture_feedback_swipe_too_far_from_edge" translatable="false">Make sure you swipe from the bottom edge of the screen</string>
<!-- Feedback shown during interactive parts of Home gesture tutorial when the Overview gesture is detected. [CHAR LIMIT=100] -->
<string name="home_gesture_feedback_overview_detected" translatable="false">Make sure you don\'t pause before letting go</string>
<!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
<string name="home_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up</string>
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>

View File

@ -47,6 +47,14 @@
<item name="android:textSize">21sp</item>
</style>
<style name="TextAppearance.GestureTutorial.Feedback"
parent="TextAppearance.GestureTutorial">
<item name="android:gravity">center</item>
<item name="android:textColor">@color/gesture_tutorial_feedback_color</item>
<item name="android:letterSpacing">0.03</item>
<item name="android:textSize">21sp</item>
</style>
<style name="TextAppearance.GestureTutorial.ButtonLabel"
parent="TextAppearance.GestureTutorial.CallToAction">
<item name="android:gravity">center</item>

View File

@ -35,7 +35,7 @@ final class BackGestureTutorialController extends TutorialController {
void transitToController() {
super.transitToController();
if (mTutorialType != BACK_NAVIGATION_COMPLETE) {
mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
showHandCoachingAnimation();
}
}
@ -96,16 +96,10 @@ final class BackGestureTutorialController extends TutorialController {
public void onBackGestureAttempted(BackGestureResult result) {
switch (mTutorialType) {
case RIGHT_EDGE_BACK_NAVIGATION:
if (result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) {
hideHandCoachingAnimation();
mTutorialFragment.changeController(LEFT_EDGE_BACK_NAVIGATION);
}
handleAttemptFromRight(result);
break;
case LEFT_EDGE_BACK_NAVIGATION:
if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT) {
hideHandCoachingAnimation();
mTutorialFragment.changeController(BACK_NAVIGATION_COMPLETE);
}
handleAttemptFromLeft(result);
break;
case BACK_NAVIGATION_COMPLETE:
if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
@ -116,6 +110,50 @@ final class BackGestureTutorialController extends TutorialController {
}
}
private void handleAttemptFromRight(BackGestureResult result) {
switch (result) {
case BACK_COMPLETED_FROM_RIGHT:
hideFeedback();
hideHandCoachingAnimation();
showRippleEffect(
() -> mTutorialFragment.changeController(LEFT_EDGE_BACK_NAVIGATION));
break;
case BACK_CANCELLED_FROM_RIGHT:
showFeedback(R.string.back_gesture_feedback_cancelled_right_edge);
break;
case BACK_COMPLETED_FROM_LEFT:
case BACK_CANCELLED_FROM_LEFT:
case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
showFeedback(R.string.back_gesture_feedback_swipe_too_far_from_right_edge);
break;
case BACK_NOT_STARTED_IN_NAV_BAR_REGION:
showFeedback(R.string.back_gesture_feedback_swipe_in_nav_bar);
break;
}
}
private void handleAttemptFromLeft(BackGestureResult result) {
switch (result) {
case BACK_COMPLETED_FROM_LEFT:
hideFeedback();
hideHandCoachingAnimation();
showRippleEffect(
() -> mTutorialFragment.changeController(BACK_NAVIGATION_COMPLETE));
break;
case BACK_CANCELLED_FROM_LEFT:
showFeedback(R.string.back_gesture_feedback_cancelled_left_edge);
break;
case BACK_COMPLETED_FROM_RIGHT:
case BACK_CANCELLED_FROM_RIGHT:
case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
showFeedback(R.string.back_gesture_feedback_swipe_too_far_from_left_edge);
break;
case BACK_NOT_STARTED_IN_NAV_BAR_REGION:
showFeedback(R.string.back_gesture_feedback_swipe_in_nav_bar);
break;
}
}
@Override
public void onNavBarGestureAttempted(NavBarGestureResult result) {
if (mTutorialType == BACK_NAVIGATION_COMPLETE) {

View File

@ -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;
@ -29,4 +32,17 @@ public class BackGestureTutorialFragment extends TutorialFragment {
TutorialController createController(TutorialType type) {
return new BackGestureTutorialController(this, type);
}
@Override
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);
}
}

View File

@ -58,6 +58,7 @@ public class EdgeBackGestureHandler implements OnTouchListener {
private final PointF mDownPoint = new PointF();
private boolean mThresholdCrossed = false;
private boolean mAllowGesture = false;
private BackGestureResult mDisallowedGestureReason;
private boolean mIsEnabled;
private int mLeftInset;
private int mRightInset;
@ -145,11 +146,13 @@ public class EdgeBackGestureHandler implements OnTouchListener {
private boolean isWithinTouchRegion(int x, int y) {
// Disallow if too far from the edge
if (x > mEdgeWidth + mLeftInset && x < (mDisplaySize.x - mEdgeWidth - mRightInset)) {
mDisallowedGestureReason = BackGestureResult.BACK_NOT_STARTED_TOO_FAR_FROM_EDGE;
return false;
}
// Disallow if we are in the bottom gesture area
if (y >= (mDisplaySize.y - mBottomGestureHeight)) {
mDisallowedGestureReason = BackGestureResult.BACK_NOT_STARTED_IN_NAV_BAR_REGION;
return false;
}
@ -169,12 +172,12 @@ public class EdgeBackGestureHandler implements OnTouchListener {
int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
boolean isOnLeftEdge = ev.getX() <= mEdgeWidth + mLeftInset;
mDisallowedGestureReason = BackGestureResult.UNKNOWN;
mAllowGesture = isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
mDownPoint.set(ev.getX(), ev.getY());
if (mAllowGesture) {
mEdgeBackPanel.setIsLeftPanel(isOnLeftEdge);
mEdgeBackPanel.onMotionEvent(ev);
mDownPoint.set(ev.getX(), ev.getY());
mThresholdCrossed = false;
}
} else if (mAllowGesture) {
@ -193,7 +196,6 @@ public class EdgeBackGestureHandler implements OnTouchListener {
if (dy > dx && dy > mTouchSlop) {
cancelGesture(ev);
return;
} else if (dx > dy && dx > mTouchSlop) {
mThresholdCrossed = true;
}
@ -206,8 +208,10 @@ public class EdgeBackGestureHandler implements OnTouchListener {
}
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (!mAllowGesture && mGestureCallback != null) {
mGestureCallback.onBackGestureAttempted(BackGestureResult.BACK_NOT_STARTED);
float dx = Math.abs(ev.getX() - mDownPoint.x);
float dy = Math.abs(ev.getY() - mDownPoint.y);
if (dx > dy && dx > mTouchSlop && !mAllowGesture && mGestureCallback != null) {
mGestureCallback.onBackGestureAttempted(mDisallowedGestureReason);
}
}
}
@ -223,7 +227,8 @@ public class EdgeBackGestureHandler implements OnTouchListener {
BACK_COMPLETED_FROM_RIGHT,
BACK_CANCELLED_FROM_LEFT,
BACK_CANCELLED_FROM_RIGHT,
BACK_NOT_STARTED,
BACK_NOT_STARTED_TOO_FAR_FROM_EDGE,
BACK_NOT_STARTED_IN_NAV_BAR_REGION,
}
/** Callback to let the UI react to attempted back gestures. */

View File

@ -34,7 +34,7 @@ final class HomeGestureTutorialController extends TutorialController {
void transitToController() {
super.transitToController();
if (mTutorialType != HOME_NAVIGATION_COMPLETE) {
mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
showHandCoachingAnimation();
}
}
@ -88,9 +88,21 @@ final class HomeGestureTutorialController extends TutorialController {
public void onNavBarGestureAttempted(NavBarGestureResult result) {
switch (mTutorialType) {
case HOME_NAVIGATION:
if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) {
hideHandCoachingAnimation();
mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE);
switch (result) {
case HOME_GESTURE_COMPLETED:
hideHandCoachingAnimation();
mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE);
break;
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
break;
case OVERVIEW_GESTURE_COMPLETED:
showFeedback(R.string.home_gesture_feedback_overview_detected);
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
showFeedback(R.string.home_gesture_feedback_wrong_swipe_direction);
break;
}
break;
case HOME_NAVIGATION_COMPLETE:

View File

@ -29,4 +29,9 @@ public class HomeGestureTutorialFragment extends TutorialFragment {
TutorialController createController(TutorialType type) {
return new HomeGestureTutorialController(this, type);
}
@Override
Class<? extends TutorialController> getControllerClass() {
return HomeGestureTutorialController.class;
}
}

View File

@ -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;
@ -32,16 +33,24 @@ import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureAttem
abstract class TutorialController implements BackGestureAttemptCallback,
NavBarGestureAttemptCallback {
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;
final TutorialType mTutorialType;
TutorialType mTutorialType;
final ImageButton mCloseButton;
final TextView mTitleTextView;
final TextView mSubtitleTextView;
final TextView mFeedbackView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
final TutorialHandAnimation mHandCoachingAnimation;
final ImageView mHandCoachingView;
final Button mActionTextButton;
final Button mActionButton;
private final Runnable mHideFeedbackRunnable;
TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
mTutorialFragment = tutorialFragment;
@ -52,12 +61,23 @@ abstract class TutorialController implements BackGestureAttemptCallback,
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);
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();
mActionTextButton =
rootView.findViewById(R.id.gesture_tutorial_fragment_action_text_button);
mActionButton = rootView.findViewById(R.id.gesture_tutorial_fragment_action_button);
mHideFeedbackRunnable =
() -> mFeedbackView.animate().alpha(0).setDuration(FEEDBACK_ANIMATION_MS)
.withEndAction(this::showHandCoachingAnimation).start();
}
void setTutorialType(TutorialType tutorialType) {
mTutorialType = tutorialType;
}
@Nullable
@ -80,10 +100,44 @@ abstract class TutorialController implements BackGestureAttemptCallback,
return null;
}
void showFeedback(int resId) {
hideHandCoachingAnimation();
mFeedbackView.setText(resId);
mFeedbackView.animate().alpha(1).setDuration(FEEDBACK_ANIMATION_MS).start();
mFeedbackView.removeCallbacks(mHideFeedbackRunnable);
mFeedbackView.postDelayed(mHideFeedbackRunnable, FEEDBACK_VISIBLE_MS);
}
void hideFeedback() {
mFeedbackView.setText(null);
mFeedbackView.removeCallbacks(mHideFeedbackRunnable);
mFeedbackView.clearAnimation();
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) {}
void showHandCoachingAnimation() {
mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
}
void hideHandCoachingAnimation() {
mHandCoachingAnimation.stop();
mHandCoachingView.setVisibility(View.INVISIBLE);
@ -91,6 +145,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
@CallSuper
void transitToController() {
hideFeedback();
updateTitles();
updateActionButtons();
}

View File

@ -86,6 +86,8 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
abstract TutorialController createController(TutorialType type);
abstract Class<? extends TutorialController> getControllerClass();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -147,7 +149,11 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
}
void changeController(TutorialType tutorialType) {
mTutorialController = createController(tutorialType);
if (getControllerClass().isInstance(mTutorialController)) {
mTutorialController.setTutorialType(tutorialType);
} else {
mTutorialController = createController(tutorialType);
}
mTutorialController.transitToController();
mEdgeBackGestureHandler.registerBackGestureAttemptCallback(mTutorialController);
mNavBarGestureHandler.registerNavBarGestureAttemptCallback(mTutorialController);

View File

@ -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>

View File

@ -39,8 +39,10 @@
<color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
<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_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 -->