From 96ac68a481ce5b794b5227e09ace7c30d6dd5e7b Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 2 Feb 2017 16:37:21 -0800 Subject: [PATCH] Updating the PreloadIconDrawable > The drawable gets the path from MaskIconDrawable path, instead of using a circle > The progress changes are animated as well Bug: 34831873 Change-Id: I4e7f0b610f4fd94de8e0cfcf8b179b775cf0b4d8 --- res/drawable-hdpi/virtual_preload.9.png | Bin 2353 -> 0 bytes .../virtual_preload_folder.9.png | Bin 1187 -> 0 bytes res/drawable-mdpi/virtual_preload.9.png | Bin 1599 -> 0 bytes .../virtual_preload_folder.9.png | Bin 847 -> 0 bytes res/drawable-v26/mask_drawable_wrapper.xml | 22 ++ res/drawable-xhdpi/virtual_preload.9.png | Bin 3726 -> 0 bytes .../virtual_preload_folder.9.png | Bin 1655 -> 0 bytes res/drawable-xxhdpi/virtual_preload.9.png | Bin 6802 -> 0 bytes .../virtual_preload_folder.9.png | Bin 2986 -> 0 bytes res/values/attrs.xml | 6 - res/values/colors.xml | 1 - res/values/styles.xml | 13 - src/com/android/launcher3/BubbleTextView.java | 26 +- .../android/launcher3/FastBitmapDrawable.java | 2 +- .../launcher3/PendingAppWidgetHostView.java | 19 +- .../launcher3/PreloadIconDrawable.java | 252 --------------- src/com/android/launcher3/Workspace.java | 1 + .../android/launcher3/folder/FolderIcon.java | 13 +- .../graphics/DragPreviewProvider.java | 5 - .../launcher3/graphics/DrawableFactory.java | 41 ++- .../graphics/FixedScaleDrawable.java | 41 +++ .../launcher3/graphics/IconPalette.java | 42 ++- .../launcher3/graphics/LauncherIcons.java | 20 +- .../graphics/PreloadIconDrawable.java | 289 ++++++++++++++++++ 24 files changed, 443 insertions(+), 350 deletions(-) delete mode 100644 res/drawable-hdpi/virtual_preload.9.png delete mode 100644 res/drawable-hdpi/virtual_preload_folder.9.png delete mode 100644 res/drawable-mdpi/virtual_preload.9.png delete mode 100644 res/drawable-mdpi/virtual_preload_folder.9.png create mode 100644 res/drawable-v26/mask_drawable_wrapper.xml delete mode 100644 res/drawable-xhdpi/virtual_preload.9.png delete mode 100644 res/drawable-xhdpi/virtual_preload_folder.9.png delete mode 100644 res/drawable-xxhdpi/virtual_preload.9.png delete mode 100644 res/drawable-xxhdpi/virtual_preload_folder.9.png delete mode 100644 src/com/android/launcher3/PreloadIconDrawable.java create mode 100644 src/com/android/launcher3/graphics/FixedScaleDrawable.java create mode 100644 src/com/android/launcher3/graphics/PreloadIconDrawable.java diff --git a/res/drawable-hdpi/virtual_preload.9.png b/res/drawable-hdpi/virtual_preload.9.png deleted file mode 100644 index 670088f84df3f4bddc0bccffeff4079c287eae22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2353 zcmV-13C{M3P)TgR2(ihlav{qGILXg<=reZ<1jNbGnbh$P{`Do);XDzbG*E4E{^pO<$dgv(#PfQYhu0r3R{gQ2ZSklUKl(fHpb{(mg;1d)PZ zyz9zqX@`3>RCvaFXSXczt^CXSzie!4>wPO*mUw4-#y3!3Y(K){Je<1PknN+LL}#vZ?ayEYcUc zx5@ocHjPM3APC@r1kc2dPt&vT<8pTvoUp>km6p_&U2+f8RA1sqRyf^RAD4R;Ui6fS z443@WPfek7Qh@=>x!uHFq&CBU6O;Z+Iz#<93e&qDdriY)JHYz>rG0+*0QR$~N z{qWBIkrOOZ5bPFb%L01v?h$Z=KL!ED!?AmWrsNB5A&jsg*pKbr`D9MtD~BBl7@{c* z3heKd(=zIv|6@B?xDc$uTm4`qs}W^kkYRnRpN27mR6HCA<;+Mz*fAJZNQjk4 zu)bHWS*npx!hw+X-AE7GKN5Dxh^5G|?bklQLpMMQ6@opJNlRP9)R-d>hMg>xZ|yUg zU_nEWHjqL$S5HWdsygea_=MEvYEtkD6Ik#N@<~1?ed}-O0!_8zfML9)3!PU^mO~B} zg58_yTgMf82rMulUSfb{#}GO^-J1#)9E9?z+kfl%MR_jBh^NSTuJeohefiW4B^U_y zdLG$@2fITBLp+5+eXu+A=FNPt&Oy*PRB@{`1=ctt5Qep3s=q&}_SupcInQM<1UGDH#izA`fS zKTH4%3?Uuv&+XEJxafn9UYzI0fy4bF1%^=1b4S3Y0Z<{5sGA1x4|g8aKoIPYspJA) zno7jNh_p17+-TJsZM*K@ z8X=-+TCwdqNdF%~K0erg(UH+mA)=^9M*I7Bd@$ty522i%)*gD{hU{c4J!5bUcd znvpf@K+yhmjSGUxvIN@8>O#;l5Eh6k7V6=Z4k7+@TI1@(bRxyBNd|+EQj;85u}#fO z`Q9W)Pzd%=4tK0Bg-Hj(GuMC7+g(LnC*JPL7rVK75NiEo?z-$N>WaOiFOQ#3hN`o7 zIylsSQSC@k_fEAuVsUV&-rh<6;Cj9lp9v#G6eDfLKe%3R7i+jJn+`=cSRkNendwk; zTQ&?jCp%cl$i7x6;>qsOT+P5*^-gwxkzBWjDn&eF9~r0x-;4pg9iQ~41FC>$JC!tI z(||zU4(ab1eZ2E zn zK<6N6EVzrmc_HOg#8Fsm6TrA3^)Io=rsCvT>-h?-o;LFRVAykjsK zwU-OxncMMlfp5K*G-eJqw*!#!TokYTd|6Grq7|&h@%b`}<>t8{g^=$A<);OdwAJK} zSH4q|o07JET0lJr5`w1G+x@ky@S$6`h{%G!TDuXU+b9WcFD5+Otgf-qbzvQ%wteQkx?9O?QA zx4E{Wz2fWW_?!enh$IAM(>vbk*Itg(vUq!G#MGQY-d@_WxV;?bt$uKj?nR@fNP_jd zMYI{Am7L1_!Ugy!n^tDpV0^cTr`EIRRd*R+%u4*EqIGS1iJE8f=G<_qyFM! zKTx&=-be`s(ESSyju6J;V<^8DMTV1u)s*BK)CNH z;4o%bVTThgBwo~9yiVH&Gw-|z-%+3=9d*|-ZweIpQ%9Zl7vJ0Q1;iH+u?4z(+C}m& XC#GXxG}Xl*00000NkvXXu0mjfiO8B3 diff --git a/res/drawable-hdpi/virtual_preload_folder.9.png b/res/drawable-hdpi/virtual_preload_folder.9.png deleted file mode 100644 index 68e2afe8a11f08a0415a8f5bacd95f8fa531d2b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1187 zcmV;U1YG-xP)f~U^CAfGR{^2`an?Z;AlkDI!EmnNZuam7pYtQlw9`&AKk_+mu!p<3 zg5hQ%7{Dr;_@4Fv<$Ib~MSnvO)Nu`O(MEg7(#oqWraE#6MzfoLIX<*sd66Al%VmtE z7d6gNNj*cD#ARH|4qoI}j<5eWyBHlA1d};NYbux)p65EoQS5tNG2^(7=V?CfnIxE; zcL;iO;J6p)1J=+Gx{U_b@B!_qa)91>gP@da_$_r0k1)e!Am;Ey>UR9bHI(K7f{}bk zyOv{&aajiO4z2|{LdYfyDW=x?%;pz zVH+hmfS`&;wS#Y%?s6oi@s0NKC{tYRzL94^dN4P z%l~7#i%?AGKZ)bkG$0trKXUO#7qPfa;`oO_;USLbbW<8RM5#`-M?yj{g*KTR<~svo zzD6@69KTTP`^442i=M)9!!})axe9EK?A( zB&L6<4+gP8s(dvww)y$?js~lii!~ zUUsYqvh27g77M_8ydkcTO3xc#ieKRkF+y`J?Ee(S_V;wW-|wl4g#C?zZn9+)^UX6A z@5Ffo9W1t;l!ODCs@1$X6ZsS#!QfHyPV0~;S<^}qlC002ovPDHLkV1jS! BGCcqQ diff --git a/res/drawable-mdpi/virtual_preload.9.png b/res/drawable-mdpi/virtual_preload.9.png deleted file mode 100644 index c4a01fec135a4fe99e1d48c2f587136be0ed236a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1599 zcmV-F2Eh4=P)>X<2_yIW>vW@g@Gm>E6Z!GIjaYRRfazkyzA z2i;z}-%RaK)vw;G`X562{5!r70={GQ7UKU90z^pAg)aKb7kVy1gwPX$ZbHzXdkhWf z-eDJJ`B%!N!D`Mp3s%de{*@PId51Nmdkh4l6@&n3s_~$wX&(J?xC;R_&ENa8)h0*~ zA__qO^;X|lxso%wv=twj{m!WSfBxHy8L3I`B=?Ne-)7wZ^LIuancY@=8Ku%Uw%$r0 zk%AD5EFX;z*3iLQ*EfzWONR|{u)qYP5)($4U_l&gW$BG$Ti0I%squ{~vOw%TgaB!` zM=qs3Sor_ zx=v>R!RTOu^}52=b@baaQx}*a^b|t8&)&X8i@g!s=c%Xh-iQv?OWFvxj!8E1jg`&|&a2tncKU&~q3nlY{r zf`HyifMJZQDHL7)wG^UVgV6h?Q$m`V7y$$YV`d^HGT(IQy8q|4@##|U9fuLX* zZ_K5cvaK(~&LD)cSh<|DhS9J@3PHiJG>qmj*-qw^EI`EguGGA^pvHoCRy^tq{UP=)B{oMj!?Pw2*)pswv)a(1nE6t>#T2{iS0udqRIMdUu+k<8W)%op8N-5T$U^@W7Qz#YD995V7DBG!tk!`jsMf)m zT%!hIqQJZ)1|;PsX#QX;_Ri|Xv~h6aye^Sr3PU*F`KjPL!yx(f&*QAUC>ph+y@<2N^VDjGkQYa#{A#z>RrG2%mGZne zwJHjje2bLorj3+p?OQ})sRp5c?H8Q+*J-`7@~`9UwO>H54k2X6%T>y9LmLUNWYI!5 zJ05~M1Yp`TiL>)dG@K#&^Gi6}Gl@<{I0$J)La>&z=QFh0cRZg#LAgE=Qg{dfroB@* z^RLM^YJeeR8~tlI+dBoO@H;S)G}#fT;OyWqE%u@ZhjJFEnCyVm$*vs6=YB=j!0Txd zt|H>=X=DvN_baj-I`tG%}#N?B2ojmkha*Mx)-^TlcQs zN~0iG{w0HEMYnuRnEsv_D5KbTGhN-w?V7LqW_o)ujl$nEVd{>LsbG|(Qfvh4P7e0; z#LW~vhLeMXbrcIFsf5rYZyUyZ=i!;OGHze}ZXf8n{L$3ft0zxH5sO?5gH!Ey#T)x;~rRE&9 x<}~Vys&|Mf48L-bE(h!X8}<=`iT>rXz5ua}Oa6Sje;NP)002ovPDHLkV1l{F0+j#& diff --git a/res/drawable-mdpi/virtual_preload_folder.9.png b/res/drawable-mdpi/virtual_preload_folder.9.png deleted file mode 100644 index 2f3e420077e37ffa2805f8485b0a2524fcc191f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 847 zcmV-V1F-ywP)Z z|E_ZE8DH!DlJ65GuOA5|=kJC1KO(w77~uhf=38cuQ$jdpk7ec?^nejLBaAY^hfWFU z>y%GCuO}CT0h1jOLfC4K*FEPJ6(fyQaf|1?ZjP-&2**t}kSRi+Y0e5^qpItgUiUgx z8-;MzRDBsCj6>M+_qZsGZv){n`-OLs z9O4~ezsp)9rU`2e&jm5uT47oXgaK#OJ(%Pa52!n5pgCfausF#v77LS_AdGTUcr;hU zBf?Rm(h=i?jY-b2K^UKo_*kgsj;IQsq#%rPR=6&A#C5_sqZ%U~6SgJ=#1`SP#)$WY zIfWqR2-U`jxx(v(AYK>dHAZ|TJX;9jS>fx(h?;OyA&8rVT4Tg%p|21`pK!V{qArqx zB19^}$U+Ds(-EhIN+F0!`rAY;)(RH=v?8YLJ%*d|5#Op*@Ylx z3)S>Luq~zjftCMP{&Rd%$foA~^i9q8F}{TDT`3#ghlOKCmA~bm-0JXiPTd1JAAZKP za|~RQ+c9vBFs5KPxXGQOf!` Z-vJpE9_eH + + + + + + + diff --git a/res/drawable-xhdpi/virtual_preload.9.png b/res/drawable-xhdpi/virtual_preload.9.png deleted file mode 100644 index 2afade1b25a5422025b6b45330907249ea90e134..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3726 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 B?#%!I diff --git a/res/drawable-xxhdpi/virtual_preload.9.png b/res/drawable-xxhdpi/virtual_preload.9.png deleted file mode 100644 index 03c6e7f7d935cd6e16f3b63c1a1954b741c04070..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6802 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 AMF0Q* diff --git a/res/drawable-xxhdpi/virtual_preload_folder.9.png b/res/drawable-xxhdpi/virtual_preload_folder.9.png deleted file mode 100644 index 052a72e0728560dcb9c37dd3431d8f9b13938587..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2986 zcmV;b3sv-qP)xmO*J!@FOGTz}?=5YgaIEAr9OhOi* zgecRwg6H{#cn0Ygp63dt6Q#r?qzR?e(#YeiB%Yp@o@@=OBhLhzR}UZ_tkjgBZp^jAte-+`@CTvLoeZZ{j9~7M%n} zv4qYPif23TaXquCp-R$(Dr%U`^}NUS6n?3bC5$Q>2@L1KZUuDm4wrBweIyIeha?@88lmrHFH?gGIeT8w95VTDNU~3xzE_k2NI~J z%_aD+sTH3=4PU$Dq>btVm%veMa0&cD`iKvq4-dNJW&=kRumnzYnIG%mcj9CCoy%uw zD<>AH1SYt&DwcDI_#6&lxl1c=LIFyk!9~Fr>?;9)efiu)LqmZ{;4n73^ok=A5Qw-8 z^lj$w0+K)->l`6IN|^)*%6Qa~$92>dhy?cFM@M+`=p_MzUd(gk^Jn%b011To#1YzE zgd~6v;x0#CKOvlF350mb5!QUIAW$0SJM#N7q5Mj?+F2I_PJ!0&h$GKe=TQP@5Oe%1 z$|T@W#>b;%BGJLA@p%f z``qf01P&#pYJ*xSQm9ciLyW^bkU(#~Q1+Xoh@nZ9#+UTYy@WaHN8ceNMGPU{QYA7c z#}XK#7PoisYbkOVLx);eKP0yjZd2AT6GOOEmC9{7l)!Mc%jP>O#1Ja@PVM#?o;wM8 z824YpRtBf*;rtv)V3bEK)7v1LQv#RIA?8k{n22sCo|;Ndg8B zt9M~&_9fh)ej+Lf7>rSW(;KoZfx+qkgvDYwV4+%9}}ZX)avc0vLJzon!uYRMwc*2P5wrDE@7JLfbkE+U00ugn8L6xM8L8ZFCVPIww>JsPE#7GM@$5xk#1U)4Cq8MqRPQ;v?nS^r^ z9&(2mX~7){<#$d-5>z9rMU1qdMK$mQCK{#IKyRV7&E)ysOy1lx2?yG-3RyT-q2A{QjMxDq&SPVih~f27JC44>X8MTX z`Jq#G{94|RUvnNr_^24^97OoE9m(lA>_Uf{n-9q0w01bH;|`HlO2id|628^PH0SET z@)N`rgX2|69h=Rg`QbiW=KLSEMMoMIv@+g={Y<-mttQkF4(2m zUSAJCMski_53gX3vi=q!DPjommMW1sBDt2(n=gpl(00-RoiFK~3keDiRW0Ins*895 ze7ovB9VU_+2?}me_P?f2kxuD{&L z@+l$2OOB8pBotr;4?6PuG9iy8XbAI-Bdj|ql>kC1cM*552R)XcVJIscq0J){z_(zY zBcIFJLnJQ}G}N=srEVw-Sas~I3)WFDk~aw&4rjB=w=yCDfe0@<^0%48Me-^^!|}8` z!u*_l1JX77%#pWtju*+h1Pv2iG_-MW00t=9TogwiUO6OA`%CrPg`j*>iW{T|0FN#lxf4+BJeEJ4GOy6cmWT4`h#@ep>UiPkP6 z`ii4O;X?@;%9yJb*6Z%vV@#rt2ZIrlcuaT2)Z+HJl!*jHf`-A|takh8w3)@6#lRe$ zO?MWH^~{G#+qs#+qVT;04a1qQDne)4!5dt_k@U&ZfB#4>;0<pGwaBxoq% zSQfF(^WxveB97HPl%kTLA=wWG-@Gpokm3gelS@Ex69#e^k#w2Jc zrItpXWOddGe>G3iNG+wJF$rBm2~lQnB`?sHQPH>Y0#`DVsQU7ogv=nqSWaOsH!z>) zc#mbQVhtPqwf - - - - - - diff --git a/res/values/colors.xml b/res/values/colors.xml index 19bf51af8d..a7b507c268 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -52,5 +52,4 @@ #FF37474F #757575 - #FFE0E0E0 diff --git a/res/values/styles.xml b/res/values/styles.xml index 8b4a1dba40..8ffc53fd76 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -148,17 +148,4 @@ - - diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 2efe31fa02..8043eacdbe 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -19,7 +19,6 @@ package com.android.launcher3; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; -import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -27,7 +26,6 @@ import android.graphics.Paint; import android.graphics.Region; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.SparseArray; import android.util.TypedValue; import android.view.KeyEvent; import android.view.MotionEvent; @@ -45,6 +43,7 @@ import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.graphics.DrawableFactory; import com.android.launcher3.graphics.HolographicOutlineHelper; import com.android.launcher3.graphics.IconPalette; +import com.android.launcher3.graphics.PreloadIconDrawable; import com.android.launcher3.model.PackageItemInfo; import java.text.NumberFormat; @@ -57,8 +56,6 @@ import java.text.NumberFormat; public class BubbleTextView extends TextView implements BaseRecyclerViewFastScrollBar.FastScrollFocusableView, ItemInfoUpdateReceiver { - private static SparseArray sPreloaderThemes = new SparseArray(2); - // Dimensions in DP private static final float AMBIENT_SHADOW_RADIUS = 2.5f; private static final float KEY_SHADOW_RADIUS = 1f; @@ -423,10 +420,6 @@ public class BubbleTextView extends TextView super.onAttachedToWindow(); if (mBackground != null) mBackground.setCallback(this); - - if (mIcon instanceof PreloadIconDrawable) { - ((PreloadIconDrawable) mIcon).applyPreloaderTheme(getPreloaderTheme()); - } mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } @@ -495,7 +488,8 @@ public class BubbleTextView extends TextView if (mIcon instanceof PreloadIconDrawable) { preloadDrawable = (PreloadIconDrawable) mIcon; } else { - preloadDrawable = new PreloadIconDrawable(mIcon, getPreloaderTheme()); + preloadDrawable = DrawableFactory.get(getContext()) + .newPendingIcon(info.iconBitmap, getContext()); setIcon(preloadDrawable); } @@ -520,20 +514,6 @@ public class BubbleTextView extends TextView : null; } - private Theme getPreloaderTheme() { - Object tag = getTag(); - int style = ((tag != null) && (tag instanceof ShortcutInfo) && - (((ShortcutInfo) tag).container >= 0)) ? R.style.PreloadIcon_Folder - : R.style.PreloadIcon; - Theme theme = sPreloaderThemes.get(style); - if (theme == null) { - theme = getResources().newTheme(); - theme.applyStyle(style, true); - sPreloaderThemes.put(style, theme); - } - return theme; - } - /** * Sets the icon for this view based on the layout direction. */ diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java index df195471bc..95d2dafcea 100644 --- a/src/com/android/launcher3/FastBitmapDrawable.java +++ b/src/com/android/launcher3/FastBitmapDrawable.java @@ -120,7 +120,7 @@ public class FastBitmapDrawable extends Drawable { public FastBitmapDrawable(Bitmap b) { mBitmap = b; - setBounds(0, 0, b.getWidth(), b.getHeight()); + setFilterBitmap(true); } public void applyIconBadge(BadgeInfo badgeInfo, BadgeRenderer badgeRenderer) { diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java index 3256df6fe9..354cf20654 100644 --- a/src/com/android/launcher3/PendingAppWidgetHostView.java +++ b/src/com/android/launcher3/PendingAppWidgetHostView.java @@ -17,7 +17,6 @@ package com.android.launcher3; import android.content.Context; -import android.content.res.Resources.Theme; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -33,8 +32,8 @@ import android.view.ContextThemeWrapper; import android.view.View; import android.view.View.OnClickListener; -import com.android.launcher3.graphics.DrawableFactory; import com.android.launcher3.IconCache.ItemInfoUpdateReceiver; +import com.android.launcher3.graphics.DrawableFactory; import com.android.launcher3.model.PackageItemInfo; public class PendingAppWidgetHostView extends LauncherAppWidgetHostView @@ -42,8 +41,6 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView private static final float SETUP_ICON_SIZE_FACTOR = 2f / 5; private static final float MIN_SATUNATION = 0.7f; - private static Theme sPreloaderTheme; - private final Rect mRect = new Rect(); private View mDefaultView; private OnClickListener mClickListener; @@ -149,13 +146,8 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView updateSettingColor(); } else { - if (sPreloaderTheme == null) { - sPreloaderTheme = getResources().newTheme(); - sPreloaderTheme.applyStyle(R.style.PreloadIcon, true); - } - - FastBitmapDrawable drawable = drawableFactory.newIcon(mIcon, mInfo); - mCenterDrawable = new PreloadIconDrawable(drawable, sPreloaderTheme); + mCenterDrawable = DrawableFactory.get(getContext()) + .newPendingIcon(mIcon, getContext()); mCenterDrawable.setCallback(this); mSettingIconDrawable = null; applyState(); @@ -226,13 +218,10 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView int availableHeight = getHeight() - paddingTop - paddingBottom - 2 * minPadding; if (mSettingIconDrawable == null) { - int outset = (mCenterDrawable instanceof PreloadIconDrawable) ? - ((PreloadIconDrawable) mCenterDrawable).getOutset() : 0; - int maxSize = grid.iconSizePx + 2 * outset; + int maxSize = grid.iconSizePx; int size = Math.min(maxSize, Math.min(availableWidth, availableHeight)); mRect.set(0, 0, size, size); - mRect.inset(outset, outset); mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2); mCenterDrawable.setBounds(mRect); } else { diff --git a/src/com/android/launcher3/PreloadIconDrawable.java b/src/com/android/launcher3/PreloadIconDrawable.java deleted file mode 100644 index 973e688d92..0000000000 --- a/src/com/android/launcher3/PreloadIconDrawable.java +++ /dev/null @@ -1,252 +0,0 @@ -package com.android.launcher3; - -import android.animation.ObjectAnimator; -import android.content.res.Resources.Theme; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; - -public class PreloadIconDrawable extends Drawable { - - private static final float ANIMATION_PROGRESS_STOPPED = -1.0f; - private static final float ANIMATION_PROGRESS_STARTED = 0f; - private static final float ANIMATION_PROGRESS_COMPLETED = 1.0f; - - private static final float MIN_SATURATION = 0.2f; - private static final float MIN_LIGHTNESS = 0.6f; - - private static final float ICON_SCALE_FACTOR = 0.5f; - private static final int DEFAULT_COLOR = 0xFF009688; - - private static final Rect sTempRect = new Rect(); - - private final RectF mIndicatorRect = new RectF(); - private boolean mIndicatorRectDirty; - - private final Paint mPaint; - public final Drawable mIcon; - - private Drawable mBgDrawable; - private int mRingOutset; - - private int mIndicatorColor = 0; - - /** - * Indicates the progress of the preloader [0-100]. If it goes above 100, only the icon - * is shown with no progress bar. - */ - private int mProgress = 0; - - private float mAnimationProgress = ANIMATION_PROGRESS_STOPPED; - private ObjectAnimator mAnimator; - - public PreloadIconDrawable(Drawable icon, Theme theme) { - mIcon = icon; - - mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mPaint.setStyle(Paint.Style.STROKE); - mPaint.setStrokeCap(Paint.Cap.ROUND); - - setBounds(icon.getBounds()); - applyPreloaderTheme(theme); - onLevelChange(0); - } - - public void applyPreloaderTheme(Theme t) { - TypedArray ta = t.obtainStyledAttributes(R.styleable.PreloadIconDrawable); - mBgDrawable = ta.getDrawable(R.styleable.PreloadIconDrawable_background); - mBgDrawable.setFilterBitmap(true); - mPaint.setStrokeWidth(ta.getDimension(R.styleable.PreloadIconDrawable_indicatorSize, 0)); - mRingOutset = ta.getDimensionPixelSize(R.styleable.PreloadIconDrawable_ringOutset, 0); - ta.recycle(); - onBoundsChange(getBounds()); - invalidateSelf(); - } - - @Override - protected void onBoundsChange(Rect bounds) { - mIcon.setBounds(bounds); - if (mBgDrawable != null) { - sTempRect.set(bounds); - sTempRect.inset(-mRingOutset, -mRingOutset); - mBgDrawable.setBounds(sTempRect); - } - mIndicatorRectDirty = true; - } - - public int getOutset() { - return mRingOutset; - } - - /** - * The size of the indicator is same as the content region of the {@link #mBgDrawable} minus - * half the stroke size to accommodate the indicator. - */ - private void initIndicatorRect() { - Drawable d = mBgDrawable; - Rect bounds = d.getBounds(); - - d.getPadding(sTempRect); - // Amount by which padding has to be scaled - float paddingScaleX = ((float) bounds.width()) / d.getIntrinsicWidth(); - float paddingScaleY = ((float) bounds.height()) / d.getIntrinsicHeight(); - mIndicatorRect.set( - bounds.left + sTempRect.left * paddingScaleX, - bounds.top + sTempRect.top * paddingScaleY, - bounds.right - sTempRect.right * paddingScaleX, - bounds.bottom - sTempRect.bottom * paddingScaleY); - - float inset = mPaint.getStrokeWidth() / 2; - mIndicatorRect.inset(inset, inset); - mIndicatorRectDirty = false; - } - - @Override - public void draw(Canvas canvas) { - final Rect r = new Rect(getBounds()); - if (canvas.getClipBounds(sTempRect) && !Rect.intersects(sTempRect, r)) { - // The draw region has been clipped. - return; - } - if (mIndicatorRectDirty) { - initIndicatorRect(); - } - final float iconScale; - - if ((mAnimationProgress >= ANIMATION_PROGRESS_STARTED) - && (mAnimationProgress < ANIMATION_PROGRESS_COMPLETED)) { - mPaint.setAlpha((int) ((1 - mAnimationProgress) * 255)); - mBgDrawable.setAlpha(mPaint.getAlpha()); - mBgDrawable.draw(canvas); - canvas.drawOval(mIndicatorRect, mPaint); - - iconScale = ICON_SCALE_FACTOR + (1 - ICON_SCALE_FACTOR) * mAnimationProgress; - } else if (mAnimationProgress == ANIMATION_PROGRESS_STOPPED) { - mPaint.setAlpha(255); - iconScale = ICON_SCALE_FACTOR; - mBgDrawable.setAlpha(255); - mBgDrawable.draw(canvas); - - if (mProgress >= 100) { - canvas.drawOval(mIndicatorRect, mPaint); - } else if (mProgress > 0) { - canvas.drawArc(mIndicatorRect, -90, mProgress * 3.6f, false, mPaint); - } - } else { - iconScale = 1; - } - - canvas.save(); - canvas.scale(iconScale, iconScale, r.exactCenterX(), r.exactCenterY()); - mIcon.draw(canvas); - canvas.restore(); - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - @Override - public void setAlpha(int alpha) { - mIcon.setAlpha(alpha); - } - - @Override - public void setColorFilter(ColorFilter cf) { - mIcon.setColorFilter(cf); - } - - @Override - protected boolean onLevelChange(int level) { - mProgress = level; - - // Stop Animation - if (mAnimator != null) { - mAnimator.cancel(); - mAnimator = null; - } - mAnimationProgress = ANIMATION_PROGRESS_STOPPED; - if (level > 0) { - // Set the paint color only when the level changes, so that the dominant color - // is only calculated when needed. - mPaint.setColor(getIndicatorColor()); - } - if (mIcon instanceof FastBitmapDrawable) { - ((FastBitmapDrawable) mIcon).setIsDisabled(level < 100); - } - - invalidateSelf(); - return true; - } - - /** - * Runs the finish animation if it is has not been run after last level change. - */ - public void maybePerformFinishedAnimation() { - if (mAnimationProgress > ANIMATION_PROGRESS_STOPPED) { - return; - } - if (mAnimator != null) { - mAnimator.cancel(); - } - setAnimationProgress(ANIMATION_PROGRESS_STARTED); - mAnimator = ObjectAnimator.ofFloat(this, "animationProgress", - ANIMATION_PROGRESS_STARTED, ANIMATION_PROGRESS_COMPLETED); - mAnimator.start(); - } - - public void setAnimationProgress(float progress) { - if (progress != mAnimationProgress) { - mAnimationProgress = progress; - invalidateSelf(); - } - } - - public float getAnimationProgress() { - return mAnimationProgress; - } - - public boolean hasNotCompleted() { - return mAnimationProgress < ANIMATION_PROGRESS_COMPLETED; - } - - @Override - public int getIntrinsicHeight() { - return mIcon.getIntrinsicHeight(); - } - - @Override - public int getIntrinsicWidth() { - return mIcon.getIntrinsicWidth(); - } - - private int getIndicatorColor() { - if (mIndicatorColor != 0) { - return mIndicatorColor; - } - if (!(mIcon instanceof FastBitmapDrawable)) { - mIndicatorColor = DEFAULT_COLOR; - return mIndicatorColor; - } - mIndicatorColor = Utilities.findDominantColorByHue( - ((FastBitmapDrawable) mIcon).getBitmap(), 20); - - // Make sure that the dominant color has enough saturation to be visible properly. - float[] hsv = new float[3]; - Color.colorToHSV(mIndicatorColor, hsv); - if (hsv[1] < MIN_SATURATION) { - mIndicatorColor = DEFAULT_COLOR; - return mIndicatorColor; - } - hsv[2] = Math.max(MIN_LIGHTNESS, hsv[2]); - mIndicatorColor = Color.HSVToColor(hsv); - return mIndicatorColor; - } -} diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 9819418922..c80d4a883a 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -72,6 +72,7 @@ import com.android.launcher3.dragndrop.SpringLoadedDragController; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.graphics.DragPreviewProvider; +import com.android.launcher3.graphics.PreloadIconDrawable; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 973245b92f..5dc9633118 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -53,13 +53,11 @@ import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.FastBitmapDrawable; import com.android.launcher3.FolderInfo; import com.android.launcher3.FolderInfo.FolderListener; -import com.android.launcher3.IconCache; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherSettings; import com.android.launcher3.OnAlarmListener; -import com.android.launcher3.PreloadIconDrawable; import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.SimpleOnStylusPressListener; @@ -245,7 +243,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { }; public Drawable prepareCreate(final View destView) { - Drawable animateDrawable = getTopDrawable((TextView) destView); + Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1]; computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth()); return animateDrawable; @@ -270,7 +268,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { } public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) { - Drawable animateDrawable = getTopDrawable((TextView) finalView); + Drawable animateDrawable = ((TextView) finalView).getCompoundDrawables()[1]; computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), finalView.getMeasuredWidth()); @@ -771,11 +769,6 @@ public class FolderIcon extends FrameLayout implements FolderListener { } } - private Drawable getTopDrawable(TextView v) { - Drawable d = v.getCompoundDrawables()[1]; - return (d instanceof PreloadIconDrawable) ? ((PreloadIconDrawable) d).mIcon : d; - } - class FolderPreviewItemAnim { ValueAnimator mValueAnimator; float finalScale; @@ -892,7 +885,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { for (int i = 0; i < mDrawingParams.size(); i++) { PreviewItemDrawingParams p = mDrawingParams.get(i); - p.drawable = getTopDrawable((TextView) items.get(i)); + p.drawable = ((TextView) items.get(i)).getCompoundDrawables()[1]; if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) { computePreviewItemDrawingParams(i, nItemsInPreview, p); diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java index 1a470ff11d..bb136f7a37 100644 --- a/src/com/android/launcher3/graphics/DragPreviewProvider.java +++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java @@ -27,7 +27,6 @@ import android.widget.TextView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppWidgetHostView; -import com.android.launcher3.PreloadIconDrawable; import com.android.launcher3.R; import com.android.launcher3.Workspace; import com.android.launcher3.config.ProviderConfig; @@ -185,10 +184,6 @@ public class DragPreviewProvider { } else { bounds.offsetTo(0, 0); } - if (d instanceof PreloadIconDrawable) { - int inset = -((PreloadIconDrawable) d).getOutset(); - bounds.inset(inset, inset); - } return bounds; } diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java index 4d4d5087fc..2493447924 100644 --- a/src/com/android/launcher3/graphics/DrawableFactory.java +++ b/src/com/android/launcher3/graphics/DrawableFactory.java @@ -21,12 +21,14 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Path; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Process; import android.os.UserHandle; import android.support.annotation.UiThread; +import android.util.Log; import com.android.launcher3.FastBitmapDrawable; import com.android.launcher3.ItemInfo; @@ -41,9 +43,13 @@ import java.util.HashMap; */ public class DrawableFactory { + private static final String TAG = "DrawableFactory"; + private static DrawableFactory sInstance; private static final Object LOCK = new Object(); + private Path mPreloadProgressPath; + public static DrawableFactory get(Context context) { synchronized (LOCK) { if (sInstance == null) { @@ -61,9 +67,38 @@ public class DrawableFactory { * Returns a FastBitmapDrawable with the icon. */ public FastBitmapDrawable newIcon(Bitmap icon, ItemInfo info) { - FastBitmapDrawable d = new FastBitmapDrawable(icon); - d.setFilterBitmap(true); - return d; + return new FastBitmapDrawable(icon); + } + + /** + * Returns a FastBitmapDrawable with the icon. + */ + public PreloadIconDrawable newPendingIcon(Bitmap icon, Context context) { + if (mPreloadProgressPath == null) { + mPreloadProgressPath = getPreloadProgressPath(context); + } + return new PreloadIconDrawable(icon, mPreloadProgressPath); + } + + + protected Path getPreloadProgressPath(Context context) { + if (Utilities.isAtLeastO()) { + try { + // Try to load the path from Mask Icon + Drawable maskIcon = context.getDrawable(R.drawable.mask_drawable_wrapper); + maskIcon.setBounds(0, 0, + PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE); + return (Path) maskIcon.getClass().getMethod("getIconMask").invoke(maskIcon); + } catch (Exception e) { + Log.e(TAG, "Error loading mask icon", e); + } + } + + // Create a circle static from top center and going clockwise. + Path p = new Path(); + p.moveTo(PreloadIconDrawable.PATH_SIZE / 2, 0); + p.addArc(0, 0, PreloadIconDrawable.PATH_SIZE, PreloadIconDrawable.PATH_SIZE, -90, 360); + return p; } public AllAppsBackgroundDrawable getAllAppsBackground(Context context) { diff --git a/src/com/android/launcher3/graphics/FixedScaleDrawable.java b/src/com/android/launcher3/graphics/FixedScaleDrawable.java new file mode 100644 index 0000000000..4be4bd5526 --- /dev/null +++ b/src/com/android/launcher3/graphics/FixedScaleDrawable.java @@ -0,0 +1,41 @@ +package com.android.launcher3.graphics; + +import android.annotation.TargetApi; +import android.content.res.Resources; +import android.content.res.Resources.Theme; +import android.graphics.Canvas; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.DrawableWrapper; +import android.os.Build; +import android.util.AttributeSet; + +import org.xmlpull.v1.XmlPullParser; + +/** + * Extension of {@link DrawableWrapper} which scales the child drawables by a fixed amount. + */ +@TargetApi(Build.VERSION_CODES.N) +public class FixedScaleDrawable extends DrawableWrapper { + + // TODO b/33553066 use the constant defined in MaskableIconDrawable + private static final float LEGACY_ICON_SCALE = .7f * .6667f; + + public FixedScaleDrawable() { + super(new ColorDrawable()); + } + + @Override + public void draw(Canvas canvas) { + int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.scale(LEGACY_ICON_SCALE, LEGACY_ICON_SCALE, + getBounds().exactCenterX(), getBounds().exactCenterY()); + super.draw(canvas); + canvas.restoreToCount(saveCount); + } + + @Override + public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) { } + + @Override + public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) { } +} diff --git a/src/com/android/launcher3/graphics/IconPalette.java b/src/com/android/launcher3/graphics/IconPalette.java index 27aeaba341..991038cca2 100644 --- a/src/com/android/launcher3/graphics/IconPalette.java +++ b/src/com/android/launcher3/graphics/IconPalette.java @@ -32,16 +32,42 @@ public class IconPalette { private static final boolean DEBUG = false; private static final String TAG = "IconPalette"; - public int backgroundColor; - public int textColor; - public int secondaryColor; + private static final float MIN_PRELOAD_COLOR_SATURATION = 0.2f; + private static final float MIN_PRELOAD_COLOR_LIGHTNESS = 0.6f; + private static final int DEFAULT_PRELOAD_COLOR = 0xFF009688; + + public final int dominantColor; + public final int backgroundColor; + public final int textColor; + public final int secondaryColor; + + private IconPalette(int color) { + dominantColor = color; + backgroundColor = getMutedColor(dominantColor); + textColor = getTextColorForBackground(backgroundColor); + secondaryColor = getLowContrastColor(backgroundColor); + } + + /** + * Returns a color suitable for the progress bar color of preload icon. + */ + public int getPreloadProgressColor() { + int result = dominantColor; + + // Make sure that the dominant color has enough saturation to be visible properly. + float[] hsv = new float[3]; + Color.colorToHSV(result, hsv); + if (hsv[1] < MIN_PRELOAD_COLOR_SATURATION) { + result = DEFAULT_PRELOAD_COLOR; + } else { + hsv[2] = Math.max(MIN_PRELOAD_COLOR_LIGHTNESS, hsv[2]); + result = Color.HSVToColor(hsv); + } + return result; + } public static IconPalette fromDominantColor(int dominantColor) { - IconPalette palette = new IconPalette(); - palette.backgroundColor = getMutedColor(dominantColor); - palette.textColor = getTextColorForBackground(palette.backgroundColor); - palette.secondaryColor = getLowContrastColor(palette.backgroundColor); - return palette; + return new IconPalette(dominantColor); } /** diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java index 472b9135b6..3fffb5bb5a 100644 --- a/src/com/android/launcher3/graphics/LauncherIcons.java +++ b/src/com/android/launcher3/graphics/LauncherIcons.java @@ -29,13 +29,10 @@ import android.graphics.PaintFlagsDrawFilter; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.PaintDrawable; -import android.graphics.drawable.ScaleDrawable; import android.os.Process; import android.os.UserHandle; -import android.view.Gravity; import com.android.launcher3.AppInfo; import com.android.launcher3.IconCache; @@ -52,8 +49,6 @@ import com.android.launcher3.shortcuts.ShortcutInfoCompat; * Helper methods for generating various launcher icons */ public class LauncherIcons { - // TODO b/33553066 use the constant defined in MaskableIconDrawable - private static final float LEGACY_ICON_SCALE = .7f * .6667f; private static final Rect sOldBounds = new Rect(); private static final Canvas sCanvas = new Canvas(); @@ -236,17 +231,16 @@ public class LauncherIcons { if (!(ProviderConfig.IS_DOGFOOD_BUILD && Utilities.isAtLeastO())) { return drawable; } - int color = context.getResources().getColor(R.color.legacy_icon_background); - ColorDrawable colorDrawable = new ColorDrawable(color); - ScaleDrawable scaleDrawable = new ScaleDrawable(drawable, - Gravity.CENTER, LEGACY_ICON_SCALE, LEGACY_ICON_SCALE); - scaleDrawable.setLevel(1); + try { Class clazz = Class.forName("android.graphics.drawable.MaskableIconDrawable"); - if (!clazz.isAssignableFrom(drawable.getClass())){ + if (!clazz.isAssignableFrom(drawable.getClass())) { + Drawable maskWrapper = + context.getDrawable(R.drawable.mask_drawable_wrapper).mutate(); + ((FixedScaleDrawable) clazz.getMethod("getForeground").invoke(maskWrapper)) + .setDrawable(drawable); - return (Drawable) clazz.getConstructor(Drawable.class, Drawable.class) - .newInstance(colorDrawable, scaleDrawable); + return maskWrapper; } } catch (Exception e) { return drawable; diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java new file mode 100644 index 0000000000..bc07ce1a5c --- /dev/null +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2017 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.graphics; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PathMeasure; +import android.graphics.Rect; +import android.util.Property; +import android.util.SparseArray; +import android.view.animation.LinearInterpolator; + +import com.android.launcher3.FastBitmapDrawable; + +import java.lang.ref.WeakReference; + +/** + * Extension of {@link FastBitmapDrawable} which shows a progress bar around the icon. + */ +public class PreloadIconDrawable extends FastBitmapDrawable { + + private static final Property INTERNAL_STATE = + new Property(Float.TYPE, "internalStateProgress") { + @Override + public Float get(PreloadIconDrawable object) { + return object.mInternalStateProgress; + } + + @Override + public void set(PreloadIconDrawable object, Float value) { + object.setInternalProgress(value); + } + }; + + public static final int PATH_SIZE = 100; + + private static final float PROGRESS_WIDTH = 7; + private static final float PROGRESS_GAP = 2; + private static final int MAX_PAINT_ALPHA = 255; + + private static final long DURATION_SCALE = 500; + + // The smaller the number, the faster the animation would be. + // Duration = COMPLETE_ANIM_FRACTION * DURATION_SCALE + private static final float COMPLETE_ANIM_FRACTION = 0.3f; + + private static final int COLOR_TRACK = 0x77EEEEEE; + private static final int COLOR_SHADOW = 0x55000000; + + private static final float SMALL_SCALE = 0.75f; + + private static final SparseArray> sShadowCache = new SparseArray<>(); + + private final Matrix mTmpMatrix = new Matrix(); + private final PathMeasure mPathMeasure = new PathMeasure(); + + // Path in [0, 100] bounds. + private final Path mProgressPath; + + private final Path mScaledTrackPath; + private final Path mScaledProgressPath; + private final Paint mProgressPaint; + + private Bitmap mShadowBitmap; + private int mIndicatorColor = 0; + + private int mTrackAlpha; + private float mTrackLength; + private float mIconScale; + + private boolean mRanFinishAnimation; + + // Progress of the internal state. [0, 1] indicates the fraction of completed progress, + // [1, (1 + COMPLETE_ANIM_FRACTION)] indicates the progress of zoom animation. + private float mInternalStateProgress; + + private ObjectAnimator mCurrentAnim; + + /** + * @param progressPath fixed path in the bounds [0, 0, 100, 100] representing a progress bar. + */ + public PreloadIconDrawable(Bitmap b, Path progressPath) { + super(b); + mProgressPath = progressPath; + mScaledTrackPath = new Path(); + mScaledProgressPath = new Path(); + + mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + mProgressPaint.setStyle(Paint.Style.STROKE); + mProgressPaint.setStrokeCap(Paint.Cap.ROUND); + + setInternalProgress(0); + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + mTmpMatrix.setScale( + (bounds.width() - PROGRESS_WIDTH - 2 * PROGRESS_GAP) / PATH_SIZE, + (bounds.height() - PROGRESS_WIDTH - 2 * PROGRESS_GAP) / PATH_SIZE); + mTmpMatrix.postTranslate( + bounds.left + PROGRESS_WIDTH / 2 + PROGRESS_GAP, + bounds.top + PROGRESS_WIDTH / 2 + PROGRESS_GAP); + + mProgressPath.transform(mTmpMatrix, mScaledTrackPath); + float scale = bounds.width() / PATH_SIZE; + mProgressPaint.setStrokeWidth(PROGRESS_WIDTH * scale); + + mShadowBitmap = getShadowBitmap(bounds.width(), bounds.height(), + (PROGRESS_GAP ) * scale); + mPathMeasure.setPath(mScaledTrackPath, true); + mTrackLength = mPathMeasure.getLength(); + + setInternalProgress(mInternalStateProgress); + } + + private Bitmap getShadowBitmap(int width, int height, float shadowRadius) { + int key = (width << 16) | height; + WeakReference shadowRef = sShadowCache.get(key); + Bitmap shadow = shadowRef != null ? shadowRef.get() : null; + if (shadow != null) { + return shadow; + } + shadow = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(shadow); + mProgressPaint.setShadowLayer(shadowRadius, 0, 0, COLOR_SHADOW); + mProgressPaint.setColor(COLOR_TRACK); + mProgressPaint.setAlpha(MAX_PAINT_ALPHA); + c.drawPath(mScaledTrackPath, mProgressPaint); + mProgressPaint.clearShadowLayer(); + c.setBitmap(null); + + sShadowCache.put(key, new WeakReference<>(shadow)); + return shadow; + } + + @Override + public void draw(Canvas canvas) { + if (mRanFinishAnimation) { + super.draw(canvas); + return; + } + + // Draw track. + mProgressPaint.setColor(mIndicatorColor); + mProgressPaint.setAlpha(mTrackAlpha); + if (mShadowBitmap != null) { + canvas.drawBitmap(mShadowBitmap, getBounds().left, getBounds().top, mProgressPaint); + } + canvas.drawPath(mScaledProgressPath, mProgressPaint); + + int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + Rect bounds = getBounds(); + + canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY()); + drawInternal(canvas); + canvas.restoreToCount(saveCount); + } + + /** + * Updates the install progress based on the level + */ + @Override + protected boolean onLevelChange(int level) { + // Run the animation if we have already been bound. + updateInternalState(level * 0.01f, getBounds().width() > 0, false); + return true; + } + + /** + * Runs the finish animation if it is has not been run after last call to + * {@link #onLevelChange} + */ + public void maybePerformFinishedAnimation() { + // If the drawable was recently initialized, skip the progress animation. + if (mInternalStateProgress == 0) { + mInternalStateProgress = 1; + } + updateInternalState(1 + COMPLETE_ANIM_FRACTION, true, true); + } + + public boolean hasNotCompleted() { + return !mRanFinishAnimation; + } + + private void updateInternalState(float finalProgress, boolean shouldAnimate, boolean isFinish) { + if (mCurrentAnim != null) { + mCurrentAnim.cancel(); + mCurrentAnim = null; + } + + if (Float.compare(finalProgress, mInternalStateProgress) == 0) { + return; + } + if (!shouldAnimate || mRanFinishAnimation) { + setInternalProgress(finalProgress); + } else { + mCurrentAnim = ObjectAnimator.ofFloat(this, INTERNAL_STATE, finalProgress); + mCurrentAnim.setDuration( + (long) ((finalProgress - mInternalStateProgress) * DURATION_SCALE)); + mCurrentAnim.setInterpolator(new LinearInterpolator()); + if (isFinish) { + mCurrentAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mRanFinishAnimation = true; + } + }); + } + mCurrentAnim.start(); + } + + } + + /** + * Sets the internal progress and updates the UI accordingly + * for progress <= 0: + * - icon in the small scale and disabled state + * - progress track is visible + * - progress bar is not visible + * for 0 < progress < 1 + * - icon in the small scale and disabled state + * - progress track is visible + * - progress bar is visible with dominant color. Progress bar is drawn as a fraction of + * {@link #mScaledTrackPath}. + * @see PathMeasure#getSegment(float, float, Path, boolean) + * for 1 <= progress < (1 + COMPLETE_ANIM_FRACTION) + * - we calculate fraction of progress in the above range + * - progress track is drawn with alpha based on fraction + * - progress bar is drawn at 100% with alpha based on fraction + * - icon is scaled up based on fraction and is drawn in enabled state + * for progress >= (1 + COMPLETE_ANIM_FRACTION) + * - only icon is drawn in normal state + */ + private void setInternalProgress(float progress) { + mInternalStateProgress = progress; + if (progress <= 0) { + mIconScale = SMALL_SCALE; + mScaledTrackPath.reset(); + mTrackAlpha = MAX_PAINT_ALPHA; + setIsDisabled(true); + } else if (mIndicatorColor == 0) { + // Update the indicator color + mIndicatorColor = getIconPalette().getPreloadProgressColor(); + } + + if (progress < 1 && progress > 0) { + mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true); + mIconScale = SMALL_SCALE; + mTrackAlpha = MAX_PAINT_ALPHA; + setIsDisabled(true); + } else if (progress >= 1) { + setIsDisabled(false); + mScaledTrackPath.set(mScaledProgressPath); + float fraction = (progress - 1) / COMPLETE_ANIM_FRACTION; + + if (fraction >= 1) { + // Animation has completed + mIconScale = 1; + mTrackAlpha = 0; + } else { + mTrackAlpha = Math.round((1 - fraction) * MAX_PAINT_ALPHA); + mIconScale = SMALL_SCALE + (1 - SMALL_SCALE) * fraction; + } + } + invalidateSelf(); + } +}