[vlc-devel] [PATCH 1/2] Made database crash (line 308) non-fatal. Implemented repeat and shuffle. Added next and previous to mini player. Implemented album artwork acquisition.
John Mooring
jrmooring at gmail.com
Mon Sep 26 16:55:01 CEST 2011
---
.../package/android/vlc-android/default.properties | 2 +-
.../vlc-android/res/drawable/ic_repeat_glow.png | Bin 0 -> 12360 bytes
.../vlc-android/res/drawable/ic_shuffle_glow.png | Bin 0 -> 11105 bytes
.../vlc-android/res/layout/audio_player.xml | 2 +-
.../vlc-android/res/layout/audio_player_mini.xml | 19 +-
.../videolan/vlc/android/AudioBrowserActivity.java | 25 +-
.../src/org/videolan/vlc/android/AudioPlayer.java | 4 +-
.../videolan/vlc/android/AudioPlayerActivity.java | 79 +-
.../src/org/videolan/vlc/android/AudioService.java | 566 ++++++-----
.../vlc/android/AudioServiceController.java | 529 ++++++-----
.../org/videolan/vlc/android/DatabaseManager.java | 261 +++---
.../org/videolan/vlc/android/IAudioService.aidl | 5 +
.../src/org/videolan/vlc/android/MainActivity.java | 85 +-
.../src/org/videolan/vlc/android/Media.java | 32 +-
.../videolan/vlc/android/MediaInfoActivity.java | 43 +-
.../src/org/videolan/vlc/android/MediaLibrary.java | 80 +-
.../org/videolan/vlc/android/SearchActivity.java | 373 ++++----
.../videolan/vlc/android/SearchResultAdapter.java | 15 +-
.../org/videolan/vlc/android/VideoListAdapter.java | 37 +-
.../videolan/vlc/android/VideoPlayerActivity.java | 1017 ++++++++++----------
.../vlc/android/widget/AudioMiniPlayer.java | 268 +++---
21 files changed, 1767 insertions(+), 1675 deletions(-)
create mode 100644 extras/package/android/vlc-android/res/drawable/ic_repeat_glow.png
create mode 100644 extras/package/android/vlc-android/res/drawable/ic_shuffle_glow.png
diff --git a/extras/package/android/vlc-android/default.properties b/extras/package/android/vlc-android/default.properties
index 0b9250e..510b090 100644
--- a/extras/package/android/vlc-android/default.properties
+++ b/extras/package/android/vlc-android/default.properties
@@ -8,4 +8,4 @@
# project structure.
# Project target.
-target=android-8
+target=android-11
diff --git a/extras/package/android/vlc-android/res/drawable/ic_repeat_glow.png b/extras/package/android/vlc-android/res/drawable/ic_repeat_glow.png
new file mode 100644
index 0000000000000000000000000000000000000000..fcf9e9d7bd6f0a5d120805fb75202d4311808808
GIT binary patch
literal 12360
zcmXw9byO667am}N1&JkuC8WUx0Rd4`Sdd&gm2PQRx?v>*q+3c5TvAe{yGxK(Iz&1a
zBqYCm|M<?H**P=k%*>rTzx&*KpXWwvsw<Kb(-Q*#K&q at Hr;XjC{@cI=*#B-Ri(%{z
z$3t6D7N{I$+{PXdSgI(>0eAoX@>`2juxE&nN(LSPaF6Q04F|}|fnrY*dMc~Q6V4OS
z0h|nHO`Plizyc`C$>{pd?FSk7un&6uiHjQPX`@&eTr&)K>AI8LR9>IVIXv_CmDO1L
zQP>?S;VwS!W{q~(pN_d+vJS0Pk9N_UMNl#jSt{Z-D)i(MT8Bnkhsy19#`vkzynFRz
zJ=n)Al!eWhF{FjC^;PISz?hL1Xb|NGkZ#7n%31@^(TnN#Hg0%BOZopJe;BRGkv6&e
z2ZA=BgPCxAkh&{nmNe=f&?32(@&tg(_VjU&nE@;0i5FT4zez9&I9==I1fBSRDHF6P
z*J4dEw at UQ^_U0Rq4+__LZ#mv*IMHD)hW0`?2~bi$I&1lUyeFvfC4pLXh!FxnzZ(lv
zLRgXgX7E`3a`3%a!JmtZ_yDS~kX?WTk9y<OQWrrK4*B`>r|5|km{p4<AAq|CV&sJk
zV6XtQ+X-jpy(<tIrKGRy3Iz at dIhsU)Yd#M|g8*QmJ%o7;BkJVrY|?{c%A-Ps8wI`z
zW`<x|2J90rMyv$BHGD}i2sms-Ka##2XPo>h3iJRSAyX|nr%Pik9=w9o@~p0(K^InH
zFtk-P0BD)BP%MlA at S3Y8%3<rxS?LS7TkI;v^=_5fzsrjgi0T+ at P4P{Dq*8|qhQ576
z3;5!3gszL4&!0ho2-!E`pByxC?QRNRJWWUNZRo!gvE2Tvb$7JY+!}I)<`*NUTsj at i
zzv;j$gC|=juiR5#!g`R7Ob(={r>OlV at ry2s7}&`V9w{mKP5JNoDJRo%(`m-tqd(AY
z!VR-KLvqM6X0*CyO9e~}Y?X4f038fSC2kqL=@Tbl|0sL;O|WNAMy1)~Pqefdv&(m;
z6Lch0$uSS7tJ-&bf$G+jh);0M`$}fSLFbD;zBnim_yaI&0ZAtjyC(5RuOS=$2u-WZ
z5yb5Tx~GpkI3Ija^uBB_E%>y&NHK8oijfFEc>yJ!2mrHHW|22HLD#NCfZF6hwzpb^
z{=MSTFm8pFSGWLtWX4MmsZOUe<;!0$P~Un(!^Q<pB(d0Y+Yo8D2lr#1<Iqz`9#3~d
zK_Bi#g&+Zz at R4MJ%(DeYt*c&3Op7BC<%i3K!(2g^dBN=_)dD#LOzpRO at 7id*ELd4v
z?>o$JZ at e?)Rx!>fo$@2D5}Xna(?2q1(KN;D9E?qHr379ZSm$lYbUA)#&s&LqKvh|u
zpNfhF^r*82Hrzet=Xvx}L3*iQv!eR*u8%WpYz53A4`iim-b%Vo9ieepl9W{0FL^h!
z2|$vYVw3>t55BME8<d7 at lO)zV>cWI<7O@=ejnp<yaoY5=l+jQNUenv at sx!j4J_AQ8
z{7_p2M=KI2DMO61h?C+Y3M at BlaaL{0z=1=v-64ct!EAxVvuaACbm4eP;c&?el at Vvx
z$J%;&?~CjQ8^xRt&DyPVCvfED#BJ2BbwEyG#RQ%A at ZkJ;5;4Q}FgWFD$R!DjuO84r
zx1{(2P{M@|NjF+O`~)Fpqr?S7-@({??_Q=TS0J~wlS<2E_2fBIc>>IW2gT8pX*pxH
zOl{d0x-7mffb~S?k^DHf9Qg-CkH;8s=u6JaF+3RvfB}FBAd#Sl15v8VN`?!-qQjF-
z3<mL7Q#FSG)Og69&&<+tahKa`laylI&J$de90*<zRT)n5X=Qm5byS3FP7eu94_QdT
z<pu at -I6YYTiC!FqEEo~JQjW7Mr69)=4y%C<S5*GtwhD*HQu8UKy^3X8Zr8wN5!JvQ
zCBfYgi<aiY>5}a^<FkAkD5R%HWW at u(5WGbIVD+vGk_50}Cfus%LB(RJ5J=^toKCm`
zs>2LV`kLWIPd@#CfSSsqESj)tLdLIz3Vk>hWe6b^mBwkGrNsi(kEvSkv?uzyBUu=2
z^-o2pz^SwYrxslaLFS^$e(`r>x=(3_ttk<bOe*(dN?(aTm`yH)#@Lq?^y&^lUvS&X
zUmM`iN0CXW-Z8R*G^FE1ou2NSese(fCt0UH$T<ROA_xE;L at ACX2|$^A((s&-i?Y#J
zU715SZ)@pLwGqVl#@tPi6v)73>0G}$*K%j#OzV1>+1sFJ3Shb|P4DG&F8DA4mKbCH
zTqC1l^t)b9Z$HjF6NAx*#}TTvno6am*0OQER;rV_Ya3?IAuUUZkI^XYg5SnUte>bE
zi9WKHDTlHv%WENc8qI<HGK_C54}!P3HhF}Xzc;i;lD#-AN~xr5Vr0#dz-4icC045p
zmRd?*dNVt_74%9WM{C38sDKkLx<E&LA`_ahnE!jh*n7J#E at JKAz|z9XinaNxvFh)W
zUveK4$CC%c(-FPz%Xn1v=su=W_9<}yT}@A}ji+`er9uqJyEEA?<%G<899K$tk92A9
z0U@?5L}>vw0OjQT-U)OrKX2p$p(w!V=|ZU!q(e|WDrE#+8Wy5xw87G8dwFc2x3ms;
zsxe-K@<EAP%77B*<{$UrdKbQ`wwtrLu8l{#zrKCz^{jdIV`AGnaZ6Q?=%X-<mdJN|
z3^vXbcxzBw7>w4qxSL#}y8l!1MXW~4f!prZ-#cb5-wPjwkOX)KRGE+W(@Sa_6E%(!
z$^_Pry1H$bLuolzULY3$EZpVWw~5nX&@+q6nD=*7c=GGWaa{KBE^}aY<Jm#;yoZrd
z`8FDDDVeR-r_CLwi2z#xDV*c%>zo}FlTk4#eUrbmS!Ib=43_Vo&c8W)!Ch=-rqs2<
zAy|m+|3|?6F;>PQSW5oBjY)LBj0y+qhvDdlX2JFz!?luzqD;=dDAO at M93{D0cGYV+
zmaU}G%F5BI*7K#l8AYGU&n>4j>MlV+f?6=^uX3`dQBulBC22XvUv-S{H)@;WZ1w~c
z@%=RbMfsAVL9(TH^kNyP+Z)L+&v%LLRvPR{V-I6uE6Qu2Jzoqy4AAcN-yMg1mMOI8
zQszqfkn+O!H4%iMBfP!5XT1^aIQz0r>fgoAT)?4;K|`PodvlXG^O&`8f|a`5iqrTv
zrJBGcM-8h}={VL4N#%@UJq_E&q8eSEBoiZ}4E8G}80Nj--KI3NKMR;(t>>iajaG0Q
z<-|WMD)b0tcA?2#T%AHL2jj4j+4`*g%a;#1*~2^-Q9QYADkiiX03WOU at apH$vQDGG
z+CP at 0>-I60m7a6__VX4;(To7R_M5NgzB7*6U_cJ(oGsd<zSqfOb$;a-KB3+uddE>;
zXG$+je*@&2(@2=>6G1p`OOeG{O2229LPFMu5`zDZqUY;fY4}YH<2K!ihM+idZ=#gI
zm}u!5O{*aB^!GU3yp}QrQO{V##~_W9ZLaioAJSgQ6#P4<!0!<_>f#w~XO;tPyRW?`
z5NtLPDw!<}4&)_>>+7(qmsoU|h6*!W$A*tjExoW&sL_xukp5$IsjBxxW!ClcUhvtk
zIF)+WcD;pP1_`!8g5YP*V_k4<SF;2m*U}mp#yIX$LVaCTx$=RBty;?>`>mU;Aw`G8
z_ at BDMrSMzebw5IW*QptIvnVvHU7d>Wr>nFWRSN&T9B*A(U3E3m_ at L{b_Rd2g^{kNt
zAi at s_Juu~|Z>p>I+bmq1_E~P$Z}7DL^-wCFc&oojYK1b_y9y%Xj-yQ+8uc)Say27w
zEvqA-YvJifji5^6K(3LXaBVm%N`R(9zhDidbt}2H<zY=d$d!s~LsB}sLG5j!JWzNv
zONa&?i1s`niyn8GG_6pOKvN#3s#FB;AIa1k-xmG*jcJ?SB^_hA&eVqc5iCm6+&Qo%
z8MU3xTn<&#S5ZHErvFWsXO&8N<w^nChcn)XPqBb+F&{2LhMecRb%ZIP-b3<M1DiBP
zAPwrhM59DBaWZtLK}^u!Vmw^dgE&?sC1nMaF(2s at sEX`MdMv?GC9*k8EvBiI4bD`y
z0xaF$*=J>XGu&wlXG^B#FUzH-5_ZlFuL3yBXTO-&3Pt6l==ByS0mWI2p=%-kD(cgp
zxrBuHtPZ8c>DIirDMO$k6EWy at 1O9ZR7}l^^fha3z4;@+b6DXu#044EEi4}+-QJmvq
zE{?uEX+f==hf7moa%`Iu1zE=Ma9H7Vc(U9*6ZWw-LWw!qDbdDcV04G>{o*-trVf)~
zda8CK{+dylLHqr~Z<o_^>!ua{RYs+$PA1H<`7yB8>io*K6Mjdj;Mo0}=Lh5aBXuVR
z&L|z3yuBR<i_?7{e!iuKnluwr{xXc{iI<dm!V-WWs&uAu$?7?i%l@^E8h4>8T>Nu}
z+(OQ~<Cr^1s(ZC}$puFLl1WWg;@2c*9YdBY36P8kr`eZ&%`!E%_Q=jowWrrf8QgZ^
zVN+s7Ns!fe<&tEp&6VpJIJ%D6AMQUD-#9jHH*8(5&@W%84O~lbAX;;?+3r*OR^6z4
zdCK12V(dRFbRRVIMDE5?S1b9XxmhJ<w#xap{>zN7);w=lJJg~C*hL6X&4t-dnoY#*
zgq7~975)}BJ#l&#so%a_Pv}1 at _#KDE5XSj174euq9t8eCJ8{bHrDb8f93Xnw*x|UP
ze2)!3W1;TBY%Oo9wgR>y0McXy;Ea*|r3F3QI&0a?x8~c6|Ni}37<xx at zf_JJCjvBE
z7d5>*Zc#2D at Qug*x!>B?^RxKow4rrV^ks?9t8(IgO!T3dXzOKhh<H1ubN}o3ws2;F
zgTT%c at FxC>Jtq)XeY>8CMqjT at J3i`NT>Lh59hhE5oEha6Nz?zZ&C#f5=ls9r?}AqK
z-ylBJFMrV*JS8li%l>8lx%b=dI!9;|vM~Z?B3r^?%{GirRrA-LDDA{FPyQVUP0rSo
z-fJ at HS*-NQT;f#&4~%N;HTt(CVR#Q$L5@{`VyI(g&)(_Q%7w4>(F4Yx-}@7G7u~nD
z>J5WFGe4N-+*CkafPk%;T!{#VklV at O(trP~Pj{=@&wvtDWwP&1pa~ce{61%rkx}-e
zgT2qMX)@k9NLEHrKA^fMK9MQ#W>39TP8^Nbti$u|>RWfMsWcDW{#nwm-ER#xbbvX2
zG6P%cpTOx}mg4n`@xzl at 9=nHPZSP-aiKogo0B}^In>++TwBQwuWUTgoUdH at j+~pf$
z?&|9G=1Tq&cLtN^qqJ6;)}>V0_ivu!0QruGZ5i#S86n at kAWwImrcS_n4nI*Ff&n%*
z1=QFl+^@PkV)c!BBNY|j`=4Y|+mQ5WwN*dejn+R9$2xd0e>{H?fj<`zpdS!&*I-m3
zx&6{H;L@#iE$cO{LWNd(J<<i(o&=7{UT=?RGe9eeJh?>gTWlE??KakcC at 9dN)uwPG
znpaKgr-kfu+-XVyA<J8-h{#36KdoY2e<3Gf!>Fw%5r2h}hmPl6ZC!5n9zS~=bktd4
z{jpluPMFEy#&qPVTKgpeR2wD?<dpKT at L-<cps+A8T2=M<)1S?I2)2*0Urfgbb82L)
zyv4u1ESCvz9dp^=pAMKF3R7>qMj``^sp2Q`Q5Ile_4-*?d2W7$22MB&U|AeR-ho2N
zpc-Vhw<z-7FY<5C?taw~N4b;=+Z{49o;gfM=4x-Vzyp~ENXk at 1T#H<SF};8OkV~~B
znHV&xf^iBbxic3l`<&+qQHMmTYGk>zgzpmpRlWaKt&_JG`u)J><h!EMLd#N$tZtRw
zMJ-78p11wo5oGQv!28O)eW_fJx$gYDouSS!vde7_$PWOjCD(1TE<&a~{vs7LL9LwU
z)EFG<B6}`9>i8%n2oV-(EFguGtp2T|*!A;EN)(Fy*oNo%p6xo~q5{o}{A_be;w*sX
z(ED2CzTxGZ#;udbZlT2NpJyWVU#*2~PyL(59k|cT^ZlQ{?ffg?mt_sfe2rKAiZ|WF
zbg<~%i5Op!l5c at 3L7_|M3IQ=rygg;%<Qo at sS92Po*{D>~<#2!TBx)Iik^)G84si6{
zmxenp)t^0Ij!$ubC;<!(+~%Ewmi+3{T)tygk6pcTm40EayMZTy at W!RlcweuKTzo@&
zaLZGC$?)PbTU&mdrqcAg at zrFWlXFnu=Fq~-i~?`UAOMhLsac+0y+bmRqW?OhkZGqn
zinw78a6PM<SN`^bw8O6_oOC;5s7T4ycW8i4leMfr19{HE`5~U7Q{)Lem*eA0)xRVu
zE9cLmssaFk=LbHrO=eQ~B5nLEpvfv|l7v=fnPI9RnJ6(YX|~!-`Lx~D3d&~~tzK-*
z at AD|F|Hk2))7SY$6oVpw((3!#SW$7k(d;8qf3VPKxG-m$VEctm<2&(}S at c3J^|rej
z at yE9S{DT6%oc<NIb4uy8WJ?;ewJh~a<{{4hj1>F#m3hdMFXmMfnSZMbc|3#KO at ryq
zw8PWYrdD8;5C<b2cV#9rZi^3pe^KWu!Hsz at 54#@~^}1LkATsjvxB5*_GP11J?m5#c
z!=R~hT?d8c#q*iYhi$k3)?fOo$BWD^&LP)>X=|gShHPd703Z|HwQ~xqcj7^t%OW{f
z2x?D=UyKUjK7 at Bz3O@btoog-A2{A4lr%9i9-nmB;nu_~rH?-Qh`c&%uVx|4pd9PN}
zD!1VsKafbvB*|8=*>56WwJ at qYDrl!^>&g~wjKFJ3gozyY>1EP{|Mky3Mn*>O^0dfS
zhf}R8!wQD|GXZO97?4lx<9$4z7ueKz^2_$+pDJSmmC^4uM4Tu}bSiGduJ)i<lCc0>
zS2j(?R-aHU1z3Fr*t{z%i4HH~qI9E);Z7BTM{5b{K$}J4U+lH<JDD6BwYqdOZa>Z2
zvgjh at yCYh=yFG93pMCoHM;<|4bv5AO;gP>9F8c60T|SKX_sKu=0(`tSk at JJ$QGPz1
zA?Wz7*M$FZ&rYh!6&86+>$UxUNQst6guTH_`Oe4#R5w=aFKjeRFU;LspOnYUR#p_h
z>m{*?&6kUYY5jagQAY~nl;QqWa))#uSup4y`2`<>VeJ*r)8n?{t%m#Z%s&Jr$)b=Z
zp3d_%kzs9EB#+poM+)8RCyELb=@1h#*D-HjCInE16$DY>*qRLO<5ONjG&Pu0tFwRw
zSkSG3)joQ}!(v%)eBgsX8&(<Kl<Dv<yFT}uSV_Mh%YV5OHsb7TTXlQUZzPcy<n4^P
zJXK-B$PlxRm)9QCE8d(Y>@;y{+(Qi<n5HJ<0)_7iH03cWh2xw4vandhl12jo7KlZS
zn-*5;o|8~4ZTd2?o~_>AT!Dea at 2?eCt;NcC9KRW^h>pUh5oXIdDzZeH5x8%KmRJF7
z!kLVTkxc)t)H)8u2J*63dD?Q_*;(*x;6?Su_j at E7G&;u&45g1kjvq4oXIl`qdyUg|
zlTw4xQ7u<hies97!;H8=@~LCG)QC}BTsDYo=~%EZ;&0?V#uiKPo2Yo|uD64iUKE|D
zI;VkBdCVcjSXK{80DX%wM8Uc7hqi==<=%1tYBVu9+4{>5=*h7u(|f%$Y<Z^rrY<5l
z0%P5m#*Gne{@Y4UBXSt%>4$X=1%`-KW|Wz5KGed8TiNadAXz~HwhaUN&1m3DVmY#$
zHmY)v8`UneX79LgPeFn=*u`U)MUdkGC5vP)XklZ~M7#mSp6A<W<6b=V$5xRZ6~T8u
znYOyuBguELgkTd{3Mo36><unZ^iIB_;meaev-Yn!1Dj8xl9j}S{)IZ;pZ<!g at e3aC
zfmGm at Vcc;_a(n6l?Uni`(-%*jQ?*!95wfK at vc5T%;p#`TuQq+nJ`7s3qzt0$v(_C2
z)I2!6Ohe;VmQ%{g*4=7u1sTZ%(-8O!#@8#Pgg~sV(8As+{psOB8q at U}?M)Q2StF1L
z=+ITuvou_Ad`PJATd^(`f95hX%g#0pfcy?jJq|w^+o`21cIjtxGd!{Uu|gt$pR4@?
zL`abTX_8XMpFdn+)|HhN0BVJ0Q|}SJDS)A(APN0r9(Z9aZ~*Qi(XGCXVh%aaWjD?s
zJaBe8@=IuA;*3(#LL|xpHckauS>cGG(CB(vP8>Fq?jv83oS9h~|IzZDB#O at 5{BkkA
z1qK&CDSTW2=!5R<?Eyf?($bQz^-au5U?23id!vCB4%Pa+b}!q)U9U9xXH!=o<@A!H
z`WCU`@nJk}>JYyJz9TBPr)9F?p)1cl)&%oae{RyDF2mCE66ZKJ3lDem at ROj9rd>b)
z!`b<Hr`O_UIw*C*_ScsVLR`9d0#yYyiH~o1Efcw6fIw<;*QZx`#_L}k*b4WPi{0 at G
z+wBcW19Zbay*!m22saA<_?w8-IE;i!T90?FdYY1T)E`YDBMU~3TDZEBLn!L%>PCg0
zbzcFwPtQgPgI=*wM!Wy^PT+U|uU1`p*k)$%Aeo>_4mX at MF}gSc;07s;${;hq8C36u
zExV*1gY at 9Fnk>zE%W;mG!gnDdcjsXc(a}A>4DGJlTPfH(+^*drKds0r?V$}JFsr$<
zGpS|G&+v at 3(t#4S`~m>dmJt0u<{?gjnB-?l^@L2nXsflNsoE>r at F*5zpQ-L=P|8^$
zEn;pk8k!`Y_K}y~Dd<?)fBR3|r(e6<rX at cUsx*)^tRPR5yasSc{9O!J+hd~Z<wR}S
zR#PlEH8zSV6;Eohh(3y at wmDHPkxNZRu&VzuUgb(w7FQM6P|1XZLbCFnu!e>MF7rJz
zUJl;kQ+D;82fLL>M#ZK|h6XLpj_+3UEBo!2%Mld`hrH!A4f9yo9s88TO+Z5uw at S1N
zA=VyBO1Pzb(c9yAQO)bfn7em=m54yIWDLhGPN6y(H~y at pe#+JeBtTL3`4SskQ=ol<
zO}T!gyrFQ|ZUm6;E at Vns#0XcL3cJR<vv(8~KfNp`J-r;SF_m_BUr0tnc^uI1-MPVh
zt9(0`ck}D}-tqB7{x8w3)ZzPwK{9KTEMUfAy7mDmo|=xCvv8tzwKD at rH!xq<>Bgu@
zjZYlWB^UpDwL219DeJlGSK_ND%oM`Gr;So&x%}219~n=1hMq))Ab4O;sH7XdWiEpt
zKV%9=%<{+#`R1zhm9JJh_Vjt~SJmwgJS7oH+ at NoUtLhE@QDnApz3shgslnbhAXX6l
zvclWh<eX3qKW-q}w7w=yx^JT#4-N(Ac-Vb2T(`c at Ci_uSbhsj(z8Z~-Dl5rCz$RNh
zF<^9uiOwSp_X4x;Ddzr6hKQeZz-;u_sAO9e*}D0`^`BWVA6wg9>&VG?S`AN4H&<3_
zOsmfEGWnT79l~+g8bNt=P9xaeW`FT~N#j1TQF<jaX?(&{ThYHbkk3xJsrz!cp&*5{
z*$=E7;jxRog at uJRZTi%l12<ZX%pVF%IFJ8%vSp|Us_FE{6%>YW=^aL0$hoUGSgBY@
zFh<CUwmw{aG7nIhDS$I$|M>OPUj_-;eY305esgx)HZ3Mv;{9mj3R_NN8;Y%t!4D!*
z=PADY#U__4XA9HJcNfQ(=WXZuuie}-1ZXCipF5Dw^Er?c1X~o|(|KgX$<kC6aWWP|
zj|)ugdNl;!h-XrsgA>vcaNs#Y=>xovH?S$nfG<ru?AeQ+YNEAL)5IK=)uu|wf=nu-
z`k at MxPEl(VV}sX2hywya*l++XFkH@)B#g|6?~g}ty>TVhw#Z!fe^}e>2zY&^e-Bdr
zleIkQX6AJXIo>|oX+AXl&dYCFP?qIRnzE~?=!sl_f0;)wbzSH^EiN<i_Ni)hlZa7`
zE)9>C_WES{+J;lQzO^;c)NsUM at YBxIq!r&b85VjN8q_I<9LBY^LmvFBLoymQ9Po-|
zJmKuvUL%kdwTab<h$}ZWnGEm52=321{NPR-G5uz^um6Y~+cOt-V%+Yji@&4;G-ac*
zVAR?S%XhaE2b(@VFPDRSB<gEx3pgm<sAb9M`>}m%)VNFG%el{fJ?ES<)q|@o`4GPs
zfPgatUEWsk)vIKCL;qk~pVEfb*3_&=MVV#VjE(e3X8aMrc2l^-S&8#^fyhextO>7N
z)S at RBIF*i68V3mFdDl&y)?I at 43d>BOUzR7SH#&JgN^_{v5Beb{`jdf?x&C<<{&4mb
zmcRZpu|NN)*(b!;?=;t^u6Fp5JSS5EUIBGH`~E7*z5jKW*Ub!1-c^|13n6L-UmYCe
zQXo2d&;dv^ZSi)t*>64PzwhHin;an<$cVfrZ%#q+DUn6&yeRU07abW%=i(bjXnF>6
zP3QRWg)ji6eWuxGT;#z2Q5Qf7H=E3q>)96 at KWp01M*F-9_)(#sN0R;hSv<8zb+r~&
zV91Okmo{F$xjr};sxZoKOiL5vWO at nFDu7G~lCU{N=0jAGvzzfHhB9Ua15xmyY?gyU
zprZ&GLJ!o2CpuYJdHCJj96DFFU5%pmjuGi)Jg4+70y!7QwKYA=WftU-6HisUcTO+Q
zkaiu`Zu?J^Q3GoVvQaPSJOKDv0 at +6o&53|%MB~fypjqy;4_lFuCSr4nd`d7rF_Da4
z7f0PH8HY=)E$+MfaeK$^qwG=zkSOf}B%?UuDf<i7>(M#$47KXtSsF=z>rkK0YAaRO
zOxxqjNmad*%(OIgZgZa5uj{SC;oge<USBRM_Hfj1#^Mb_j?LQ(Xtlpd|HSEsaTg!0
zp%QJ0f5Ojzx1SYp0De8{$X?-W9%2zgzOA%J{`J~oTj`J5U6~oNjedEMtFP>jpX2Vk
zyNz-4%Vx`$7o!I|^M_8aX=tAyBu6!eFax68asuem{M0sI68B&vqeOyIK?@NmPyRfi
zS6XM<$;HdrZS!C=qh9KIYo}|v{1KKa0a=i6Y*Mm6gPp}m4~jLsmH8ZOX4oWEeHuKB
zHBscL=bssIPPq%D-$_Gln!q2J;YgZn)a|%Mm5*=9c>-Ao)^|*2LpF=$@>Viyw9iED
zWlLWmJ+9UheA1WvceR^dsXoGprsX8q5)`DuT88wC%HX at pBy#{j-tylpfSx=?&f1?C
zvserQ{NgS{=6qYjDHCjCBqUTaT$Yy>F1JS0BFbOBoanX85>P<uUWwG+7XFpq>=7if
zBqzXz*Qe>j^H}v_n>a*CSZf+%0fW=)bYPu}P=3<5$iC8%zQ|NsYD<4eBP)Sv at sM$k
z961%6PvG+G!}3qq-coCG<LP*AxeB(&;E3s^*3sh;JAY)T*yJp%LAY&KPx2#~JFcv(
zeUjj9SAXXp3O|C6W+GrVqg{ZdsAqi;%X{Q4x3*N at -d<%7yDm2gx3_+I52H?2os8=L
zH{sY6_w_nr9VLMaK=<qHy_@;UXC=;FKMLRHqDXSc8zeYN>c&Cw)Vz<;Htg0f7b}@f
z*jc{4bvs$@mWrQC?91lV?pr&_cuXrIeQg)8yPoj)@p4OJIxjV4xHeYxbNj>vP$VX%
z^bo}KYNk+5#N5-3>rDX?Nuf!C(5K1aM*V&FD!Ecr<NCK53dpW62Ppus)|9mn)7b0D
z2$c+Ctb}u~H#ZmkpS1PbLXcr>BQW=|7D7zuT3!3D6O at QFS%bcnRt_hhuZaJ(tsAFa
z%&Bq7-(@;E;s(Sf0 at Q#gn|NrmLX~#Vl<$SP at 5T4Srl=BpvAj|TOKi#Co2wzcxOm+e
z*^K21(O4M51r$U!W9l%Zxg4S;1?IfDZ?ET?YA;76PR`()x_W%FQSz{-L?8KWMmSU5
zWe0s-5`W`P$r&rt#1J`uWmnWp!$AaYus~gXp3KRIQzGalb^i;~L0-PiC&R=4un!Q=
zeBATCOhAJkL5-`(nO>~O_pe}ixBgSNJ{3X5ALLIb{mAdHd-puWqoCH5x4b}9GJp$|
z{9d?U=gb^@@;w;K7&gqlDf?$!#zi@}QNLt3cYCouoFUZ^<ac|#f%fI6Rb<s9ego6G
z)RyL{P;TX3i<XsX#`MybWBaUUkI|`Jb&4jn;b2)X!47dpOfm()qN at iz^}&cfKaUI#
z@!09Xa93$CY(d)+egw)2QF?|$5Sdv at b~T=cI%{rv<H88ogQx!B)yE at KI9OE&sYaF4
ziGo(p&@qZ!RFB)ySLoX#0|PmXXRGq6^QOU)I>aQ|d_Kqps4$Z>n?iF1!54q5Y+B>K
zJ99j0n`dGYbd|e^<w`bQiC27tz>E*5f{S?W7r_!uUuk|B9?p6wrat2>cRe6W{k|k4
zWRk5591dAiBj)_D$v(aTH7AaxkC5iCt#QT%+0>rrR{nSgHtE^^blNA+{*L!$*0FmV
zBfchyhnx`w=<tKZ4^qs6OYikZ6G|zrHyUHJH91x~Yx3~AxjC=0*4L-`Cdc+x8&Q?g
zOa6MK&#Ta_f|8R`7R7?A8KJhv<nC}i55wP0$do_E9VQ?`uYcV&VBf%HTfu%wdK}FL
zMnLm&ifl|Dym@`Iyiupd*v+C}rFeOIX*bj5*7})wmU*|oUvJRQw=MKuF at v)$0id1)
zf-ydX{{9#p$l7*_$xR#fIW#qE at xF2Jwz1KQ>wlW6O*}T2;K20!g%2+As@{~+k=Td%
zK-E}tSq{~bL^)pz0Q`Dw^y<L=kjNz96P$!L(6=?Mhlxz_NjjP1SF`e8H*>2W$6cg_
z#B-A?c5egG)fX9K$t3UI;mZ|KZa%ADo6ifb4c-o$ucxUpX-?0|Gt(93;}T=0kao~V
z+5sm9^Gz&lmpYyOV}4%8Nrwqp3(tpJI!eaB=(LHri~GH at zB(i#56!Wt6^+eyQSeA^
zTt`*xPVJnRno1Y6I(*+|W?~{Y`X1S8xStg4sT(=j{Vg<iW^)FAG?|n{1y5=8JGX?7
zwAm6CJu4y}y>#I^{&!#2P8G?oiAa?-ulDKATM&zTp-lY{bUt%WIGf;nmxzk3gsrdf
z<Y>xOjzuQ^jEL%~fcwy)den|)u{ts at 3<(u!`ISn&X3aqFdVOQ(3S=~-KV?Eoh)QwY
zbZ0#mbz$6&TMr0ZUtium^*3;5%Bg(ay}j*l at tFtJLHC_*I|85cd3&PrZ}$^yf`p-Y
zIB7d&DgJuBo&p`($8o-?Db+%;#;Pq+hjv(__eu?}JGFO8at8{)oSd46A`}!`0}gqN
z51E1fi*dY6jo&)wL;?qoN&ft6+@;)Z>bZwWwrG|o>?hrNFhkJ&`sBx+=K(o=TmaTR
zg7u%D<)|8BdZqL9&d1nrltAa~z<|Y<?Y|Dw`u=V;sxXt-O?TqSuOMILkg_u9hgAt@
z$2y`#+N8hWV1-MbRmmH=Qy<OLD at GA?5bwp{it8nla>tX*%VwdqW*fV#EKd_QyrvIE
zG&O{Hmb>Cl#UK3GRSf)L=NYTtjHNBf|Mp?JExs76rcb{~8TbE_x{?scbRU?EA_v at m
zI{YFJ#>DJY|GM5k{+?~<;v8p9lQFaY%Skr6pXdds2*&<IYTz4Akc8F}b*0;RS9qHe
zi5n-~%b`oPl*u|vQu25*7yi}qbjUy#UNL)X{EBT at wp#eJK(Ny_9L&0YLvT&u-?i?0
zAi4s5u|uM0)CJvt#w^V6cHBi|#N~Xj`d6T^lknMhmvbn^71L^@ZA0)Akw{53y(2jn
z^Pdix33nT2Lki^&jDoLdz7XPJXJAZJzK=Z=mcy-q3doDOxxr2)R3FL}w-2<HQ0JtK
z|K1zNRoknl(&h|S`TH6F<EHapQ5CqI_ql~TGl$s&@Tj6!VEl^)D=HU5Y$SCGzBTt2
z$C4+i%~d`lF7>ZZ{jb9GJv5}nu~S0<I9&`+E^o#bp`nu#-M|X*>{G|~o2pvJ%reLK
zx()n@(b<WZ7;frNxDe5l$3~wqbfqbOID9E5 at PJObt1cRn6RR5Yr6Pdx{WMjh^9WtD
zw|uMZj-~3s11Q-{Ub+)<;_K=gdXss!<a;Yc(ed`g{ZNFDo#+|Td at f98dFIs0h*|e@
zaFvkLHwXQy*<<j5N1$)RjE9=u^C~tw2mhbVfF7}hFq72hf>c#eG9`XU#4D_8iUAZ1
zBPt*-LuWTj|JV|4Mm!qr2(|ucuTwb9rr)k%(%qx=X3(xX9;O>$Wd{MXrq-PFwJRRd
zN;+z8l4z{vY-%;|gAWkYp&rBO3pFM#zlyBrUsy;4^+W57yPaP7w at cXx?~I!NkncHy
zJ<mI`$d%TaIyBG&6s!q at 04&d|G at ACOQ1Skt*!>0hRZ(q34H>WvWqTus`_pdycXThN
zx9#sG5uZu%%^a)q;r=iG^`FU=yGpE1LqDUV*sZ6sAwMvwg68ka6b5!@^|-tp%1T!%
z;oM at x7ApL_vvnjc22G9zCN5c6+41ts{D%)|;h~z&JxWPQ^~WQp8hn>|{RH3)Q61=h
zs!Y?ggBtO+;t2<<CmvWC59oYFQc}P|db#wFMw|jG-%oOMzwWLGJk|SmaqDxXI;lGJ
z69RE&=^+3zAYC|c2%`TA!V?`%sZy+?syB`5JS!XSKFWzIlVderZ6ZT#gGc#%L>Y-k
z)n<j&WJ}qd=8w6;Bm{zTOsCXW$0Rj%{N7~~CrC?tW4~X|yT$w<-Y6AK&4T_pz|U8V
zlO&*q_d|HO33tb!55 at _u`tfGI?vZivZq}a~$1MMWtr|Q_*9GSh-L$Ml{=(Q+qEnz4
zSn<*$;*Ow>?<Qi!r7+oU;zw-z%YW at 8-eT#r&HQ{eGO3%VkDF7>g)*Y~>!3#zuGGFp
z8}W01m(SK}TbPbC-V%Nv-=?Jhy98sZJ5VSyag*5Y7-6}%&PF7-L-olOjA1V<iGnV4
zz95Ji!Yg}v9YWEt%(BYaf)Z@{G6z at _Kys8kXM0CGr3`OA0CMr#h}Gk`ziYBwNsnRg
zidbK8OnFc}51G3o&E|P0EoT_H<#x=do{;^fW1&?9ft$0crq(d?QIW!b?Ca~XO+=7X
z97yyYsJN>)DoUZ5kG%axzbTzFVx2hE9S=ChIH}8UYen~hKT at M1>%4Ryr_iaHNFn6~
zLRrz at ++*Vy*LR?(k<aQlp|JvcY(#g=cmMJ(rd@;aLT+Y5NULxGjYmX%wDVQdpOB2K
z5y*z!hJ~7X_ebTua#B^e1st(S=Dz8gJYcjw%a$O?zs|N`Npiq7`5{V&Lx!3KNj%;k
z_GNZvW~KS++-yLeXAG%h{f;cld&uGoccXLjnfVHGxQ=5p0}VNeHs&vi50#g>Gk_?l
zy~k#U904W}&}JbgO%B?unAWAZn+^$#fCOM at OC;CT at cVP3xcPtd*zYzuN&0r+ba18q
zgkj$O4ix0JN$$0jbC){a=H5sZ^gtYS6P2JuT1Ac|XCdZqwfOJOLheYJpZoru;Meqv
zXSf#%A5B(WOXo~DT=a-=&W3$r6>Dchzfz$g7UK at jP-E3rLHo%yJlP^^6lfLvttK_P
zc-H4-a-H4&kKu<f>FvScE!l^?=YFNMpISPylQy>`K>)Y$OUC7PR~1&()h2N)Inh&>
zrG!NSTs`U^6Wl|((-eizHmk`cYchTu9xirgi at 02W#Lia(2aC;-*eO)PZh at 6-*ESrr
z$(75~-Td9lNA2mGOK;bi?=Z|5Tj?tUD9E-E&IsgS!6DtVF&>2nR44ahssCdDKINN(
zrltM(vO>Kai36ZQZjMzz0CY?IS+?2_LcFM6%Q0aAjLidCuo72_fV4EZqM~ATd;6Wj
z8%)Gr_wh!C*;;X4Fg*cIUcqwTV&8sP5Ebw?^#=}O+adF>9{lV3vL;on!aumG0Ng)K
zgtp%iJ5mmBUseq9A%EXC|I+vIgKt6Au9OOqx_TAYb8`@|GLPX%Q5ofdn?%}nLF}7)
zuYG(@GZE~&(#H|-^YQ|6#mQl;Hqv?d0BT}s{z+yLouQC at uh6z$8LU-K>an at IQKn8b
zc?1N at -K{i at +HuUUgyvV>$6lYSPIxb(>nlo&8i2CZVm<M?R<rt at goNTdnr>gNfJ)*Y
z9C#p5vm?BpCUM9Xu0<`Nb`n}!br1Nk8s<d3DnSmq{qc}X>>*Zfn2SYEhK&p%4AnUO
z!U+ZJLAO^Kg^&LdhrcfhErT6Nw_R9DPM)v%l42iwv8 at sE?(VO~om^4)v#{L$b&PA5
zm-6<@cJE}52pM-5{;k8jA-}u*<y*d)>^LIhkBrkxHz#8uWXy|=co^SnT+pWc at P{JJ
zV}lU(Bj~~yze7m#k@?n%<!{>lY#y9ZA}Idmj!M+hzJsCD_1Xm<9-JBiDLDVePT>{?
z(^$iv!Sao3YQtNd)B?t+6>=yb6S_{q(m|KkEP9IqAo6lTcovVrcgtXawkPNXnSTxF
z|0DC)HB6w#+NJ-Wm3PBI#jN83wEfJBm^&PWqKwe}rOF)aD+0>$>T;E`=Ar)s?KW+9
literal 0
HcmV?d00001
diff --git a/extras/package/android/vlc-android/res/drawable/ic_shuffle_glow.png b/extras/package/android/vlc-android/res/drawable/ic_shuffle_glow.png
new file mode 100644
index 0000000000000000000000000000000000000000..8f4349d1f5905e9742cf8513c4cf3ee68106ab28
GIT binary patch
literal 11105
zcmZ{KWl$V#u=U_>fxzNUaCdiy1PJa9i(7!8fndRc2X_L&-Q9zGa25{`BtUTZ=DqdZ
zpSQMVr*^h>=6QO%`<y=AQSa0hu+T}+0RX^KQk2yM&%ys4sL0 at Zzqt7rc!KlLRFDR$
zCdqz-ACN6n6l8&y|6X~W-;=;AXs(L-9sq!W|K9-zWMo0WizuE-YH}#6Xv6>mF;6<t
zH~>%qO0rV#eOCSi+$E7N1svRTF0Bh9L&is8<LCRBgZ&>0LWLO(W`8Eq4}WQNOEgwV
zl~sz#s!RHz)*<od`E`5uALl<M%w>()g6*mNQL_3?MTt1eb!3U#iv6uh*ryLrAfT&R
zB9HX)yyR0W+p at H-7aT$e(AJ%M_7spC0kNDG5${AfT at RrEJ}Te<orNgD8#4%!XNPck
z-dDi1$VcFiTnxC1`~P3>ct3p|Ai|aIZ2!w7xJL1HzWp`j7&VmmVL&f<qxPWh-$yJj
z0R9+m%Uk9)n<787C&*Ir5N=C=_EG&iqt(Tl2ksS6b3-Mm-n4fei3m4`9q)$>KKh@|
zc~#9_lIzs^4X66nqrJz}4I-i#a3Y55)2lK`3k%*dfHOHfjmlE^#RA^pJhK+Q>f9QZ
zfC{)GxxfYg1_pM;r#77a=jJPC(Dsw8pVKhffbY4te?J%ho;`7>CS)Eh8inieR7V3a
zv1L;)Tien9d#*S_PuAiC&?E44-XAd;urp;U{rNT`p1hsl>AHGuOv3k#?$`mJ!Ywjz
z7!th|Z;T*?1Nd?H(*RVG{>t4PWa7IxH<T?qW#6%L{7)`+xAJAuHeTAhjeihDV*%4y
zH|=ilC$CXI0>3&WoBxt<_~_n#!2k+Pa8^>o;3WS>Jlu at +Zk=aOiS8^pG*X&84WDs1
z?71)aN-XF3G+6$(o!aTakhmp}i_YV5ao`q?3Ka;j>BO^2Zkm;lrsH-!->UWFFnL56
zo8HXu-AkeG)GTua4j1!R at xX^3I(D^ZLl$+fgzo|*07NpF0Nixxjm8)a&;#K_1~Bny
zu*iknch>}-A2p!*UGdL%xkOjc6wf>C=U*QxC09y_*DCbaCVM}euQ+2+cnfthe^dm5
z`{43$0BHcXPL1afK3D`!<rRhahm);4m%w9csQ&D=N*du6v at sLu93Fn>i;4&`u=0s`
zt?c}6D01m?9gq>|#ix$N#}K4}bg%~ZWd@=E=1_xx at g^<=<QOh*<WM+(rY;8j2Si+-
zGdDj5Ysl{h-ri>+gs7(~Rp3S5IIIGPpB*{yBl%(FP3Z6 at B8)x)DiFtRol`HTf*yJp
zLAh_X<n#pmm0|dX0+ZK-$PVElHz28(Ix{jqKXB&~a4ZT&VaNn;YSS)uk=py(4rkoc
z0wlZW)V$2aOEtV|EyQ7)Pt!^}QD2)zjS$bY2WiQxOflitAykNf`6{o>d=r`_W-u4<
zd0;axvLJ8f_ir~8#KZgJw0%r%IZ{11{3bo&jTnr>BH~lp{Q~U{1eIx}TmFjb1TC1*
zIy~+>qDrE$Q+$for<-!PK5&xT+`*}@&6?IxV({#K1YO!t&m;C{D1qxW#$Ce!T%WF0
zE-9!E_dg0CeriDa^Hr2r=5&j627A0a?VL at oJi(A6$OReIgu!&)Ck(&ER4 at S8!obA*
z7aMe1->=MhXq&7YqlsDJwcZ192;{f?w$d~JNhxz0i_xU4cakXN<@DS=#7%hJdc9+$
zQuA!ma%%SYDA4UI0pu+&nPdwbU#r7!j>tI+A@>+Nf2~Hq<#cpe(Yv}!#_#gWm at MoS
z6F{PhWSe*HOA|D$bnU}-wVkGnx_aw>>hX|l#>wltwY8P~RwBUE)s7J!7#}_8)!zO0
zF#Ht(b%0SWh6^)>nr2MXZnG3IhOhSseUp5|sSQb-Q<ipaZs(x;ZURi6_0`W~9m{q;
zXdQ+XyXnM^1PJE>%6Q}YlAN*rd7qo{5F&{zFbqx?NA9!^dbV<$Wn)AuK0UNYDuhi=
z?Hx%0hnEU82s^oV<IlBP-`|}2AC-CZ=I5iPS_=sZLWb&M1PaY_h*X(8Sj8OX{Lc<(
zP*2kk0uzn(B1>#+3qLk8Z?Md07dYEfzhbg@$MdE)<U_+<t)Gd{MbS*@Lz(>@>)g4<
znC3U9vH2!?vk9Lbspox}zm1ZS at bF(aOHip-OP5G%S#;gQfAEu;JH%}bD&S$Bs^P)~
zBf&1iGIXj=kIyJ?Pm<nle3-iA5QUJClA>W_hu6}X??WrUL0b)2#J{{OcIfGzI{|+S
zj-^mr%V^*Mt4sz5g6IV(f2QBd+4H}NbX}9Xch&FRfp^HjYXAyNZzT^Li#K$Y;{zQH
z8=X?H7hZuEQ%LbQ4dri6mcs)u_I+0jNni+t^V*{Jv3m1v(r<8Kp`eTpdVwRZNc!W4
zFwrs)+;&;&X2vPB)I+4eNp!-LMene8_^fDU_ma+oZ`qtJ>Ux90kwqyK=>JOPm3u>@
z+O4B4qDn<lP5TB#3?65Asr7Q0VY74RjX==l%EHTK{1O at NdotX4q_8c^LViGz^jpwH
z_#GS-gp5pdtqqPn(f7080}t#kQY9{p`3>sXro`=ZbGMiyX}CTM!OyhrhxMCTkENuj
z^z@?qAFrvAVa7N+&^=K=b^@pMuC=;5=#b~FxbJ-q#*_rXO0x@{ATNPD1fg)=IsJq$
zmkm0(Um=<1U`m8p6 at +7%3@?p}OYL)b4wJbt>9~~}{m#oCbar+et67WvCzOHI#>x;4
z-cTS`;|N(Vxm7?$wn__jgbS;>@ihq&fzAkU&*A`#y!`yPTc$79uJkECP46~t0 at HJH
zqv>sJUVUsd*#69MZ#@7P?DPJhFYY`-;xeT=tLtpa<i2m at Vh0768WmC)!}TRYpsT&x
zJE(n$mg6?|xqHch9XHEwV)0Y}9TSu6Zd^C#ksFw=e(aYhy_U}3$QNv^l>VwqxaDFG
z5B#yI{}2^|EtD4f4j(gNYs>5~-zCVeG*R7l6U3eXzx}<mgDdE3VS+D4fEhIhj&L82
zM_-WD?(K!r at c2sAvaJb8H@)Q)|IG at +vqT|*<D6`2l}xAJz_q`LbF%WVLP^OfsfZVJ
zZ)hsWWUbQKOaS+McKvvP1v3M#nADN_GZ!{CmfT~4;_U_z$IrScj=j`WXE~0S;~zTg
zmrVJnfbN5#csKoHbkM(%|Jm_S43|y+z1f+i7{uv_gpaMLT>Jfmjhhf5?Sg8?VqL2p
z^k3mkB4wc7^3hpJ(=?raG#a98)1AM-w|viR92rP+24$s!@=_;u3|!y0VdBdX2rdI6
z4yDM4t;?XhG}AJo=+W|*+b3O)pquukqrn1Fpe at 7}J2If-_l*LLjBSq3_El?I*F{)<
zp~4$H>Tx%hWUisL at qtdliyMvA4P{{IABAe<!9m;2c;_27m==1fIaR%m%z`5!k*-U^
zEHpW#U?%f->+wtSw{(5Z_u7|?;ZE(i^H{iB#6VPuX$v*Go&nJ!?Aogb`jVCUMi#=O
zih4>)Onjw4lb;kX_FO!^=5GU=pj^s2OmmZCisE^q22jr=JobCmr at GI#&TB1`B5_?C
za+>~n_NMV1AOdDhSo00I#s5}Z*2iN9Ae;>9SdiBBynU~~duDC>#%1=@W7GK>%;tPa
zy~RFR$va#+M#jc!CYio`ViL_}_6F;P%xw<9;jcI+`_Gnei}o#<F6bm7D-N4EXI`8A
zpQl{pU=yTMR|Z%M?n1db?D2x|A9xUcBFUf=T}K4K&Zj}7?43S5WbA{8i0ATK1`HYK
zsCM8rVWryBKr_tvNk(S9cJKGRUW-xhP}hyuu!g=u<=npfRK$p>GTWAy-c6KRMO$y8
z(CAN5zRb!#yi=5 at Jfq1<qBc3+kz;I>)y!M at vp7H}0(zJV^t2`0I!*fXn25+?Y+V~H
zb^B7goWH;Uj&q2GI{i?F(6J~)_Q4%l-E#kjRCg?v+~Wsug<ECA-JYvrL^<6Yg1qww
zc4B)WtJj;ukY6QXti}kH27?C0Aq~pJ$0^Kpm<Uc*NVw8ecmCs>n^Pg7p}c~ks$A5;
zXy!Rf6A-=dPatYT*&|eD7?}nw-WeHJ at +%h`*#w>{q~G27u5$iVCzmBs-W6#AEcBbS
z<Gki*h9EqASWbh8&Xcm+i?LEw_E*!g^)r&!7I-Q6Xht#e`B{;=F(22rX##JA*Jdid
zg30Opit at 47>A>WEC=|pt{5Xy#kquS_#*)IQYtTfkWI8;=6*l!1sZ;h%<_16yZZBrO
z&BVxz#V%qEs(Fl65P*b?toO2uNO5*dt8ALv-00dh^-jCUroIJYOh0JYOx51<P2K;z
zcd8M3t;3cUy&Rr!fG$CT0 at U6&vtev8`2*9XPFg at -qa)#QBS}F?REK5{zt(B~)Aq4m
zDsdl#E;oMk6JVwUucQI#Yr#T|(d6_Zw_kv2JtU!xR993CRh#&VG&j882ZCD;B~XF<
z3m#jBGvAAC1aLb^ap$YNrUb|ye6<F0Q1SS&+Hd7iu?FnA>ZZBbGY*Zf`hE?dMlYk7
z_s|V}g9p&1M<USBFv*34Z%2Z}KMHbl<$FGL8DSF at mKV8RGVG?N&R($SZj4q}j4zk`
z)_MA&{yPmNSeLA(_yZ>nJO$uP-evw<n5D8xIpsaNz)$NFo$tSFz7R`?RUo~J`84t>
z=?Sg`F?5_ViqkYm;`;g;PJ^K5Gv{ZwIo=EgZU?^iQwMJJ>2!N~9b^G7Pr1caQyUFf
z{RGImYg-&epQZo%f0AG`GkB_~1x-%P3*4e1`eU45P09)k#3L}8ofEf at n0E<@JTA(0
zIhLXaJqz`~RhFTz9KiQ at Fe{>ku}Y5=?W8VhlE0Z<DreU8&^K}q>+Z<<V%m8`|H!P1
ze)9#ciSJd@<iX_%4&Z)N7;h1lDX^!^%tYEqlHU{?%r(vz%)f-;y19vn(DymG==N)O
zcP=Km*wHa5G4;P5085r8`PM&D at f8BH87VUFPwU-p<^~*uf3G#UoJhkby?W at _Z;vm-
z`V+vsBOdUt72^geBK+Qn1-av&N8k6RKet;Xn)SpRn6{Q_9NmU3zL&_26|a^erjY<M
zXPS{pF+D(%UjJ0#bIV!&>CJLU6iDPJPDJ{GM7ldfZ8L2)?C;+T&28c~m?HMX838WO
z>&42q>n|6ZFAjxzSI3PRxfvz#D@}clhBh%#UWeFnSlEm)=IUmz07Z~?jm*p7WK#%#
zYzR7^&Zh#lB<ZAyi%}s6#@ZU4?|MKe0Q0QR<IzH{PU0xp(ygQsPCpLN3lg`XvreCj
z=b5rHG!$3=fbI#BR*g>m at _YmFW`>yJV%7hC^4ewHpdeM7fP|y%T`&z95c1e<uJnU8
zhUq(^BbH-MU-yRGZCk|IW{PmI9h^aI>Tz`^f4j;hV1mJz;?6y@#F&<tFggn33A&AF
zjvxCgu8Nxa6lh~eXt&2*_4;p1qG}3gu@^cXiEb-W`B;|c^L>H5&(aAq_-`1b3m at b;
zskch}=9`Eq4I9u!FneabrkP*ASE5rCA_;x`sm$<U at 8??#0cTdhzOAQfyFe+x%+OJi
zpg0^Yzj6h>xCg}_^aAScx<pm~^H1e>t!n5&Dsp+1h at TV>>sph9SFjmE2KMIIfM4Mn
zU|bNW)at#${lWNYONdnoKefbsj5i@;bjyH$xWQd$jxl9how*2YL4p`~RA!tHI=bK>
z?|$gJ^hSw54vpbzUKti0u7w1bIVkFC8~q2u3BivOr0Ku*#w6I*TDYdrLeDynrSFl9
zc9bwN at e)!<sOCv_7FP=cQcX?N8LEu^SehGnyU}2V<OR><)fiiFTh|$_6X}xk`I}VO
zdAE-J?{tH%%fGxrEzNyu4!Ux6^|`HCu=@(-m-+GAll=}hzMA663|qrZYQJOqvl(=M
z^{bPJV?#igj}P|#!Lj+*4lJXmY1{@zpE(E>R{I&%LelQO*ZKJKX9#Uf;<Wb?;^kC(
zo>w0VplVeXhg%TCWyWv4;Ay~IRh8H`L0aK at ti$T|XC<?>xEN`b7h}>}TlBNbhv`SQ
zYuh3$<k#PZt(b6vvsIC3&6S58RL5-XGwL3ba!d6Rp;|a%SAsxR>E5MkwGRHZ#YIW6
zJw0rwd8jt!9iynQSf>Q9u<&;3$1*1#v!0cc^f`8mn2^fjyp%D;32Qg{YzvT1Pcx<z
zWZ_h~u8cSou$2T;^fN*L)YLs;h5?)8Iw*f=ba}H8tQxf9gSoS>?+pJ0H_`8MQrU;q
zSI;)ez1w-zltd>(ZNYKQ!6Mf6Go|dEm+HiLnya9d(ypPet<wl!TC)@fvPicBQymfr
z=n2qsKb~9^dP}_Yt%LEEw{w}fwB0*32tiuq{HjyA4P}sF9wi{q)zt!1YG8>CH=5LW
z_7{%#K(KC>j8$$oT(G0clD?alHuHu-ak1Ws{NH{Y(+M^<w&ieGiFZ|InH&CF8>0H|
zJ<CGPnmk%I+!IghuW6)*4U96#!00<|`@3v!=0+pu6a&JdgMD<HPG at vDU6$(=aJ`3O
z99=%nAmc<+MHLk4t|uw)+?dqkIr9F9t~X)jN}v92N4M%RglAB at _soH!D;IsqR;YVI
ztq=_`+txZl{iJVXOdm$dQb7>QPH!vz7_=M~CZ{rIWZu5xeBB9J%L1tG!SzK9Uo|F;
z6t;`nb$eB5#2~O4(2RJj-;8VfoLTZR5cQNF at DNT0(^5F6K=`J<av=KzWsfdj#w;g_
zzWZ1U@%UWrju#{|?LX$QudY~ZoTdZ-W8&R9EChK3(X;NNTxl6khc7n!2ZY&iIipzZ
zP(P-}i8i3R+uOsdW{HLXW3gKLudwy0pP~KIuhFDJZ~s4K?IEEu)bdOSizjD1^4WiR
zp!VXH6=hF9zBnwimhr0vaR*)>O+j0YLU``@aA4lhPMTh81OE?JhBmEa(Uqw?QT`uK
z at 5joPmyzmcrp=yi+u8NfjbA^1Sm~{a){-ohQ45aeLiN7vFhV5MWDm;xr-I0(?4)pO
zlosDOE1_^(nmV-uWe#I0vzoi&U}yhTqJO06cFEl4<E6FkP-|qy+I6in{?6fLqI5~|
zYN?z3aN!5`pJ+2x*cv{}1qtxuIodP!KO%5#>pKW#?b<#7p#+v>>VI;$e89d&PDXa(
z(U9AS$j+Mwu{1jtK3sr~T`jq{`giKZtd at -G-XBreY;H*6#*C at n7Oyst#jh at zJWGWl
zxPBkx+?I|9_c4qW>>QjILj0N*%79J at JX(HNk6pjqjy{n8UNVd)-@{l>TsRSB;@$E&
zQ?MX4EJhvyq^L$}#rXu$^!PkH5?VazMO!zG?0bvqW;PU!1hu^kgi9SGG`~&IUXqZ3
z8BdyCHmY-zEf_*@FbCNwrI?$AXoJh<S6cs-S6xeXX-=WV_F%-em at u}Kyri`b4$2K*
zEq#`b*KKP~ko@*e#oQR(k(4cTGYM|tEset0mahq3r6f&y%~>{6zy7?OZf?GYKv20>
zDsI~PY$@ua=Ig%dlx=;?4|ZrJ<NY!iVtFsHb0a{D$)LxjF>T at 7NveO9qxL3fR;fTZ
zf&DyMBt)5!fH*xP12sMtt2H3d+hWuqF>-~U`^amak+3#n0*qK=wSe0hKPW at et64E)
zyZVpS7;BJ$M-OJBCHe6;e!{8jPlTwONscpkfw>%H6oPky!zGjA4{Ks at Z_bb39l2on
z8dPRUL at YRlFZ{jh$e5yc>M!;A7ErEI^<o&L*o|bsF<aT7wiJ^sD&+RBFYE!V^@i~J
zB<-~xGVKGkwkGezfuUdno%-dZF&K0O?NR)8>mcr*_m5_8?%vX|V_ at AkmERrCBz4!D
z0<f^2R=GXxixa0OAc3Uk<bb=173}*S<Nk at V`c8dweV*4&@RKQDw&s6iBhApjph>MB
z{`iew2fC<T(lu_i1KyOn6xFt5jjbP&|16tiv)3cFsi3IODs8-aE=XSd;1Lj{l%0kS
z4YuA)9`X$J%wk!UGFK6S8N?>vgq4uASo0_U1hdcE>qvM+oP1CGarp+1kwV8cr>S6L
zluuV^Gd?$m16$OZm0`o`Iaw_acL!&b;vXFQ^h*|apN@&h1Rai4t)N)%SqN(~Cbpmq
zl?=8v8 at lz&tPM9;cj0j?jDclB+q?~=T(m2)@r8!eksPRSCo_}OxdbKC>Q1nxV4PcR
zF_19k*Vf`G+|Fy=#_jX0BF|wxa_bw79q4zy8v!|DgA;`L;H=CnK-LCN{PkycLa7Ea
zCrqo*2pp8R0l!u7o1FjC+SuOD*(0nRu-;<Pei%n?!v`K2zDaiqhgkd|g7+p55)}2^
z#)wzlyuP;0DA{z*2(<layYAB_0(B~72CD~6HHLhG*pgRERZp4|R&`lZL_&x at oNe&1
z+-Rm;y?WeA#psx$0U`<^pCz8DKm_xXGg9(^yUv$u2_ooS2W$qjuLi?0ZxyM>geR<k
zePtUvw8dug_4Bz?yy(Z(PL9s2JDBD05Z;g^Te;Bo9$|pdOZ+>YgJxDMev(ohyNqXL
z=HelC(?E&t4*!0BHE%p72{pvteCo|84pDAY)QaNfP4)6+$83jj$d=fhtcYH)*C{47
zfksF#Sk7$r^1Kzrn_oB at d%4d(W3}I_GxT)d!JFM{|1e1I{|dCizePMIqdtJM=4>Ep
zw4R7P%jGU$tl)V6p=F_cvJZQjIb}b_lz)lrf;lZ|(gHi_@)!~D2k~&rcuLgo>gM at 2
zKDP$5(0m^H;`eVscgG0IC^RJ}x5a}@cYEK&I%GGGFyF*QMR$#blY75L8IS^j{+Vsm
zH8GiGdF}nPrFRhRQEY{q^ibWn$AmlVLk7lG)V?WNn0$CVxdbjKHbL-1K)H);j-x`&
zb7|4AZR6-tS5t{mPFHI*-J!c;&s}KptbMZ at 092o!|2&94>?WCF#l~jO{M@^mo+%uD
zN{B2;89Ob)o_h7eqdW60X{V7sOElMUEL9`xt{&Sf3ewEBCkIo%KJF_4iTku5eXjQl
z>zvXdvHDWph#~ROOax9}|24u%qJ at Q*PzL%ORoUhUkw(gfs81`TJNXgXt!eXDhP>qu
zWf at H->Hc{A1X3w1XQniVduyQQS#dz(qs4uV#H(~!RJ`Rg%C0{N3Y4*3FM)p+{mur-
zD|dZE*R_nkj<(l%eX1zq3u&@{b#Q|qt at tG-p0fS2>^nWw;B4IFqtkN5Qh8PgjJ at iE
zg8laJ1i^~E1K-jM%AT34*-?H(+`9M0)G0-J4uu>9q24L;18!IQbRXLdzwKjPg$DCQ
z$!74s*P;VUo0Ni=1NaI-XK$ac at Pr^_MNJd9Lj#+e65{?RzhDF7G0uy}KZd==Y69f}
zGyv6ok=2USW at MS8r#Qn>FYz2~zC at gU{I?uYW_`E6aSN+kw(~^jsXAf!r(}kHZ9u-8
z6x#crwlQ*eQC183(c|;T)m0>|zcO3-j_|Y2ylFYifL($4H$k$+%=^Fn>8A7Ut(X-F
zj4N5yIz!IwPA}wd#hzTPEVe;mgzJ0N)>*u4;0w4^sZO1w{Y{^p at M8PdcDV-sdhfZM
z-0TeuvHJOA#ckQ>Jy?=~EzNGVoPg6-lo~puzbq^lSC2+(6-%{SaU!kDY at vCXNQVRX
zzq}8Yx&votJ-eMU#K)!sVl=~+-<LG8X+ZJk=^9qENbUBWAi%pM`(&jU&Eg<`8u#J3
zw?X{eTr-qpWSFjf->KYr-34ac6*@r71gSk=N)-c`ztisa_N=S652~mV0m)R*1cy=h
zI|2Ru4`i@*Dg;(M`}6aJ(fTQ|8_?l4w+&s^Yj`IbgH4j8PjPnOrsY+wN#!Fom2ss<
zYOT~h at uAg>fL at D#@UqR(m1k2QHn#b6`t~63YA6c<z9TBeL51qq2)vIM?4IJWy!$ym
zhHIRWe!h;AGd!z%z3n)4PRdpu2M#ERp;pq^?Sh$0(0~MniBD|>dhwCaKd<%2us%On
zXSnjESX}#yZ!)IsOiE)k&&+W at fzT;<{cA_z)c^kY;PL5++GaJzfN+X9IFdC1MyoJ<
z7Wf?IG2WCi*u2 at b=ZTF#evd+h*x<wkG*;jiCP&6l1>?$~!Z9F%VSa-`lQ6w}kmHAn
z+qY!e?YTbNFflveLV~zzfqs2+LuumCDzZC$?9Qp2PU~~zdGn3vg3c1N)QPrU$01R0
zV5jKSTS+EDm6EEd=c3dJ26HF3utC$!XRYty|GD3#j6$3$ytLZfS at 1X$E7uUDFY&W{
z964qC!C>@_nLak5^TxOp5#is-g7?O#h{hO4%for8<QB=wk4TZ33RE#*Lybh#-)9>P
z<U7$qg8w`jwC&++H17AWZ9i=dRr4p&NzG0Rrvp~`0N0h%YjOuIlM3Q1?efyr91gfa
zJKpq`f4zp2(2YdPDmC?obPlrA8xZeT$Y}dV_$PF1q at 2=<D at NrPi+t10M=r`{P+s~?
z*LBstv*>oeJRPUJuZuzBf}_U3?`sESoiYJS?nWnKh*qgJ3Z(e?Q-4Hw4eOZ6$=2y!
z+m-J(Twb5s^IhX9u?GMl91H@>$yr_wz()<+NsoVnLaTJn-RtsvaRS~&*eD0hhW4k?
zv&T1{nN{cCD-n)s{+p!>H5m^34`BJL1xhL#>>F)-XRIfsZe5g89={==3f|>D!u4bh
zU5ybEL$d9UTXeC)p2V{ZrVr_R_;($4^XE7^CLV02TGPf5L;n&-VL~JMgmBly5I747
z%#{+Q`}<!NCiAN-kCzvm)a6mDqLK*vTm5I*C((K*J)g^o<J6L<%P^Dr&vu15y*8{p
z_o{iso?Ou78u{-Bi?CMDidc3cU+Ag9Qd9O at yUsq0u~xgeS>fZm3`gqUm{oL%3-bz;
z&*OOFZwstkSK at Kj0{vddP5q8OjSLJ(MFeDOW;QM2 at WL@(5!xl~XY+-{-pk9w>m at dI
z$YEQ?2-Sw;&NjqXRbOx-oV!vP008>Jf3pC6kiuS>2!=@$pJ!330m8t?op at F?d~Y>8
zf$?8%xQE(k$!l;Jfg2kv^!QI#$O6_{xv>2^kczJJK1`HtSS2RoyXkNcdKeVDt5CU3
zxA?cF|DdtbS}kd^Ux~}TF%o7lF^!hN4gREt2O`Y<iP{jK(VBwDBDZK3HBI7YWE}Dg
z(TBCLO9;Nhvx191i1El3o4hh>oEEE@@?PlZhN`Keg~g?VCYa_XMD6<gwS4=k^+NOd
z?3R4lL!gRNnvPjn!c#l`xE8;l%7E=q?t5&saTfPY1uR1Ac&a=8PLjWs5F?3{4PPyF
zLV{<x5NJ>h;DLIpE$UQz7^AfxKN%Db%Y{Z at t8Ltk^Wf0L#I_0qmZo2~Wk!t{S-WdB
zLhLhp^>w+2Ck(<Sph3~fP5Lm04>w at WQ~IvRmmZ=ltPNtTk+bjJFqrxD<CMl00(1CN
z;ev~F%dfAlm#y5cb>h at jvCXAX6RgAO(IQ!Sa94klm%1(!a_3E4x#$x?1CXbSR25Kh
zC`1K)!5k|QLto|wc4EC`wC_6MBNYa}IuQXTDvgVX^~5We>Io)kK?hNZplEHZ&}2<5
zqpeY?*R$|G<GrR5D9o$b?C%Hu&@G=aU?=iW4U#*5B23F{k5{&^Vet5aBH{C}OGJ5j
z^H!BCH9(vd2_DR8G+$=7aiI3aieAm-^%{LS at Z?>gtur)WyPwPL+{5(g$nx9P{YkNk
zHrVW!vQ4aFb0QfOM%_RL#+(}4oIM26rPnjJJja4(8Qemb?Wj5p2BG2+$9JMS^+E<p
z^!UG*mjzU24zuc0<KMWIdaSr$EU5sJV6XQGO#W<oSZb|*YKOZZ#FP?@naHWh3>x$a
zbUk$^j at uDSF37cGOC8}z5pwI%eluu2e;71M#vT2RddR)~%OJ7xE?p1KZsj~AnK0B>
zqcmRooQ at h}7EM*OM~x!kOGqD9<*n7udl==K>_e;}BT(M2W%i2Y$!>*4L)ZQ}Wy?l#
zy5+5Fv$KYA=PJ|cTU72hkx5OJlZD0hd!*ey-jhwL?qF#kPC`N|LiO;Z_xspVnRA3L
z7bmiyrfR8aRqt?%8B#pySQwr)LF3An`#n|@Z8f~MlCqiYhu&%(V<W2p2SJTSc_R(X
znDLQ!>4X at W``F8B{&-}bWW>=<v0BHj^Ie7Ag0gsb-CvJNqqqf(u%epevFJ{jH9-q<
z>*!*8pX;ZaYOU39%bVO6f#>Jvgsy~yn%CHt^pGNUCpLzn!P9lZ>BckEed8-!wqbcc
zG&J_!34c#*Ij}pBw&SL$_B}mgVr_(tturSlb4=<W0KwY|Zc$^9<i}5NJOvc=^>npC
zdp0X~OA;d)3VhY5)~M9fU{h;`6suO3?e)cyO1LB|M}5ry>b`$_XKmE67(LGhI^s&3
zLu!c>SkUKa&;3 at mb9DTB*!nPqrK+x;kuOg3fS`(v2+<&rw at Rm$HVAp6HZ&D?A?2W<
zT)%qoL?OO|2XA^4pdNvL!Q>*8qc<@=)tS-lX4yO2fb417-twEuRp!U9lWmI%g80!!
zM;(3=tUkx~R+jz6;oik3NvM90Bf5N{$s`BIi?Z$l4b6aAQ{|6z)y3b3d at V`eHMsIF
zNuJe7l^d&;`7tvLO%}hDmkU8NRuUd212%}TV{acG`n%pi at N?m16Nyvl<gJJ!>9}MS
zS<D<4;M)+RPW@^S$Rb+YE3cR^8`=V}`_0)Z>9mRxRckDGNv6gpI!}|^v=7zkW at gYG
z9d<@6aYS7;IdmUW^B>rZZ at 4m<F~5yxR2qc{QV_Z&p~jCIZ|pVl#}uU&m!+$2 at T&#l
z%j&ids?o~z`r$D|ldF$f8kJ9pMHR>*W0OJ7z!si_>%*TLrht6BVh#vHT?kkK5u}fb
zODMug&}t^_by%+LAX6j`L>2 at WF{=K(`&PtQ;WP$;iNjf%tv1!0%VMYPplK>GfO68{
zTz$O at sKiM$sPQ1Eol1+}u74H$SQtw?XsypJfYe}!KwTk28#*O;OYG}*te5RKp>n>x
z>-ZgpABY%xwt at slr3mVM>EFn3V&h`YM7)knq>H4WtEl)PyJnLA!ukUexBDGhg%NhW
zeouzufpG!W&b*w0ihGj57p#W`d#?I34ukL at U=?LW$}o|r6;+!C)f2=9{`%BX2bX<=
zrH2w6pTtbq2IS3c^wPLsyZmE4><Sg!q+V6+DMtvlA(iiRy_9bxi>IG=bbbxo2XlpS
zGlMkh`N?)ND}}&RqLHm*h;RIBPgWeBwBp~p1P(F_SnZSE--jqN)CQ;Q9dS)t`Xr6=
z{ExN4U?sxxXmx*o-K;!w==G`3X4Uf|n^m&eTFtLE!2f%8ztiD(=1!xb;Cj!E*Rk8k
zme>tr&gr{SRf0jV6cGQ6iw#&ta(^K%emsS~vQ$O3?MDU9X{8?#P_QvKZe~>!!sE%b
zJDBrRs|3<&tvx`!QIUxvLX$OP9Q2ppsHVF(|F&6A+g#oWV4P<beEGAFZihlOjV*m+
zF>6L at MEYktkd^w}$&%gcbuT|=na{BfVaJlP&*0k$rUSF-K3QSlG#n3 at m~3;REmtxK
z167Ffd1G~k?X2 at oyPftwL^Xdt;hJpuNxdH9hoS4CNO{kFXhQ1AXRjLGm1OU~*Ki%}
zzrRQgI}rU4<^lxE5zxyLgjp!{P2TF)_srSl$+vz6)g&-iYmV9I(`SFN-QVA29k#4D
zN;f3vBC`A)cLeyUy>3s*`}#@16nj-Ve(<<mc7<>T{rq!EM-RQ!;eZTUBmkJmFeU7g
zq|&YYy=lT~;~6Wp;Vw#4|CBNLo^((1zYO<5h at zbx)wHN~nLll7Snc&HnyX3hA)RBB
zOixsBUQJHT><Nvh#%%%8d8nkI6oI}RWZ9W#!c*`|c^LuIn^zSC#%k6?L_zr=vdNbb
z5Rn))VrO)-vG=}(*FLf7!ucSzwF(FSm-A0)^zo&^PD`BA=Mi at -TGi}I`)?UjN()wX
zOpiXS3F(<Z?F8|ytFz~%vc5A5r;&13J4IifipWhQ0llfC#`HNXcrgLjWP)6DfWJ6-
z0RzcMji0YOOI5ZW14DxO&9=&Xol)$K1rt%!k7hMGCaJSus$Ws3vx%hq>DJxd3P!w!
zzFE&hD-u-|Q{E at 0CPig}O0r6^-TWR4R8V>|WxW at i%`?84p1Ag%8E(i1`v6VW`cQrq
z<|w*yy2P=&l$0Rmjkd-^SHeT1YD?V at D93PSH*hn*`6%evD^(3YscQPi%9jl=kJ42Z
zX?e7!>`@XpZy4>~Q}|C6;%on at s)_su)Cf>XQG^vYKEXSdSJ-fuH~O=iwz%!2to{Al
zQEV^lb4Fy=!+wI at l%nbS_OpltZpG%W0<Um+h0vYcr?r+cK1Hxkh;GnY5h|dREO^ve
zh*i*`+zSpzk^=*Bd?NW#tJ*M^d5lBy_5<{f4 at g&%(>g<hEHNfVy}9>K at PSKpNX%9!
z1dGk%&9e{SC}uM*>U&1Q8EgPJcm5Cn{nZzwJ10efX at b?@tXB2*PdHw8G}Yn16&sAV
zV!$KeFv7VTS{q96rue%@dF-{M!S4@}F|`}Uw*-`87}Njvoaq0Kk>2u>y-*5p+VWlQ
Ts<nXguYi)Ax@?uSS;+qb#fhB?
literal 0
HcmV?d00001
diff --git a/extras/package/android/vlc-android/res/layout/audio_player.xml b/extras/package/android/vlc-android/res/layout/audio_player.xml
index ad93f5a..140ee5d 100644
--- a/extras/package/android/vlc-android/res/layout/audio_player.xml
+++ b/extras/package/android/vlc-android/res/layout/audio_player.xml
@@ -24,7 +24,7 @@
android:layout_height="match_parent"
android:layout_width="0dip"
android:layout_weight="1"
- android:background="#ffffff"
+ android:background="#00000000"
android:layout_marginLeft="15dip"
android:layout_marginTop="15dip"
android:id="@+id/cover"/>
diff --git a/extras/package/android/vlc-android/res/layout/audio_player_mini.xml b/extras/package/android/vlc-android/res/layout/audio_player_mini.xml
index 37fb5d4..54dfc89 100644
--- a/extras/package/android/vlc-android/res/layout/audio_player_mini.xml
+++ b/extras/package/android/vlc-android/res/layout/audio_player_mini.xml
@@ -49,6 +49,14 @@
android:singleLine="true"/>
</LinearLayout>
<ImageButton
+ android:layout_width="60dip"
+ android:src="@drawable/ic_backward"
+ android:scaleType="fitXY"
+ android:id="@+id/backward"
+ android:background="#00ffffff"
+ android:layout_height="60dip">
+ </ImageButton>
+ <ImageButton
android:id="@+id/play_pause"
android:src="@drawable/ic_pause"
android:background="#00ffffff"
@@ -56,6 +64,15 @@
android:layout_width="60dip"
android:layout_height="60dip"
android:padding="10dip"
- android:layout_marginRight="10dip"/>
+ />
+ <ImageButton
+ android:layout_width="60dip"
+ android:scaleType="fitXY"
+ android:src="@drawable/ic_forward"
+ android:background="#00ffffff"
+ android:id="@+id/forward"
+ android:layout_height="60dip"
+ android:layout_marginRight="10dip">
+ </ImageButton>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioBrowserActivity.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioBrowserActivity.java
index 0e3f235..5eef171 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioBrowserActivity.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioBrowserActivity.java
@@ -24,29 +24,28 @@ public class AudioBrowserActivity extends Activity {
private FlingViewGroup mFlingViewGroup;
ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
-
+
private HorizontalScrollView mHeader;
private AudioServiceController mAudioController;
-
+
private AudioSongsListAdapter mSongsAdapter;
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.audio_browser);
-
+
mFlingViewGroup = (FlingViewGroup)findViewById(R.id.content);
mFlingViewGroup.setOnViewSwitchedListener(mViewSwitchListener);
-
+
mHeader =(HorizontalScrollView)findViewById(R.id.header);
mAudioController = AudioServiceController.getInstance();
-
+
mSongsAdapter = new AudioSongsListAdapter(this, android.R.layout.simple_list_item_1);
-
+
ListView songsList = (ListView)findViewById(R.id.songs_list);
songsList.setAdapter(mSongsAdapter);
songsList.setOnItemClickListener(new OnItemClickListener() {
- @Override
public void onItemClick(AdapterView<?> av, View v, int p, long id) {
mAudioController.load(mSongsAdapter.getPaths(), p);
Intent intent = new Intent(AudioBrowserActivity.this, AudioPlayerActivity.class);
@@ -55,13 +54,12 @@ public class AudioBrowserActivity extends Activity {
});
updateLists();
}
-
-
+
+
private ViewSwitchListener mViewSwitchListener = new ViewSwitchListener() {
-
+
int mCurrentPosition = 0;
-
- @Override
+
public void onSwitching(float progress) {
LinearLayout hl = (LinearLayout)findViewById(R.id.header_layout);
int width = hl.getChildAt(0).getWidth();
@@ -69,7 +67,6 @@ public class AudioBrowserActivity extends Activity {
mHeader.smoothScrollTo(x, 0);
}
- @Override
public void onSwitched(int position) {
LinearLayout hl = (LinearLayout)findViewById(R.id.header_layout);
TextView oldView = (TextView)hl.getChildAt(mCurrentPosition);
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioPlayer.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioPlayer.java
index 43c1dc0..32d438e 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioPlayer.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioPlayer.java
@@ -3,9 +3,9 @@ package org.videolan.vlc.android;
import android.graphics.Bitmap;
public interface AudioPlayer {
-
+
public void update();
-
+
public interface AudioPlayerControl {
String getTitle();
String getArtist();
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioPlayerActivity.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioPlayerActivity.java
index d7a4210..81e80e8 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioPlayerActivity.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioPlayerActivity.java
@@ -2,17 +2,16 @@ package org.videolan.vlc.android;
import android.app.Activity;
import android.os.Bundle;
-import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
+import android.widget.SeekBar.OnSeekBarChangeListener;
public class AudioPlayerActivity extends Activity implements AudioPlayer {
public final static String TAG = "VLC/AudioPlayerActiviy";
-
+
private ImageView mCover;
private TextView mTitle;
private TextView mArtist;
@@ -25,15 +24,15 @@ public class AudioPlayerActivity extends Activity implements AudioPlayer {
private ImageButton mShuffle;
private ImageButton mRepeat;
private SeekBar mTimeline;
-
+
private AudioServiceController mAudioController;
private boolean mIsTracking = false;
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.audio_player);
-
+
mCover = (ImageView) findViewById(R.id.cover);
mTitle = (TextView) findViewById(R.id.title);
mArtist = (TextView) findViewById(R.id.artist);
@@ -46,36 +45,36 @@ public class AudioPlayerActivity extends Activity implements AudioPlayer {
mShuffle = (ImageButton) findViewById(R.id.shuffle);
mRepeat = (ImageButton) findViewById(R.id.repeat);
mTimeline = (SeekBar) findViewById(R.id.timeline);
-
+
mAudioController = AudioServiceController.getInstance();
-
+
}
-
+
@Override
protected void onStart() {
mAudioController.addAudioPlayer(this);
update();
super.onStart();
}
-
+
@Override
protected void onStop() {
mAudioController.removeAudioPlayer(this);
super.onStop();
}
- @Override
public void update() {
// Exit the player when there is no media
if (!mAudioController.hasMedia())
finish();
-
- // mCover....
+
+ mCover.setImageBitmap(mAudioController.getCover());
+
mTitle.setText(mAudioController.getTitle());
mArtist.setText(mAudioController.getArtist());
mAlbum.setText(mAudioController.getAlbum());
- int time = (int) mAudioController.getTime();
- int length = (int) mAudioController.getLength();
+ int time = mAudioController.getTime();
+ int length = mAudioController.getLength();
mTime.setText(Util.millisToString(time));
mLength.setText(Util.millisToString(length));
mTimeline.setMax(length);
@@ -85,7 +84,17 @@ public class AudioPlayerActivity extends Activity implements AudioPlayer {
mPlayPause.setBackgroundResource(R.drawable.ic_pause);
} else {
mPlayPause.setBackgroundResource(R.drawable.ic_play);
- }
+ }
+ if (mAudioController.isShuffling()) {
+ mShuffle.setImageResource(R.drawable.ic_shuffle_glow);
+ } else {
+ mShuffle.setImageResource(R.drawable.ic_shuffle);
+ }
+ if (mAudioController.isRepeating()) {
+ mRepeat.setImageResource(R.drawable.ic_repeat_glow);
+ } else {
+ mRepeat.setImageResource(R.drawable.ic_repeat);
+ }
if (mAudioController.hasNext())
mNext.setVisibility(ImageButton.VISIBLE);
else
@@ -96,22 +105,19 @@ public class AudioPlayerActivity extends Activity implements AudioPlayer {
mPrevious.setVisibility(ImageButton.INVISIBLE);
mTimeline.setOnSeekBarChangeListener(mTimelineListner);
}
-
+
OnSeekBarChangeListener mTimelineListner = new OnSeekBarChangeListener() {
-
- @Override
+
public void onStopTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
-
+
}
-
- @Override
+
public void onStartTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
-
+
}
-
- @Override
+
public void onProgressChanged(SeekBar sb, int prog, boolean fromUser) {
if (fromUser) {
mAudioController.setTime(prog);
@@ -119,7 +125,7 @@ public class AudioPlayerActivity extends Activity implements AudioPlayer {
; }
}
};
-
+
public void onPlayPauseClick(View view) {
if (mAudioController.isPlaying()) {
mAudioController.pause();
@@ -127,26 +133,23 @@ public class AudioPlayerActivity extends Activity implements AudioPlayer {
mAudioController.play();
}
}
-
+
public void onNextClick(View view) {
mAudioController.next();
}
-
+
public void onPreviousClick(View view) {
mAudioController.previous();
}
-
+
public void onRepeatClick(View view) {
- // mAudioController.repeat();
- Util.toaster("not implemented :(");
+ mAudioController.repeat();
+ update();
}
-
+
public void onShuffleClick(View view) {
- // mAudioController.shuffle();
- Util.toaster("not implemented :(");
+ mAudioController.shuffle();
+ update();
}
-
-
-
-
+
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioService.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioService.java
index 7c7eb05..094c2e5 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioService.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioService.java
@@ -1,315 +1,355 @@
package org.videolan.vlc.android;
-import java.util.ArrayList;
-import java.util.List;
-
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.MediaMetadataRetriever;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
public class AudioService extends Service {
- private static final String TAG = "VLC/AudioService";
-
- private static final int SHOW_PROGRESS = 0;
-
- private LibVLC mLibVLC;
- private ArrayList<Media> mMediaList;
- private Media mCurrentMedia;
- private ArrayList<IAudioServiceCallback> mCallback;
- private EventManager mEventManager;
- private Notification mNotification;
-
- @Override
- public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
-
- // Get libVLC instance
- try {
- mLibVLC = LibVLC.getInstance();
- } catch (LibVlcException e) {
- e.printStackTrace();
- }
-
- mCallback = new ArrayList<IAudioServiceCallback>();
- mMediaList = new ArrayList<Media>();
- mEventManager = EventManager.getIntance();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mInterface;
+ private static final String TAG = "VLC/AudioService";
+
+ private static final int SHOW_PROGRESS = 0;
+
+ private LibVLC mLibVLC;
+ private ArrayList<Media> mMediaList;
+ private ArrayList<Media> playedMedia;
+ private Media mCurrentMedia;
+ private ArrayList<IAudioServiceCallback> mCallback;
+ private EventManager mEventManager;
+ private Notification mNotification;
+ private boolean shuffling = false, repeating = false;
+ private Stack<Media> previous;
+
+ public void onStart(Intent intent, int startId) {
+ super.onStart(intent, startId);
+
+ // Get libVLC instance
+ try {
+ mLibVLC = LibVLC.getInstance();
+ } catch (LibVlcException e) {
+ e.printStackTrace();
}
-
+ mCallback = new ArrayList<IAudioServiceCallback>();
+ mMediaList = new ArrayList<Media>();
+ playedMedia = new ArrayList<Media>();
+ previous = new Stack<Media>();
+ mEventManager = EventManager.getIntance();
+ }
+
+ public IBinder onBind(Intent intent) {
+ return mInterface;
+ }
+
/**
- * Handle libvlc asynchronous events
+ * Handle libvlc asynchronous events
*/
private Handler mEventHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.getData().getInt("event")) {
- case EventManager.MediaPlayerPlaying:
- Log.e(TAG, "MediaPlayerPlaying");
- break;
- case EventManager.MediaPlayerPaused:
- Log.e(TAG, "MediaPlayerPaused");
- executeUpdate();
- // also hide notification if phone ringing
- hideNotification();
- break;
- case EventManager.MediaPlayerStopped:
- Log.e(TAG, "MediaPlayerStopped");
- executeUpdate();
- break;
- case EventManager.MediaPlayerEndReached:
- Log.e(TAG, "MediaPlayerEndReached");
- executeUpdate();
- next();
- break;
- default:
- Log.e(TAG, "Event not handled");
- break;
- }
- }
+ public void handleMessage(Message msg) {
+ switch (msg.getData().getInt("event")) {
+ case EventManager.MediaPlayerPlaying:
+ Log.e(TAG, "MediaPlayerPlaying");
+ break;
+ case EventManager.MediaPlayerPaused:
+ Log.e(TAG, "MediaPlayerPaused");
+ executeUpdate();
+ // also hide notification if phone ringing
+ hideNotification();
+ break;
+ case EventManager.MediaPlayerStopped:
+ Log.e(TAG, "MediaPlayerStopped");
+ executeUpdate();
+ break;
+ case EventManager.MediaPlayerEndReached:
+ Log.e(TAG, "MediaPlayerEndReached");
+ executeUpdate();
+ next();
+ break;
+ default:
+ Log.e(TAG, "Event not handled");
+ break;
+ }
+ }
};
-
+
private void executeUpdate() {
- for (int i = 0; i < mCallback.size(); i++) {
- try {
- mCallback.get(i).update();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
+ for (int i = 0; i < mCallback.size(); i++) {
+ try {
+ mCallback.get(i).update();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
}
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case SHOW_PROGRESS:
- int pos = (int) mLibVLC.getTime();
- if (mCallback.size() > 0) {
- executeUpdate();
- mHandler.removeMessages(SHOW_PROGRESS);
- sendEmptyMessageDelayed(SHOW_PROGRESS, 1000 - (pos % 1000));
- }
- break;
- }
+
+ private Handler mHandler = new Handler() {
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SHOW_PROGRESS:
+ int pos = (int) mLibVLC.getTime();
+ if (mCallback.size() > 0) {
+ executeUpdate();
+ mHandler.removeMessages(SHOW_PROGRESS);
+ sendEmptyMessageDelayed(SHOW_PROGRESS, 1000 - (pos % 1000));
}
- };
-
+ break;
+ }
+ }
+ };
+
private void showNotification() {
- // add notification to status bar
- if (mNotification == null) {
- mNotification = new Notification(R.drawable.icon, null,
- System.currentTimeMillis());
- }
- Intent notificationIntent = new Intent(this, MainActivity.class);
- notificationIntent.setAction(Intent.ACTION_MAIN);
- notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- notificationIntent.putExtra(MainActivity.START_FROM_NOTIFICATION, "");
- PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
- mNotification.setLatestEventInfo(this, mCurrentMedia.getTitle(),
- mCurrentMedia.getArtist() + " - " + mCurrentMedia.getAlbum(), pendingIntent);
- startForeground(3, mNotification);
-
+ // add notification to status bar
+ if (mNotification == null) {
+ mNotification = new Notification(R.drawable.icon, null, System
+ .currentTimeMillis());
+ }
+ Intent notificationIntent = new Intent(this, MainActivity.class);
+ notificationIntent.setAction(Intent.ACTION_MAIN);
+ notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ notificationIntent.putExtra(MainActivity.START_FROM_NOTIFICATION, "");
+ PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
+ notificationIntent, 0);
+ mNotification.setLatestEventInfo(this, mCurrentMedia.getTitle(),
+ mCurrentMedia.getArtist() + " - " + mCurrentMedia.getAlbum(),
+ pendingIntent);
+ startForeground(3, mNotification);
+
}
-
+
private void hideNotification() {
- mNotification = null;
- stopForeground(true);
+ mNotification = null;
+ stopForeground(true);
}
-
-
-
+
private void pause() {
- mHandler.removeMessages(SHOW_PROGRESS);
- // hideNotification(); <-- see event handler
- mLibVLC.pause();
+ mHandler.removeMessages(SHOW_PROGRESS);
+ // hideNotification(); <-- see event handler
+ mLibVLC.pause();
}
-
+
private void play() {
- mLibVLC.play();
- mHandler.sendEmptyMessage(SHOW_PROGRESS);
- showNotification();
+ mLibVLC.play();
+ mHandler.sendEmptyMessage(SHOW_PROGRESS);
+ showNotification();
}
-
+
private void stop() {
- mEventManager.removeHandler(mEventHandler);
- mLibVLC.stop();
- mCurrentMedia = null;
- mMediaList.clear();
- mHandler.removeMessages(SHOW_PROGRESS);
- hideNotification();
- executeUpdate();
+ mEventManager.removeHandler(mEventHandler);
+ mLibVLC.stop();
+ mCurrentMedia = null;
+ mMediaList.clear();
+ mHandler.removeMessages(SHOW_PROGRESS);
+ hideNotification();
+ executeUpdate();
}
-
+
private void next() {
- int index = mMediaList.indexOf(mCurrentMedia);
- if (index < mMediaList.size() - 1) {
- mCurrentMedia = mMediaList.get(index + 1);
- mLibVLC.readMedia(mCurrentMedia.getPath());
- showNotification();
- } else {
- stop();
- }
- }
-
- private void previous() {
- int index = mMediaList.indexOf(mCurrentMedia);
- if (index > 0) {
- mCurrentMedia = mMediaList.get(index -1);
- mLibVLC.readMedia(mCurrentMedia.getPath());
- showNotification();
- }
-
+ int index = mMediaList.indexOf(mCurrentMedia);
+ previous.push(mCurrentMedia);
+ if (playedMedia.size() < mMediaList.size()
+ && index < mMediaList.size() - 1) {
+ if (repeating)
+ mCurrentMedia = mMediaList.get(index);
+ else if (shuffling) {
+ while (playedMedia.contains(mCurrentMedia = mMediaList
+ .get((int) (Math.random() * mMediaList.size()))))
+ ;
+ } else
+ mCurrentMedia = mMediaList.get(index + 1);
+ mLibVLC.readMedia(mCurrentMedia.getPath());
+ showNotification();
+ } else {
+ stop();
}
-
+ }
+
+ private void shuffle() {
+ if (shuffling)
+ playedMedia.clear();
+ shuffling = !shuffling;
+ }
+
+ protected void repeat() {
+ repeating = !repeating;
+ }
+
+ private void previous() {
+ if (previous.size() > 0)
+ mCurrentMedia = previous.pop();
+ mLibVLC.readMedia(mCurrentMedia.getPath());
+ showNotification();
+ }
+
private IAudioService.Stub mInterface = new IAudioService.Stub() {
-
- @Override
- public String getCurrentMediaPath() throws RemoteException {
- return mCurrentMedia.getPath();
- }
-
- @Override
- public void pause() throws RemoteException {
- AudioService.this.pause();
- }
-
- @Override
- public void play() throws RemoteException {
- AudioService.this.play();
- }
-
- @Override
- public void stop() throws RemoteException {
- AudioService.this.stop();
- }
-
- @Override
- public boolean isPlaying() throws RemoteException {
- return mLibVLC.isPlaying();
- }
-
- @Override
- public boolean hasMedia() throws RemoteException {
- return mMediaList.size() != 0;
- }
- @Override
- public String getAlbum() throws RemoteException {
- if (mCurrentMedia != null)
- return mCurrentMedia.getAlbum();
- else
- return null;
- }
+ public String getCurrentMediaPath() throws RemoteException {
+ return mCurrentMedia.getPath();
+ }
- @Override
- public String getArtist() throws RemoteException {
- if (mCurrentMedia != null)
- return mCurrentMedia.getArtist();
- else
- return null;
- }
+ public void pause() throws RemoteException {
+ AudioService.this.pause();
+ }
- @Override
- public String getTitle() throws RemoteException {
- if (mCurrentMedia != null)
- return mCurrentMedia.getTitle();
- else
- return null;
- }
+ public void play() throws RemoteException {
+ AudioService.this.play();
+ }
- @Override
- public void addAudioCallback(IAudioServiceCallback cb)
- throws RemoteException {
- mCallback.add(cb);
- executeUpdate();
- }
+ public void stop() throws RemoteException {
+ AudioService.this.stop();
+ }
- @Override
- public void removeAudioCallback(IAudioServiceCallback cb)
- throws RemoteException {
- if (mCallback.contains(cb)){
- mCallback.remove(cb);
- }
- }
+ public boolean isPlaying() throws RemoteException {
+ return mLibVLC.isPlaying();
+ }
- @Override
- public int getTime() throws RemoteException {
- return (int) mLibVLC.getTime();
- }
+ public boolean isShuffling() {
+ return shuffling;
+ }
- @Override
- public int getLength() throws RemoteException {
- // TODO Auto-generated method stub
- return (int) mLibVLC.getLength();
- }
+ public boolean isRepeating() {
+ return repeating;
+ }
- @Override
- public void load(List<String> mediaPathList, int position)
- throws RemoteException {
- mEventManager.addHandler(mEventHandler);
- mMediaList.clear();
-
- DatabaseManager db = DatabaseManager.getInstance();
- for (int i = 0; i < mediaPathList.size(); i++) {
- String path = mediaPathList.get(i);
- Media media = db.getMedia(path);
- mMediaList.add(media);
- }
-
- if (mMediaList.size() > position) {
- mCurrentMedia = mMediaList.get(position);
- }
-
- mLibVLC.readMedia(mCurrentMedia.getPath());
- mHandler.sendEmptyMessage(SHOW_PROGRESS);
- showNotification();
-
- }
+ public boolean hasMedia() throws RemoteException {
+ return mMediaList.size() != 0;
+ }
- @Override
- public void next() throws RemoteException {
- AudioService.this.next();
- }
+ public String getAlbum() throws RemoteException {
+ if (mCurrentMedia != null)
+ return mCurrentMedia.getAlbum();
+ else
+ return null;
+ }
- @Override
- public void previous() throws RemoteException {
- AudioService.this.previous();
- }
+ public String getArtist() throws RemoteException {
+ if (mCurrentMedia != null)
+ return mCurrentMedia.getArtist();
+ else
+ return null;
+ }
- @Override
- public void setTime(long time) throws RemoteException {
- mLibVLC.setTime(time);
- }
+ public String getTitle() throws RemoteException {
+ if (mCurrentMedia != null)
+ return mCurrentMedia.getTitle();
+ else
+ return null;
+ }
- @Override
- public boolean hasNext() throws RemoteException {
- int index = mMediaList.indexOf(mCurrentMedia);
- if (index < mMediaList.size() - 1)
- return true;
- else
- return false;
- }
+ public Bitmap getCover() {
+ if (mCurrentMedia != null) {
+ try {
+ MediaMetadataRetriever m = new MediaMetadataRetriever();
+ m.setDataSource(mCurrentMedia.getPath());
+ byte[] b = m.getEmbeddedPicture();
+ if (b != null)
+ return BitmapFactory.decodeByteArray(b, 0, b.length);
+ File f = new File(mCurrentMedia.getPath());
+ for (File s : f.getParentFile().listFiles()) {
+ if (s.getAbsolutePath().endsWith("png")
+ || s.getAbsolutePath().endsWith("jpg"))
+ return BitmapFactory
+ .decodeFile(s.getAbsolutePath());
- @Override
- public boolean hasPrevious() throws RemoteException {
- int index = mMediaList.indexOf(mCurrentMedia);
- if (index > 0)
- return true;
- else
- return false;
+ }
+ } catch (Exception e) {
}
- };
+ }
+ return BitmapFactory.decodeResource(getResources(),R.drawable.thumbnail);
+ }
+
+ public void addAudioCallback(IAudioServiceCallback cb)
+ throws RemoteException {
+ mCallback.add(cb);
+ executeUpdate();
+ }
+
+ public void removeAudioCallback(IAudioServiceCallback cb)
+ throws RemoteException {
+ if (mCallback.contains(cb)) {
+ mCallback.remove(cb);
+ }
+ }
+
+ public int getTime() throws RemoteException {
+ return (int) mLibVLC.getTime();
+ }
+
+ public int getLength() throws RemoteException {
+ return (int) mLibVLC.getLength();
+ }
+
+ public void load(List<String> mediaPathList, int position)
+ throws RemoteException {
+ mEventManager.addHandler(mEventHandler);
+ mMediaList.clear();
+ previous.clear();
+ playedMedia.clear();
+ DatabaseManager db = DatabaseManager.getInstance();
+ for (int i = 0; i < mediaPathList.size(); i++) {
+ String path = mediaPathList.get(i);
+ Media media = db.getMedia(path);
+ mMediaList.add(media);
+ }
+
+ if (mMediaList.size() > position) {
+ mCurrentMedia = mMediaList.get(position);
+ }
+
+ mLibVLC.readMedia(mCurrentMedia.getPath());
+ mHandler.sendEmptyMessage(SHOW_PROGRESS);
+ showNotification();
+
+ }
+
+ public void next() throws RemoteException {
+ AudioService.this.next();
+ }
+
+ public void shuffle() throws RemoteException {
+ AudioService.this.shuffle();
+ }
+
+ public void repeat() throws RemoteException {
+ AudioService.this.repeat();
+ }
+
+ public void previous() throws RemoteException {
+ AudioService.this.previous();
+ }
+
+ public void setTime(long time) throws RemoteException {
+ mLibVLC.setTime(time);
+ }
+
+ public boolean hasNext() throws RemoteException {
+ int index = mMediaList.indexOf(mCurrentMedia);
+ if (index < mMediaList.size() - 1)
+ return true;
+ else
+ return false;
+ }
+
+ public boolean hasPrevious() throws RemoteException {
+ int index = mMediaList.indexOf(mCurrentMedia);
+ if (index > 0)
+ return true;
+ else
+ return false;
+ }
+ };
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioServiceController.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioServiceController.java
index 0619b46..d207a4e 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioServiceController.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/AudioServiceController.java
@@ -1,11 +1,5 @@
package org.videolan.vlc.android;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.videolan.vlc.android.AudioPlayer.AudioPlayerControl;
-import org.videolan.vlc.android.AudioPlayer;
-
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -14,293 +8,324 @@ import android.graphics.Bitmap;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
+import java.util.ArrayList;
+import java.util.List;
+import org.videolan.vlc.android.AudioPlayer.AudioPlayerControl;
public class AudioServiceController implements AudioPlayerControl {
- public static final String TAG = "VLC/AudioServiceContoller";
-
- private static AudioServiceController mInstance;
- private static boolean mIsBound = false;
- private Context mContext;
- private IAudioService mAudioServiceBinder;
- private ServiceConnection mAudioServiceConnection;
- private ArrayList<AudioPlayer> mAudioPlayer;
- private IAudioServiceCallback mCallback = new IAudioServiceCallback.Stub() {
- @Override
- public void update() throws RemoteException {
- updateAudioPlayer();
- }
- };
-
- private AudioServiceController() {
-
- // Get context from MainActivity
- mContext = MainActivity.getInstance();
-
- mAudioPlayer = new ArrayList<AudioPlayer>();
-
- // Setup audio service connection
- mAudioServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.d(TAG, "Service Disconnected");
- mAudioServiceBinder = null;
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.d(TAG, "Service Connected");
- mAudioServiceBinder = IAudioService.Stub.asInterface(service);
-
- // Register controller to the service
- try {
- mAudioServiceBinder.addAudioCallback(mCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: addAudioCallback()");
- }
- updateAudioPlayer();
- }
- };
- }
-
- public static AudioServiceController getInstance() {
- if (mInstance == null) {
- mInstance = new AudioServiceController();
- }
- if (!mIsBound) {
- mInstance.bindAudioService();
- }
- return mInstance;
+ public static final String TAG = "VLC/AudioServiceContoller";
+
+ private static AudioServiceController mInstance;
+ private static boolean mIsBound = false;
+ private Context mContext;
+ private IAudioService mAudioServiceBinder;
+ private ServiceConnection mAudioServiceConnection;
+ private ArrayList<AudioPlayer> mAudioPlayer;
+ private IAudioServiceCallback mCallback = new IAudioServiceCallback.Stub() {
+
+ public void update() throws RemoteException {
+ updateAudioPlayer();
}
+ };
+
+ private AudioServiceController() {
+
+ // Get context from MainActivity
+ mContext = MainActivity.getInstance();
+
+ mAudioPlayer = new ArrayList<AudioPlayer>();
- public void load(List<String> mediaPathList, int position) {
+ // Setup audio service connection
+ mAudioServiceConnection = new ServiceConnection() {
+
+ public void onServiceDisconnected(ComponentName name) {
+ Log.d(TAG, "Service Disconnected");
+ mAudioServiceBinder = null;
+ }
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.d(TAG, "Service Connected");
+ mAudioServiceBinder = IAudioService.Stub.asInterface(service);
+
+ // Register controller to the service
try {
- mAudioServiceBinder.load(mediaPathList, position);
+ mAudioServiceBinder.addAudioCallback(mCallback);
} catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: load()");
+ Log.e(TAG,
+ "remote procedure call failed: addAudioCallback()");
}
+ updateAudioPlayer();
+ }
+ };
+ }
+
+ public static AudioServiceController getInstance() {
+ if (mInstance == null) {
+ mInstance = new AudioServiceController();
}
-
- /**
- * Bind to audio service if it is running
- * @return true if the binding was successful.
- */
- public void bindAudioService() {
- if (mAudioServiceBinder == null) {
- Intent service = new Intent(mContext, AudioService.class);
- mContext.startService(service);
- mIsBound = mContext.bindService(service, mAudioServiceConnection, Context.BIND_AUTO_CREATE);
- } else {
- // Register controller to the service
- try {
- mAudioServiceBinder.addAudioCallback(mCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: addAudioCallback()");
- }
- }
+ if (!mIsBound) {
+ mInstance.bindAudioService();
}
-
- public void unbindAudioService() {
- if (mAudioServiceBinder != null) {
- try {
- mAudioServiceBinder.removeAudioCallback(mCallback);
- if (mIsBound) {
- mContext.unbindService(mAudioServiceConnection);
- mIsBound = false;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: removeAudioCallback()");
- }
-
- }
+ return mInstance;
+ }
+
+ public void load(List<String> mediaPathList, int position) {
+ try {
+ mAudioServiceBinder.load(mediaPathList, position);
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: load()");
}
-
- /**
- * Add a AudioPlayer
- * @param ap
- */
- public void addAudioPlayer(AudioPlayer ap) {
- mAudioPlayer.add(ap);
+ }
+
+ /**
+ * Bind to audio service if it is running
+ *
+ */
+ public void bindAudioService() {
+ if (mAudioServiceBinder == null) {
+ Intent service = new Intent(mContext, AudioService.class);
+ mContext.startService(service);
+ mIsBound = mContext.bindService(service, mAudioServiceConnection,
+ Context.BIND_AUTO_CREATE);
+ } else {
+ // Register controller to the service
+ try {
+ mAudioServiceBinder.addAudioCallback(mCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: addAudioCallback()");
+ }
}
-
- /**
- * Remove AudioPlayer from list
- * @param ap
- */
- public void removeAudioPlayer(AudioPlayer ap) {
- if (mAudioPlayer.contains(ap)) {
- mAudioPlayer.remove(ap);
+ }
+
+ public void unbindAudioService() {
+ if (mAudioServiceBinder != null) {
+ try {
+ mAudioServiceBinder.removeAudioCallback(mCallback);
+ if (mIsBound) {
+ mContext.unbindService(mAudioServiceConnection);
+ mIsBound = false;
}
+ } catch (RemoteException e) {
+ Log.e(TAG,
+ "remote procedure call failed: removeAudioCallback()");
+ }
+
}
-
- /**
- * Update all AudioPlayer
- */
- private void updateAudioPlayer() {
- for (int i = 0; i < mAudioPlayer.size(); i++)
- mAudioPlayer.get(i).update();
+ }
+
+ /**
+ * Add a AudioPlayer
+ *
+ * @param ap
+ */
+ public void addAudioPlayer(AudioPlayer ap) {
+ mAudioPlayer.add(ap);
+ }
+
+ /**
+ * Remove AudioPlayer from list
+ *
+ * @param ap
+ */
+ public void removeAudioPlayer(AudioPlayer ap) {
+ if (mAudioPlayer.contains(ap)) {
+ mAudioPlayer.remove(ap);
}
-
- public void stop() {
- if (mAudioServiceBinder == null)
- return;
- try {
- mAudioServiceBinder.stop();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: stop()");
- }
- updateAudioPlayer();
+ }
+
+ /**
+ * Update all AudioPlayer
+ */
+ private void updateAudioPlayer() {
+ for (int i = 0; i < mAudioPlayer.size(); i++)
+ mAudioPlayer.get(i).update();
+ }
+
+ public void stop() {
+ if (mAudioServiceBinder == null)
+ return;
+ try {
+ mAudioServiceBinder.stop();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: stop()");
}
+ updateAudioPlayer();
+ }
- @Override
- public String getAlbum() {
- String album = null;
- try {
- album = mAudioServiceBinder.getAlbum();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: getAlbum()");
- }
- return album;
+ public String getAlbum() {
+ String album = null;
+ try {
+ album = mAudioServiceBinder.getAlbum();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: getAlbum()");
}
+ return album;
+ }
- @Override
- public String getArtist() {
- String artist = null;
- try {
- artist = mAudioServiceBinder.getArtist();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: getArtist()");
- }
- return artist;
+ public String getArtist() {
+ String artist = null;
+ try {
+ artist = mAudioServiceBinder.getArtist();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: getArtist()");
}
+ return artist;
+ }
- @Override
- public String getTitle() {
- String title = null;
- try {
- title = mAudioServiceBinder.getTitle();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: getTitle()");
- }
- return title;
+ public String getTitle() {
+ String title = null;
+ try {
+ title = mAudioServiceBinder.getTitle();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: getTitle()");
}
-
- @Override
- public boolean isPlaying() {
- boolean playing = false;
- if (mAudioServiceBinder != null) {
- try {
- playing = (hasMedia() && mAudioServiceBinder.isPlaying());
-
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: isPlaying()");
- }
- }
- return playing;
+ return title;
+ }
+
+ public boolean isPlaying() {
+ boolean playing = false;
+ if (mAudioServiceBinder != null) {
+ try {
+ playing = (hasMedia() && mAudioServiceBinder.isPlaying());
+
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: isPlaying()");
+ }
}
-
- @Override
- public void pause() {
- try {
- mAudioServiceBinder.pause();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: pause()");
- }
- updateAudioPlayer();
+ return playing;
+ }
+
+ public void pause() {
+ try {
+ mAudioServiceBinder.pause();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: pause()");
}
-
- @Override
- public void play() {
- try {
- mAudioServiceBinder.play();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: play()");
- }
- updateAudioPlayer();
+ updateAudioPlayer();
+ }
+
+ public void play() {
+ try {
+ mAudioServiceBinder.play();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: play()");
}
+ updateAudioPlayer();
+ }
- @Override
- public boolean hasMedia() {
- if (mAudioServiceBinder != null) {
- try {
- return mAudioServiceBinder.hasMedia();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: hasMedia()");
- }
- }
- return false;
+ public boolean hasMedia() {
+ if (mAudioServiceBinder != null) {
+ try {
+ return mAudioServiceBinder.hasMedia();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: hasMedia()");
+ }
}
+ return false;
+ }
- @Override
- public int getLength() {
- try {
- return mAudioServiceBinder.getLength();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: getLength()");
- }
- return 0;
+ public int getLength() {
+ try {
+ return mAudioServiceBinder.getLength();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: getLength()");
}
+ return 0;
+ }
- @Override
- public int getTime() {
- try {
- return mAudioServiceBinder.getTime();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: getTime()");
- }
- return 0;
+ public int getTime() {
+ try {
+ return mAudioServiceBinder.getTime();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: getTime()");
}
+ return 0;
+ }
- @Override
- public Bitmap getCover() {
- return null;
+ public Bitmap getCover() {
+ try {
+ return mAudioServiceBinder.getCover();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: getCover()");
+ return null;
}
+ }
- @Override
- public void next() {
- try {
- mAudioServiceBinder.next();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: next()");
- }
+ public void next() {
+ try {
+ mAudioServiceBinder.next();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: next()");
}
+ }
- @Override
- public void previous() {
- try {
- mAudioServiceBinder.previous();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: previous()");
- }
+ public void previous() {
+ try {
+ mAudioServiceBinder.previous();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: previous()");
}
+ }
- public void setTime(long time) {
- try {
- mAudioServiceBinder.setTime(time);
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: setTime()");
- }
+ public void setTime(long time) {
+ try {
+ mAudioServiceBinder.setTime(time);
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: setTime()");
}
+ }
- @Override
- public boolean hasNext() {
- try {
- return mAudioServiceBinder.hasNext();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: hasNext()");
- }
- return false;
+ public boolean hasNext() {
+ try {
+ return mAudioServiceBinder.hasNext();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: hasNext()");
}
+ return false;
+ }
- @Override
- public boolean hasPrevious() {
- try {
- return mAudioServiceBinder.hasPrevious();
- } catch (RemoteException e) {
- Log.e(TAG, "remote procedure call failed: hasPrevious()");
- }
- return false;
+ public boolean hasPrevious() {
+ try {
+ return mAudioServiceBinder.hasPrevious();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: hasPrevious()");
+ }
+ return false;
+ }
+
+ public void shuffle() {
+ try {
+ mAudioServiceBinder.shuffle();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: shuffle()");
+ }
+ }
+
+ public void repeat() {
+ try {
+ mAudioServiceBinder.repeat();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: repeat()");
+ }
+
+ }
+
+ public boolean isShuffling() {
+ try {
+ return mAudioServiceBinder.isShuffling();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: isShuffling()");
+ return false;
+ }
+ }
+
+ public boolean isRepeating() {
+ try {
+ return mAudioServiceBinder.isRepeating();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote procedure call failed: isRepeating()");
+ return false;
}
-
-
+ }
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/DatabaseManager.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/DatabaseManager.java
index a56aecf..3a76258 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/DatabaseManager.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/DatabaseManager.java
@@ -1,6 +1,8 @@
package org.videolan.vlc.android;
+import android.widget.Toast;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.text.SimpleDateFormat;
@@ -18,16 +20,16 @@ import android.graphics.BitmapFactory;
public class DatabaseManager {
public final static String TAG = "VLC/DatabaseManager";
-
+
private static DatabaseManager instance;
private SQLiteDatabase mDb;
private final String DB_NAME = "vlc_database";
private final int DB_VERSION = 5;
-
+
private final String DIR_TABLE_NAME = "directories_table";
private final String DIR_ROW_PATH = "path";
-
+
private final String MEDIA_TABLE_NAME = "media_table";
private final String MEDIA_PATH = "path";
private final String MEDIA_TIME = "time";
@@ -38,29 +40,29 @@ public class DatabaseManager {
private final String MEDIA_ARTIST = "artist";
private final String MEDIA_GENRE = "genre";
private final String MEDIA_ALBUM = "album";
-
+
private final String PLAYLIST_TABLE_NAME = "playlist_table";
private final String PLAYLIST_NAME = "name";
-
+
private final String PLAYLIST_MEDIA_TABLE_NAME = "playlist_media_table";
private final String PLAYLIST_MEDIA_ID = "id";
private final String PLAYLIST_MEDIA_PLAYLISTNAME = "playlist_name";
private final String PLAYLIST_MEDIA_MEDIAPATH = "media_path";
-
+
private final String SEARCHHISTORY_TABLE_NAME = "searchhistory_table";
private final String SEARCHHISTORY_DATE = "date";
private final String SEARCHHISTORY_KEY = "key";
-
+
private Context mContext;
-
- public enum mediaColumn { MEDIA_TABLE_NAME, MEDIA_PATH, MEDIA_TIME, MEDIA_LENGTH,
+
+ public enum mediaColumn { MEDIA_TABLE_NAME, MEDIA_PATH, MEDIA_TIME, MEDIA_LENGTH,
MEDIA_TYPE, MEDIA_PICTURE, MEDIA_TITLE, MEDIA_ARTIST, MEDIA_GENRE, MEDIA_ALBUM
}
-
-
+
+
/**
- * Constructor
- *
+ * Constructor
+ *
* @param context
*/
private DatabaseManager(Context context) {
@@ -69,7 +71,7 @@ public class DatabaseManager {
DatabaseHelper helper = new DatabaseHelper(context);
this.mDb = helper.getWritableDatabase();
}
-
+
public synchronized static DatabaseManager getInstance() {
if (instance == null) {
Context context = MainActivity.getInstance();
@@ -77,8 +79,8 @@ public class DatabaseManager {
}
return instance;
}
-
-
+
+
private class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
@@ -87,76 +89,76 @@ public class DatabaseManager {
@Override
public void onCreate(SQLiteDatabase db) {
-
- String createDirTabelQuery = "CREATE TABLE IF NOT EXISTS "
- + DIR_TABLE_NAME + " ("
- + DIR_ROW_PATH + " TEXT PRIMARY KEY NOT NULL"
- + ");";
-
+
+ String createDirTabelQuery = "CREATE TABLE IF NOT EXISTS "
+ + DIR_TABLE_NAME + " ("
+ + DIR_ROW_PATH + " TEXT PRIMARY KEY NOT NULL"
+ + ");";
+
// Create the directories table
db.execSQL(createDirTabelQuery);
-
-
- String createMediaTabelQuery = "CREATE TABLE IF NOT EXISTS "
- + MEDIA_TABLE_NAME + " ("
- + MEDIA_PATH + " TEXT PRIMARY KEY NOT NULL, "
+
+
+ String createMediaTabelQuery = "CREATE TABLE IF NOT EXISTS "
+ + MEDIA_TABLE_NAME + " ("
+ + MEDIA_PATH + " TEXT PRIMARY KEY NOT NULL, "
+ MEDIA_TIME + " INTEGER, "
+ MEDIA_LENGTH + " INTEGER, "
+ MEDIA_TYPE + " INTEGER, "
- + MEDIA_PICTURE + " BLOB, "
+ + MEDIA_PICTURE + " BLOB, "
+ MEDIA_TITLE + " VARCHAR(200), "
+ MEDIA_ARTIST + " VARCHAR(200), "
+ MEDIA_GENRE + " VARCHAR(200), "
+ MEDIA_ALBUM + " VARCHAR(200)"
- + ");";
-
-
+ + ");";
+
+
// Create the media table
db.execSQL(createMediaTabelQuery);
-
+
String createPlaylistTableQuery = "CREATE TABLE IF NOT EXISTS " +
PLAYLIST_TABLE_NAME + " (" +
PLAYLIST_NAME + " VARCHAR(200) PRIMARY KEY NOT NULL);";
-
+
db.execSQL(createPlaylistTableQuery);
-
+
String createPlaylistMediaTableQuery = "CREATE TABLE IF NOT EXISTS " +
PLAYLIST_MEDIA_TABLE_NAME + " (" +
PLAYLIST_MEDIA_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
PLAYLIST_MEDIA_PLAYLISTNAME + " VARCHAR(200) NOT NULL," +
PLAYLIST_MEDIA_MEDIAPATH + " TEXT NOT NULL);";
-
+
db.execSQL(createPlaylistMediaTableQuery);
-
-
- String createSearchhistoryTabelQuery = "CREATE TABLE IF NOT EXISTS "
- + SEARCHHISTORY_TABLE_NAME + " ("
+
+
+ String createSearchhistoryTabelQuery = "CREATE TABLE IF NOT EXISTS "
+ + SEARCHHISTORY_TABLE_NAME + " ("
+ SEARCHHISTORY_KEY + " VARCHAR(200) PRIMARY KEY NOT NULL, "
- + SEARCHHISTORY_DATE + " DATETIME NOT NULL"
- + ");";
-
+ + SEARCHHISTORY_DATE + " DATETIME NOT NULL"
+ + ");";
+
// Create the searchhistory table
db.execSQL(createSearchhistoryTabelQuery);
}
@Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion,
+ public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
// TODO ??
}
}
-
+
/**
* Get all playlists in the database
- * @return
+ * @return
*/
public String[] getPlaylists() {
ArrayList<String> playlists = new ArrayList<String>();
Cursor cursor;
-
+
cursor = mDb.query(
- PLAYLIST_TABLE_NAME,
- new String[] { PLAYLIST_NAME },
+ PLAYLIST_TABLE_NAME,
+ new String[] { PLAYLIST_NAME },
null, null, null, null, null);
cursor.moveToFirst();
if (!cursor.isAfterLast()) {
@@ -167,7 +169,7 @@ public class DatabaseManager {
cursor.close();
return (String[]) playlists.toArray();
}
-
+
/**
* Add new playlist
* @param name
@@ -178,33 +180,33 @@ public class DatabaseManager {
values.put(PLAYLIST_NAME, name);
mDb.insert(PLAYLIST_TABLE_NAME, "NULL", values);
}
-
+
public void deletePlaylist(String name) {
- mDb.delete(PLAYLIST_TABLE_NAME, PLAYLIST_NAME + "=?",
+ mDb.delete(PLAYLIST_TABLE_NAME, PLAYLIST_NAME + "=?",
new String[] { name });
}
-
+
public void addMediaToPlaylist(String playlistName, String mediaPath) {
ContentValues values = new ContentValues();
values.put(PLAYLIST_MEDIA_PLAYLISTNAME, playlistName);
values.put(PLAYLIST_MEDIA_MEDIAPATH, mediaPath);
}
-
+
public void removeMediaFromPlaylist(String playlistName, String mediaPath) {
- mDb.delete(PLAYLIST_MEDIA_TABLE_NAME,
- PLAYLIST_MEDIA_PLAYLISTNAME + "=? "
- + PLAYLIST_MEDIA_MEDIAPATH + "=?",
+ mDb.delete(PLAYLIST_MEDIA_TABLE_NAME,
+ PLAYLIST_MEDIA_PLAYLISTNAME + "=? "
+ + PLAYLIST_MEDIA_MEDIAPATH + "=?",
new String[] { playlistName, mediaPath});
}
-
+
public Media[] getMediaFromPlaylist(String playlistName) {
ArrayList<Media> media = new ArrayList<Media>();
-
- Cursor cursor = mDb.query(PLAYLIST_MEDIA_PLAYLISTNAME,
- new String[] { PLAYLIST_MEDIA_MEDIAPATH },
- PLAYLIST_MEDIA_PLAYLISTNAME + "=?", new String[]{ playlistName },
+
+ Cursor cursor = mDb.query(PLAYLIST_MEDIA_PLAYLISTNAME,
+ new String[] { PLAYLIST_MEDIA_MEDIAPATH },
+ PLAYLIST_MEDIA_PLAYLISTNAME + "=?", new String[]{ playlistName },
null, null, "ASC");
-
+
MediaLibrary mediaLibrary = MediaLibrary.getInstance(mContext);
cursor.moveToFirst();
if (!cursor.isAfterLast()) {
@@ -217,15 +219,15 @@ public class DatabaseManager {
return (Media[])media.toArray();
}
-
+
/**
* Add a new media to the database. The picture can only added by update.
* @param meida which you like to add to the database
*/
public synchronized void addMedia(Media media) {
-
+
ContentValues values = new ContentValues();
-
+
values.put(MEDIA_PATH, media.getPath());
values.put(MEDIA_TIME, media.getTime());
values.put(MEDIA_LENGTH, media.getLength());
@@ -234,39 +236,39 @@ public class DatabaseManager {
values.put(MEDIA_ARTIST, media.getArtist());
values.put(MEDIA_GENRE, media.getGenre());
values.put(MEDIA_ALBUM, media.getAlbum());
-
- mDb.replace(MEDIA_TABLE_NAME, "NULL", values);
+
+ mDb.replace(MEDIA_TABLE_NAME, "NULL", values);
}
-
+
// /**
// * Check if the item already in the database
// * @param path of the item (primary key)
-// * @return
+// * @return
// */
// public synchronized boolean mediaItemExists(String path) {
-// Cursor cursor = mDb.query(MEDIA_TABLE_NAME,
-// new String[] { DIR_ROW_PATH },
-// MEDIA_PATH + "=?",
+// Cursor cursor = mDb.query(MEDIA_TABLE_NAME,
+// new String[] { DIR_ROW_PATH },
+// MEDIA_PATH + "=?",
// new String[] { path },
// null, null, null);
// boolean exists = cursor.moveToFirst();
// cursor.close();
// return exists;
// }
-
+
/**
* Get all paths from the items in the database
* @return list of File
*/
public synchronized List<File> getMediaFiles() {
-
+
List<File> files = new ArrayList<File>();
Cursor cursor;
-
+
cursor = mDb.query(
- MEDIA_TABLE_NAME,
- new String[] { MEDIA_PATH },
+ MEDIA_TABLE_NAME,
+ new String[] { MEDIA_PATH },
null, null, null, null, null);
cursor.moveToFirst();
if (!cursor.isAfterLast()) {
@@ -279,18 +281,18 @@ public class DatabaseManager {
return files;
}
-
+
public synchronized Media getMedia(String path) {
-
+
Cursor cursor;
Media media = null;
Bitmap picture = null;
byte[] blob;
-
+
cursor = mDb.query(
- MEDIA_TABLE_NAME,
- new String[] {
+ MEDIA_TABLE_NAME,
+ new String[] {
MEDIA_TIME, //0 long
MEDIA_LENGTH, //1 long
MEDIA_TYPE, //2 int
@@ -299,39 +301,38 @@ public class DatabaseManager {
MEDIA_ARTIST, //5 string
MEDIA_GENRE, //6 string
MEDIA_ALBUM //7 string
- },
- MEDIA_PATH + "=?",
+ },
+ MEDIA_PATH + "=?",
new String[] { path },
null, null, null);
+ try {
if (cursor.moveToFirst()) {
-
blob = cursor.getBlob(3);
if (blob != null) {
picture = BitmapFactory.decodeByteArray(blob, 0, blob.length);
}
-
- media = new Media(mContext, new File(path), cursor.getLong(0),
- cursor.getLong(1), cursor.getInt(2),
- picture, cursor.getString(4),
- cursor.getString(5), cursor.getString(6),
- cursor.getString(7));
- }
+ media = new Media(mContext, new File(path), cursor.getLong(0),
+ cursor.getLong(1), cursor.getInt(2),
+ picture, cursor.getString(4),
+ cursor.getString(5), cursor.getString(6),
+ cursor.getString(7));
+ }}catch(Exception e) {}
return media;
}
-
+
public synchronized void removeMedia(String path) {
mDb.delete(MEDIA_TABLE_NAME, MEDIA_PATH + "=?", new String[] { path });
}
-
- public synchronized void updateMedia(String path, mediaColumn col,
+
+ public synchronized void updateMedia(String path, mediaColumn col,
Object object ) {
ContentValues values = new ContentValues();
switch (col) {
- case MEDIA_PICTURE:
+ case MEDIA_PICTURE:
Bitmap picture = (Bitmap)object;
ByteArrayOutputStream out = new ByteArrayOutputStream();
- picture.compress(Bitmap.CompressFormat.PNG, 100, out);
+ picture.compress(Bitmap.CompressFormat.PNG, 100, out);
values.put(MEDIA_PICTURE, out.toByteArray());
break;
default:
@@ -339,24 +340,24 @@ public class DatabaseManager {
}
mDb.update(MEDIA_TABLE_NAME, values, MEDIA_PATH +"=?", new String[] { path });
}
-
-
- /**
+
+
+ /**
* Add directory to the directories table
- *
+ *
* @param path
*/
- public synchronized void addDir(String path) {
+ public synchronized void addDir(String path) {
if (!mediaDirExists(path)) {
ContentValues values = new ContentValues();
values.put(DIR_ROW_PATH, path);
- mDb.insert(DIR_TABLE_NAME, null, values);
+ mDb.insert(DIR_TABLE_NAME, null, values);
}
}
-
+
/**
* Delete directory from directories table
- *
+ *
* @param path
*/
public synchronized void removeDir(String path) {
@@ -364,17 +365,17 @@ public class DatabaseManager {
}
/**
- *
+ *
* @return
*/
public synchronized List<File> getMediaDirs() {
-
+
List<File> paths = new ArrayList<File>();
Cursor cursor;
-
+
cursor = mDb.query(
- DIR_TABLE_NAME,
- new String[] { DIR_ROW_PATH },
+ DIR_TABLE_NAME,
+ new String[] { DIR_ROW_PATH },
null, null, null, null, null);
cursor.moveToFirst();
if (!cursor.isAfterLast()) {
@@ -387,54 +388,54 @@ public class DatabaseManager {
return paths;
}
-
+
public synchronized boolean mediaDirExists(String path) {
- Cursor cursor = mDb.query(DIR_TABLE_NAME,
- new String[] { DIR_ROW_PATH },
- DIR_ROW_PATH + "=?",
- new String[] { path },
+ Cursor cursor = mDb.query(DIR_TABLE_NAME,
+ new String[] { DIR_ROW_PATH },
+ DIR_ROW_PATH + "=?",
+ new String[] { path },
null, null, null);
boolean exists = cursor.moveToFirst();
cursor.close();
return exists;
}
-
+
/**
- *
+ *
* @param key
*/
public synchronized void addSearchhistoryItem(String key) {
// set the format to sql date time
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
ContentValues values = new ContentValues();
values.put(SEARCHHISTORY_KEY, key);
values.put(SEARCHHISTORY_DATE, dateFormat.format(date));
-
- mDb.replace(SEARCHHISTORY_TABLE_NAME, null, values);
+
+ mDb.replace(SEARCHHISTORY_TABLE_NAME, null, values);
}
-
-
+
+
public synchronized ArrayList<String> getSearchhistory(int size) {
ArrayList<String> history = new ArrayList<String>();
-
- Cursor cursor = mDb.query(SEARCHHISTORY_TABLE_NAME,
- new String[] { SEARCHHISTORY_KEY },
- null, null, null, null,
+
+ Cursor cursor = mDb.query(SEARCHHISTORY_TABLE_NAME,
+ new String[] { SEARCHHISTORY_KEY },
+ null, null, null, null,
SEARCHHISTORY_DATE + " DESC",
Integer.toString(size));
-
+
while(cursor.moveToNext()) {
history.add(cursor.getString(0));
}
cursor.close();
-
+
return history;
}
-
+
public synchronized void clearSearchhistory() {
mDb.delete(SEARCHHISTORY_TABLE_NAME, null, null);
}
-
+
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/IAudioService.aidl b/extras/package/android/vlc-android/src/org/videolan/vlc/android/IAudioService.aidl
index d31cd1c..b694057 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/IAudioService.aidl
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/IAudioService.aidl
@@ -6,11 +6,15 @@ interface IAudioService {
void pause();
void stop();
void next();
+ void shuffle();
+ void repeat();
void previous();
void setTime(long time);
String getCurrentMediaPath();
void load(in List<String> mediaPathList, int position);
boolean isPlaying();
+ boolean isShuffling();
+ boolean isRepeating();
boolean hasMedia();
boolean hasNext();
boolean hasPrevious();
@@ -19,6 +23,7 @@ interface IAudioService {
String getAlbum();
int getTime();
int getLength();
+ Bitmap getCover();
void addAudioCallback(IAudioServiceCallback cb);
void removeAudioCallback(IAudioServiceCallback cb);
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/MainActivity.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/MainActivity.java
index d0220ac..c08e37e 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/MainActivity.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/MainActivity.java
@@ -35,32 +35,32 @@ public class MainActivity extends TabActivity {
private static final int AUDIO_TAB = 1;
public static final String START_FROM_NOTIFICATION = "from_notification";
private static final String PREF_SHOW_INFO = "show_info";
-
+
private VideoListActivity mVideoListActivity;
-
- private static MainActivity mInstance;
+
+ private static MainActivity mInstance;
private ProgressBar mProgressBar;
private TabHost mTabHost;
private int mCurrentState = 0;
private ImageButton mChangeTab;
private AudioMiniPlayer mAudioPlayer;
private AudioServiceController mAudioController;
-
+
private SharedPreferences mSettings;
private int mVersionNumber = -1;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setContentView(R.layout.main);
- super.onCreate(savedInstanceState);
-
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setContentView(R.layout.main);
+ super.onCreate(savedInstanceState);
+
/* Get settings */
mSettings = PreferenceManager.getDefaultSharedPreferences(this);
/* Initialize variables */
- mInstance = this;
+ mInstance = this;
mProgressBar = (ProgressBar)findViewById(R.id.ml_progress_bar);
mChangeTab = (ImageButton) findViewById(R.id.change_tab);
@@ -68,22 +68,22 @@ public class MainActivity extends TabActivity {
mTabHost = getTabHost();
mTabHost.addTab(mTabHost.newTabSpec("VIDEO TAB").setIndicator("VIDEO TAB")
.setContent(new Intent(this, VideoActivityGroup.class)));
-
+
mTabHost.addTab(mTabHost.newTabSpec("AUDIO TAB").setIndicator("AUDIO TAB")
.setContent(new Intent(this, AudioActivityGroup.class)));
-
+
// Get video list instance to sort the list.
mVideoListActivity = VideoListActivity.getInstance();
-
+
// add mini audio player
mAudioPlayer = (AudioMiniPlayer) findViewById(R.id.audio_mini_player);
mAudioController = AudioServiceController.getInstance();
mAudioController.addAudioPlayer(mAudioPlayer);
mAudioPlayer.setAudioPlayerControl(mAudioController);
mAudioPlayer.update();
-
-
-
+
+
+
// Start audio player when audio is playing
if (getIntent().hasExtra(START_FROM_NOTIFICATION)) {
Log.d(TAG, "Started from notification.");
@@ -92,7 +92,7 @@ public class MainActivity extends TabActivity {
// TODO: load the last tab-state
showVideoTab();
}
-
+
/* Show info/alpha/beta Warning */
PackageInfo pinfo = null;
try {
@@ -102,16 +102,16 @@ public class MainActivity extends TabActivity {
}
if (pinfo != null) {
mVersionNumber = pinfo.versionCode;
-
+
if (mSettings.getInt(PREF_SHOW_INFO, -1) != mVersionNumber)
showInfoDialog();
}
-
+
/* Load media items from database and storage */
MediaLibrary.getInstance(this).loadMediaItems();
}
- /** Create menu from XML
+ /** Create menu from XML
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
@@ -132,10 +132,10 @@ public class MainActivity extends TabActivity {
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
-
+
// Intent to start new Activity
Intent intent;
-
+
// Handle item selection
switch (item.getItemId()) {
// Sort by name
@@ -143,17 +143,18 @@ public class MainActivity extends TabActivity {
if (mCurrentState == VIDEO_TAB) {
mVideoListActivity.sortBy(
VideoListAdapter.SORT_BY_TITLE);
- }
+ }
break;
// Sort by length
case R.id.ml_menu_sortby_length:
if (mCurrentState == VIDEO_TAB) {
mVideoListActivity.sortBy(
VideoListAdapter.SORT_BY_LENGTH);
- }
+ }
break;
// About
case R.id.ml_menu_about:
+ assert false;
intent = new Intent(this, AboutActivity.class);
startActivity(intent);
break;
@@ -165,7 +166,7 @@ public class MainActivity extends TabActivity {
}
return super.onOptionsItemSelected(item);
}
-
+
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
@@ -176,7 +177,7 @@ public class MainActivity extends TabActivity {
mAudioController.play();
}
case R.id.show_player:
- // TODO: start audio player activity
+ // TODO: start audio player activity
break;
case R.id.hide_mini_player:
hideAudioPlayer();
@@ -189,19 +190,19 @@ public class MainActivity extends TabActivity {
mAudioPlayer.setVisibility(AudioMiniPlayer.GONE);
mAudioController.stop();
}
-
+
public void showAudioPlayer() {
mAudioPlayer.setVisibility(AudioMiniPlayer.VISIBLE);
}
-
+
private void showInfoDialog() {
final Dialog infoDialog = new Dialog(this, R.style.info_dialog);
infoDialog.setContentView(R.layout.info_dialog);
Button okButton = (Button) infoDialog.findViewById(R.id.ok);
okButton.setOnClickListener(new OnClickListener() {
- @Override
+
public void onClick(View view) {
- CheckBox notShowAgain =
+ CheckBox notShowAgain =
(CheckBox) infoDialog.findViewById(R.id.not_show_again);
if (notShowAgain.isChecked() && mSettings != null) {
Editor editor = mSettings.edit();
@@ -213,8 +214,8 @@ public class MainActivity extends TabActivity {
});
infoDialog.show();
}
-
-
+
+
/**
* onClick event from xml
* @param view
@@ -227,20 +228,20 @@ public class MainActivity extends TabActivity {
showVideoTab();
}
}
-
+
private void showVideoTab() {
mChangeTab.setImageResource(R.drawable.header_icon_audio);
mTabHost.setCurrentTab(VIDEO_TAB);
mCurrentState = VIDEO_TAB;
}
-
+
private void showAudioTab() {
mChangeTab.setImageResource(R.drawable.header_icon_video);
mTabHost.setCurrentTab(AUDIO_TAB);
mCurrentState = AUDIO_TAB;
}
-
-
+
+
/**
* onClick event from xml
* @param view
@@ -254,10 +255,10 @@ public class MainActivity extends TabActivity {
* @return this ;)
*/
public static MainActivity getInstance() {
- return mInstance;
+ return mInstance;
}
-
- protected Handler mHandler = new Handler() {
+
+ protected Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -265,10 +266,10 @@ public class MainActivity extends TabActivity {
mProgressBar.setVisibility(View.VISIBLE);
break;
case HIDE_PROGRESSBAR:
- mProgressBar.setVisibility(View.INVISIBLE);
+ mProgressBar.setVisibility(View.INVISIBLE);
break;
}
};
};
-
+
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/Media.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/Media.java
index 4e0b2a9..97b4087 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/Media.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/Media.java
@@ -21,12 +21,12 @@ public class Media implements Comparable<Media> {
".a52", ".aac", ".ac3", ".adt", ".adts", ".aif", ".aifc", ".aiff", ".amr", ".aob", ".ape",
".awb", ".cda", ".dts", ".flac", ".it", ".m4a", ".m4p", ".mid", ".mka", ".mlp", ".mod",
".mp1", ".mp2", ".mp3", ".mpc", ".oga", ".ogg", ".oma", ".rmi", ".s3m", ".spx", ".tta",
- ".voc", ".vqf", ".w64", ".wav", ".wma", ".wv", ".xa", ".xm"};
-
+ ".voc", ".vqf", ".w64", ".wav", ".wma", ".wv", ".xa", ".xm"};
+
public final static int TYPE_ALL = -1;
public final static int TYPE_VIDEO = 0;
public final static int TYPE_AUDIO = 1;
-
+
/** Meta data form libvlc_media */
private String mTitle;
private String mArtist;
@@ -50,13 +50,13 @@ public class Media implements Comparable<Media> {
private int mWidth = 0;
private int mHeight = 0;
private Bitmap mPicture;
-
+
private Context mContext;
/**
* Create an new Media
- * @param file: path on the local storage
+ * @param file path on the local storage
*/
public Media(Context context, File file) {
this.mFile = file;
@@ -66,6 +66,7 @@ public class Media implements Comparable<Media> {
try {
mLibVlc = LibVLC.getInstance();
mType = (mLibVlc.hasVideoTrack(file.getPath())) ? TYPE_VIDEO : TYPE_AUDIO;
+ if(file.getPath().endsWith("mpg"))mType=TYPE_VIDEO;
mLength = mLibVlc.getLengthFromFile(file.getPath());
String[] array = mLibVlc.readMediaMeta(file.getPath());
@@ -74,7 +75,6 @@ public class Media implements Comparable<Media> {
for(i=0; i < array.length; i++) {
String s = array[i++];
String v = array[i];
-
if (s.equals("title")) {
mTitle = v;
Log.d(TAG, "Title " + mTitle);
@@ -98,23 +98,23 @@ public class Media implements Comparable<Media> {
db.addMedia(this);
}
-
- public Media(Context context, File file, long time, long length, int type,
+
+ public Media(Context context, File file, long time, long length, int type,
Bitmap picture, String title, String artist, String genre, String album) {
mContext = context;
-
+
mFile = file;
mTime = time;
mLength = length;
mType = type;
mPicture = picture;
-
+
mTitle = title;
mArtist = artist;
mGenre = genre;
mAlbum = album;
}
-
+
/**
* Compare the filenames to sort items
*/
@@ -122,17 +122,17 @@ public class Media implements Comparable<Media> {
return mTitle.toUpperCase().compareTo(
another.getTitle().toUpperCase());
}
-
+
public File getFile() {
return mFile;
}
-
+
public String getPath() {
return mFile.getPath();
}
public void updateMeta() {
-
+
}
public String getFileName() {
@@ -142,7 +142,7 @@ public class Media implements Comparable<Media> {
public long getTime() {
return mTime;
}
-
+
public void setTime(long time) {
mTime = time;
}
@@ -182,7 +182,7 @@ public class Media implements Comparable<Media> {
else
return mTitle;
}
-
+
public String getArtist() {
if (mArtist == null)
return mContext.getString(R.string.unknown_artist);
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/MediaInfoActivity.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/MediaInfoActivity.java
index b6460b5..ccf3324 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/MediaInfoActivity.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/MediaInfoActivity.java
@@ -17,7 +17,7 @@ public class MediaInfoActivity extends Activity {
private Media mItem;
private Bitmap mImage;
private final static int NEW_IMAGE = 0;
-
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -26,26 +26,25 @@ public class MediaInfoActivity extends Activity {
if (path == null)
return;
mItem = MediaLibrary.getInstance(this).getMediaItem(path);
-
+
// set title
TextView titleView = (TextView)findViewById(R.id.title);
titleView.setText(mItem.getTitle());
-
+
// set length
TextView lengthView = (TextView)findViewById(R.id.length);
lengthView.setText(Util.millisToString(mItem.getLength()));
-
+
new Thread(mLoadImage).start();
-
+
}
-
+
@Override
public void onBackPressed() {
Log.e(TAG, TAG + " onBackPressed()");
}
-
- Runnable mLoadImage = new Runnable() {
- @Override
+
+ Runnable mLoadImage = new Runnable() {
public void run() {
LibVLC mLibVlc = null;
try {
@@ -53,10 +52,10 @@ public class MediaInfoActivity extends Activity {
} catch (LibVlcException e) {
return;
}
-
+
int width = getWindowManager().getDefaultDisplay().getHeight();
int height = width;
-
+
// Get the thumbnail.
mImage = Bitmap.createBitmap(width, height, Config.ARGB_8888);
@@ -65,7 +64,7 @@ public class MediaInfoActivity extends Activity {
if (b == null) // We were not able to create a thumbnail for this item.
return;
-
+
mImage.copyPixelsFromBuffer(ByteBuffer.wrap(b));
int top = 0;
for (int i = 0; i < height; i++) {
@@ -76,7 +75,7 @@ public class MediaInfoActivity extends Activity {
break;
}
}
-
+
int left = 0;
for (int i = 0; i < width; i++) {
int pixel = mImage.getPixel(i, height/2);
@@ -86,30 +85,30 @@ public class MediaInfoActivity extends Activity {
break;
}
}
-
+
// Cut off the transparency on the borders
- mImage = Bitmap.createBitmap(mImage, top, left,
+ mImage = Bitmap.createBitmap(mImage, top, left,
(width - (2 * top)), (height - (2 * left)));
-
+
mHandler.sendEmptyMessage(NEW_IMAGE);
}
};
-
-
-
+
+
+
Handler mHandler = new Handler() {
-
+
public void handleMessage(Message msg) {
switch (msg.what) {
case NEW_IMAGE:
- ImageView imageView =
+ ImageView imageView =
(ImageView)MediaInfoActivity.this.findViewById(R.id.image);
imageView.setImageBitmap(mImage);
imageView.setVisibility(ImageView.VISIBLE);
break;
}
};
-
+
};
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/MediaLibrary.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/MediaLibrary.java
index 4bbe259..bbe73b5 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/MediaLibrary.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/MediaLibrary.java
@@ -15,35 +15,35 @@ import android.os.Handler;
public class MediaLibrary {
public final static String TAG = "VLC/MediaLibrary";
-
+
protected static final int MEDIA_ITEMS_UPDATED = 100;
private static MediaLibrary mInstance;
- private DatabaseManager mDBManager;
+ private DatabaseManager mDBManager;
private ArrayList<Media> mItemList;
private final CyclicBarrier mBarrier = new CyclicBarrier(2);
private ArrayList<Handler> mUpdateHandler;
protected Context mContext;
-
+
private MediaLibrary(Context context) {
mInstance = this;
mContext = context;
mItemList = new ArrayList<Media>();
mUpdateHandler = new ArrayList<Handler>();
- mDBManager = DatabaseManager.getInstance();
+ mDBManager = DatabaseManager.getInstance();
}
-
+
public void loadMediaItems() {
new Thread(mGetMediaItems).start();
}
-
+
public static MediaLibrary getInstance(Context context) {
if (mInstance == null)
mInstance = new MediaLibrary(context);
return mInstance;
}
-
+
public void addUpdateHandler(Handler handler) {
mUpdateHandler.add(handler);
}
@@ -58,7 +58,7 @@ public class MediaLibrary {
}
return videoItems;
}
-
+
public ArrayList<Media> getAudioItems() {
ArrayList<Media> videoItems = new ArrayList<Media>();
for (int i = 0; i < mItemList.size(); i++) {
@@ -69,11 +69,11 @@ public class MediaLibrary {
}
return videoItems;
}
-
+
public ArrayList<Media> getMediaItems() {
return mItemList;
}
-
+
public Media getMediaItem(String path) {
for (int i = 0; i < mItemList.size(); i++) {
Media item = mItemList.get(i);
@@ -83,10 +83,10 @@ public class MediaLibrary {
}
return null;
}
-
-
+
+
private final Runnable mGetMediaItems = new Runnable() {
-
+
private Stack<File> directorys = new Stack<File>();
private MainActivity mMainActivity;
@@ -94,41 +94,41 @@ public class MediaLibrary {
// Initialize variables
mMainActivity = MainActivity.getInstance();
Handler mainHandler = mMainActivity.mHandler;
-
-
+
+
// show progressbar in header
- mainHandler.sendEmptyMessage(MainActivity.SHOW_PROGRESSBAR);
-
+ mainHandler.sendEmptyMessage(MainActivity.SHOW_PROGRESSBAR);
+
// get directories from database
directorys.addAll(mDBManager.getMediaDirs());
-
+
// get all paths of the existing media items
List<File> existingFiles = mDBManager.getMediaFiles();
-
+
// list of all added files
List<File> addedFiles = new ArrayList<File>();
-
+
// clear all old item
mItemList.clear();
-
+
MediaItemFilter mediaFileFilter = new MediaItemFilter();
-
-
+
+
while (!directorys.isEmpty()) {
File dir = directorys.pop();
File[] f = null;
- if ((f = dir.listFiles(mediaFileFilter)) != null) {
+ if ((f = dir.listFiles(mediaFileFilter)) != null) {
for (int i = 0; i < f.length; i++) {
if (f[i].isFile()) {
if (existingFiles.contains(f[i])) {
-
- /** only add file if it is not already in the
+
+ /** only add file if it is not already in the
* list. eg. if user select an subfolder as well
*/
if (!addedFiles.contains(f[i])) {
// get existing media item from database
mItemList.add(mDBManager.getMedia(
- f[i].getPath()));
+ f[i].getPath()));
addedFiles.add( f[i] );
}
} else {
@@ -138,17 +138,17 @@ public class MediaLibrary {
} else if (f[i].isDirectory()) {
directorys.push(f[i]);
}
- }
+ }
}
}
-
+
// update the video and audio activities
for (int i = 0; i < mUpdateHandler.size(); i++) {
Handler h = mUpdateHandler.get(i);
h.sendEmptyMessage(MEDIA_ITEMS_UPDATED);
}
-
-
+
+
try {
mBarrier.await();
} catch (InterruptedException e) {
@@ -156,8 +156,8 @@ public class MediaLibrary {
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
-
- // remove file from database
+
+ // remove file from database
for (int i = 0; i < existingFiles.size(); i++) {
if (!addedFiles.contains(existingFiles.get(i))) {
mDBManager.removeMedia(existingFiles.get(i).getPath());
@@ -165,18 +165,18 @@ public class MediaLibrary {
}
// hide progressbar in header
mainHandler.sendEmptyMessage(MainActivity.HIDE_PROGRESSBAR);
-
+
}
};
-
- /**
- * Filters all irrelevant files
+
+ /**
+ * Filters all irrelevant files
*/
private class MediaItemFilter implements FileFilter {
-
+
// FIXME: save extensions in external database
- private String[] extensions = Media.EXTENTIONS;
+ private String[] extensions = Media.EXTENTIONS;
public boolean accept(File f) {
boolean accepted = false;
if (!f.isHidden()) {
@@ -192,6 +192,6 @@ public class MediaLibrary {
}
}
return accepted;
- }
+ }
}
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/SearchActivity.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/SearchActivity.java
index 70f401f..e34cb5b 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/SearchActivity.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/SearchActivity.java
@@ -24,208 +24,215 @@ import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
public class SearchActivity extends ListActivity {
- public final static String TAG = "VLC/SearchActivit";
-
- private EditText mSearchText;
- private ArrayAdapter<String> mHistoryAdapter;
- private ArrayList<String> mHistory = new ArrayList<String>();
- private SearchResultAdapter mResultAdapter;
- private LinearLayout mListHeader;
-
+ public final static String TAG = "VLC/SearchActivit";
+
+ private EditText mSearchText;
+ private ArrayAdapter<String> mHistoryAdapter;
+ private ArrayList<String> mHistory = new ArrayList<String>();
+ private SearchResultAdapter mResultAdapter;
+ private LinearLayout mListHeader;
+
@Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.search);
-
- // TODO: create layout
- mResultAdapter = new SearchResultAdapter(this, android.R.layout.simple_list_item_1);
-
- mSearchText = (EditText)findViewById(R.id.search_text);
- mSearchText.setOnEditorActionListener(searchTextListener);
- mSearchText.addTextChangedListener(searchTextWatcher);
-
- final Intent queryIntent = getIntent();
- final String queryAction = queryIntent.getAction();
- if (Intent.ACTION_SEARCH.equals(queryAction)) {
- String query = queryIntent.getStringExtra(SearchManager.QUERY);
- mSearchText.setText(query);
- mSearchText.setSelection(query.length());
- } else {
- InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(mSearchText, InputMethodManager.RESULT_SHOWN);
- showSearchHistory();
- }
-
-
- mSearchText.requestFocus();
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search);
+
+ // TODO: create layout
+ mResultAdapter = new SearchResultAdapter(this,
+ android.R.layout.simple_list_item_1);
+
+ mSearchText = (EditText) findViewById(R.id.search_text);
+ mSearchText.setOnEditorActionListener(searchTextListener);
+ mSearchText.addTextChangedListener(searchTextWatcher);
+
+ final Intent queryIntent = getIntent();
+ final String queryAction = queryIntent.getAction();
+ if (Intent.ACTION_SEARCH.equals(queryAction)) {
+ String query = queryIntent.getStringExtra(SearchManager.QUERY);
+ mSearchText.setText(query);
+ mSearchText.setSelection(query.length());
+ } else {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mSearchText, InputMethodManager.RESULT_SHOWN);
+ showSearchHistory();
+ }
+
+ mSearchText.requestFocus();
}
-
+
private void search(CharSequence key, int type) {
-
- // set result adapter to the list
- mResultAdapter.clear();
- String[] keys = key.toString().split("\\s+");
- ArrayList<Media> allItems = MediaLibrary.getInstance(this).getMediaItems();
- int results = 0;
- for (int i = 0; i < allItems.size(); i++) {
- Media item = allItems.get(i);
- if (type != Media.TYPE_ALL && type != item.getType())
- continue;
- boolean add = true;
- String name = item.getTitle().toLowerCase();
- String path = item.getPath().toLowerCase();
- for (int k = 0; k < keys.length; k++) {
- if (!(name.contains(keys[k].toLowerCase()) ||
- path.contains(keys[k].toLowerCase()))) {
- add = false;
- break;
- }
- }
-
- if (add) {
- mResultAdapter.add(item);
- results++;
- }
+ // set result adapter to the list
+ mResultAdapter.clear();
+ String[] keys = key.toString().split("\\s+");
+ ArrayList<Media> allItems = MediaLibrary.getInstance(this)
+ .getMediaItems();
+ int results = 0;
+ for (int i = 0; i < allItems.size(); i++) {
+ Media item = allItems.get(i);
+ if (type != Media.TYPE_ALL && type != item.getType())
+ continue;
+ boolean add = true;
+ String name = item.getTitle().toLowerCase();
+ String path = item.getPath().toLowerCase();
+ for (int k = 0; k < keys.length; k++) {
+ if (!(name.contains(keys[k].toLowerCase()) || path
+ .contains(keys[k].toLowerCase()))) {
+ add = false;
+ break;
}
- mResultAdapter.sort();
-
- String headerText = getString(R.string.search_found_results, results);
- showListHeader(headerText);
-
- setListAdapter(mResultAdapter);
+ }
+
+ if (add) {
+ mResultAdapter.add(item);
+ results++;
+ }
+
+ }
+ mResultAdapter.sort();
+
+ String headerText = getString(R.string.search_found_results, results);
+ showListHeader(headerText);
+
+ setListAdapter(mResultAdapter);
}
-
-
+
private void showListHeader(String text) {
- ListView lv = getListView();
-
- // create a new header if not exists
- if (mListHeader == null) {
- LayoutInflater infalter = getLayoutInflater();
- mListHeader = (LinearLayout) infalter.inflate(R.layout.list_header, lv, false);
- lv.addHeaderView(mListHeader, null, false);
- }
-
- // set header text
- TextView headerText = (TextView)mListHeader.findViewById(R.id.text);
- headerText.setText(text);
+ ListView lv = getListView();
+
+ // create a new header if not exists
+ if (mListHeader == null) {
+ LayoutInflater infalter = getLayoutInflater();
+ mListHeader = (LinearLayout) infalter.inflate(R.layout.list_header,
+ lv, false);
+ lv.addHeaderView(mListHeader, null, false);
+ }
+
+ // set header text
+ TextView headerText = (TextView) mListHeader.findViewById(R.id.text);
+ headerText.setText(text);
}
-
private void showSearchHistory() {
- // Add header to the history
- String headerText = getString(R.string.search_history);
- showListHeader(headerText);
-
- DatabaseManager db = DatabaseManager.getInstance();
- mHistory.clear();
- mHistory.addAll(db.getSearchhistory(20));
- if (mHistoryAdapter == null) {
- mHistoryAdapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_list_item_1, mHistory);
- } else {
- mHistoryAdapter.notifyDataSetChanged();
- }
- setListAdapter(mHistoryAdapter);
+ // Add header to the history
+ String headerText = getString(R.string.search_history);
+ showListHeader(headerText);
+
+ DatabaseManager db = DatabaseManager.getInstance();
+ mHistory.clear();
+ mHistory.addAll(db.getSearchhistory(20));
+ if (mHistoryAdapter == null) {
+ mHistoryAdapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, mHistory);
+ } else {
+ mHistoryAdapter.notifyDataSetChanged();
+ }
+ setListAdapter(mHistoryAdapter);
}
-
+
private TextWatcher searchTextWatcher = new TextWatcher() {
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- if (s.length() > 0) {
- search(s, Media.TYPE_ALL);
- } else {
- showSearchHistory();
- }
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
-
- }
-
- @Override
- public void afterTextChanged(Editable s) {
-
- }
- };
-
- /** Create menu from XML
- */
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.search, menu);
- return super.onCreateOptionsMenu(menu);
+
+ public void onTextChanged(CharSequence s, int start, int before,
+ int count) {
+ if (s.length() > 0) {
+ search(s, Media.TYPE_ALL);
+ } else {
+ showSearchHistory();
+ }
}
-
- /**
- * Handle onClick form menu buttons
- */
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
-
- // Handle item selection
- switch (item.getItemId()) {
- // Sort by name
- case R.id.search_clear_history:
- DatabaseManager db = DatabaseManager.getInstance();
- db.clearSearchhistory();
- if (mHistoryAdapter == getListAdapter())
- showSearchHistory();
- }
- return super.onOptionsItemSelected(item);
+
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+
}
-
-
- private OnEditorActionListener searchTextListener = new OnEditorActionListener() {
- @Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(mSearchText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- return false;
- }
- };
-
- protected void onListItemClick(ListView l, View v, int position, long id) {
- if (getListAdapter() == mHistoryAdapter) {
- String selection = ((TextView)v.findViewById(android.R.id.text1)).getText().toString();
- mSearchText.setText(selection);
- mSearchText.setSelection(selection.length());
- mSearchText.requestFocus();
- } else if (getListAdapter() == mResultAdapter) {
- // add search text to the database (history)
- DatabaseManager db = DatabaseManager.getInstance();
- db.addSearchhistoryItem(mSearchText.getText().toString());
-
- // open media in the player
- Media item = (Media) getListAdapter().getItem(position - 1);
- Intent intent = new Intent(this, VideoPlayerActivity.class);
- intent.putExtra("filePath", item.getPath());
- startActivity(intent);
- super.onListItemClick(l, v, position, id);
-
- }
- };
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_SEARCH) {
- mSearchText.requestFocus();
- mSearchText.setSelection(mSearchText.getText().length());
- InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(mSearchText, InputMethodManager.RESULT_SHOWN);
- return true;
+
+ public void afterTextChanged(Editable s) {
+
+ }
+ };
+
+ /**
+ * Create menu from XML
+ */
+
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.search, menu);
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ /**
+ * Handle onClick form menu buttons
+ */
+
+ public boolean onOptionsItemSelected(MenuItem item) {
+
+ // Handle item selection
+ switch (item.getItemId()) {
+ // Sort by name
+ case R.id.search_clear_history:
+ DatabaseManager db = DatabaseManager.getInstance();
+ db.clearSearchhistory();
+ if (mHistoryAdapter == getListAdapter())
+ showSearchHistory();
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private OnEditorActionListener searchTextListener = new OnEditorActionListener() {
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mSearchText.getWindowToken(),
+ InputMethodManager.HIDE_NOT_ALWAYS);
+ return false;
+ }
+ };
+
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+ if (getListAdapter() == mHistoryAdapter) {
+ String selection = ((TextView) v.findViewById(android.R.id.text1))
+ .getText().toString();
+ mSearchText.setText(selection);
+ mSearchText.setSelection(selection.length());
+ mSearchText.requestFocus();
+ } else if (getListAdapter() == mResultAdapter) {
+ // add search text to the database (history)
+ DatabaseManager db = DatabaseManager.getInstance();
+ db.addSearchhistoryItem(mSearchText.getText().toString());
+
+ // open media in the player
+ Media item = (Media) getListAdapter().getItem(position - 1);
+ Intent intent;
+ if (item.getType() == Media.TYPE_VIDEO) {
+ intent = new Intent(this, VideoPlayerActivity.class);
+ intent.putExtra("filePath", item.getPath());
+ startActivity(intent);
+ } else {
+ ArrayList<String> arr = new ArrayList<String>();
+ for (int i=0;i<getListAdapter().getCount();i++)
+ arr.add(((Media)getListAdapter().getItem(i)).getPath());
+ AudioServiceController.getInstance().load(arr, position-1);
+ intent = new Intent(this, AudioPlayerActivity.class);
+ startActivity(intent);
}
+ super.onListItemClick(l, v, position, id);
+
+ }
+ };
- return super.onKeyDown(keyCode, event);
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+ mSearchText.requestFocus();
+ mSearchText.setSelection(mSearchText.getText().length());
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mSearchText, InputMethodManager.RESULT_SHOWN);
+ return true;
}
-
-
+
+ return super.onKeyDown(keyCode, event);
+ }
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/SearchResultAdapter.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/SearchResultAdapter.java
index c656d34..eb92b1d 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/SearchResultAdapter.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/SearchResultAdapter.java
@@ -9,31 +9,30 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
-public class SearchResultAdapter extends ArrayAdapter<Media>
+public class SearchResultAdapter extends ArrayAdapter<Media>
implements Comparator<Media> {
public SearchResultAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
-
+
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null){
- LayoutInflater inflater = (LayoutInflater)
+ LayoutInflater inflater = (LayoutInflater)
getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = inflater.inflate(android.R.layout.simple_list_item_1,
+ v = inflater.inflate(android.R.layout.simple_list_item_1,
parent, false);
}
Media item = getItem(position);
TextView textView = (TextView)v.findViewById(android.R.id.text1);
textView.setText(item.getTitle());
-
+
return v;
}
- @Override
public int compare(Media object1, Media object2) {
return object1.getTitle().compareToIgnoreCase(object2.getTitle());
}
@@ -41,7 +40,7 @@ public class SearchResultAdapter extends ArrayAdapter<Media>
public void sort() {
super.sort(this);
}
-
-
+
+
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/VideoListAdapter.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/VideoListAdapter.java
index de44388..3119acf 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/VideoListAdapter.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/VideoListAdapter.java
@@ -15,22 +15,22 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
-public class VideoListAdapter extends ArrayAdapter<Media>
+public class VideoListAdapter extends ArrayAdapter<Media>
implements Comparator<Media> {
public final static int SORT_BY_TITLE = 0;
public final static int SORT_BY_LENGTH = 1;
private int mSortDirection = 1;
private int mSortBy = SORT_BY_TITLE;
-
-
-
+
+
+
public VideoListAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
public final static String TAG = "VLC/MediaLibraryAdapter";
-
+
public synchronized void update(Media item) {
int position = getPosition(item);
@@ -39,7 +39,7 @@ public class VideoListAdapter extends ArrayAdapter<Media>
insert(item, position);
}
}
-
+
public void sortBy(int sortby) {
switch (sortby) {
case SORT_BY_TITLE:
@@ -65,9 +65,9 @@ public class VideoListAdapter extends ArrayAdapter<Media>
}
sort();
}
-
+
public void sort() {
- super.sort(this);
+ super.sort(this);
}
public int compare(Media item1, Media item2) {
@@ -83,8 +83,8 @@ public class VideoListAdapter extends ArrayAdapter<Media>
}
return mSortDirection * compare;
}
-
-
+
+
/**
* Display the view of a file browser item.
@@ -94,9 +94,9 @@ public class VideoListAdapter extends ArrayAdapter<Media>
View v = convertView;
if (v == null){
- LayoutInflater inflater = (LayoutInflater)
+ LayoutInflater inflater = (LayoutInflater)
getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = inflater.inflate(R.layout.video_list_item,
+ v = inflater.inflate(R.layout.video_list_item,
parent, false);
}
@@ -107,7 +107,7 @@ public class VideoListAdapter extends ArrayAdapter<Media>
titleView.setText(media.getTitle());
lengthView.setText(" " + Util.millisToString(media.getLength()) + " ");
ImageView moreView = (ImageView)v.findViewById(R.id.ml_item_more);
-
+
Bitmap thumbnail;
if (media.getPicture() != null) {
thumbnail = media.getPicture();
@@ -115,20 +115,19 @@ public class VideoListAdapter extends ArrayAdapter<Media>
} else {
// set default thumbnail
thumbnail = BitmapFactory.decodeResource(
- MainActivity.getInstance().getResources(),
+ MainActivity.getInstance().getResources(),
R.drawable.thumbnail);
thumbnailView.setImageBitmap(thumbnail);
}
-
+
moreView.setTag(media);
moreView.setOnClickListener(moreClickListener);
-
+
return v;
}
private OnClickListener moreClickListener = new OnClickListener() {
-
- @Override
+
public void onClick(View v) {
Media item = (Media)v.getTag();
Intent intent = new Intent(getContext(), MediaInfoActivity.class);
@@ -137,6 +136,6 @@ public class VideoListAdapter extends ArrayAdapter<Media>
group.startChildAcitvity("MediaInfo", intent);
}
};
-
+
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/VideoPlayerActivity.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/VideoPlayerActivity.java
index 2cf16f4..956c920 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/VideoPlayerActivity.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/VideoPlayerActivity.java
@@ -33,561 +33,554 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
public class VideoPlayerActivity extends Activity {
- public final static String TAG = "VLC/VideoPlayerActivity";
-
- private SurfaceView mSurface;
- private SurfaceHolder mSurfaceHolder;
- private LibVLC mLibVLC;
-
- private static final int SURFACE_FIT_HORIZONTAL = 0;
- private static final int SURFACE_FIT_VERTICAL = 1;
- private static final int SURFACE_FILL = 2;
- private static final int SURFACE_16_9 = 3;
- private static final int SURFACE_4_3 = 4;
- private static final int SURFACE_ORIGINAL = 5;
- private int mCurrentSize = SURFACE_FIT_HORIZONTAL;
-
- /** Overlay */
- private LinearLayout mOverlay;
- private LinearLayout mDecor;
- private View mSpacer;
- private static final int OVERLAY_TIMEOUT = 4000;
- private static final int FADE_OUT = 1;
- private static final int SHOW_PROGRESS = 2;
- private static final int SURFACE_SIZE = 3;
- private static final int FADE_OUT_INFO = 4;
- private boolean mDragging;
- private boolean mShowing;
- private SeekBar mSeekbar;
- private TextView mTime;
- private TextView mLength;
- private TextView mInfo;
- private ImageButton mPause;
- private ImageButton mLock;
- private ImageButton mSize;
-
- // size of the video
- private int mVideoHeight;
- private int mVideoWidth;
+ public final static String TAG = "VLC/VideoPlayerActivity";
+
+ private SurfaceView mSurface;
+ private SurfaceHolder mSurfaceHolder;
+ private LibVLC mLibVLC;
+
+ private static final int SURFACE_FIT_HORIZONTAL = 0;
+ private static final int SURFACE_FIT_VERTICAL = 1;
+ private static final int SURFACE_FILL = 2;
+ private static final int SURFACE_16_9 = 3;
+ private static final int SURFACE_4_3 = 4;
+ private static final int SURFACE_ORIGINAL = 5;
+ private int mCurrentSize = SURFACE_FIT_HORIZONTAL;
+
+ /** Overlay */
+ private LinearLayout mOverlay;
+ private LinearLayout mDecor;
+ private View mSpacer;
+ private static final int OVERLAY_TIMEOUT = 4000;
+ private static final int FADE_OUT = 1;
+ private static final int SHOW_PROGRESS = 2;
+ private static final int SURFACE_SIZE = 3;
+ private static final int FADE_OUT_INFO = 4;
+ private boolean mDragging;
+ private boolean mShowing;
+ private SeekBar mSeekbar;
+ private TextView mTime;
+ private TextView mLength;
+ private TextView mInfo;
+ private ImageButton mPause;
+ private ImageButton mLock;
+ private ImageButton mSize;
+
+ // size of the video
+ private int mVideoHeight;
+ private int mVideoWidth;
+
+ // stop screen from dimming
+ private WakeLock mWakeLock;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.player);
// stop screen from dimming
- private WakeLock mWakeLock;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.player);
-
- // stop screen from dimming
- PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, TAG);
-
- /** initialize Views an their Events */
- mDecor = (LinearLayout)findViewById(R.id.player_overlay_decor);
- mSpacer = (View)findViewById(R.id.player_overlay_spacer);
- mSpacer.setOnTouchListener(mTouchListener);
-
- LayoutInflater inflater = (LayoutInflater) getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- mOverlay = (LinearLayout)inflater.inflate(R.layout.player_overlay, null);
-
- mTime = (TextView) mOverlay.findViewById(R.id.player_overlay_time);
- mLength = (TextView) mOverlay.findViewById(R.id.player_overlay_length);
- // the info textView is not on the overlay
- mInfo = (TextView) findViewById(R.id.player_overlay_info);
-
- mPause = (ImageButton) mOverlay.findViewById(R.id.player_overlay_play);
- mPause.setOnClickListener(mPauseListener);
-
- mLock = (ImageButton) mOverlay.findViewById(R.id.player_overlay_lock);
- mLock.setOnClickListener(mLockListener);
-
- mSize = (ImageButton) mOverlay.findViewById(R.id.player_overlay_size);
- mSize.setOnClickListener(mSizeListener);
-
- mSurface = (SurfaceView) findViewById(R.id.player_surface);
- mSurfaceHolder = mSurface.getHolder();
- mSurfaceHolder.setKeepScreenOn(true);
- mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);
- mSurfaceHolder.addCallback(mSurfaceCallback);
-
- mSeekbar = (SeekBar)mOverlay.findViewById(R.id.player_overlay_seekbar);
- mSeekbar.setOnSeekBarChangeListener(mSeekListener);
-
- try {
- mLibVLC = LibVLC.getInstance();
- } catch (LibVlcException e) {
- e.printStackTrace();
- }
-
- EventManager em = EventManager.getIntance();
- em.addHandler(eventHandler);
-
- load();
-
+ PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, TAG);
+
+ /** initialize Views an their Events */
+ mDecor = (LinearLayout) findViewById(R.id.player_overlay_decor);
+ mSpacer = findViewById(R.id.player_overlay_spacer);
+ mSpacer.setOnTouchListener(mTouchListener);
+
+ LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mOverlay = (LinearLayout) inflater.inflate(R.layout.player_overlay,
+ null);
+
+ mTime = (TextView) mOverlay.findViewById(R.id.player_overlay_time);
+ mLength = (TextView) mOverlay.findViewById(R.id.player_overlay_length);
+ // the info textView is not on the overlay
+ mInfo = (TextView) findViewById(R.id.player_overlay_info);
+
+ mPause = (ImageButton) mOverlay.findViewById(R.id.player_overlay_play);
+ mPause.setOnClickListener(mPauseListener);
+
+ mLock = (ImageButton) mOverlay.findViewById(R.id.player_overlay_lock);
+ mLock.setOnClickListener(mLockListener);
+
+ mSize = (ImageButton) mOverlay.findViewById(R.id.player_overlay_size);
+ mSize.setOnClickListener(mSizeListener);
+
+ mSurface = (SurfaceView) findViewById(R.id.player_surface);
+ mSurfaceHolder = mSurface.getHolder();
+ mSurfaceHolder.setKeepScreenOn(true);
+ mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);
+ mSurfaceHolder.addCallback(mSurfaceCallback);
+ mSeekbar = (SeekBar) mOverlay.findViewById(R.id.player_overlay_seekbar);
+ mSeekbar.setOnSeekBarChangeListener(mSeekListener);
+
+ try {
+ mLibVLC = LibVLC.getInstance();
+ } catch (LibVlcException e) {
+ e.printStackTrace();
}
-
-
- @Override
- protected void onPause() {
- if (mLibVLC.isPlaying())
- pause();
- super.onPause();
+
+ EventManager em = EventManager.getIntance();
+ em.addHandler(eventHandler);
+
+ load();
+
+ }
+
+ @Override
+ protected void onPause() {
+ if (mLibVLC.isPlaying())
+ pause();
+ super.onPause();
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mLibVLC != null) {
+ mLibVLC.stop();
}
- @Override
- protected void onDestroy() {
- if (mLibVLC != null) {
- mLibVLC.stop();
- }
-
- EventManager em = EventManager.getIntance();
- em.removeHandler(eventHandler);
-
- super.onDestroy();
+ EventManager em = EventManager.getIntance();
+ em.removeHandler(eventHandler);
+
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ showOverlay();
+ return true;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ setSurfaceSize(mVideoWidth, mVideoHeight);
+ super.onConfigurationChanged(newConfig);
+ }
+
+ public void setSurfaceSize(int width, int height) {
+ // store video size
+ mVideoHeight = height;
+ mVideoWidth = width;
+ Message msg = mHandler.obtainMessage(SURFACE_SIZE);
+ mHandler.sendMessage(msg);
+ }
+
+ /**
+ * Lock screen rotation
+ */
+ private void lockScreen() {
+ WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+
+ switch (display.getRotation()) {
+ case Surface.ROTATION_0:
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ break;
+ case Surface.ROTATION_90:
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ break;
+ case Surface.ROTATION_270:
+ // FIXME: API Level 9+ (not tested on a device with API Level < 9)
+ setRequestedOrientation(8); // SCREEN_ORIENTATION_REVERSE_LANDSCAPE
+ break;
}
+ showInfo("locked", 500);
+ }
+
+ /**
+ * Remove screen lock
+ */
+ private void unlockScreen() {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ showInfo("unlocked", 500);
+ }
+
+ /**
+ * Show text in the info view for "duration" milliseconds
+ *
+ * @param text
+ * @param duration
+ */
+ private void showInfo(String text, int duration) {
+ mInfo.setVisibility(View.VISIBLE);
+ mInfo.setText(text);
+ mHandler.removeMessages(FADE_OUT_INFO);
+ mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, duration);
+ }
+
+ /**
+ * Show text in the info view
+ *
+ * @param text
+ */
+ private void showInfo(String text) {
+ mInfo.setVisibility(View.VISIBLE);
+ mInfo.setText(text);
+ mHandler.removeMessages(FADE_OUT_INFO);
+ }
+
+ /**
+ * hide the info view with "delay" milliseconds delay
+ *
+ * @param delay
+ */
+ private void hideInfo(int delay) {
+ mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, delay);
+ }
+
+ /**
+ * hide the info view
+ */
+ private void hideInfo() {
+ hideInfo(0);
+ }
+
+ /**
+ * Handle libvlc asynchronous events
+ */
+ private Handler eventHandler = new Handler() {
@Override
- public boolean onTrackballEvent(MotionEvent event) {
- showOverlay();
- return true;
+ public void handleMessage(Message msg) {
+ switch (msg.getData().getInt("event")) {
+ case EventManager.MediaPlayerPlaying:
+ Log.e(TAG, "MediaPlayerPlaying");
+ break;
+ case EventManager.MediaPlayerPaused:
+ Log.e(TAG, "MediaPlayerPaused");
+ break;
+ case EventManager.MediaPlayerStopped:
+ Log.e(TAG, "MediaPlayerStopped");
+ break;
+ case EventManager.MediaPlayerEndReached:
+ Log.e(TAG, "MediaPlayerEndReached");
+ /* Exit player when reach the end */
+ VideoPlayerActivity.this.finish();
+ break;
+ default:
+ Log.e(TAG, "Event not handled");
+ break;
+ }
+ updateOverlayPausePlay();
}
-
+ };
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- setSurfaceSize(mVideoWidth, mVideoHeight);
- super.onConfigurationChanged(newConfig);
+ /**
+ * Handle resize of the surface and the overlay
+ */
+ private Handler mHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case FADE_OUT:
+ hideOverlay(false);
+ break;
+ case SHOW_PROGRESS:
+ int pos = setOverlayProgress();
+ if (!mDragging && mShowing && mLibVLC.isPlaying()) {
+ msg = obtainMessage(SHOW_PROGRESS);
+ sendMessageDelayed(msg, 1000 - (pos % 1000));
+ }
+ break;
+ case SURFACE_SIZE:
+ changeSurfaceSize();
+ break;
+ case FADE_OUT_INFO:
+ mInfo.startAnimation(AnimationUtils.loadAnimation(
+ VideoPlayerActivity.this, android.R.anim.fade_out));
+ mInfo.setVisibility(View.INVISIBLE);
+ }
}
+ };
+
+ private void changeSurfaceSize() {
+ // get screen size
+ int dw = getWindowManager().getDefaultDisplay().getWidth();
+ int dh = getWindowManager().getDefaultDisplay().getHeight();
+ // calculate aspect ratio
+ double ar = (double) mVideoWidth / (double) mVideoHeight;
+ // calculate display aspect ratio
+ double dar = (double) dw / (double) dh;
- public void setSurfaceSize(int width, int height) {
- // store video size
- mVideoHeight = height;
- mVideoWidth = width;
- Message msg = mHandler.obtainMessage(SURFACE_SIZE);
- mHandler.sendMessage(msg);
+ switch (mCurrentSize) {
+ case SURFACE_FIT_HORIZONTAL:
+ dh = (int) (dw / ar);
+ break;
+ case SURFACE_FIT_VERTICAL:
+ dw = (int) (dh * ar);
+ break;
+ case SURFACE_FILL:
+ break;
+ case SURFACE_16_9:
+ ar = 16.0 / 9.0;
+ if (dar < ar)
+ dh = (int) (dw / ar);
+ else
+ dw = (int) (dh * ar);
+ break;
+ case SURFACE_4_3:
+ ar = 4.0 / 3.0;
+ if (dar < ar)
+ dh = (int) (dw / ar);
+ else
+ dw = (int) (dh * ar);
+ break;
+ case SURFACE_ORIGINAL:
+ dh = mVideoHeight;
+ dw = mVideoWidth;
+ break;
+ }
+
+ mSurfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);
+ LayoutParams lp = mSurface.getLayoutParams();
+ lp.width = dw;
+ lp.height = dh;
+ mSurface.setLayoutParams(lp);
+ mSurface.invalidate();
}
-
- /**
- * Lock screen rotation
- */
- private void lockScreen() {
- WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
- Display display = wm.getDefaultDisplay();
-
- switch (display.getRotation()) {
- case Surface.ROTATION_0:
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- break;
- case Surface.ROTATION_90:
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- break;
- case Surface.ROTATION_270:
- // FIXME: API Level 9+ (not tested on a device with API Level < 9)
- setRequestedOrientation(8); // SCREEN_ORIENTATION_REVERSE_LANDSCAPE
- break;
+
+ /**
+ * show/hide the overlay
+ */
+ private OnTouchListener mTouchListener = new OnTouchListener() {
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (!mShowing) {
+ showOverlay();
+ } else {
+ hideOverlay(true);
}
-
- showInfo("locked", 500);
+ }
+ return false;
}
-
- /**
- * Remove screen lock
- */
- private void unlockScreen() {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- showInfo("unlocked", 500);
+ };
+
+ /**
+ * handle changes of the seekbar (slicer)
+ */
+ private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
+
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ mDragging = true;
+ showOverlay(3600000);
}
-
- /**
- * Show text in the info view for "duration" milliseconds
- * @param text
- * @param duration
- */
- private void showInfo(String text, int duration) {
- mInfo.setVisibility(View.VISIBLE);
- mInfo.setText(text);
- mHandler.removeMessages(FADE_OUT_INFO);
- mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, duration);
+
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ mDragging = false;
+ showOverlay();
+ hideInfo();
+ }
+
+ public void onProgressChanged(SeekBar seekBar, int progress,
+ boolean fromUser) {
+ if (fromUser) {
+ mLibVLC.setTime(progress);
+ setOverlayProgress();
+ mTime.setText(Util.millisToString(progress));
+ showInfo(Util.millisToString(progress));
+ }
+
}
-
- /**
- * Show text in the info view
- * @param text
+ };
+
+ /**
+ *
*/
- private void showInfo(String text) {
- mInfo.setVisibility(View.VISIBLE);
- mInfo.setText(text);
- mHandler.removeMessages(FADE_OUT_INFO);
+ private OnClickListener mPauseListener = new OnClickListener() {
+ public void onClick(View v) {
+ doPausePlay();
+ showOverlay();
}
-
- /**
- * hide the info view with "delay" milliseconds delay
- * @param delay
+ };
+
+ /**
+ *
*/
- private void hideInfo(int delay) {
- mHandler.sendEmptyMessageDelayed(FADE_OUT_INFO, delay);
+ private OnClickListener mLockListener = new OnClickListener() {
+ boolean isLocked = false;
+
+ public void onClick(View v) {
+ if (isLocked) {
+ unlockScreen();
+ isLocked = false;
+ } else {
+ lockScreen();
+ isLocked = true;
+ }
+ showOverlay();
}
-
- /**
- * hide the info view
+ };
+
+ /**
+ *
*/
- private void hideInfo() {
- hideInfo(0);
+ private OnClickListener mSizeListener = new OnClickListener() {
+
+ public void onClick(View v) {
+ if (mCurrentSize < SURFACE_ORIGINAL) {
+ mCurrentSize++;
+ } else {
+ mCurrentSize = 0;
+ }
+ changeSurfaceSize();
+ switch (mCurrentSize) {
+ case SURFACE_FIT_HORIZONTAL:
+ showInfo("fit horizontal", 500);
+ break;
+ case SURFACE_FIT_VERTICAL:
+ showInfo("fit vertival", 500);
+ break;
+ case SURFACE_FILL:
+ showInfo("fill", 500);
+ break;
+ case SURFACE_16_9:
+ showInfo("16:9", 500);
+ break;
+ case SURFACE_4_3:
+ showInfo("4:3", 500);
+ break;
+ case SURFACE_ORIGINAL:
+ showInfo("original", 500);
+ break;
+ }
+ showOverlay();
}
-
+ };
+
/**
- * Handle libvlc asynchronous events
+ * attach and disattach surface to the lib
*/
- private Handler eventHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.getData().getInt("event")) {
- case EventManager.MediaPlayerPlaying:
- Log.e(TAG, "MediaPlayerPlaying");
- break;
- case EventManager.MediaPlayerPaused:
- Log.e(TAG, "MediaPlayerPaused");
- break;
- case EventManager.MediaPlayerStopped:
- Log.e(TAG, "MediaPlayerStopped");
- break;
- case EventManager.MediaPlayerEndReached:
- Log.e(TAG, "MediaPlayerEndReached");
- /* Exit player when reach the end */
- VideoPlayerActivity.this.finish();
- break;
- default:
- Log.e(TAG, "Event not handled");
- break;
- }
- updateOverlayPausePlay();
- }
- };
-
- /**
- * Handle resize of the surface and the overlay
- */
- private Handler mHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case FADE_OUT:
- hideOverlay(false);
- break;
- case SHOW_PROGRESS:
- int pos = setOverlayProgress();
- if (!mDragging && mShowing && mLibVLC.isPlaying()) {
- msg = obtainMessage(SHOW_PROGRESS);
- sendMessageDelayed(msg, 1000 - (pos % 1000));
- }
- break;
- case SURFACE_SIZE:
- changeSurfaceSize();
- break;
- case FADE_OUT_INFO:
- mInfo.startAnimation(AnimationUtils.loadAnimation(
- VideoPlayerActivity.this, android.R.anim.fade_out));
- mInfo.setVisibility(View.INVISIBLE);
- }
- }
- };
-
- private void changeSurfaceSize() {
- // get screen size
- int dw = getWindowManager().getDefaultDisplay().getWidth();
- int dh = getWindowManager().getDefaultDisplay().getHeight();
-
- // calculate aspect ratio
- double ar = (double)mVideoWidth / (double)mVideoHeight;
- // calculate display aspect ratio
- double dar = (double)dw / (double)dh;
-
- switch (mCurrentSize) {
- case SURFACE_FIT_HORIZONTAL:
- dh = (int) (dw / ar);
- break;
- case SURFACE_FIT_VERTICAL:
- dw = (int) (dh * ar);
- break;
- case SURFACE_FILL:
- break;
- case SURFACE_16_9:
- ar = 16.0/9.0;
- if (dar < ar)
- dh = (int) (dw / ar);
- else
- dw = (int) (dh * ar);
- break;
- case SURFACE_4_3:
- ar = 4.0/3.0;
- if (dar < ar)
- dh = (int) (dw / ar);
- else
- dw = (int) (dh * ar);
- break;
- case SURFACE_ORIGINAL:
- dh = mVideoHeight;
- dw = mVideoWidth;
- break;
- }
-
- mSurfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);
- LayoutParams lp = mSurface.getLayoutParams();
- lp.width = dw;
- lp.height = dh;
- mSurface.setLayoutParams(lp);
- mSurface.invalidate();
+ private SurfaceHolder.Callback mSurfaceCallback = new Callback() {
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+ mLibVLC.attachSurface(holder.getSurface(),
+ VideoPlayerActivity.this, width, height);
}
-
- /**
- * show/hide the overlay
- */
- private OnTouchListener mTouchListener = new OnTouchListener() {
- public boolean onTouch(View v, MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- if (!mShowing) {
- showOverlay();
- } else {
- hideOverlay(true);
- }
- }
- return false;
- }
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ mLibVLC.detachSurface();
+ }
};
-
-
+
/**
- * handle changes of the seekbar (slicer)
+ * show overlay the the default timeout
*/
- private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
-
- public void onStartTrackingTouch(SeekBar seekBar) {
- mDragging = true;
- showOverlay(3600000);
- }
-
- public void onStopTrackingTouch(SeekBar seekBar) {
- mDragging = false;
- showOverlay();
- hideInfo();
- }
-
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (fromUser) {
- mLibVLC.setTime(progress);
- setOverlayProgress();
- mTime.setText(Util.millisToString(progress));
- showInfo(Util.millisToString(progress));
- }
-
- }
- };
-
-
- /**
- *
- */
- private OnClickListener mPauseListener = new OnClickListener() {
- public void onClick(View v) {
- doPausePlay();
- showOverlay();
- }
- };
-
- /**
- *
- */
- private OnClickListener mLockListener = new OnClickListener() {
- boolean isLocked = false;
- public void onClick(View v) {
- if (isLocked) {
- unlockScreen();
- isLocked = false;
- } else {
- lockScreen();
- isLocked = true;
- }
- showOverlay();
- }
- };
-
- /**
- *
- */
- private OnClickListener mSizeListener = new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- if (mCurrentSize < SURFACE_ORIGINAL) {
- mCurrentSize++;
- } else {
- mCurrentSize = 0;
- }
- changeSurfaceSize();
- switch (mCurrentSize) {
- case SURFACE_FIT_HORIZONTAL:
- showInfo("fit horizontal", 500);
- break;
- case SURFACE_FIT_VERTICAL:
- showInfo("fit vertival", 500);
- break;
- case SURFACE_FILL:
- showInfo("fill", 500);
- break;
- case SURFACE_16_9:
- showInfo("16:9", 500);
- break;
- case SURFACE_4_3:
- showInfo("4:3", 500);
- break;
- case SURFACE_ORIGINAL:
- showInfo("original", 500);
- break;
- }
- showOverlay();
- }
- };
-
-
-
- /**
- * attach and disattach surface to the lib
- */
- private SurfaceHolder.Callback mSurfaceCallback = new Callback() {
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- mLibVLC.attachSurface(holder.getSurface(), VideoPlayerActivity.this, width, height);
- }
-
- public void surfaceCreated(SurfaceHolder holder) { }
+ private void showOverlay() {
+ showOverlay(OVERLAY_TIMEOUT);
+ }
- public void surfaceDestroyed(SurfaceHolder holder) {
- mLibVLC.detachSurface();
- }
- };
+ /**
+ * show overlay
+ */
+ private void showOverlay(int timeout) {
+ mHandler.sendEmptyMessage(SHOW_PROGRESS);
+ if (!mShowing) {
+ mShowing = true;
+ mDecor.addView(mOverlay);
+ }
+ Message msg = mHandler.obtainMessage(FADE_OUT);
+ if (timeout != 0) {
+ mHandler.removeMessages(FADE_OUT);
+ mHandler.sendMessageDelayed(msg, timeout);
+ }
+ updateOverlayPausePlay();
+ }
-
- /**
- * show overlay the the default timeout
- */
- private void showOverlay() {
- showOverlay(OVERLAY_TIMEOUT);
+ /**
+ * hider overlay
+ */
+ private void hideOverlay(boolean fromUser) {
+ mSurface.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
+ if (mShowing) {
+ mHandler.removeMessages(SHOW_PROGRESS);
+ Log.i(TAG, "remove View!");
+ if (!fromUser) {
+ mOverlay.startAnimation(AnimationUtils.loadAnimation(this,
+ android.R.anim.fade_out));
+ }
+ mDecor.removeView(mOverlay);
+ mShowing = false;
}
-
-
- /**
- * show overlay
- */
- private void showOverlay(int timeout) {
- mHandler.sendEmptyMessage(SHOW_PROGRESS);
- if (!mShowing) {
- mShowing = true;
- mDecor.addView(mOverlay);
- }
- Message msg = mHandler.obtainMessage(FADE_OUT);
- if (timeout != 0) {
- mHandler.removeMessages(FADE_OUT);
- mHandler.sendMessageDelayed(msg, timeout);
- }
- updateOverlayPausePlay();
+ }
+
+ private void updateOverlayPausePlay() {
+ if (mLibVLC == null) {
+ return;
}
-
-
- /**
- * hider overlay
- */
- private void hideOverlay(boolean fromUser) {
- if (mShowing) {
- mHandler.removeMessages(SHOW_PROGRESS);
- Log.i(TAG, "remove View!");
- if (!fromUser) {
- mOverlay.startAnimation(AnimationUtils.loadAnimation(
- this, android.R.anim.fade_out));
- }
- mDecor.removeView(mOverlay);
- mShowing = false;
- }
+
+ if (mLibVLC.isPlaying()) {
+ mPause.setBackgroundResource(R.drawable.ic_pause);
+ } else {
+ mPause.setBackgroundResource(R.drawable.ic_play);
}
+ }
-
- private void updateOverlayPausePlay() {
- if (mLibVLC == null) {
- return;
- }
-
- if (mLibVLC.isPlaying()) {
- mPause.setBackgroundResource(R.drawable.ic_pause);
- } else {
- mPause.setBackgroundResource(R.drawable.ic_play);
- }
+ /**
+ * play or pause the media
+ */
+ private void doPausePlay() {
+ if (mLibVLC.isPlaying()) {
+ pause();
+ } else {
+ play();
}
-
-
- /**
- * play or pause the media
- */
- private void doPausePlay() {
- if (mLibVLC.isPlaying()) {
- pause();
- } else {
- play();
- }
+ }
+
+ /**
+ * update the overlay
+ */
+ private int setOverlayProgress() {
+ if (mLibVLC == null) {
+ return 0;
}
-
-
- /**
- * update the overlay
+ int time = (int) mLibVLC.getTime();
+ int length = (int) mLibVLC.getLength();
+ // Update all view elements
+
+ mSeekbar.setMax(length);
+ mSeekbar.setProgress(time);
+ mTime.setText(Util.millisToString(time));
+ mLength.setText(Util.millisToString(length));
+ return time;
+ }
+
+ /**
+ *
*/
- private int setOverlayProgress() {
- if (mLibVLC == null) {
- return 0;
- }
- int time = (int)mLibVLC.getTime();
- int length = (int)mLibVLC.getLength();
- // Update all view elements
-
- mSeekbar.setMax(length);
- mSeekbar.setProgress(time);
- mTime.setText(Util.millisToString(time));
- mLength.setText(Util.millisToString(length));
- return time;
- }
+ private void play() {
+ mLibVLC.play();
+ mWakeLock.acquire();
+ }
- /**
- *
+ /**
+ *
*/
- private void play() {
- mLibVLC.play();
- mWakeLock.acquire();
- }
-
- /**
- *
+ private void pause() {
+ mLibVLC.pause();
+ mWakeLock.release();
+ }
+
+ /**
+ *
*/
- private void pause() {
- mLibVLC.pause();
- mWakeLock.release();
+ private void load() {
+ String path = null;
+ if (getIntent().getAction() != null
+ && getIntent().getAction().equals(Intent.ACTION_VIEW)) {
+ /* Started from external application */
+ path = getIntent().getData().getPath();
+ } else {
+ /* Started from VideoListActivity */
+ path = getIntent().getExtras().getString("filePath");
}
-
- /**
- *
- */
- private void load() {
- String path = null;
- if (getIntent().getAction() != null
- && getIntent().getAction().equals(Intent.ACTION_VIEW )) {
- /* Started from external application */
- path = getIntent().getData().getPath();
- } else {
- /* Started from VideoListActivity */
- path = getIntent().getExtras().getString("filePath");
- }
- if (path != null && path.length() > 0) {
- mLibVLC.readMedia(path);
- mWakeLock.acquire();
- }
+ if (path != null && path.length() > 0) {
+ mLibVLC.readMedia(path);
+ mWakeLock.acquire();
}
+ }
}
diff --git a/extras/package/android/vlc-android/src/org/videolan/vlc/android/widget/AudioMiniPlayer.java b/extras/package/android/vlc-android/src/org/videolan/vlc/android/widget/AudioMiniPlayer.java
index 621a28b..63dc844 100644
--- a/extras/package/android/vlc-android/src/org/videolan/vlc/android/widget/AudioMiniPlayer.java
+++ b/extras/package/android/vlc-android/src/org/videolan/vlc/android/widget/AudioMiniPlayer.java
@@ -1,10 +1,5 @@
package org.videolan.vlc.android.widget;
-import org.videolan.vlc.android.AudioPlayer;
-import org.videolan.vlc.android.AudioPlayerActivity;
-import org.videolan.vlc.android.MainActivity;
-import org.videolan.vlc.android.R;
-
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -19,138 +14,149 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
+import org.videolan.vlc.android.AudioPlayer;
+import org.videolan.vlc.android.AudioPlayerActivity;
+import org.videolan.vlc.android.MainActivity;
+import org.videolan.vlc.android.R;
public class AudioMiniPlayer extends LinearLayout implements AudioPlayer {
- public static final String TAG = "VLC/AudioMiniPlayer";
-
-
- private AudioPlayerControl mAudioPlayerControl;
-
- private TextView mTitle;
- private TextView mArtist;
- private ImageButton mPlayPause;
- private ImageView mCover;
- private SeekBar mSeekbar;
-
- // Listener for the play and pause buttons
- private OnClickListener onPlayPauseClickListener = new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mAudioPlayerControl != null) {
- if (mAudioPlayerControl.isPlaying()) {
- mAudioPlayerControl.pause();
- } else {
- mAudioPlayerControl.play();
- }
- }
- update();
- }
- };
+ public static final String TAG = "VLC/AudioMiniPlayer";
-
- public AudioMiniPlayer(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
+ private AudioPlayerControl mAudioPlayerControl;
- public AudioMiniPlayer(Context context) {
- super(context);
- init();
- }
-
- private void init() {
- // get inflater and create the new view
- LayoutInflater layoutInflater =
- (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View mMiniPlayerView = layoutInflater.inflate(R.layout.audio_player_mini, this, false);
-
- addView(mMiniPlayerView);
-
- // Initialize the children
- mCover = (ImageView) findViewById(R.id.cover);
- mTitle = (TextView) findViewById(R.id.title);
- mArtist = (TextView) findViewById(R.id.artist);
- mPlayPause = (ImageButton) findViewById(R.id.play_pause);
- mPlayPause.setOnClickListener(onPlayPauseClickListener);
- mSeekbar = (SeekBar) findViewById(R.id.timeline);
-
- this.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View view) {
- // Start audio player
-
- Intent intent = new Intent(getContext(),
- AudioPlayerActivity.class);
- getContext().startActivity(intent);
- }
-
- });
-
- this.setOnLongClickListener(new OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View arg0) {
- showContextMenu();
- return true;
- }
- });
- }
-
- @Override
- protected void onCreateContextMenu(ContextMenu menu) {
- MenuInflater inflater = MainActivity.getInstance().getMenuInflater();
- inflater.inflate(R.menu.audio_player_mini, menu);
- MenuItem hmi = menu.findItem(R.id.hide_mini_player);
- MenuItem pp = menu.findItem(R.id.play_pause);
- if (mAudioPlayerControl.isPlaying()) {
- hmi.setVisible(false);
- pp.setTitle(R.string.pause);
- } else {
- pp.setTitle(R.string.play);
+ private TextView mTitle;
+ private TextView mArtist;
+ private ImageButton mPlayPause;
+ private ImageButton mForward;
+ private ImageButton mBackward;
+ private ImageView mCover;
+ private SeekBar mSeekbar;
+
+ // Listener for the play and pause buttons
+ private OnClickListener onMediaControlClickListener = new OnClickListener() {
+ public void onClick(View v) {
+ if (mAudioPlayerControl != null) {
+ if (v == mPlayPause) {
+ if (mAudioPlayerControl.isPlaying()) {
+ mAudioPlayerControl.pause();
+ } else {
+ mAudioPlayerControl.play();
+ }
+ } else if (v==mForward) {
+ mAudioPlayerControl.next();
+ } else if (v==mBackward) {
+ mAudioPlayerControl.previous();
}
-
- super.onCreateContextMenu(menu);
+ }
+ update();
}
-
- public void setAudioPlayerControl(AudioPlayerControl control) {
- mAudioPlayerControl = control;
+ };
+
+ public AudioMiniPlayer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public AudioMiniPlayer(Context context) {
+ super(context);
+ init();
+ }
+
+ private void init() {
+ // get inflater and create the new view
+ LayoutInflater layoutInflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View mMiniPlayerView = layoutInflater.inflate(
+ R.layout.audio_player_mini, this, false);
+
+ addView(mMiniPlayerView);
+
+ // Initialize the children
+ mCover = (ImageView) findViewById(R.id.cover);
+ mTitle = (TextView) findViewById(R.id.title);
+ mArtist = (TextView) findViewById(R.id.artist);
+ mPlayPause = (ImageButton) findViewById(R.id.play_pause);
+ mForward = (ImageButton) findViewById(R.id.forward);
+ mBackward = (ImageButton) findViewById(R.id.backward);
+ mPlayPause.setOnClickListener(onMediaControlClickListener);
+ mForward.setOnClickListener(onMediaControlClickListener);
+ mBackward.setOnClickListener(onMediaControlClickListener);
+ mSeekbar = (SeekBar) findViewById(R.id.timeline);
+
+ this.setOnClickListener(new OnClickListener() {
+
+ public void onClick(View view) {
+ // Start audio player
+
+ Intent intent = new Intent(getContext(),
+ AudioPlayerActivity.class);
+ getContext().startActivity(intent);
+ }
+
+ });
+
+ this.setOnLongClickListener(new OnLongClickListener() {
+
+ public boolean onLongClick(View arg0) {
+ showContextMenu();
+ return true;
+ }
+ });
+ }
+
+ @Override
+ protected void onCreateContextMenu(ContextMenu menu) {
+ MenuInflater inflater = MainActivity.getInstance().getMenuInflater();
+ inflater.inflate(R.menu.audio_player_mini, menu);
+ MenuItem hmi = menu.findItem(R.id.hide_mini_player);
+ MenuItem pp = menu.findItem(R.id.play_pause);
+ if (mAudioPlayerControl.isPlaying()) {
+ hmi.setVisible(false);
+ pp.setTitle(R.string.pause);
+ } else {
+ pp.setTitle(R.string.play);
}
-
- public void update() {
- if (mAudioPlayerControl != null) {
-
- if (mAudioPlayerControl.hasMedia()) {
- this.setVisibility(LinearLayout.VISIBLE);
- } else {
- this.setVisibility(LinearLayout.GONE);
- return;
- }
-
- Bitmap cover = mAudioPlayerControl.getCover();
- if (cover != null) {
- mCover.setVisibility(ImageView.VISIBLE);
- mCover.setImageBitmap(cover);
- } else {
- mCover.setVisibility(ImageView.GONE);
- }
-
- mTitle.setText(mAudioPlayerControl.getTitle());
- mArtist.setText(mAudioPlayerControl.getArtist());
- if (mAudioPlayerControl.isPlaying()) {
- mPlayPause.setImageResource(R.drawable.ic_pause);
- } else {
- mPlayPause.setImageResource(R.drawable.ic_play);
- }
- int time = (int)mAudioPlayerControl.getTime();
- int length = (int)mAudioPlayerControl.getLength();
- // Update all view elements
-
- mSeekbar.setMax(length);
- mSeekbar.setProgress(time);
- }
-
-
+
+ super.onCreateContextMenu(menu);
+ }
+
+ public void setAudioPlayerControl(AudioPlayerControl control) {
+ mAudioPlayerControl = control;
+ }
+
+ public void update() {
+ if (mAudioPlayerControl != null) {
+
+ if (mAudioPlayerControl.hasMedia()) {
+ this.setVisibility(LinearLayout.VISIBLE);
+ } else {
+ this.setVisibility(LinearLayout.GONE);
+ return;
+ }
+ // TODO
+ Bitmap cover = mAudioPlayerControl.getCover();
+ if (cover != null) {
+ mCover.setVisibility(ImageView.VISIBLE);
+ mCover.setImageBitmap(cover);
+ } else {
+ mCover.setVisibility(ImageView.GONE);
+ }
+
+ mTitle.setText(mAudioPlayerControl.getTitle());
+ mArtist.setText(mAudioPlayerControl.getArtist());
+ if (mAudioPlayerControl.isPlaying()) {
+ mPlayPause.setImageResource(R.drawable.ic_pause);
+ } else {
+ mPlayPause.setImageResource(R.drawable.ic_play);
+ }
+ int time = mAudioPlayerControl.getTime();
+ int length = mAudioPlayerControl.getLength();
+ // Update all view elements
+
+ mSeekbar.setMax(length);
+ mSeekbar.setProgress(time);
}
-
+
+ }
+
}
--
1.7.4.1
More information about the vlc-devel
mailing list