mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-27 15:26:58 +00:00
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
This commit is contained in:
10
quickstep/res/drawable/bg_sandbox_feedback.xml
Normal file
10
quickstep/res/drawable/bg_sandbox_feedback.xml
Normal file
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
21
quickstep/res/drawable/default_sandbox_mock_launcher.xml
Normal file
21
quickstep/res/drawable/default_sandbox_mock_launcher.xml
Normal file
@@ -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>
|
||||
79
quickstep/res/drawable/sandbox_fake_google_search.xml
Normal file
79
quickstep/res/drawable/sandbox_fake_google_search.xml
Normal file
@@ -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>
|
||||
@@ -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 -->
|
||||
|
||||
BIN
quickstep/res/raw/tips_nav_back_left.mp4
Normal file
BIN
quickstep/res/raw/tips_nav_back_left.mp4
Normal file
Binary file not shown.
BIN
quickstep/res/raw/tips_nav_back_right.mp4
Normal file
BIN
quickstep/res/raw/tips_nav_back_right.mp4
Normal file
Binary file not shown.
BIN
quickstep/res/raw/tips_nav_home.mp4
Normal file
BIN
quickstep/res/raw/tips_nav_home.mp4
Normal file
Binary file not shown.
BIN
quickstep/res/raw/tips_nav_overview.mp4
Normal file
BIN
quickstep/res/raw/tips_nav_overview.mp4
Normal file
Binary file not shown.
@@ -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"
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.quickstep.interaction;
|
||||
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;
|
||||
@@ -59,11 +58,6 @@ final class AssistantGestureTutorialController extends TutorialController {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void onActionButtonClicked(View button) {
|
||||
mTutorialFragment.closeTutorial();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackGestureAttempted(BackGestureResult result) {
|
||||
switch (mTutorialType) {
|
||||
@@ -101,8 +95,7 @@ final class AssistantGestureTutorialController extends TutorialController {
|
||||
showFeedback(R.string.assistant_gesture_feedback_swipe_too_far_from_corner);
|
||||
break;
|
||||
case ASSISTANT_COMPLETED:
|
||||
hideFeedback();
|
||||
hideHandCoachingAnimation();
|
||||
hideFeedback(true);
|
||||
showRippleEffect(
|
||||
() -> {
|
||||
if (mTutorialFragment.isTutorialComplete()) {
|
||||
|
||||
@@ -18,16 +18,10 @@ 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;
|
||||
|
||||
/** 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);
|
||||
|
||||
@@ -17,10 +17,14 @@ package com.android.quickstep.interaction;
|
||||
|
||||
import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION_COMPLETE;
|
||||
import static com.android.quickstep.interaction.TutorialController.TutorialType.LEFT_EDGE_BACK_NAVIGATION;
|
||||
import 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;
|
||||
@@ -72,16 +76,17 @@ final class BackGestureTutorialController extends TutorialController {
|
||||
return null;
|
||||
}
|
||||
|
||||
@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 @@ 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));
|
||||
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 @@ final class BackGestureTutorialController extends TutorialController {
|
||||
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 @@ final class BackGestureTutorialController extends TutorialController {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,19 @@ package com.android.quickstep.interaction;
|
||||
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
|
||||
|
||||
@@ -145,6 +145,7 @@ public class GestureSandboxActivity extends FragmentActivity {
|
||||
| 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);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import static com.android.quickstep.interaction.TutorialController.TutorialType.
|
||||
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;
|
||||
@@ -61,11 +60,6 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void onActionButtonClicked(View button) {
|
||||
mTutorialFragment.closeTutorial();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackGestureAttempted(BackGestureResult result) {
|
||||
switch (mTutorialType) {
|
||||
@@ -90,17 +84,16 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
|
||||
|
||||
@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 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
void onActionButtonClicked(View button) {
|
||||
mTutorialFragment.closeTutorial();
|
||||
public View getMockLauncherView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,12 +99,17 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
|
||||
|
||||
@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 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.android.quickstep.interaction;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -49,11 +48,6 @@ public class SandboxModeTutorialController extends SwipeUpGestureTutorialControl
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void onActionButtonClicked(View button) {
|
||||
mTutorialFragment.closeTutorial();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackGestureAttempted(BackGestureResult result) {
|
||||
switch (result) {
|
||||
@@ -87,7 +81,7 @@ public class SandboxModeTutorialController extends SwipeUpGestureTutorialControl
|
||||
});
|
||||
break;
|
||||
case OVERVIEW_GESTURE_COMPLETED:
|
||||
fadeOutFakeTaskView(true, () -> {
|
||||
fadeOutFakeTaskView(true, true, () -> {
|
||||
showFeedback(R.string.sandbox_mode_overview_gesture_feedback_successful);
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -27,17 +27,15 @@ import android.animation.AnimatorListenerAdapter;
|
||||
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;
|
||||
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 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
|
||||
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 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
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 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
}
|
||||
|
||||
/** 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 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
@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 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
}
|
||||
});
|
||||
} 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 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
if (mShowPreviousTasks) {
|
||||
mFakePreviousTaskView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (mRunningWindowAnim == null) {
|
||||
if (mRunningWindowAnim == null && displacement != null) {
|
||||
mTaskViewSwipeUpAnimation.updateDisplacement(displacement);
|
||||
}
|
||||
}
|
||||
@@ -196,6 +237,9 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
|
||||
@Override
|
||||
public void onMotionPaused(boolean unused) {
|
||||
if (mHideFeedbackEndAction != null) {
|
||||
return;
|
||||
}
|
||||
if (mShowTasks) {
|
||||
if (!mShowPreviousTasks) {
|
||||
mFakePreviousTaskView.setTranslationX(
|
||||
@@ -253,9 +297,9 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
@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);
|
||||
|
||||
@@ -19,17 +19,21 @@ import android.content.Context;
|
||||
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 @@ 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 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 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
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 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
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) {
|
||||
@@ -126,6 +119,11 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
return null;
|
||||
}
|
||||
|
||||
@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 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
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 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
}, 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 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
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.Fragment;
|
||||
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 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
||||
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 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable Integer getHandAnimationResId() {
|
||||
@Nullable Integer getFeedbackVideoResId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -120,29 +125,66 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
||||
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.
|
||||
@@ -167,10 +209,11 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
||||
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 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
@Nullable TutorialHandAnimation getHandAnimation() {
|
||||
return mHandCoachingAnimation;
|
||||
}
|
||||
|
||||
void continueTutorial() {
|
||||
if (!(getContext() instanceof GestureSandboxActivity)) {
|
||||
closeTutorial();
|
||||
@@ -207,6 +246,7 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
||||
void closeTutorial() {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
activity.setResult(Activity.RESULT_OK);
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 -->
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user