From 4d113a5ff44ff1a7f19263bde21581fbf9a54212 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 27 May 2015 10:05:28 -0700 Subject: [PATCH] Using material style overscroll effect for workspace and folders Bug: 21335369 Change-Id: I53cc6edfa87334b9326f1dedd90c3e2222beade5 --- res/drawable-hdpi/overscroll_glow_left.9.png | Bin 858 -> 0 bytes res/drawable-hdpi/overscroll_glow_right.9.png | Bin 856 -> 0 bytes res/drawable-mdpi/overscroll_glow_left.9.png | Bin 552 -> 0 bytes res/drawable-mdpi/overscroll_glow_right.9.png | Bin 525 -> 0 bytes res/drawable-xhdpi/overscroll_glow_left.9.png | Bin 1249 -> 0 bytes .../overscroll_glow_right.9.png | Bin 1248 -> 0 bytes .../overscroll_glow_left.9.png | Bin 4562 -> 0 bytes .../overscroll_glow_right.9.png | Bin 2738 -> 0 bytes res/values/colors.xml | 3 + src/com/android/launcher3/CellLayout.java | 33 -- .../android/launcher3/FolderPagedView.java | 14 +- src/com/android/launcher3/PagedView.java | 212 ++++------ src/com/android/launcher3/Workspace.java | 44 +-- .../launcher3/util/LauncherEdgeEffect.java | 365 ++++++++++++++++++ .../util/ManagedProfileHeuristic.java | 19 + 15 files changed, 488 insertions(+), 202 deletions(-) delete mode 100644 res/drawable-hdpi/overscroll_glow_left.9.png delete mode 100644 res/drawable-hdpi/overscroll_glow_right.9.png delete mode 100644 res/drawable-mdpi/overscroll_glow_left.9.png delete mode 100644 res/drawable-mdpi/overscroll_glow_right.9.png delete mode 100644 res/drawable-xhdpi/overscroll_glow_left.9.png delete mode 100644 res/drawable-xhdpi/overscroll_glow_right.9.png delete mode 100644 res/drawable-xxhdpi/overscroll_glow_left.9.png delete mode 100644 res/drawable-xxhdpi/overscroll_glow_right.9.png create mode 100644 src/com/android/launcher3/util/LauncherEdgeEffect.java diff --git a/res/drawable-hdpi/overscroll_glow_left.9.png b/res/drawable-hdpi/overscroll_glow_left.9.png deleted file mode 100644 index aaf43c73ab38f09244325767109396fb496435fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 858 zcmV-g1Eu_lP)#?0okANO#EJaD|#N*h1(#lB@5lSfpB#~gHCq-_6MPw=v z5r9oJ=@E2KVEU)Flv3`+7jhM35!nDQfY-otjzH*E7PKQ?G(OWKjWJ%^(=kWy9R0W0 zlJPxRkGvOT7XX}g{u|&k@D=#L5dfJ1+L>b@8%^Jq(a{shdt}l0u`xcIf2(Yc{a!!v zRpw7CJNKQRdfBPY26zX22Y%RrjkX7f)EI6HysmA#RR*UXjC?TigCncFgTwdwhlFQ! z9RmH@j?5;z7QNn4L`IH4ILA-}pa8FcPp5XYvuis-qQ|o`Z`Wi&j{u-$gR1qofvIz} zlf>ag?H144q}N@2T)3R9Tjgsl8%}lo&YtVQd$qSlUCK$vFJ;da0ATv(&pU!}78o71 zt+p4yp2c{9^U$Bkyj{`)Kz3U6==E2+j~DO=;5{Wf9i!89kD)pL@}CN2f1>P>JZDZccaB|mNB<)L zR+>R802WRw02WRw02WRw02WRw02WRw02WR=rq{mNHE=PtzAW-mnsbsEQ3}^4cf|Cw zq>nhfEW1||J%XR`$r4N6H(Pe;#FDpmn=pz}-ChEy@+)tTv*B$j*d{A<-WpSTd4H4v ztt?_Ivl!+6vs7}+X+4?6p7d}F1m1;BPc|_Fs0K>3o~+cnfGg4f5a2iPQ}OCaTGXPvfIGzsbB9_YN=E=mG*Bf8YEV?2ObT$=#U!G}Dkt(^~kU~dV028fK;bGl@w&fM?Ju|M;P=97%IE=x*7W>7T<3`Hh!BGKIwYCh(8a9lZwx kkaBtzd{0KL^!KPd0J!!_DNJge7ytkO07*qoM6N<$f`5{T6#xJL diff --git a/res/drawable-hdpi/overscroll_glow_right.9.png b/res/drawable-hdpi/overscroll_glow_right.9.png deleted file mode 100644 index d03486441a51305a6e1a185dd4c929a7174a1306..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 856 zcmV-e1E>6nP)vZk?YkF*56gX4?zs%T)b0p~Z$YlY))xSjU?fcleEL|IoTk|tI06&3mz=Mb! z$N-?KWrO-a(b$vik~y9{8@Kwly;NrB^zOSv|1u_#TYK)zxaJecY7!;@d;&fIAAx%j z(b3L4MtN<39WYewU}R&(9}LgR$BH*PyuoQBUNr8}$;#~6Y}@l#(DZ_YKn~|Xuzbs- z(Fb@3+yUP?8pWeGN0~YY^^6i3Zglw8`1XA^1#9&jj8Xm=dC~Xa?6Y_DD1B+@RL0`0 zvBBa2U`fU(Ek@qTz%@^+aj{7mzXe{GH4y*?rr(R-$)Rckcn0#K#51;+Sv){Ryd_cH z^S(@M~yYrV|V<6tj4 zWnk&mCz_i9qxUJcR_4Bdc@}`Vk7s}Fcib-hOAW&QEM(6mYo86>G5|Ju0@?tua@qi} za@qi}a@qi}a@qi}a@qi}avJe34|c!{&MQp=ejz9;l}1IMx@a^8>!M1ZHz%v&)deEq zyhPnoG|Kd{@3LpNb8N-5x0u#b3ACkjOEXzi3f=>+fR~9fQAMlnkA~mlG+V{9bF)jG z-b!A}fwrH4xmC)w!4kFJy+HJo%pKhY5bz3}idhi=zB&i>qN{d@=fr&_FPoOjiBeUw z2P^wrdK>5grw14^rYaLC4SLieFz|kLP01y!cR8{MnH>*&DN;}u4 zE6)&1A|y(MSsHCc&UB ztSp+_nist{YkPHQrPkg(y|o!HlSlJB+5{@BI=idY# izY2aG~7^0000Kn#YzNdpy&Zny`m z*l-ih!KvA@LTVmnk&NmZ&#SZuL4V2ejK@hlf8E5MAR>eiFc53FB8wveMdV-*5r7TQ zTStRh(o23VKVHf=caL*EpAbS*yuF%ifk)s0xN(9IGfv4|7|)JPup1M0Ah*P#NGq1z>6UKPM<;T74fd)cu3v*Vt(z*{73V*0im5J|)&m%}A@9(k|ny9f@ga#U8@+z%BVhm=szMN?Po-zAc9` qrykOXa~k;7XFWFjk)rt@A$$U8qC1!j8W+I;0000v1&> z!isw!aR6XeGi}Xc(viot9e1E;1bvbf$8|n^N!6DSGlPhrz&fxY#07!Oj2WXDF!Pdj znOrX?YMY%yE$^rL83FV}Gy<3t#LQDCS!-))PL$H$1?9D7^&?}R$$3WB1g00jBN-(Q6_e#7fG3nmX*>Yl$I$;Dbl#aR7 zdjLm=gdHvyEMq#~T5xMaWC?Fosr~4ykp6vXhpvzzxAr@LJ?1N`2d_<9zpQ>?kEm#u zMtPaOwZCKmbjgC73Fn`_46co=(%`@{c{hRIB=%onBX%Wh#IA&m*p<*>E_Ux=OO8&( zBB>MU;Eeogop{ubS2nQ!{*B6sq?f0E^InOdAg)fCCW?0GP_P;mru^KLYv!4e(H!|10LU P00000NkvXXu0mjfB2(n9 diff --git a/res/drawable-xhdpi/overscroll_glow_left.9.png b/res/drawable-xhdpi/overscroll_glow_left.9.png deleted file mode 100644 index 4f248f70b32ee7b24942abe127fb55ca44b55372..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1249 zcmV<71Rnc|P)NENYExv?F`N&ay=)3j4ciD{ZB zP%0S=8uS2#08A;_1}UXn`S1ckx$!))t*vP9mq8AU(2x^h^QmTL!a{ zO>g~P-&^~9$r!!4+ycNax(Mz9Pbp2n3HTQH3i$3;UIAKBQe4YDyA`{4-EaIM> zciy6Z)NdryI?uLNUeZa|R>gjQ_#xDVLTJAm5 zG);Fnvoh*y7O;NKa%Ql;LVG!5+Y@ z4qF4}WyY)WZ2uSYC*WTU$}2l*6O<#MO8!Bd-_bMw(BBi4 z7N$P7@>BBH+mGGT0P3J!&;aV7UC;pPpk2@a>Y!cF0P3J!&;aV7UC;pPpk2@a>Y!cF z0P3J!&;aV7UC@dCS4}44Jnyp6kM43g@6yS3z0ZzIyPK?M_S#>|=8>A`{ob>FOMX%M znq5}jrWXSJ#qf*cS3i@l*^DA>_59%YMd>9!3*8-gyQd~>Aj)!5TsD{kJE*cgaz|i2 zAXZ0mJ-uB`53KfY0X3QcYeKBeANjm?Q^+GgZCPMmJ62rL0x$Ka2B@>L)$@ShU*had z&_JDUo%?WWOaoDFq|T%>XDd&gW!cfF9G!c>_A-z)q25GG0G2jJOM6*Q@6@;SS}ys~ z@FT$?6A9wnYtJf69_{*y7G6I8UB&W|ETFyz{$#x`u;ms(1H2Znmdw(5nbtcrAU$B} zm7WLmsPwfNuokG^L?5^Z*g@G%$}aOsl@az*e`S5ulecehKZn-b$hZzlJ}Dm-*H>qg z^joNB;0xd#@B{Fc<<*qPiImSu)|)xKOsV~Q0QBmW09y;}s4Uy*(YN@oiMO@?+8)Oq zRmYnH92+eM@Luj)y@h%O{sw*p{sI1Cc{Sx|)s~JNUefChSoUGZ3bw7fo`n_JSPQGB z{?>8m_G`x^vi0mNdrObjM<1?OX>K2&IP>X6KmEh1hID|B)@kwA>!+p-&!$ygvMbf= zjkPzPUi;8b!xvT3_@vJ^w1?QA65|Ve&Ice(w~wUlVW0>7e`)#;WIB^P9k)*Y00000 LNkvXXu0mjfh5lzzT!} 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 diff --git a/res/drawable-xxhdpi/overscroll_glow_right.9.png b/res/drawable-xxhdpi/overscroll_glow_right.9.png deleted file mode 100644 index 5766761452aef49c2ef1526521925101d3998187..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2738 zcmbVOd00~E8fT0gvmBKc8(Tyy%dYH#!bmEhX$E@HF_$a}2*?0s2}H|KN*!BmvY8fb z8MjQlQ{rSnR%2$S*DWzMv!*fBEX6H!9J$zb?;rEbANM@xobUVI^ZtJC{yZlul)A~r z+R+*S0N4Ztl4<63*8I3zS(@Meaq}hS)m1SR4Y4 z#C?n$;f2Pb5m>SZ3Pncyp&%cz%>O5AaI-V;x%T*4tmU1r`V~Qr`Wn-ZN&Y3 zHzr9}a|Uw{TJ;*x2@R&wh?EC|{T;^KH;TtSHCcTtxJ_G!#&q3p+V#N|`TjG6`437G z245bEsd{{i@@LDhV@f&2qzPNmI8~e)vIDK^x%UHF-@mp)At@Urzr7GWyJbYL_Ez=f zt7o*iMMpvri=FnJ=(mU)k(WaMG2J%Kz)jYkZJ$(cJKLiZk)LVz#wO{?YiyMMggQoZTlEy*AmoCcpbwS=c?_lfR(9k2W5M>UlL zzN$$JWK1;scIIW7LIX`NqjQNy>5A;Qz?1=helTdTa$!lk>$g0bdO59Ve~Bu1AM8l{ z<>X%&<8N0@RE0PB61%tedUIUV9giovz{6)0(nd=^=GuyHe?FXfn3J46nXf%k*Jq4v z8MiGMIZU|S;nY0c3Jt0|P~oqxsXO!h?xoH5aGpS2rHxHy0q*q1#m%k?i&*)xfm>1E z>1ZQ%skM`Sr2W~$j6-9FvuaK3qqFLis@!)D@alucDnn?Mb7JM{`oVKuMb(&(uOy}qo=?+U^%~_iPhtjR4ZuQJ|&B4cr7TTtpt|JAT zyFA=}anM5NO9n&R9NLQ){m?<6RSqV1uUoc^tOD{ZSMI3-30pOj&+Hd8Q3A@!4T~e) zffn;KYke@n!Hf5tJ(s`-f!^Pb9?USZTTKz(hX`qx3uP9{d5S`~jf$J)HsRTtTU@1T zsV&oAvtDIc?SPwxTpqr#I^XhM2+gr9QFC-_cDjA15S&&l+1S;a-E3zX^}PFFGdfhy zvh!t%f7AZ4Y2gZv^)ysds81R+Xl?H0a!}RHsM8r8?I^vPy^j_CuW}-}4x25RSVO}o>+OUC8{e-gu z)uzZ}b5d*{3KADJ%Bq|XfSQl#HM1!wxw@cf!EzI`|MZI6>4aB-G14;3UXiIgf4!a6 z(^Y9k#T_jub+r7Ag~FFJ;|sQ{u?1TA{rv_E%Ey6T0xd2Y<|%ybeC(`%hT)_gck-jA zw!Ql1LJhqr>$7~@bV?$VbdU}g`E*XE24fkeZ_udHeEB{&XNnRk-t!9&N}g9qVH&p zscTYvJT4`c!XdcA>LqpJe>N=mLgXbMcA&_{&I+9eBb#l{zZ+|^s z)e=oF2Kl}%x_k5b8lK<7Cy+wd@;E^@uhFGMXY390Iai52;9{TmtmKzsjN4DgE26ah zl_eMZ3LZyvkFj?bwcR}DG*G<&Bb1a;7tyL47QyzrQBCWEk76SALrTXpPnC|N@*Keh zWm|3Qx;}MYZT0VAUgad|nLQEim7P^%@^{ffeQcfXyTocM;)Qi<3N4ex}sK6MH%Wi|A&KbJqGbeNJQ_{woH-8U2e9H2uDvHsRce-UJ2HhK} zTk1C58okmb6)?)43a`v$UovTOophsZ(X$&SIxiVs6AHiImi|pLO>F!7()DQIu|B+; z!`ELgd)07Tg?x3jY8=!Q9NM(~*)^zdqN@@2vK`mg(`{qOuUESjZp?{dR~$18C0{Mc zEXxZ!Hl^pie)C$FFDS&lX$%?e$!@9_37r2d85(f1e$l&h;q%U051P(rG}KQntG=_E zC(B5ls(;t8pMP6{d-6IqwzRQ9o02`_RIh(zxRD`(hk#b+ZQRj?OR{}AcE0J4_+(Wy zAe3V4tf@XUlF42OtN@kH08OFPo%Am)q&240`O5+5iGE7vqt@MXf004{RI-W~m-Ziv C9=Uh` diff --git a/res/values/colors.xml b/res/values/colors.xml index e2b8a2ea76..7d36101ef2 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -29,6 +29,9 @@ #FFF + #FFFFFFFF + #FF757575 + #FF666666 #FFF5F5F5 #FF243036 diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index b5d0dca24c..2cde3d53dc 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -100,17 +100,11 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { private ArrayList mFolderOuterRings = new ArrayList(); private int[] mFolderLeaveBehindCell = {-1, -1}; - private static final float FOREGROUND_ALPHA_DAMPER = 0.65f; - private int mForegroundAlpha = 0; private float mBackgroundAlpha; private static final int BACKGROUND_ACTIVATE_DURATION = 120; private final TransitionDrawable mBackground; - private final Drawable mOverScrollLeft; - private final Drawable mOverScrollRight; - private Drawable mOverScrollForegroundDrawable; - // These values allow a fixed measurement to be set on the CellLayout. private int mFixedWidth = -1; private int mFixedHeight = -1; @@ -218,9 +212,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { mBackground = (TransitionDrawable) res.getDrawable(R.drawable.bg_screenpanel); mBackground.setCallback(this); - mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left); - mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right); - mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE * grid.iconSizePx); @@ -396,19 +387,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { return mDropPending; } - void setOverScrollAmount(float r, boolean left) { - if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { - mOverScrollForegroundDrawable = mOverScrollLeft; - } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) { - mOverScrollForegroundDrawable = mOverScrollRight; - } - - r *= FOREGROUND_ALPHA_DAMPER; - mForegroundAlpha = (int) Math.round((r * 255)); - mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha); - invalidate(); - } - @Override public void setPressedIcon(BubbleTextView icon, Bitmap background) { if (icon == null || background == null) { @@ -553,14 +531,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { } } - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - if (mForegroundAlpha > 0) { - mOverScrollForegroundDrawable.draw(canvas); - } - } - public void showFolderAccept(FolderRingAnimator fra) { mFolderOuterRings.add(fra); } @@ -920,9 +890,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { mBackground.getPadding(mTempRect); mBackground.setBounds(-mTempRect.left, -mTempRect.top, w + mTempRect.right, h + mTempRect.bottom); - - mOverScrollLeft.setBounds(0, 0, w, h); - mOverScrollRight.setBounds(0, 0, w, h); } @Override diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java index b7a5aa8cf2..f2ec1b68c5 100644 --- a/src/com/android/launcher3/FolderPagedView.java +++ b/src/com/android/launcher3/FolderPagedView.java @@ -97,6 +97,8 @@ public class FolderPagedView extends PagedView { mIsRtl = Utilities.isRtl(getResources()); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + + setEdgeGlowColor(getResources().getColor(R.color.folder_edge_effect_color)); } public void setFolder(Folder folder) { @@ -459,16 +461,16 @@ public class FolderPagedView extends PagedView { ? -SCROLL_HINT_FRACTION : SCROLL_HINT_FRACTION; int hint = (int) (fraction * getWidth()); int scroll = getScrollForPage(getNextPage()) + hint; - int delta = scroll - mUnboundedScrollX; + int delta = scroll - getScrollX(); if (delta != 0) { mScroller.setInterpolator(new DecelerateInterpolator()); - mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, Folder.SCROLL_HINT_DURATION); + mScroller.startScroll(getScrollX(), 0, delta, 0, Folder.SCROLL_HINT_DURATION); invalidate(); } } public void clearScrollHint() { - if (mUnboundedScrollX != getScrollForPage(getNextPage())) { + if (getScrollX() != getScrollForPage(getNextPage())) { snapToPage(getNextPage()); } } @@ -667,4 +669,10 @@ public class FolderPagedView extends PagedView { public int itemsPerPage() { return mMaxItemsPerPage; } + + @Override + protected void getEdgeVerticalPostion(int[] pos) { + pos[0] = 0; + pos[1] = getViewportHeight(); + } } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 3d00034ccc..e3cdc29a0f 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -47,7 +47,10 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Interpolator; + +import com.android.launcher3.util.LauncherEdgeEffect; import com.android.launcher3.util.Thunk; + import java.util.ArrayList; /** @@ -63,13 +66,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private static final int MIN_LENGTH_FOR_FLING = 25; protected static final int PAGE_SNAP_ANIMATION_DURATION = 750; - protected static final int OVER_SCROLL_PAGE_SNAP_ANIMATION_DURATION = 350; protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950; protected static final float NANOTIME_DIV = 1000000000.0f; - private static final float OVERSCROLL_ACCELERATE_FACTOR = 2; - private static final float OVERSCROLL_DAMP_FACTOR = 0.07f; - private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f; // The page is moved more than halfway, automatically move to the next page on touch up. private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f; @@ -82,10 +81,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private static final int MIN_SNAP_VELOCITY = 1500; private static final int MIN_FLING_VELOCITY = 250; - // We are disabling touch interaction of the widget region for factory ROM. - private static final boolean DISABLE_TOUCH_INTERACTION = false; - private static final boolean DISABLE_TOUCH_SIDE_PAGES = true; - public static final int INVALID_RESTORE_PAGE = -1001; private boolean mFreeScroll = false; @@ -153,15 +148,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected int mCellCountY = 0; protected boolean mCenterPagesVertically; protected boolean mAllowOverScroll = true; - protected int mUnboundedScrollX; protected int[] mTempVisiblePagesRange = new int[2]; protected boolean mForceDrawAllChildrenNextFrame; - // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise - // it is equal to the scaled overscroll position. We use a separate value so as to prevent - // the screens from continuing to translate beyond the normal bounds. - protected int mOverScrollX; - protected static final int INVALID_POINTER = -1; protected int mActivePointerId = INVALID_POINTER; @@ -192,7 +181,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private float mMinScale = 1f; private boolean mUseMinScale = false; protected View mDragView; - protected AnimatorSet mZoomInOutAnim; private Runnable mSidePageHoverRunnable; @Thunk int mSidePageHoverIndex = -1; // This variable's scope is only for the duration of startReordering() and endReordering() @@ -214,6 +202,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected final Rect mInsets = new Rect(); protected final boolean mIsRtl; + // Edge effect + private final LauncherEdgeEffect mEdgeGlowLeft = new LauncherEdgeEffect(); + private final LauncherEdgeEffect mEdgeGlowRight = new LauncherEdgeEffect(); + public interface PageSwitchListener { void onPageSwitch(View newPage, int newPageIndex); } @@ -262,6 +254,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * mDensity); mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * mDensity); setOnHierarchyChangeListener(this); + setWillNotDraw(false); + } + + protected void setEdgeGlowColor(int color) { + mEdgeGlowLeft.setColor(color); + mEdgeGlowRight.setColor(color); } protected void setDefaultInterpolator(Interpolator interpolator) { @@ -560,7 +558,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc @Override public void scrollBy(int x, int y) { - scrollTo(mUnboundedScrollX + x, getScrollY() + y); + scrollTo(getScrollX() + x, getScrollY() + y); } @Override @@ -578,12 +576,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc x = Math.max(x, mFreeScrollMinScrollX); } - mUnboundedScrollX = x; - boolean isXBeforeFirstPage = mIsRtl ? (x > mMaxScrollX) : (x < 0); boolean isXAfterLastPage = mIsRtl ? (x < 0) : (x > mMaxScrollX); if (isXBeforeFirstPage) { - super.scrollTo(0, y); + super.scrollTo(mIsRtl ? mMaxScrollX : 0, y); if (mAllowOverScroll) { mWasInOverscroll = true; if (mIsRtl) { @@ -593,7 +589,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } } else if (isXAfterLastPage) { - super.scrollTo(mMaxScrollX, y); + super.scrollTo(mIsRtl ? 0 : mMaxScrollX, y); if (mAllowOverScroll) { mWasInOverscroll = true; if (mIsRtl) { @@ -607,7 +603,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc overScroll(0); mWasInOverscroll = false; } - mOverScrollX = x; super.scrollTo(x, y); } @@ -646,8 +641,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (mScroller.computeScrollOffset()) { // Don't bother scrolling if the page does not need to be moved if (getScrollX() != mScroller.getCurrX() - || getScrollY() != mScroller.getCurrY() - || mOverScrollX != mScroller.getCurrX()) { + || getScrollY() != mScroller.getCurrY()) { float scaleX = mFreeScroll ? getScaleX() : 1f; int scrollX = (int) (mScroller.getCurrX() * (1 / scaleX)); scrollTo(scrollX, mScroller.getCurrY()); @@ -978,21 +972,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc requestLayout(); } - protected void screenScrolled(int screenCenter) { - boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX; - - if (mFadeInAdjacentScreens && !isInOverscroll) { - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - if (child != null) { - float scrollProgress = getScrollProgress(screenCenter, child, i); - float alpha = 1 - Math.abs(scrollProgress); - child.setAlpha(alpha); - } - } - invalidate(); - } - } + /** + * Called when the center screen changes during scrolling. + */ + protected void screenScrolled(int screenCenter) { } @Override public void onChildViewAdded(View parent, View child) { @@ -1129,9 +1112,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc final int pageCount = getChildCount(); if (pageCount > 0) { int halfScreenSize = getViewportWidth() / 2; - // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. - // Otherwise it is equal to the scaled overscroll position. - int screenCenter = mOverScrollX + halfScreenSize; + int screenCenter = getScrollX() + halfScreenSize; if (screenCenter != mLastScreenCenter || mForceScreenScrolled) { // set mForceScreenScrolled before calling screenScrolled so that screenScrolled can @@ -1171,6 +1152,47 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + if (getPageCount() > 0) { + if (!mEdgeGlowLeft.isFinished()) { + final int restoreCount = canvas.save(); + Rect display = mViewport; + canvas.translate(display.left, display.top); + canvas.rotate(270); + + getEdgeVerticalPostion(sTmpIntPoint); + canvas.translate(display.top - sTmpIntPoint[1], 0); + mEdgeGlowLeft.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], display.width()); + if (mEdgeGlowLeft.draw(canvas)) { + postInvalidateOnAnimation(); + } + canvas.restoreToCount(restoreCount); + } + if (!mEdgeGlowRight.isFinished()) { + final int restoreCount = canvas.save(); + Rect display = mViewport; + canvas.translate(display.left + + display.width() * (getChildCount() - 1), display.top); + canvas.rotate(90); + + getEdgeVerticalPostion(sTmpIntPoint); + canvas.translate(sTmpIntPoint[0] - display.top, -display.width()); + mEdgeGlowRight.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], display.width()); + if (mEdgeGlowRight.draw(canvas)) { + postInvalidateOnAnimation(); + } + canvas.restoreToCount(restoreCount); + } + } + } + + /** + * Returns the top and bottom position for the edge effect. + */ + protected abstract void getEdgeVerticalPostion(int[] pos); + @Override public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { int page = indexToPage(indexOfChild(child)); @@ -1303,10 +1325,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - if (DISABLE_TOUCH_INTERACTION) { - return false; - } - /* * This method JUST determines whether we want to intercept the motion. * If we return true, onTouchEvent will be called and we do the actual @@ -1383,19 +1401,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } - // check if this can be the beginning of a tap on the side of the pages - // to scroll the current page - if (!DISABLE_TOUCH_SIDE_PAGES) { - if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) { - if (getChildCount() > 0) { - if (hitsPreviousPage(x, y)) { - mTouchState = TOUCH_STATE_PREV_PAGE; - } else if (hitsNextPage(x, y)) { - mTouchState = TOUCH_STATE_NEXT_PAGE; - } - } - } - } break; } @@ -1515,49 +1520,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } - // This curve determines how the effect of scrolling over the limits of the page dimishes - // as the user pulls further and further from the bounds - private float overScrollInfluenceCurve(float f) { - f -= 1.0f; - return f * f * f + 1.0f; - } - - protected float acceleratedOverFactor(float amount) { - int screenSize = getViewportWidth(); - - // We want to reach the max over scroll effect when the user has - // over scrolled half the size of the screen - float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize); - - if (f == 0) return 0; - - // Clamp this factor, f, to -1 < f < 1 - if (Math.abs(f) >= 1) { - f /= Math.abs(f); - } - return f; - } - protected void dampedOverScroll(float amount) { int screenSize = getViewportWidth(); - float f = (amount / screenSize); - - if (f == 0) return; - f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f))); - - // Clamp this factor, f, to -1 < f < 1 - if (Math.abs(f) >= 1) { - f /= Math.abs(f); - } - - int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize); - if (amount < 0) { - mOverScrollX = overScrollAmount; - super.scrollTo(mOverScrollX, getScrollY()); + if (f < 0) { + mEdgeGlowLeft.onPull(-f); + } else if (f > 0) { + mEdgeGlowRight.onPull(f); } else { - mOverScrollX = mMaxScrollX + overScrollAmount; - super.scrollTo(mOverScrollX, getScrollY()); + return; } invalidate(); } @@ -1566,14 +1537,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc dampedOverScroll(amount); } - protected float maxOverScroll() { - // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not - // exceed). Used to find out how much extra wallpaper we need for the over scroll effect - float f = 1.0f; - f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f))); - return OVERSCROLL_DAMP_FACTOR * f; - } - public void enableFreeScroll() { setEnableFreeScroll(true); } @@ -1636,10 +1599,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc @Override public boolean onTouchEvent(MotionEvent ev) { - if (DISABLE_TOUCH_INTERACTION) { - return false; - } - super.onTouchEvent(ev); // Skip touch handling if there are no pages to swipe @@ -1912,6 +1871,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mCancelTap = false; mTouchState = TOUCH_STATE_REST; mActivePointerId = INVALID_POINTER; + mEdgeGlowLeft.onRelease(); + mEdgeGlowRight.onRelease(); } /** @@ -2020,20 +1981,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return minDistanceFromScreenCenterIndex; } - protected boolean isInOverScroll() { - return (mOverScrollX > mMaxScrollX || mOverScrollX < 0); - } - - protected int getPageSnapDuration() { - if (isInOverScroll()) { - return OVER_SCROLL_PAGE_SNAP_ANIMATION_DURATION; - } - return PAGE_SNAP_ANIMATION_DURATION; - - } - protected void snapToDestination() { - snapToPage(getPageNearestToCenterOfScreen(), getPageSnapDuration()); + snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION); } private static class ScrollInterpolator implements Interpolator { @@ -2050,7 +1999,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // the screen has to travel, however, we don't want this duration to be effected in a // purely linear fashion. Instead, we use this method to moderate the effect that the distance // of travel has on the overall snap duration. - float distanceInfluenceForSnapDuration(float f) { + private float distanceInfluenceForSnapDuration(float f) { f -= 0.5f; // center the values about 0. f *= 0.3f * Math.PI / 2.0f; return (float) Math.sin(f); @@ -2061,13 +2010,13 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc int halfScreenSize = getViewportWidth() / 2; final int newX = getScrollForPage(whichPage); - int delta = newX - mUnboundedScrollX; + int delta = newX - getScrollX(); int duration = 0; - if (Math.abs(velocity) < mMinFlingVelocity || isInOverScroll()) { + if (Math.abs(velocity) < mMinFlingVelocity) { // If the velocity is low enough, then treat this more as an automatic page advance // as opposed to an apparent physical response to flinging - snapToPage(whichPage, getPageSnapDuration()); + snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); return; } @@ -2091,11 +2040,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } public void snapToPage(int whichPage) { - snapToPage(whichPage, getPageSnapDuration()); + snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); } protected void snapToPageImmediately(int whichPage) { - snapToPage(whichPage, getPageSnapDuration(), true, null); + snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true, null); } protected void snapToPage(int whichPage, int duration) { @@ -2111,8 +2060,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc whichPage = validateNewPage(whichPage); int newX = getScrollForPage(whichPage); - final int sX = mUnboundedScrollX; - final int delta = newX - sX; + final int delta = newX - getScrollX(); snapToPage(whichPage, delta, duration, immediate, interpolator); } @@ -2149,7 +2097,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mScroller.setInterpolator(mDefaultInterpolator); } - mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration); + mScroller.startScroll(getScrollX(), 0, delta, 0, duration); updatePageIndicator(); @@ -2221,7 +2169,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } // Animate the drag view back to the original position - void animateDragViewToOriginalPosition() { + private void animateDragViewToOriginalPosition() { if (mDragView != null) { AnimatorSet anim = new AnimatorSet(); anim.setDuration(REORDERING_DROP_REPOSITION_DURATION); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 76f872bae1..fb0a54d3c2 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -197,7 +197,6 @@ public class Workspace extends PagedView private static final Rect sTempRect = new Rect(); private final int[] mTempXY = new int[2]; private int[] mTempVisiblePagesRange = new int[2]; - private boolean mOverscrollEffectSet; public static final int DRAG_BITMAP_PADDING = 2; private boolean mWorkspaceFadeInAdjacentScreens; @@ -257,8 +256,6 @@ public class Workspace extends PagedView private float mCurrentScale; private float mTransitionProgress; - float mOverScrollEffect = 0f; - @Thunk Runnable mDeferredAction; private boolean mDeferDropAfterUninstall; private boolean mUninstallSuccessful; @@ -443,6 +440,8 @@ public class Workspace extends PagedView // Set the wallpaper dimensions when Launcher starts up setWallpaperDimension(); + + setEdgeGlowColor(getResources().getColor(R.color.workspace_edge_effect_color)); } private void setupLayoutTransition() { @@ -1260,9 +1259,6 @@ public class Workspace extends PagedView mLauncherOverlay.onScrollChange(progress, mIsRtl); } else if (shouldOverScroll) { dampedOverScroll(amount); - mOverScrollEffect = acceleratedOverFactor(amount); - } else { - mOverScrollEffect = 0; } if (shouldZeroOverlay) { @@ -1270,6 +1266,13 @@ public class Workspace extends PagedView } } + @Override + protected void getEdgeVerticalPostion(int[] pos) { + View child = getChildAt(getPageCount() - 1); + pos[0] = child.getTop(); + pos[1] = child.getBottom(); + } + @Override protected void notifyPageSwitchListener() { super.notifyPageSwitchListener(); @@ -1540,11 +1543,9 @@ public class Workspace extends PagedView } private void updatePageAlphaValues(int screenCenter) { - boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX; if (mWorkspaceFadeInAdjacentScreens && !workspaceInModalState() && - !mIsSwitchingState && - !isInOverscroll) { + !mIsSwitchingState) { for (int i = numCustomPages(); i < getChildCount(); i++) { CellLayout child = (CellLayout) getChildAt(i); if (child != null) { @@ -1654,34 +1655,9 @@ public class Workspace extends PagedView @Override protected void screenScrolled(int screenCenter) { - super.screenScrolled(screenCenter); - updatePageAlphaValues(screenCenter); updateStateForCustomContent(screenCenter); enableHwLayersOnVisiblePages(); - - boolean shouldOverScroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX; - - if (shouldOverScroll) { - int index = 0; - final int lowerIndex = 0; - final int upperIndex = getChildCount() - 1; - - final boolean isLeftPage = mOverScrollX < 0; - index = (!mIsRtl && isLeftPage) || (mIsRtl && !isLeftPage) ? lowerIndex : upperIndex; - - CellLayout cl = (CellLayout) getChildAt(index); - float effect = Math.abs(mOverScrollEffect); - cl.setOverScrollAmount(Math.abs(effect), isLeftPage); - - mOverscrollEffectSet = true; - } else { - if (mOverscrollEffectSet && getChildCount() > 0) { - mOverscrollEffectSet = false; - ((CellLayout) getChildAt(0)).setOverScrollAmount(0, false); - ((CellLayout) getChildAt(getChildCount() - 1)).setOverScrollAmount(0, false); - } - } } protected void onAttachedToWindow() { diff --git a/src/com/android/launcher3/util/LauncherEdgeEffect.java b/src/com/android/launcher3/util/LauncherEdgeEffect.java new file mode 100644 index 0000000000..3e3b255add --- /dev/null +++ b/src/com/android/launcher3/util/LauncherEdgeEffect.java @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2015 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.launcher3.util; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.view.animation.AnimationUtils; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; + +/** + * This class differs from the framework {@link android.widget.EdgeEffect}: + * 1) It does not use PorterDuffXfermode + * 2) The width to radius factor is smaller (0.5 instead of 0.75) + */ +public class LauncherEdgeEffect { + + // Time it will take the effect to fully recede in ms + private static final int RECEDE_TIME = 600; + + // Time it will take before a pulled glow begins receding in ms + private static final int PULL_TIME = 167; + + // Time it will take in ms for a pulled glow to decay to partial strength before release + private static final int PULL_DECAY_TIME = 2000; + + private static final float MAX_ALPHA = 0.5f; + + private static final float MAX_GLOW_SCALE = 2.f; + + private static final float PULL_GLOW_BEGIN = 0.f; + + // Minimum velocity that will be absorbed + private static final int MIN_VELOCITY = 100; + // Maximum velocity, clamps at this value + private static final int MAX_VELOCITY = 10000; + + private static final float EPSILON = 0.001f; + + private static final double ANGLE = Math.PI / 6; + private static final float SIN = (float) Math.sin(ANGLE); + private static final float COS = (float) Math.cos(ANGLE); + + private float mGlowAlpha; + private float mGlowScaleY; + + private float mGlowAlphaStart; + private float mGlowAlphaFinish; + private float mGlowScaleYStart; + private float mGlowScaleYFinish; + + private long mStartTime; + private float mDuration; + + private final Interpolator mInterpolator; + + private static final int STATE_IDLE = 0; + private static final int STATE_PULL = 1; + private static final int STATE_ABSORB = 2; + private static final int STATE_RECEDE = 3; + private static final int STATE_PULL_DECAY = 4; + + private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f; + + private static final int VELOCITY_GLOW_FACTOR = 6; + + private int mState = STATE_IDLE; + + private float mPullDistance; + + private final Rect mBounds = new Rect(); + private final Paint mPaint = new Paint(); + private float mRadius; + private float mBaseGlowScale; + private float mDisplacement = 0.5f; + private float mTargetDisplacement = 0.5f; + + /** + * Construct a new EdgeEffect with a theme appropriate for the provided context. + */ + public LauncherEdgeEffect() { + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.FILL); + mInterpolator = new DecelerateInterpolator(); + } + + /** + * Set the size of this edge effect in pixels. + * + * @param width Effect width in pixels + * @param height Effect height in pixels + */ + public void setSize(int width, int height) { + final float r = width * 0.5f / SIN; + final float y = COS * r; + final float h = r - y; + final float or = height * 0.75f / SIN; + final float oy = COS * or; + final float oh = or - oy; + + mRadius = r; + mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f; + + mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h)); + } + + /** + * Reports if this EdgeEffect's animation is finished. If this method returns false + * after a call to {@link #draw(Canvas)} the host widget should schedule another + * drawing pass to continue the animation. + * + * @return true if animation is finished, false if drawing should continue on the next frame. + */ + public boolean isFinished() { + return mState == STATE_IDLE; + } + + /** + * Immediately finish the current animation. + * After this call {@link #isFinished()} will return true. + */ + public void finish() { + mState = STATE_IDLE; + } + + /** + * A view should call this when content is pulled away from an edge by the user. + * This will update the state of the current visual effect and its associated animation. + * The host view should always {@link android.view.View#invalidate()} after this + * and draw the results accordingly. + * + *

Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement + * of the pull point is known.

+ * + * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to + * 1.f (full length of the view) or negative values to express change + * back toward the edge reached to initiate the effect. + */ + public void onPull(float deltaDistance) { + onPull(deltaDistance, 0.5f); + } + + /** + * A view should call this when content is pulled away from an edge by the user. + * This will update the state of the current visual effect and its associated animation. + * The host view should always {@link android.view.View#invalidate()} after this + * and draw the results accordingly. + * + * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to + * 1.f (full length of the view) or negative values to express change + * back toward the edge reached to initiate the effect. + * @param displacement The displacement from the starting side of the effect of the point + * initiating the pull. In the case of touch this is the finger position. + * Values may be from 0-1. + */ + public void onPull(float deltaDistance, float displacement) { + final long now = AnimationUtils.currentAnimationTimeMillis(); + mTargetDisplacement = displacement; + if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) { + return; + } + if (mState != STATE_PULL) { + mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY); + } + mState = STATE_PULL; + + mStartTime = now; + mDuration = PULL_TIME; + + mPullDistance += deltaDistance; + + final float absdd = Math.abs(deltaDistance); + mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA, + mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR)); + + if (mPullDistance == 0) { + mGlowScaleY = mGlowScaleYStart = 0; + } else { + final float scale = (float) (Math.max(0, 1 - 1 / + Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d); + + mGlowScaleY = mGlowScaleYStart = scale; + } + + mGlowAlphaFinish = mGlowAlpha; + mGlowScaleYFinish = mGlowScaleY; + } + + /** + * Call when the object is released after being pulled. + * This will begin the "decay" phase of the effect. After calling this method + * the host view should {@link android.view.View#invalidate()} and thereby + * draw the results accordingly. + */ + public void onRelease() { + mPullDistance = 0; + + if (mState != STATE_PULL && mState != STATE_PULL_DECAY) { + return; + } + + mState = STATE_RECEDE; + mGlowAlphaStart = mGlowAlpha; + mGlowScaleYStart = mGlowScaleY; + + mGlowAlphaFinish = 0.f; + mGlowScaleYFinish = 0.f; + + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mDuration = RECEDE_TIME; + } + + /** + * Call when the effect absorbs an impact at the given velocity. + * Used when a fling reaches the scroll boundary. + * + *

When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller}, + * the method getCurrVelocity will provide a reasonable approximation + * to use here.

+ * + * @param velocity Velocity at impact in pixels per second. + */ + public void onAbsorb(int velocity) { + mState = STATE_ABSORB; + velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY); + + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mDuration = 0.15f + (velocity * 0.02f); + + // The glow depends more on the velocity, and therefore starts out + // nearly invisible. + mGlowAlphaStart = 0.3f; + mGlowScaleYStart = Math.max(mGlowScaleY, 0.f); + + + // Growth for the size of the glow should be quadratic to properly + // respond + // to a user's scrolling speed. The faster the scrolling speed, the more + // intense the effect should be for both the size and the saturation. + mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f); + // Alpha should change for the glow as well as size. + mGlowAlphaFinish = Math.max( + mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); + mTargetDisplacement = 0.5f; + } + + /** + * Set the color of this edge effect in argb. + * + * @param color Color in argb + */ + public void setColor(int color) { + mPaint.setColor(color); + } + + /** + * Return the color of this edge effect in argb. + * @return The color of this edge effect in argb + */ + public int getColor() { + return mPaint.getColor(); + } + + /** + * Draw into the provided canvas. Assumes that the canvas has been rotated + * accordingly and the size has been set. The effect will be drawn the full + * width of X=0 to X=width, beginning from Y=0 and extending to some factor < + * 1.f of height. + * + * @param canvas Canvas to draw into + * @return true if drawing should continue beyond this frame to continue the + * animation + */ + public boolean draw(Canvas canvas) { + update(); + + final float centerX = mBounds.centerX(); + final float centerY = mBounds.height() - mRadius; + + canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, centerX, 0); + + final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f; + float translateX = mBounds.width() * displacement / 2; + mPaint.setAlpha((int) (0xff * mGlowAlpha)); + canvas.drawCircle(centerX + translateX, centerY, mRadius, mPaint); + + boolean oneLastFrame = false; + if (mState == STATE_RECEDE && mGlowScaleY == 0) { + mState = STATE_IDLE; + oneLastFrame = true; + } + + return mState != STATE_IDLE || oneLastFrame; + } + + /** + * Return the maximum height that the edge effect will be drawn at given the original + * {@link #setSize(int, int) input size}. + * @return The maximum height of the edge effect + */ + public int getMaxHeight() { + return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f); + } + + private void update() { + final long time = AnimationUtils.currentAnimationTimeMillis(); + final float t = Math.min((time - mStartTime) / mDuration, 1.f); + + final float interp = mInterpolator.getInterpolation(t); + + mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp; + mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp; + mDisplacement = (mDisplacement + mTargetDisplacement) / 2; + + if (t >= 1.f - EPSILON) { + switch (mState) { + case STATE_ABSORB: + mState = STATE_RECEDE; + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mDuration = RECEDE_TIME; + + mGlowAlphaStart = mGlowAlpha; + mGlowScaleYStart = mGlowScaleY; + + // After absorb, the glow should fade to nothing. + mGlowAlphaFinish = 0.f; + mGlowScaleYFinish = 0.f; + break; + case STATE_PULL: + mState = STATE_PULL_DECAY; + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mDuration = PULL_DECAY_TIME; + + mGlowAlphaStart = mGlowAlpha; + mGlowScaleYStart = mGlowScaleY; + + // After pull, the glow should fade to nothing. + mGlowAlphaFinish = 0.f; + mGlowScaleYFinish = 0.f; + break; + case STATE_PULL_DECAY: + mState = STATE_RECEDE; + break; + case STATE_RECEDE: + mState = STATE_IDLE; + break; + } + } + } +} diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java index 94dc47f096..b37f44719d 100644 --- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java +++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java @@ -1,10 +1,28 @@ +/* + * Copyright (C) 2015 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.launcher3.util; +import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Build; import android.util.Log; import com.android.launcher3.FolderInfo; @@ -32,6 +50,7 @@ import java.util.Set; * Handles addition of app shortcuts for managed profiles. * Methods of class should only be called on {@link LauncherModel#sWorkerThread}. */ +@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class ManagedProfileHeuristic { private static final String TAG = "ManagedProfileHeuristic";