Sandbox changes for use in UXR prototype.
- "All Set" screen doesn't show after Home/Overview/Back tutorials.
- X button in top left is hidden (we'll want to move this to the
feedback view).
- Feedback pops in and out from the top of the screen.
- Hand animation is replaced by video feedback at start and after
incorrect gesture.
- Back tutorial goes left then right, in order to match video.
- Updated strings and marked translatable (UX-reviewed already).
- Added Chinese translations.
- Many other things.
Test: Manual
Change-Id: I126a3ea0dad645014fab9cdee2ed19e06a8a56e9
diff --git a/quickstep/res/drawable/bg_sandbox_feedback.xml b/quickstep/res/drawable/bg_sandbox_feedback.xml
new file mode 100644
index 0000000..1b3265d
--- /dev/null
+++ b/quickstep/res/drawable/bg_sandbox_feedback.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="394dp"
+ android:height="172dp"
+ android:viewportWidth="394"
+ android:viewportHeight="172">
+ <path
+ android:pathData="M20,0L374,0A20,20 0,0 1,394 20L394,152A20,20 0,0 1,374 172L20,172A20,20 0,0 1,0 152L0,20A20,20 0,0 1,20 0z"
+ android:fillColor="?android:attr/colorBackgroundFloating"
+ android:fillAlpha="0.9"/>
+</vector>
diff --git a/quickstep/res/drawable/default_sandbox_app_task_thumbnail.xml b/quickstep/res/drawable/default_sandbox_app_task_thumbnail.xml
index 9d4cc95..0d85c9a 100644
--- a/quickstep/res/drawable/default_sandbox_app_task_thumbnail.xml
+++ b/quickstep/res/drawable/default_sandbox_app_task_thumbnail.xml
@@ -11,7 +11,237 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@color/gesture_tutorial_fake_task_view_color" />
-</shape>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="412dp"
+ android:height="892dp"
+ android:viewportWidth="412"
+ android:viewportHeight="892">
+ <path
+ android:pathData="M0,101h412v791h-412z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M28,222L282,222A4,4 0,0 1,286 226L286,254A4,4 0,0 1,282 258L28,258A4,4 0,0 1,24 254L24,226A4,4 0,0 1,28 222z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M28,266L344,266A4,4 0,0 1,348 270L348,298A4,4 0,0 1,344 302L28,302A4,4 0,0 1,24 298L24,270A4,4 0,0 1,28 266z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M28,310L257,310A4,4 0,0 1,261 314L261,342A4,4 0,0 1,257 346L28,346A4,4 0,0 1,24 342L24,314A4,4 0,0 1,28 310z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M28,354L67,354A4,4 0,0 1,71 358L71,362A4,4 0,0 1,67 366L28,366A4,4 0,0 1,24 362L24,358A4,4 0,0 1,28 354z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M86,354L125,354A4,4 0,0 1,129 358L129,362A4,4 0,0 1,125 366L86,366A4,4 0,0 1,82 362L82,358A4,4 0,0 1,86 354z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M28,390L384,390A4,4 0,0 1,388 394L388,626A4,4 0,0 1,384 630L28,630A4,4 0,0 1,24 626L24,394A4,4 0,0 1,28 390z"
+ android:fillColor="#5F6368"/>
+ <path
+ android:pathData="M101.322,469.362L71.101,577.73H131.543L101.322,469.362Z"
+ android:strokeWidth="2"
+ android:fillColor="#5F6368"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M101.322,522.516V543.644V611.743"
+ android:fillColor="#5F6368"/>
+ <path
+ android:pathData="M101.322,522.516V543.644V611.743"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M109.577,532.822L101.322,548.135"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M109.577,558.221L101.322,574.196"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M94.54,524.945L101.322,534.442"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M90.929,549.239L101.322,561.166"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M62.772,412.307L30.855,563.669H94.688L62.772,412.307Z"
+ android:strokeWidth="2"
+ android:fillColor="#5F6368"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M62.772,486.516V516.037V611.154"
+ android:fillColor="#5F6368"/>
+ <path
+ android:pathData="M62.772,486.516V516.037V611.154"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M74.344,500.944L62.772,522.368"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M74.344,536.43L62.772,558.736"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M53.263,489.976L62.772,503.154"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M48.251,523.914L62.772,540.552"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#9ADCB2"/>
+ <path
+ android:pathData="M37,612H377"
+ android:strokeWidth="4"
+ android:fillColor="#00000000"
+ android:strokeColor="#9AA0A6"/>
+ <path
+ android:pathData="M81.24,441.187L84.066,443.127L87.333,441.98L86.273,445.244L88.393,447.978H84.949L83.006,450.8L81.947,447.537L78.679,446.655L81.417,444.626L81.24,441.187Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M172.561,469L175.387,471.029L178.654,469.794L177.594,473.057L179.714,475.791H176.27L174.327,478.702L173.267,475.438L170,474.468L172.737,472.44L172.561,469Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M278.073,481.229L280.81,483.257L284.078,482.022L283.018,485.286L285.137,488.02H281.693L279.839,490.93L278.691,487.667L275.424,486.697L278.161,484.668L278.073,481.229Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M325.561,459L328.387,460.94L331.654,459.794L330.594,463.057L332.714,465.791H329.27L327.327,468.613L326.267,465.35L323,464.468L325.737,462.44L325.561,459Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M209.649,517L212.475,519.029L215.654,517.794L214.682,521.057L216.802,523.791H213.358L211.415,526.702L210.356,523.438L207,522.468L209.737,520.44L209.649,517Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M128.836,482.816L129.455,485.11L131.662,485.815L129.808,487.314L129.896,489.784L128.042,488.285L125.922,489.078L126.629,486.785L125.304,484.757L127.512,484.845L128.836,482.816Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M37.532,450L38.239,452.381L40.358,453.087L38.504,454.498L38.592,456.968L36.737,455.556L34.618,456.35L35.325,453.969L34,452.029H36.208L37.532,450Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M284.077,516.947L284.784,519.329L286.903,520.034L285.048,521.445L285.137,523.915L283.282,522.415L281.163,523.297L281.869,520.916L280.545,518.976H282.753L284.077,516.947Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M232.771,444.893L233.478,447.274L235.597,447.979L233.743,449.391L233.831,451.86L231.977,450.449L229.857,451.243L230.564,448.861L229.239,446.921H231.447L232.771,444.893Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M152.384,521L152.914,522.676L154.415,523.117L153.091,524.175L153.179,525.851L151.854,524.881L150.442,525.41L150.883,523.734L150,522.411H151.501L152.384,521Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M136.473,515L136.914,516.676L138.415,517.117L137.179,518.175V519.851L135.943,518.881L134.442,519.41L134.971,517.822L134,516.411H135.589L136.473,515Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M314.454,410.406L314.896,412.082L316.397,412.523L315.16,413.493V415.257L313.924,414.199L312.423,414.816L312.953,413.14L311.981,411.817H313.571L314.454,410.406Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M344.212,488.195L344.742,489.871L346.243,490.4L344.919,491.37L345.007,493.046L343.683,492.076L342.27,492.605L342.711,491.018L341.828,489.606H343.329L344.212,488.195Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M47.067,420.814L47.508,422.402L49.009,422.931L47.773,423.901V425.665L46.537,424.607L45.036,425.136L45.566,423.549L44.594,422.137L46.184,422.226L47.067,420.814Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M265.887,448.42L266.328,450.007L267.829,450.537L266.593,451.507V453.271L265.357,452.212L263.856,452.83L264.385,451.154L263.414,449.831H265.004L265.887,448.42Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M110.912,413.759L111.441,415.435L112.854,415.876L111.618,416.934V418.61L110.382,417.551L108.969,418.169L109.41,416.493L108.439,415.17H110.028L110.912,413.759Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M149.412,418.344L152.238,420.372L155.505,419.138L154.445,422.489L156.565,425.135L153.121,425.223L151.178,428.045L150.118,424.782L146.851,423.812L149.589,421.783L149.412,418.344Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M37.532,450L38.239,452.381L40.358,453.087L38.504,454.498L38.592,456.968L36.737,455.556L34.618,456.35L35.325,453.969L34,452.029H36.208L37.532,450Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M141.906,455.74L142.612,458.122L144.731,458.827L142.877,460.238L142.965,462.708L141.111,461.208L139.08,462.09L139.786,459.709L138.374,457.769H140.669L141.906,455.74Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M201.777,459.267L202.395,461.56L204.603,462.265L202.748,463.765L202.836,466.146L200.982,464.735L198.863,465.529L199.569,463.235L198.245,461.207H200.452L201.777,459.267Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M370.175,504.248L370.793,506.629L373.001,507.335L371.146,508.746L371.234,511.216L369.38,509.716L367.261,510.598L367.967,508.217L366.643,506.277H368.85L370.175,504.248Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M300.532,437L301.239,439.381L303.358,440.087L301.592,441.498V443.968L299.826,442.468L297.706,443.35L298.413,440.969L297,439.029H299.296L300.532,437Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M193.384,420L193.914,421.676L195.415,422.117L194.091,423.087L194.179,424.851L192.854,423.792L191.442,424.41L191.883,422.734L191,421.411H192.501L193.384,420Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M248.313,469.323L248.843,470.911L250.256,471.44L249.02,472.41V474.174L247.784,473.116L246.371,473.645L246.812,472.057L245.841,470.646L247.43,470.734L248.313,469.323Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M169.988,496.751L170.518,498.427L172.019,498.956L170.694,499.926L170.782,501.602L169.458,500.632L168.045,501.161L168.487,499.573L167.604,498.162H169.105L169.988,496.751Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M222.441,400L222.882,401.676L224.384,402.117L223.059,403.175L223.147,404.851L221.911,403.792L220.41,404.41L220.851,402.734L219.968,401.411H221.469L222.441,400Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M211.754,492.341L212.284,493.928L213.785,494.458L212.461,495.428L212.549,497.192L211.225,496.133L209.812,496.662L210.253,495.075L209.37,493.664L210.871,493.752L211.754,492.341Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M254.054,420.814L254.584,422.402L256.085,422.931L254.761,423.901L254.849,425.665L253.524,424.607L252.111,425.136L252.553,423.549L251.67,422.137L253.171,422.226L254.054,420.814Z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M307.162,602.392H205L255.565,502.27H322.273L374.238,602.392H307.162L255.565,502.785L307.162,602.392Z"
+ android:fillColor="#5F6368"/>
+ <path
+ android:pathData="M307.162,602.392H205L255.565,502.27H322.273L374.238,602.392H307.162ZM307.162,602.392L255.565,502.785"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#A8CBFE"/>
+ <path
+ android:pathData="M255.565,503.079V602.392"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#A8CBFE"/>
+ <path
+ android:pathData="M356.686,430.931C358.218,423.774 353.2,416.635 345.477,414.986C337.754,413.337 330.251,417.801 328.719,424.958C327.186,432.115 332.205,439.254 339.928,440.903C347.651,442.553 355.154,438.088 356.686,430.931Z"
+ android:fillColor="#FEEFC3"/>
+ <path
+ android:pathData="M344.708,427.026C345.789,421.976 342.244,416.939 336.79,415.774C331.336,414.609 326.038,417.759 324.957,422.808C323.876,427.858 327.421,432.895 332.875,434.06C338.329,435.225 343.627,432.076 344.708,427.026Z"
+ android:fillColor="#5F6368"/>
+ <path
+ android:pathData="M2,101L410,101A2,2 0,0 1,412 103L412,187A2,2 0,0 1,410 189L2,189A2,2 0,0 1,0 187L0,103A2,2 0,0 1,2 101z"
+ android:fillColor="#E8EAED"/>
+ <path
+ android:pathData="M99,129L313,129A2,2 0,0 1,315 131L315,159A2,2 0,0 1,313 161L99,161A2,2 0,0 1,97 159L97,131A2,2 0,0 1,99 129z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M32,123L60,123A8,8 0,0 1,68 131L68,159A8,8 0,0 1,60 167L32,167A8,8 0,0 1,24 159L24,131A8,8 0,0 1,32 123z"
+ android:fillColor="#80868B"/>
+ <path
+ android:pathData="M0,0h412v101h-412z"
+ android:fillColor="#202124"/>
+ <path
+ android:pathData="M34.5,48L377.5,48A18.5,18.5 0,0 1,396 66.5L396,66.5A18.5,18.5 0,0 1,377.5 85L34.5,85A18.5,18.5 0,0 1,16 66.5L16,66.5A18.5,18.5 0,0 1,34.5 48z"
+ android:fillColor="#3C4043"/>
+ <path
+ android:pathData="M28,654L356,654A4,4 0,0 1,360 658L360,672A4,4 0,0 1,356 676L28,676A4,4 0,0 1,24 672L24,658A4,4 0,0 1,28 654z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M28,684L367,684A4,4 0,0 1,371 688L371,702A4,4 0,0 1,367 706L28,706A4,4 0,0 1,24 702L24,688A4,4 0,0 1,28 684z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M28,714L337,714A4,4 0,0 1,341 718L341,732A4,4 0,0 1,337 736L28,736A4,4 0,0 1,24 732L24,718A4,4 0,0 1,28 714z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M28,744L210,744A4,4 0,0 1,214 748L214,762A4,4 0,0 1,210 766L28,766A4,4 0,0 1,24 762L24,748A4,4 0,0 1,28 744z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M28,790L344,790A4,4 0,0 1,348 794L348,808A4,4 0,0 1,344 812L28,812A4,4 0,0 1,24 808L24,794A4,4 0,0 1,28 790z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M28,820L337,820A4,4 0,0 1,341 824L341,838A4,4 0,0 1,337 842L28,842A4,4 0,0 1,24 838L24,824A4,4 0,0 1,28 820z"
+ android:fillColor="#BDC1C6"/>
+</vector>
diff --git a/quickstep/res/drawable/default_sandbox_mock_launcher.xml b/quickstep/res/drawable/default_sandbox_mock_launcher.xml
new file mode 100644
index 0000000..38fbcf0
--- /dev/null
+++ b/quickstep/res/drawable/default_sandbox_mock_launcher.xml
@@ -0,0 +1,21 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="360dp"
+ android:height="146dp"
+ android:viewportWidth="360"
+ android:viewportHeight="146">
+ <path
+ android:pathData="M25,96L335,96A25,25 0,0 1,360 121L360,121A25,25 0,0 1,335 146L25,146A25,25 0,0 1,0 121L0,121A25,25 0,0 1,25 96z"
+ android:fillColor="#3C4043"/>
+ <path
+ android:pathData="M30,30m-30,0a30,30 0,1 1,60 0a30,30 0,1 1,-60 0"
+ android:fillColor="#8AB4F8"/>
+ <path
+ android:pathData="M130,30m-30,0a30,30 0,1 1,60 0a30,30 0,1 1,-60 0"
+ android:fillColor="#F28B82"/>
+ <path
+ android:pathData="M230,30m-30,0a30,30 0,1 1,60 0a30,30 0,1 1,-60 0"
+ android:fillColor="#FDD663"/>
+ <path
+ android:pathData="M330,30m-30,0a30,30 0,1 1,60 0a30,30 0,1 1,-60 0"
+ android:fillColor="#81C995"/>
+</vector>
diff --git a/quickstep/res/drawable/sandbox_fake_google_search.xml b/quickstep/res/drawable/sandbox_fake_google_search.xml
new file mode 100644
index 0000000..f06b927
--- /dev/null
+++ b/quickstep/res/drawable/sandbox_fake_google_search.xml
@@ -0,0 +1,79 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="412dp"
+ android:height="892dp"
+ android:viewportWidth="412"
+ android:viewportHeight="892">
+ <group>
+ <clip-path
+ android:pathData="M24,0L388,0A24,24 0,0 1,412 24L412,868A24,24 0,0 1,388 892L24,892A24,24 0,0 1,0 868L0,24A24,24 0,0 1,24 0z"/>
+ <path
+ android:pathData="M24,0L388,0A24,24 0,0 1,412 24L412,868A24,24 0,0 1,388 892L24,892A24,24 0,0 1,0 868L0,24A24,24 0,0 1,24 0z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M183,464L183,464A46,46 0,0 1,137 510L-81,510A46,46 0,0 1,-127 464L-127,464A46,46 0,0 1,-81 418L137,418A46,46 0,0 1,183 464z"
+ android:strokeAlpha="0.6"
+ android:fillColor="#EA4335"
+ android:fillAlpha="0.3"/>
+ <path
+ android:pathData="M91,464C91,489.405 111.595,510 137,510C162.405,510 183,489.405 183,464C183,438.595 162.405,418 137,418C111.595,418 91,438.595 91,464Z"
+ android:strokeAlpha="0.6"
+ android:fillColor="#EA4335"
+ android:fillAlpha="0.6"/>
+ <path
+ android:pathData="M100,464C100,484.435 116.565,501 137,501C157.434,501 174,484.435 174,464C174,443.565 157.434,427 137,427C116.565,427 100,443.565 100,464Z"
+ android:fillColor="#EA4335"/>
+ <path
+ android:pathData="M24,0L388,0A24,24 0,0 1,412 24L412,868A24,24 0,0 1,388 892L24,892A24,24 0,0 1,0 868L0,24A24,24 0,0 1,24 0z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M24,0L388,0A24,24 0,0 1,412 24L412,868A24,24 0,0 1,388 892L24,892A24,24 0,0 1,0 868L0,24A24,24 0,0 1,24 0z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M0,101h412v791h-412z"
+ android:fillColor="#F1F3F4"/>
+ <path
+ android:pathData="M0,0h412v101h-412z"
+ android:fillColor="#202124"/>
+ <path
+ android:pathData="M34.5,48L377.5,48A18.5,18.5 0,0 1,396 66.5L396,66.5A18.5,18.5 0,0 1,377.5 85L34.5,85A18.5,18.5 0,0 1,16 66.5L16,66.5A18.5,18.5 0,0 1,34.5 48z"
+ android:fillColor="#3C4043"/>
+ <path
+ android:pathData="M168,875L244,875A2,2 0,0 1,246 877L246,877A2,2 0,0 1,244 879L168,879A2,2 0,0 1,166 877L166,877A2,2 0,0 1,168 875z"
+ android:fillColor="#373737"/>
+ <path
+ android:pathData="M57,355L355,355A25,25 0,0 1,380 380L380,380A25,25 0,0 1,355 405L57,405A25,25 0,0 1,32 380L32,380A25,25 0,0 1,57 355z"
+ android:strokeWidth="4"
+ android:fillColor="#DADCE0"
+ android:strokeColor="#BDC1C6"/>
+ <path
+ android:pathData="M104,429L192,429A4,4 0,0 1,196 433L196,449A4,4 0,0 1,192 453L104,453A4,4 0,0 1,100 449L100,433A4,4 0,0 1,104 429z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M220,429L308,429A4,4 0,0 1,312 433L312,449A4,4 0,0 1,308 453L220,453A4,4 0,0 1,216 449L216,433A4,4 0,0 1,220 429z"
+ android:fillColor="#DADCE0"/>
+ <path
+ android:pathData="M120,242L120,242A26,26 0,0 1,146 268L146,268A26,26 0,0 1,120 294L120,294A26,26 0,0 1,94 268L94,268A26,26 0,0 1,120 242z"
+ android:fillColor="#4285F4"/>
+ <path
+ android:pathData="M243,261L243,261A17,17 0,0 1,260 278L260,294A17,17 0,0 1,243 311L243,311A17,17 0,0 1,226 294L226,278A17,17 0,0 1,243 261z"
+ android:fillColor="#4285F4"/>
+ <path
+ android:pathData="M272,244L272,244A8,8 0,0 1,280 252L280,286A8,8 0,0 1,272 294L272,294A8,8 0,0 1,264 286L264,252A8,8 0,0 1,272 244z"
+ android:fillColor="#34A853"/>
+ <path
+ android:pathData="M167,261L167,261A17,17 0,0 1,184 278L184,278A17,17 0,0 1,167 295L167,295A17,17 0,0 1,150 278L150,278A17,17 0,0 1,167 261z"
+ android:fillColor="#E94235"/>
+ <path
+ android:pathData="M301,261L301,261A17,17 0,0 1,318 278L318,278A17,17 0,0 1,301 295L301,295A17,17 0,0 1,284 278L284,278A17,17 0,0 1,301 261z"
+ android:fillColor="#E94235"/>
+ <path
+ android:pathData="M205,261L205,261A17,17 0,0 1,222 278L222,278A17,17 0,0 1,205 295L205,295A17,17 0,0 1,188 278L188,278A17,17 0,0 1,205 261z"
+ android:fillColor="#FABB05"/>
+ <path
+ android:pathData="M34,128L50,128A4,4 0,0 1,54 132L54,148A4,4 0,0 1,50 152L34,152A4,4 0,0 1,30 148L30,132A4,4 0,0 1,34 128z"
+ android:fillColor="#BDC1C6"/>
+ <path
+ android:pathData="M68,131L117,131A4,4 0,0 1,121 135L121,145A4,4 0,0 1,117 149L68,149A4,4 0,0 1,64 145L64,135A4,4 0,0 1,68 131z"
+ android:fillColor="#BDC1C6"/>
+ </group>
+</vector>
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 9d06dfb..16b2c56 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -16,13 +16,16 @@
<com.android.quickstep.interaction.RootSandboxLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:clipChildren="false">
- <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_fake_launcher_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="70dp" />
<com.android.launcher3.views.ClipIconView
android:id="@+id/gesture_tutorial_fake_icon_view"
@@ -42,13 +45,22 @@
android:id="@+id/gesture_tutorial_fake_task_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="invisible" />
+ android:visibility="visible" />
- <ImageView
- android:id="@+id/gesture_tutorial_fragment_hand_coaching"
+ <View
+ android:id="@+id/gesture_tutorial_ripple_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:scaleType="centerCrop"/>
+ android:background="@drawable/gesture_tutorial_ripple"/>
+
+ <VideoView
+ android:id="@+id/gesture_tutorial_feedback_video"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentEnd="true"/>
<ImageButton
android:id="@+id/gesture_tutorial_fragment_close_button"
@@ -63,7 +75,8 @@
android:contentDescription="@string/gesture_tutorial_close_button_content_description"
android:padding="18dp"
android:src="@drawable/gesture_tutorial_close_button"
- android:tint="?android:attr/textColorPrimary"/>
+ android:tint="?android:attr/textColorPrimary"
+ android:visibility="gone"/>
<LinearLayout
android:id="@+id/gesture_tutorial_fragment_titles_container"
@@ -93,16 +106,33 @@
android:layout_marginEnd="@dimen/gesture_tutorial_subtitle_margin_start_end"/>
</LinearLayout>
- <TextView
+ <LinearLayout
android:id="@+id/gesture_tutorial_fragment_feedback_view"
- style="@style/TextAppearance.GestureTutorial.Feedback"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@id/gesture_tutorial_fragment_titles_container"
+ android:orientation="vertical"
+ android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginStart="@dimen/gesture_tutorial_feedback_margin_start_end"
android:layout_marginEnd="@dimen/gesture_tutorial_feedback_margin_start_end"
- android:layout_marginTop="40dp"/>
+ android:layout_marginTop="24dp"
+ android:padding="24dp"
+ android:gravity="center_vertical"
+ android:background="@drawable/bg_sandbox_feedback">
+
+ <TextView
+ android:id="@+id/gesture_tutorial_fragment_feedback_title"
+ style="@style/TextAppearance.GestureTutorial.Feedback.Title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"/>
+
+ <TextView
+ android:id="@+id/gesture_tutorial_fragment_feedback_subtitle"
+ style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
<!-- android:stateListAnimator="@null" removes shadow and normal on click behavior (increase
of elevation and shadow) which is replaced by ripple effect in android:foreground -->
diff --git a/quickstep/res/raw/tips_nav_back_left.mp4 b/quickstep/res/raw/tips_nav_back_left.mp4
new file mode 100644
index 0000000..f40b3b7
--- /dev/null
+++ b/quickstep/res/raw/tips_nav_back_left.mp4
Binary files differ
diff --git a/quickstep/res/raw/tips_nav_back_right.mp4 b/quickstep/res/raw/tips_nav_back_right.mp4
new file mode 100644
index 0000000..93841c7
--- /dev/null
+++ b/quickstep/res/raw/tips_nav_back_right.mp4
Binary files differ
diff --git a/quickstep/res/raw/tips_nav_home.mp4 b/quickstep/res/raw/tips_nav_home.mp4
new file mode 100644
index 0000000..ce33df2
--- /dev/null
+++ b/quickstep/res/raw/tips_nav_home.mp4
Binary files differ
diff --git a/quickstep/res/raw/tips_nav_overview.mp4 b/quickstep/res/raw/tips_nav_overview.mp4
new file mode 100644
index 0000000..17f4b80
--- /dev/null
+++ b/quickstep/res/raw/tips_nav_overview.mp4
Binary files differ
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index e56397a..387d4ec 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -47,12 +47,24 @@
<item name="android:textSize">21sp</item>
</style>
- <style name="TextAppearance.GestureTutorial.Feedback"
+ <style name="TextAppearance.GestureTutorial.Feedback.Title"
parent="TextAppearance.GestureTutorial">
- <item name="android:gravity">center</item>
+ <item name="android:gravity">start</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:fontFamily">google-sans-display</item>
<item name="android:letterSpacing">0.03</item>
- <item name="android:textSize">21sp</item>
+ <item name="android:textSize">36sp</item>
+ <item name="android:lineHeight">42sp</item>
+ </style>
+
+ <style name="TextAppearance.GestureTutorial.Feedback.Subtitle"
+ parent="TextAppearance.GestureTutorial">
+ <item name="android:gravity">start</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:fontFamily">google-sans</item>
+ <item name="android:letterSpacing">0.03</item>
+ <item name="android:textSize">18sp</item>
+ <item name="android:lineHeight">24sp</item>
</style>
<style name="TextAppearance.GestureTutorial.ButtonLabel"
diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java
index 5c81e5f..7c293c3 100644
--- a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialController.java
@@ -18,7 +18,6 @@
import static com.android.quickstep.interaction.TutorialController.TutorialType.ASSISTANT_COMPLETE;
import android.graphics.PointF;
-import android.view.View;
import com.android.launcher3.R;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
@@ -60,11 +59,6 @@
}
@Override
- void onActionButtonClicked(View button) {
- mTutorialFragment.closeTutorial();
- }
-
- @Override
public void onBackGestureAttempted(BackGestureResult result) {
switch (mTutorialType) {
case ASSISTANT:
@@ -101,8 +95,7 @@
showFeedback(R.string.assistant_gesture_feedback_swipe_too_far_from_corner);
break;
case ASSISTANT_COMPLETED:
- hideFeedback();
- hideHandCoachingAnimation();
+ hideFeedback(true);
showRippleEffect(
() -> {
if (mTutorialFragment.isTutorialComplete()) {
diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
index 16886ec..b797f0c 100644
--- a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
@@ -18,17 +18,11 @@
import android.view.MotionEvent;
import android.view.View;
-import com.android.launcher3.R;
import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Home gesture interactive tutorial. */
public class AssistantGestureTutorialFragment extends TutorialFragment {
@Override
- Integer getHandAnimationResId() {
- return R.drawable.assistant_gesture;
- }
-
- @Override
TutorialController createController(TutorialType type) {
return new AssistantGestureTutorialController(this, type);
}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index a1b7e01..300ca7d 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -17,10 +17,14 @@
import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION_COMPLETE;
import static com.android.quickstep.interaction.TutorialController.TutorialType.LEFT_EDGE_BACK_NAVIGATION;
+import static com.android.quickstep.interaction.TutorialController.TutorialType.RIGHT_EDGE_BACK_NAVIGATION;
import android.graphics.PointF;
import android.view.View;
+import androidx.annotation.Nullable;
+import androidx.appcompat.content.res.AppCompatResources;
+
import com.android.launcher3.R;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
@@ -73,15 +77,16 @@
}
@Override
- void onActionButtonClicked(View button) {
- mTutorialFragment.closeTutorial();
- }
-
- @Override
void onActionTextButtonClicked(View button) {
mTutorialFragment.startSystemNavigationSetting();
}
+ @Nullable
+ @Override
+ public View getMockLauncherView() {
+ return null;
+ }
+
@Override
public void onBackGestureAttempted(BackGestureResult result) {
switch (mTutorialType) {
@@ -103,10 +108,12 @@
private void handleAttemptFromRight(BackGestureResult result) {
switch (result) {
case BACK_COMPLETED_FROM_RIGHT:
- hideFeedback();
- hideHandCoachingAnimation();
- showRippleEffect(
- () -> mTutorialFragment.changeController(LEFT_EDGE_BACK_NAVIGATION));
+ hideFeedback(true);
+ mFakeTaskView.setBackground(AppCompatResources.getDrawable(mContext,
+ R.drawable.sandbox_fake_google_search));
+ showRippleEffect(null);
+ showFeedback(R.string.back_gesture_feedback_complete,
+ mTutorialFragment::continueTutorial);
break;
case BACK_CANCELLED_FROM_RIGHT:
showFeedback(R.string.back_gesture_feedback_cancelled_right_edge);
@@ -125,16 +132,12 @@
private void handleAttemptFromLeft(BackGestureResult result) {
switch (result) {
case BACK_COMPLETED_FROM_LEFT:
- hideFeedback();
- hideHandCoachingAnimation();
- showRippleEffect(
- () -> {
- if (mTutorialFragment.isTutorialComplete()) {
- mTutorialFragment.changeController(BACK_NAVIGATION_COMPLETE);
- } else {
- mTutorialFragment.continueTutorial();
- }
- });
+ hideFeedback(true);
+ mFakeTaskView.setBackground(AppCompatResources.getDrawable(mContext,
+ R.drawable.sandbox_fake_google_search));
+ showRippleEffect(null);
+ showFeedback(R.string.back_gesture_feedback_complete_left_edge,
+ () -> mTutorialFragment.changeController(RIGHT_EDGE_BACK_NAVIGATION));
break;
case BACK_CANCELLED_FROM_LEFT:
showFeedback(R.string.back_gesture_feedback_cancelled_left_edge);
@@ -156,6 +159,9 @@
if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) {
mTutorialFragment.closeTutorial();
}
+ } else if (mTutorialType == LEFT_EDGE_BACK_NAVIGATION
+ || mTutorialType == RIGHT_EDGE_BACK_NAVIGATION) {
+ showFeedback(R.string.back_gesture_feedback_swipe_in_nav_bar);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
index 41db684..b3eb1c0 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
@@ -18,14 +18,19 @@
import android.view.MotionEvent;
import android.view.View;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Back gesture interactive tutorial. */
public class BackGestureTutorialFragment extends TutorialFragment {
+ @Nullable
@Override
- Integer getHandAnimationResId() {
- return R.drawable.back_gesture;
+ Integer getFeedbackVideoResId() {
+ return mTutorialType == TutorialType.RIGHT_EDGE_BACK_NAVIGATION
+ ? R.raw.tips_nav_back_right
+ : R.raw.tips_nav_back_left;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 8b6777b..ebb4bfc 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -145,6 +145,7 @@
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
}
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index fbf3a0a..d0f21c2 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -20,7 +20,6 @@
import android.annotation.TargetApi;
import android.graphics.PointF;
import android.os.Build;
-import android.view.View;
import com.android.launcher3.R;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
@@ -62,11 +61,6 @@
}
@Override
- void onActionButtonClicked(View button) {
- mTutorialFragment.closeTutorial();
- }
-
- @Override
public void onBackGestureAttempted(BackGestureResult result) {
switch (mTutorialType) {
case HOME_NAVIGATION:
@@ -90,17 +84,16 @@
@Override
public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
+ if (mHideFeedbackEndAction != null) {
+ return;
+ }
switch (mTutorialType) {
case HOME_NAVIGATION:
switch (result) {
case HOME_GESTURE_COMPLETED: {
- animateFakeTaskViewHome(finalVelocity, () -> {
- if (mTutorialFragment.isTutorialComplete()) {
- mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE);
- } else {
- mTutorialFragment.continueTutorial();
- }
- });
+ animateFakeTaskViewHome(finalVelocity, null);
+ showFeedback(R.string.home_gesture_feedback_complete,
+ mTutorialFragment::continueTutorial);
break;
}
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
@@ -108,12 +101,12 @@
showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
break;
case OVERVIEW_GESTURE_COMPLETED:
- fadeOutFakeTaskView(true, () ->
+ fadeOutFakeTaskView(true, true, () ->
showFeedback(R.string.home_gesture_feedback_overview_detected));
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
case HOME_OR_OVERVIEW_CANCELLED:
- fadeOutFakeTaskView(false, null);
+ fadeOutFakeTaskView(false, true, null);
showFeedback(R.string.home_gesture_feedback_wrong_swipe_direction);
break;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
index 63595a5..31e0351 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
@@ -15,14 +15,17 @@
*/
package com.android.quickstep.interaction;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Home gesture interactive tutorial. */
public class HomeGestureTutorialFragment extends TutorialFragment {
+ @Nullable
@Override
- Integer getHandAnimationResId() {
- return R.drawable.home_gesture;
+ Integer getFeedbackVideoResId() {
+ return R.raw.tips_nav_home;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 31f26d1..66e6a0d 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -15,14 +15,21 @@
*/
package com.android.quickstep.interaction;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
+import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.graphics.PointF;
import android.os.Build;
import android.view.View;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.SwipeUpAnimationLogic;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
@@ -62,9 +69,10 @@
return null;
}
+ @Nullable
@Override
- void onActionButtonClicked(View button) {
- mTutorialFragment.closeTutorial();
+ public View getMockLauncherView() {
+ return null;
}
@Override
@@ -91,12 +99,17 @@
@Override
public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
+ if (mHideFeedbackEndAction != null) {
+ return;
+ }
switch (mTutorialType) {
case OVERVIEW_NAVIGATION:
switch (result) {
case HOME_GESTURE_COMPLETED: {
- animateFakeTaskViewHome(finalVelocity, () ->
- showFeedback(R.string.overview_gesture_feedback_home_detected));
+ animateFakeTaskViewHome(finalVelocity, () -> {
+ resetFakeTaskView();
+ showFeedback(R.string.overview_gesture_feedback_home_detected);
+ });
break;
}
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
@@ -104,17 +117,19 @@
showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
break;
case OVERVIEW_GESTURE_COMPLETED:
- fadeOutFakeTaskView(true, () -> {
- if (mTutorialFragment.isTutorialComplete()) {
- mTutorialFragment.changeController(OVERVIEW_NAVIGATION_COMPLETE);
- } else {
- mTutorialFragment.continueTutorial();
- }
- });
+ PendingAnimation anim = new PendingAnimation(300);
+ anim.setFloat(mTaskViewSwipeUpAnimation
+ .getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
+ AnimatorSet animset = anim.buildAnim();
+ animset.start();
+ mRunningWindowAnim = SwipeUpAnimationLogic.RunningWindowAnim.wrap(animset);
+ onMotionPaused(true /*arbitrary value*/);
+ showFeedback(R.string.overview_gesture_feedback_complete,
+ mTutorialFragment::continueTutorial);
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
case HOME_OR_OVERVIEW_CANCELLED:
- fadeOutFakeTaskView(false, null);
+ fadeOutFakeTaskView(false, true, null);
showFeedback(R.string.overview_gesture_feedback_wrong_swipe_direction);
break;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
index 93200bb..c6213e3 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
@@ -15,14 +15,17 @@
*/
package com.android.quickstep.interaction;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
import com.android.quickstep.interaction.TutorialController.TutorialType;
/** Shows the Overview gesture interactive tutorial. */
public class OverviewGestureTutorialFragment extends TutorialFragment {
+ @Nullable
@Override
- Integer getHandAnimationResId() {
- return R.drawable.overview_gesture;
+ Integer getFeedbackVideoResId() {
+ return R.raw.tips_nav_overview;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java
index 4c1a595..3a6d434 100644
--- a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java
@@ -16,7 +16,6 @@
package com.android.quickstep.interaction;
import android.graphics.PointF;
-import android.view.View;
import androidx.annotation.Nullable;
@@ -50,11 +49,6 @@
}
@Override
- void onActionButtonClicked(View button) {
- mTutorialFragment.closeTutorial();
- }
-
- @Override
public void onBackGestureAttempted(BackGestureResult result) {
switch (result) {
case BACK_COMPLETED_FROM_LEFT:
@@ -87,7 +81,7 @@
});
break;
case OVERVIEW_GESTURE_COMPLETED:
- fadeOutFakeTaskView(true, () -> {
+ fadeOutFakeTaskView(true, true, () -> {
showFeedback(R.string.sandbox_mode_overview_gesture_feedback_successful);
});
break;
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 68c63bf..8fc453d 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -27,17 +27,15 @@
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.content.Context;
-import android.graphics.Insets;
import android.graphics.Outline;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
+import android.util.DisplayMetrics;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewOutlineProvider;
-import android.view.WindowInsets;
-import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -56,7 +54,6 @@
import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TransformParams;
-import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
@TargetApi(Build.VERSION_CODES.R)
@@ -64,13 +61,37 @@
private static final int FAKE_PREVIOUS_TASK_MARGIN = Utilities.dpToPx(12);
- private final ViewSwipeUpAnimation mTaskViewSwipeUpAnimation;
+ final ViewSwipeUpAnimation mTaskViewSwipeUpAnimation;
private float mFakeTaskViewRadius;
private Rect mFakeTaskViewRect = new Rect();
- private RunningWindowAnim mRunningWindowAnim;
+ RunningWindowAnim mRunningWindowAnim;
private boolean mShowTasks = false;
private boolean mShowPreviousTasks = false;
+ private AnimatorListenerAdapter mResetTaskView = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mFakeLauncherView.setVisibility(View.INVISIBLE);
+ mFakeIconView.setVisibility(View.INVISIBLE);
+ if (mTutorialFragment.getActivity() != null) {
+ DisplayMetrics displayMetrics =
+ mTutorialFragment.getResources().getDisplayMetrics();
+ int height = displayMetrics.heightPixels;
+ int width = displayMetrics.widthPixels;
+ mFakeTaskViewRect.set(0, 0, width, height);
+ }
+ mFakeTaskViewRadius = 0;
+ mFakeTaskView.invalidateOutline();
+ mFakeTaskView.setVisibility(View.VISIBLE);
+ mFakeTaskView.setAlpha(1);
+ mFakePreviousTaskView.setVisibility(View.INVISIBLE);
+ mFakePreviousTaskView.setAlpha(1);
+ mShowTasks = false;
+ mShowPreviousTasks = false;
+ mRunningWindowAnim = null;
+ }
+ };
+
SwipeUpGestureTutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
super(tutorialFragment, tutorialType);
RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(mContext);
@@ -83,14 +104,13 @@
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext)
.getDeviceProfile(mContext)
.copy(mContext);
- Insets insets = mContext.getSystemService(WindowManager.class)
- .getCurrentWindowMetrics()
- .getWindowInsets()
- .getInsets(WindowInsets.Type.systemBars());
- dp.updateInsets(new Rect(insets.left, insets.top, insets.right, insets.bottom));
mTaskViewSwipeUpAnimation.initDp(dp);
- mFakeTaskViewRadius = QuickStepContract.getWindowCornerRadius(mContext.getResources());
+ DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ int height = displayMetrics.heightPixels;
+ int width = displayMetrics.widthPixels;
+ mFakeTaskViewRect.set(0, 0, width, height);
+ mFakeTaskViewRadius = 0;
ViewOutlineProvider outlineProvider = new ViewOutlineProvider() {
@Override
@@ -114,24 +134,11 @@
}
/** Fades the task view, optionally after animating to a fake Overview. */
- void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) {
- hideFeedback();
- hideHandCoachingAnimation();
+ void fadeOutFakeTaskView(boolean toOverviewFirst, boolean reset,
+ @Nullable Runnable onEndRunnable) {
+ hideFeedback(true);
cancelRunningAnimation();
PendingAnimation anim = new PendingAnimation(300);
- AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation, boolean isReverse) {
- mFakeIconView.setVisibility(View.INVISIBLE);
- mFakeTaskView.setVisibility(View.INVISIBLE);
- mFakeTaskView.setAlpha(1);
- mFakePreviousTaskView.setVisibility(View.INVISIBLE);
- mFakePreviousTaskView.setAlpha(1);
- mShowTasks = false;
- mShowPreviousTasks = false;
- mRunningWindowAnim = null;
- }
- };
if (toOverviewFirst) {
anim.setFloat(mTaskViewSwipeUpAnimation
.getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
@@ -139,9 +146,17 @@
@Override
public void onAnimationEnd(Animator animation, boolean isReverse) {
PendingAnimation fadeAnim = new PendingAnimation(300);
- fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
- fadeAnim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
- fadeAnim.addListener(resetTaskView);
+ if (reset) {
+ fadeAnim.setFloat(mTaskViewSwipeUpAnimation
+ .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+ fadeAnim.addListener(mResetTaskView);
+ } else {
+ fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
+ fadeAnim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
+ }
+ if (onEndRunnable != null) {
+ fadeAnim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable));
+ }
AnimatorSet animset = fadeAnim.buildAnim();
animset.setStartDelay(100);
animset.start();
@@ -149,36 +164,62 @@
}
});
} else {
- anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
- anim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
- anim.setViewAlpha(mFakeIconView, 0, ACCEL);
- anim.addListener(resetTaskView);
- }
- if (onEndRunnable != null) {
- anim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable));
+ if (reset) {
+ anim.setFloat(mTaskViewSwipeUpAnimation
+ .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+ anim.addListener(mResetTaskView);
+ } else {
+ anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
+ anim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
+ }
+ if (onEndRunnable != null) {
+ anim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable));
+ }
}
AnimatorSet animset = anim.buildAnim();
animset.start();
mRunningWindowAnim = RunningWindowAnim.wrap(animset);
}
+ void resetFakeTaskView() {
+ PendingAnimation anim = new PendingAnimation(300);
+ anim.setFloat(mTaskViewSwipeUpAnimation
+ .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+ anim.setViewAlpha(mFakeTaskView, 1, ACCEL);
+ anim.addListener(mResetTaskView);
+ AnimatorSet animset = anim.buildAnim();
+ animset.start();
+ mRunningWindowAnim = RunningWindowAnim.wrap(animset);
+ }
+
void animateFakeTaskViewHome(PointF finalVelocity, @Nullable Runnable onEndRunnable) {
- hideFeedback();
- hideHandCoachingAnimation();
+ hideFeedback(true);
cancelRunningAnimation();
mFakePreviousTaskView.setVisibility(View.INVISIBLE);
+ mFakeLauncherView.setVisibility(View.VISIBLE);
mShowPreviousTasks = false;
RectFSpringAnim rectAnim =
mTaskViewSwipeUpAnimation.handleSwipeUpToHome(finalVelocity);
// After home animation finishes, fade out and run onEndRunnable.
- rectAnim.addAnimatorListener(AnimationSuccessListener.forRunnable(
- () -> fadeOutFakeTaskView(false, onEndRunnable)));
+ PendingAnimation fadeAnim = new PendingAnimation(300);
+ fadeAnim.setViewAlpha(mFakeIconView, 0, ACCEL);
+ if (onEndRunnable != null) {
+ fadeAnim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable));
+ }
+ AnimatorSet animset = fadeAnim.buildAnim();
+ rectAnim.addAnimatorListener(AnimationSuccessListener.forRunnable(animset::start));
mRunningWindowAnim = RunningWindowAnim.wrap(rectAnim);
}
@Override
public void setNavBarGestureProgress(@Nullable Float displacement) {
- if (displacement == null || mTutorialType == HOME_NAVIGATION_COMPLETE
+ if (mHideFeedbackEndAction != null) {
+ return;
+ }
+ if (displacement != null) {
+ hideFeedback(true);
+ }
+ if (mTutorialType == HOME_NAVIGATION_COMPLETE
|| mTutorialType == OVERVIEW_NAVIGATION_COMPLETE) {
mFakeTaskView.setVisibility(View.INVISIBLE);
mFakePreviousTaskView.setVisibility(View.INVISIBLE);
@@ -188,7 +229,7 @@
if (mShowPreviousTasks) {
mFakePreviousTaskView.setVisibility(View.VISIBLE);
}
- if (mRunningWindowAnim == null) {
+ if (mRunningWindowAnim == null && displacement != null) {
mTaskViewSwipeUpAnimation.updateDisplacement(displacement);
}
}
@@ -196,6 +237,9 @@
@Override
public void onMotionPaused(boolean unused) {
+ if (mHideFeedbackEndAction != null) {
+ return;
+ }
if (mShowTasks) {
if (!mShowPreviousTasks) {
mFakePreviousTaskView.setTranslationX(
@@ -253,9 +297,9 @@
@NonNull
@Override
public RectF getWindowTargetRect() {
- int fakeHomeIconSizePx = mDp.allAppsIconSizePx;
- int fakeHomeIconLeft = (mDp.widthPx - fakeHomeIconSizePx) / 2;
- int fakeHomeIconTop = mDp.heightPx - (mDp.allAppsCellHeightPx * 3);
+ int fakeHomeIconSizePx = Utilities.dpToPx(60);
+ int fakeHomeIconLeft = mFakeLauncherView.getLeft();
+ int fakeHomeIconTop = mDp.heightPx - Utilities.dpToPx(216);
return new RectF(fakeHomeIconLeft, fakeHomeIconTop,
fakeHomeIconLeft + fakeHomeIconSizePx,
fakeHomeIconTop + fakeHomeIconSizePx);
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 12d2efc..cbab4f9 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -19,17 +19,21 @@
import android.graphics.drawable.RippleDrawable;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.VideoView;
import androidx.annotation.CallSuper;
import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
+import androidx.appcompat.content.res.AppCompatResources;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.views.ClipIconView;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureAttemptCallback;
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureAttemptCallback;
@@ -37,8 +41,8 @@
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 FEEDBACK_VISIBLE_MS = 2500;
+ private static final int FEEDBACK_ANIMATION_MS = 250;
private static final int RIPPLE_VISIBLE_MS = 300;
final TutorialFragment mTutorialFragment;
@@ -48,18 +52,18 @@
final ImageButton mCloseButton;
final TextView mTitleTextView;
final TextView mSubtitleTextView;
- final TextView mFeedbackView;
- final View mLauncherView;
+ final ViewGroup mFeedbackView;
+ final VideoView mFeedbackVideoView;
+ final ImageView mFakeLauncherView;
final ClipIconView mFakeIconView;
final View mFakeTaskView;
final View mFakePreviousTaskView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
- @Nullable final TutorialHandAnimation mHandCoachingAnimation;
- final ImageView mHandCoachingView;
final Button mActionTextButton;
final Button mActionButton;
private final Runnable mHideFeedbackRunnable;
+ Runnable mHideFeedbackEndAction;
TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
mTutorialFragment = tutorialFragment;
@@ -72,34 +76,23 @@
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);
- mLauncherView = getMockLauncherView();
+ mFeedbackVideoView = rootView.findViewById(R.id.gesture_tutorial_feedback_video);
+ mFakeLauncherView = rootView.findViewById(R.id.gesture_tutorial_fake_launcher_view);
mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
mFakePreviousTaskView =
rootView.findViewById(R.id.gesture_tutorial_fake_previous_task_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();
-
- if (mLauncherView != null) {
- rootView.addView(mLauncherView, 0);
- }
- if (mContext != null) {
- rootView.setBackground(mContext.getDrawable(getMockWallpaperResId()));
- mFakeTaskView.setBackground(mContext.getDrawable(getMockAppTaskThumbnailResId()));
- mFakePreviousTaskView.setBackground(
- mContext.getDrawable(getMockPreviousAppTaskThumbnailResId()));
- mFakeIconView.setBackground(mContext.getDrawable(getMockAppIconResId()));
- }
+ () -> mFeedbackView.animate()
+ .translationY(-mFeedbackView.getTop() - mFeedbackView.getHeight())
+ .setDuration(FEEDBACK_ANIMATION_MS)
+ .withEndAction(this::hideFeedbackEndAction).start();
}
void setTutorialType(TutorialType tutorialType) {
@@ -127,6 +120,11 @@
}
@DrawableRes
+ protected int getMockLauncherResId() {
+ return R.drawable.default_sandbox_mock_launcher;
+ }
+
+ @DrawableRes
protected int getMockAppTaskThumbnailResId() {
return R.drawable.default_sandbox_app_task_thumbnail;
}
@@ -153,19 +151,76 @@
return R.drawable.default_sandbox_wallpaper;
}
- 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 fadeTaskViewAndRun(Runnable r) {
+ mFakeTaskView.animate().alpha(0).setListener(AnimationSuccessListener.forRunnable(r));
}
- void hideFeedback() {
- mFeedbackView.setText(null);
+ /**
+ * Show feedback reflecting a failed gesture attempt.
+ *
+ * @param subtitleResId Resource of the text to display.
+ **/
+ void showFeedback(int subtitleResId) {
+ showFeedback(subtitleResId, null);
+ }
+
+ /**
+ * Show feedback reflecting the result of a gesture attempt.
+ *
+ * @param successEndAction Non-null iff the gesture was successful; this is run after the
+ * feedback is shown (i.e. to go to the next step)
+ **/
+ void showFeedback(int subtitleResId, @Nullable Runnable successEndAction) {
+ if (mHideFeedbackEndAction != null) {
+ return;
+ }
+ int visibleDuration = FEEDBACK_VISIBLE_MS;
+ if (mTutorialFragment.getFeedbackVideoResId() != null) {
+ if (successEndAction == null) {
+ if (mFeedbackVideoView.isPlaying()) {
+ mFeedbackVideoView.seekTo(1);
+ } else {
+ mFeedbackVideoView.start();
+ }
+ mFeedbackVideoView.setVisibility(View.VISIBLE);
+ visibleDuration = mTutorialFragment.getFeedbackVideoDuration();
+ } else {
+ mTutorialFragment.releaseFeedbackVideoView();
+ }
+ }
+ TextView title = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_title);
+ title.setText(successEndAction == null
+ ? R.string.gesture_tutorial_try_again
+ : R.string.gesture_tutorial_nice);
+ TextView subtitle =
+ mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle);
+ subtitle.setText(subtitleResId);
+ mHideFeedbackEndAction = successEndAction;
+ mFeedbackView.setTranslationY(-mFeedbackView.getHeight() - mFeedbackView.getTop());
+ mFeedbackView.setVisibility(View.VISIBLE);
+ mFeedbackView.animate()
+ .setDuration(FEEDBACK_ANIMATION_MS)
+ .translationY(0)
+ .start();
mFeedbackView.removeCallbacks(mHideFeedbackRunnable);
+ mFeedbackView.postDelayed(mHideFeedbackRunnable, visibleDuration);
+ }
+
+ void hideFeedback(boolean releaseFeedbackVideo) {
+ mFeedbackView.removeCallbacks(mHideFeedbackRunnable);
+ mHideFeedbackEndAction = null;
mFeedbackView.clearAnimation();
- mFeedbackView.setAlpha(0);
+ mFeedbackView.setVisibility(View.INVISIBLE);
+ if (releaseFeedbackVideo) {
+ mTutorialFragment.releaseFeedbackVideoView();
+ }
+ }
+
+ void hideFeedbackEndAction() {
+ if (mHideFeedbackEndAction != null) {
+ mHideFeedbackEndAction.run();
+ mHideFeedbackEndAction = null;
+ }
}
void setRippleHotspot(float x, float y) {
@@ -183,38 +238,21 @@
}, RIPPLE_VISIBLE_MS);
}
- void onActionButtonClicked(View button) {}
+ void onActionButtonClicked(View button) {
+ mTutorialFragment.closeTutorial();
+ }
void onActionTextButtonClicked(View button) {}
- void showHandCoachingAnimation() {
- if (isComplete() || mHandCoachingAnimation == null) {
- return;
- }
- mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
- }
-
- void hideHandCoachingAnimation() {
- if (mHandCoachingAnimation == null) {
- return;
- }
- mHandCoachingAnimation.stop();
- mHandCoachingView.setVisibility(View.INVISIBLE);
- }
-
@CallSuper
void transitToController() {
- hideFeedback();
+ hideFeedback(false);
updateTitles();
updateActionButtons();
+ updateDrawables();
- if (isComplete()) {
- hideHandCoachingAnimation();
- } else {
- showHandCoachingAnimation();
- }
- if (mLauncherView != null) {
- mLauncherView.setVisibility(isComplete() ? View.INVISIBLE : View.VISIBLE);
+ if (mFakeLauncherView != null) {
+ mFakeLauncherView.setVisibility(View.INVISIBLE);
}
}
@@ -253,6 +291,24 @@
button.setOnClickListener(listener);
}
+ private void updateDrawables() {
+ if (mContext != null) {
+ mTutorialFragment.getRootView().setBackground(AppCompatResources.getDrawable(
+ mContext, getMockWallpaperResId()));
+ mTutorialFragment.updateFeedbackVideo();
+ mFakeLauncherView.setImageDrawable(AppCompatResources.getDrawable(
+ mContext, getMockLauncherResId()));
+ mFakeTaskView.setBackground(AppCompatResources.getDrawable(
+ mContext, getMockAppTaskThumbnailResId()));
+ mFakeTaskView.animate().alpha(1).setListener(AnimationSuccessListener.forRunnable(
+ () -> mFakeTaskView.animate().cancel()));
+ mFakePreviousTaskView.setBackground(AppCompatResources.getDrawable(
+ mContext, getMockPreviousAppTaskThumbnailResId()));
+ mFakeIconView.setBackground(AppCompatResources.getDrawable(
+ mContext, getMockAppIconResId()));
+ }
+ }
+
private boolean isComplete() {
return mTutorialType == TutorialType.BACK_NAVIGATION_COMPLETE
|| mTutorialType == TutorialType.HOME_NAVIGATION_COMPLETE
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 413387e..6e30ad0 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -15,8 +15,10 @@
*/
package com.android.quickstep.interaction;
+import android.app.Activity;
import android.content.Intent;
import android.graphics.Insets;
+import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
@@ -25,6 +27,7 @@
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowInsets;
+import android.widget.VideoView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -32,6 +35,7 @@
import androidx.fragment.app.FragmentActivity;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.quickstep.interaction.TutorialController.TutorialType;
abstract class TutorialFragment extends Fragment implements OnTouchListener {
@@ -42,9 +46,10 @@
TutorialType mTutorialType;
@Nullable TutorialController mTutorialController = null;
RootSandboxLayout mRootView;
- @Nullable TutorialHandAnimation mHandCoachingAnimation = null;
EdgeBackGestureHandler mEdgeBackGestureHandler;
NavBarGestureHandler mNavBarGestureHandler;
+ private VideoView mFeedbackVideoView;
+ private int mFeedbackVideoDuration;
public static TutorialFragment newInstance(TutorialType tutorialType) {
TutorialFragment fragment = getFragmentForTutorialType(tutorialType);
@@ -83,7 +88,7 @@
return null;
}
- @Nullable Integer getHandAnimationResId() {
+ @Nullable Integer getFeedbackVideoResId() {
return null;
}
@@ -120,30 +125,67 @@
return insets;
});
mRootView.setOnTouchListener(this);
- Integer handAnimationResId = getHandAnimationResId();
- if (handAnimationResId != null) {
- mHandCoachingAnimation =
- new TutorialHandAnimation(getContext(), mRootView, handAnimationResId);
- }
+ mFeedbackVideoView = mRootView.findViewById(R.id.gesture_tutorial_feedback_video);
return mRootView;
}
@Override
+ public void onStart() {
+ super.onStart();
+ initializeFeedbackVideoView();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ releaseFeedbackVideoView();
+ }
+
+ void initializeFeedbackVideoView() {
+ if (!updateFeedbackVideo()) {
+ mFeedbackVideoView.setVisibility(View.INVISIBLE);
+ return;
+ } else {
+ mFeedbackVideoView.setVisibility(View.VISIBLE);
+ }
+ int heightPixels = getResources().getDisplayMetrics().heightPixels;
+ int heightPixelsWithMargin = heightPixels + Utilities.dpToPx(80);
+ int widthPixels = getResources().getDisplayMetrics().widthPixels - Utilities.dpToPx(12);
+ mFeedbackVideoView.setScaleY((float) heightPixelsWithMargin / heightPixels);
+ mFeedbackVideoView.setScaleX((float) heightPixelsWithMargin / widthPixels);
+ mFeedbackVideoView.start();
+ mFeedbackVideoView.setOnPreparedListener(
+ mp -> mFeedbackVideoDuration = mFeedbackVideoView.getDuration());
+ mFeedbackVideoView.setOnCompletionListener(mp -> releaseFeedbackVideoView());
+ }
+
+ boolean updateFeedbackVideo() {
+ Integer feedbackVideoResId = getFeedbackVideoResId();
+ if (feedbackVideoResId == null || getContext() == null) {
+ return false;
+ }
+ Uri uri = Uri.parse("android.resource://" + getContext().getPackageName() + "/"
+ + feedbackVideoResId);
+ mFeedbackVideoView.setVideoURI(uri);
+ return true;
+ }
+
+ void releaseFeedbackVideoView() {
+ mFeedbackVideoView.stopPlayback();
+ mFeedbackVideoView.setVisibility(View.INVISIBLE);
+ }
+
+ int getFeedbackVideoDuration() {
+ return mFeedbackVideoDuration;
+ }
+
+ @Override
public void onResume() {
super.onResume();
changeController(mTutorialType);
}
@Override
- public void onPause() {
- super.onPause();
-
- if (mHandCoachingAnimation != null) {
- mHandCoachingAnimation.stop();
- }
- }
-
- @Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// Note: Using logical-or to ensure both functions get called.
return mEdgeBackGestureHandler.onTouch(view, motionEvent)
@@ -167,10 +209,11 @@
void changeController(TutorialType tutorialType) {
if (getControllerClass().isInstance(mTutorialController)) {
mTutorialController.setTutorialType(tutorialType);
+ mTutorialController.fadeTaskViewAndRun(mTutorialController::transitToController);
} else {
mTutorialController = createController(tutorialType);
+ mTutorialController.transitToController();
}
- mTutorialController.transitToController();
mEdgeBackGestureHandler.registerBackGestureAttemptCallback(mTutorialController);
mNavBarGestureHandler.registerNavBarGestureAttemptCallback(mTutorialController);
mTutorialType = tutorialType;
@@ -186,10 +229,6 @@
return mRootView;
}
- @Nullable TutorialHandAnimation getHandAnimation() {
- return mHandCoachingAnimation;
- }
-
void continueTutorial() {
if (!(getContext() instanceof GestureSandboxActivity)) {
closeTutorial();
@@ -207,6 +246,7 @@
void closeTutorial() {
FragmentActivity activity = getActivity();
if (activity != null) {
+ activity.setResult(Activity.RESULT_OK);
activity.finish();
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialHandAnimation.java b/quickstep/src/com/android/quickstep/interaction/TutorialHandAnimation.java
deleted file mode 100644
index c810e43..0000000
--- a/quickstep/src/com/android/quickstep/interaction/TutorialHandAnimation.java
+++ /dev/null
@@ -1,78 +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.content.Context;
-import android.graphics.drawable.Animatable2;
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.graphics.drawable.Drawable;
-import android.view.View;
-import android.widget.ImageView;
-
-import androidx.core.content.ContextCompat;
-
-import com.android.launcher3.R;
-import com.android.quickstep.interaction.TutorialController.TutorialType;
-
-import java.time.Duration;
-
-/** Hand coaching animation. */
-final class TutorialHandAnimation {
-
- // A delay for waiting the Activity fully launches.
- private static final Duration ANIMATION_START_DELAY = Duration.ofMillis(300L);
-
- private final ImageView mHandCoachingView;
- private final AnimatedVectorDrawable mGestureAnimation;
-
- 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. */
- void startLoopedAnimation(TutorialType tutorialType) {
- mHandCoachingView.setVisibility(View.VISIBLE);
- if (mGestureAnimation.isRunning()) {
- stop();
- }
-
- mGestureAnimation.clearAnimationCallbacks();
- mGestureAnimation.registerAnimationCallback(
- new Animatable2.AnimationCallback() {
- @Override
- public void onAnimationEnd(Drawable drawable) {
- super.onAnimationEnd(drawable);
- mGestureAnimation.start();
- }
- });
- start(tutorialType);
- }
-
- private void start(TutorialType tutorialType) {
- // Because the gesture animation has only the right side form.
- // The left side form of the gesture animation is made from flipping the View.
- float rotationY = tutorialType == TutorialType.LEFT_EDGE_BACK_NAVIGATION ? 180f : 0f;
- mHandCoachingView.setRotationY(rotationY);
- mHandCoachingView.setImageDrawable(mGestureAnimation);
- mHandCoachingView.postDelayed(mGestureAnimation::start, ANIMATION_START_DELAY.toMillis());
- }
-
- void stop() {
- mGestureAnimation.clearAnimationCallbacks();
- mGestureAnimation.stop();
- }
-}
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 0b30253..2c096b4 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -37,7 +37,7 @@
<color name="gesture_tutorial_ripple_color">#A0C2F9</color> <!-- Light Blue -->
<color name="gesture_tutorial_fake_task_view_color">#6DA1FF</color> <!-- Light Blue -->
- <color name="gesture_tutorial_fake_previous_task_view_color">#9CCC65</color> <!-- Light Green -->
+ <color name="gesture_tutorial_fake_previous_task_view_color">#3C4043</color> <!-- Gray -->
<color name="gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
<color name="gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
index 8d676c9..e8695c9 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -276,7 +276,7 @@
launchBackTutorialPreference.setOnPreferenceClickListener(preference -> {
startActivity(launchSandboxIntent.putExtra(
"tutorial_steps",
- new String[] {"RIGHT_EDGE_BACK_NAVIGATION"}));
+ new String[] {"LEFT_EDGE_BACK_NAVIGATION"}));
return true;
});
sandboxCategory.addPreference(launchBackTutorialPreference);