From 37c91fcaed2f3c76ccc28fbad837dbfb747eb817 Mon Sep 17 00:00:00 2001 From: Andrew Stephan Date: Thu, 27 Feb 2014 12:00:53 -0500 Subject: [PATCH] runs in android now but doesn't work yet --- .gitignore | 2 +- plugin.xml | 47 +++ src/Android/Library/res/anim/image_pop_in.xml | 11 + .../Library/res/drawable-hdpi/icon.png | Bin 0 -> 4147 bytes .../Library/res/drawable-hdpi/image_bg.9.png | Bin 0 -> 1574 bytes .../res/drawable-hdpi/loading_icon.png | Bin 0 -> 3071 bytes .../Library/res/drawable-ldpi/icon.png | Bin 0 -> 1723 bytes .../drawable-mdpi/ic_action_discard_dark.png | Bin 0 -> 415 bytes .../drawable-mdpi/ic_action_discard_light.png | Bin 0 -> 386 bytes .../res/drawable-mdpi/ic_action_done_dark.png | Bin 0 -> 454 bytes .../drawable-mdpi/ic_action_done_light.png | Bin 0 -> 400 bytes .../Library/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 2645 bytes .../Library/res/drawable-mdpi/icon.png | Bin 0 -> 2574 bytes .../drawable-xhdpi/ic_action_discard_dark.png | Bin 0 -> 724 bytes .../ic_action_discard_light.png | Bin 0 -> 684 bytes .../drawable-xhdpi/ic_action_done_dark.png | Bin 0 -> 825 bytes .../drawable-xhdpi/ic_action_done_light.png | Bin 0 -> 759 bytes .../res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 5213 bytes .../Library/res/drawable/grid_background.xml | 12 + .../actionbar_custom_view_done_discard.xml | 27 ++ .../res/layout/actionbar_discard_button.xml | 33 ++ .../res/layout/actionbar_done_button.xml | 34 ++ .../Library/res/layout/multiselectorgrid.xml | 33 ++ .../multiimagechooser_strings_de.xml | 7 + .../multiimagechooser_strings_es.xml | 7 + .../multiimagechooser_strings_fr.xml | 6 + .../multiimagechooser_strings_hu.xml | 8 + .../multiimagechooser_strings_ja.xml | 7 + .../multiimagechooser_strings_ko.xml | 7 + .../values/multiimagechooser_strings_en.xml | 9 + src/Android/Library/res/values/themes.xml | 5 + src/Android/Library/src/ImageFetcher.java | 368 ++++++++++++++++ .../src/MultiImageChooserActivity.java | 395 ++++++++++++++++++ .../synconset/ImagePicker/ImagePicker.java | 44 ++ 34 files changed, 1061 insertions(+), 1 deletion(-) create mode 100644 src/Android/Library/res/anim/image_pop_in.xml create mode 100644 src/Android/Library/res/drawable-hdpi/icon.png create mode 100644 src/Android/Library/res/drawable-hdpi/image_bg.9.png create mode 100644 src/Android/Library/res/drawable-hdpi/loading_icon.png create mode 100644 src/Android/Library/res/drawable-ldpi/icon.png create mode 100644 src/Android/Library/res/drawable-mdpi/ic_action_discard_dark.png create mode 100644 src/Android/Library/res/drawable-mdpi/ic_action_discard_light.png create mode 100644 src/Android/Library/res/drawable-mdpi/ic_action_done_dark.png create mode 100644 src/Android/Library/res/drawable-mdpi/ic_action_done_light.png create mode 100644 src/Android/Library/res/drawable-mdpi/ic_launcher.png create mode 100644 src/Android/Library/res/drawable-mdpi/icon.png create mode 100644 src/Android/Library/res/drawable-xhdpi/ic_action_discard_dark.png create mode 100644 src/Android/Library/res/drawable-xhdpi/ic_action_discard_light.png create mode 100644 src/Android/Library/res/drawable-xhdpi/ic_action_done_dark.png create mode 100644 src/Android/Library/res/drawable-xhdpi/ic_action_done_light.png create mode 100644 src/Android/Library/res/drawable-xhdpi/ic_launcher.png create mode 100644 src/Android/Library/res/drawable/grid_background.xml create mode 100644 src/Android/Library/res/layout/actionbar_custom_view_done_discard.xml create mode 100644 src/Android/Library/res/layout/actionbar_discard_button.xml create mode 100644 src/Android/Library/res/layout/actionbar_done_button.xml create mode 100644 src/Android/Library/res/layout/multiselectorgrid.xml create mode 100644 src/Android/Library/res/values-de/multiimagechooser_strings_de.xml create mode 100644 src/Android/Library/res/values-es/multiimagechooser_strings_es.xml create mode 100644 src/Android/Library/res/values-fr/multiimagechooser_strings_fr.xml create mode 100644 src/Android/Library/res/values-hu/multiimagechooser_strings_hu.xml create mode 100644 src/Android/Library/res/values-ja/multiimagechooser_strings_ja.xml create mode 100644 src/Android/Library/res/values-ko/multiimagechooser_strings_ko.xml create mode 100644 src/Android/Library/res/values/multiimagechooser_strings_en.xml create mode 100644 src/Android/Library/res/values/themes.xml create mode 100644 src/Android/Library/src/ImageFetcher.java create mode 100644 src/Android/Library/src/MultiImageChooserActivity.java create mode 100644 src/Android/com/synconset/ImagePicker/ImagePicker.java diff --git a/.gitignore b/.gitignore index 80e7971..2e9df62 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ # Xcode 4 xcuserdata/ project.xcworkspace/ - +tags diff --git a/plugin.xml b/plugin.xml index 475b5d2..e19ae37 100644 --- a/plugin.xml +++ b/plugin.xml @@ -56,5 +56,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Android/Library/res/anim/image_pop_in.xml b/src/Android/Library/res/anim/image_pop_in.xml new file mode 100644 index 0000000..3b1f7e9 --- /dev/null +++ b/src/Android/Library/res/anim/image_pop_in.xml @@ -0,0 +1,11 @@ + + diff --git a/src/Android/Library/res/drawable-hdpi/icon.png b/src/Android/Library/res/drawable-hdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8074c4c571b8cd19e27f4ee5545df367420686d7 GIT binary patch literal 4147 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 literal 0 HcmV?d00001 diff --git a/src/Android/Library/res/drawable-hdpi/image_bg.9.png b/src/Android/Library/res/drawable-hdpi/image_bg.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9835be619c33d45984f74d151ccaf57217ba87bb GIT binary patch literal 1574 zcmV+>2HE+EP)R<9V@yPAGIebNz+PZO*d}8L zyAVNWeJLnT!Ao!bAG{I-C7>7LJBkpH?fJ>~grCP~(&8>mo&z7m3q3xcJip&LM>yXn zE-td;-x%h#jyF_X02<;Vc#}u~iG&thQjrt|sB6-q=0wRsyyQj$Um=CcBIBiBpp}HB zfXhTGktXq06d>1=iaM2=lO)LrXf#Fc5uu?(CaNT+;)FV&Co%{FFcO*P93wEGwhYuM z>b)XKmgOp9j|f%E)Jh`LB!LE;IE%<8atIS)Cf=6FJ%`ADzZrGqpw2ARZGZ7jA7$vcn;VXD(R5InR zG)N-zZ~}3{Vxoj7C2kN-!bOxt0WQ=ea1eIXTZsDe;3EsorbF`ukBibWPnKkgPvI(- zgZQ+HZ~}26H{m79iAti1sE#74P?xCB1JO6oL{^B+MY9>;D|p1?0+a;PicGP8){8a(8sF7^b2&*v*xSXk%@1OmgGo0~)H>+8eeSY2Hmi58Ta zc6N4#XJ=>s%*n}VCNCclbr5?KtF=(-)FVQZu+%e16sfiY^Vm*eB(zmT5~(Y4j+RtGvYR~D*8cj~A!^Y-`mhn!AlOp8=QTip~j*@#}R z?<7x6=+-;9me`1Evd~M|JM~LTOFjMl{bMZgID>`INX& zk*jXvGs1`c^fvLX^53bT(9X_I%huM`3zm1X(2b3a5pwk{@fEtX0eh)S7AhW{^zH5K z1uQfop+6GOh);-*a4U6F7Ah`C8Lh3Yg)H=Rp=)bvqvT55K7B)cPBi1<@dNQS(TaQ03bjxp3yoOlAJ|8q z679r&JdOs1ihEFFQ&Uqh3ynxQadZd1g$P0x_q^a%Usk=&*@ zWQHCliya&sjM{8A78ruMy1L2bThh<*%N!kPErj zAh;lkCoNboX(3-VX(3aZw2-QvwD3B!K(f*9u{sMxciJqFaMNm%C9%r1nsn8)8e^19 ztI3q6)fiOMYILYyJ*`HWvvh2p(gkVxtHo+na#KRgQi_FnO3A8uN(rInDe(xkGa8}x YA9J6cX#E3w;s5{u07*qoM6N<$g7C-pZU6uP literal 0 HcmV?d00001 diff --git a/src/Android/Library/res/drawable-hdpi/loading_icon.png b/src/Android/Library/res/drawable-hdpi/loading_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3490f83dedccc68d858b2a8ad80760890d5e726a GIT binary patch literal 3071 zcmVk_frZ}1546Ds106+UF`aU( zM6(&3{9?qx{214g{7OMnQxfd1C|0IqrHz__GMSDxx@8FlnhZHo154lsj9*|NU-G{F zv3v1ydEfKiJ!j8(FI;{zXBg(}zR$DgxqHs;v(G+Ts#Ge}LrC2NI1(5E4EO&I1$x!3 z+&$O`ECLp^yB1obHrK0IN-}_ux*1TwmB0Z}RP8>j1X_V<)~HWv6{=|fA@vc!uYhCn z(5@RXA2{C{^?J3N+ZjMe-Guv#{}IqTclEjl8-Yo{RBKeZ{f%u5;2-|4fwK!$ulw*2 za9(>OG<7KOJ$60(JUJWpjJLA22MDQ$0RJTHwevnu^8?dOXa@QRl-~dhvqmijZvg-5 zc@a3SPUXeG?{FWM`PQgaDHPu65K`}l8=8**&H}zrr^-vf3D&4`n*kJV$W)6mFb$Yw zjoJ`H>75lJbuZv1U?Q$})Zz+jlrFW5YHb3R0fTB3ECXM&Mm-l*)14e4^~u09Z2z5Y zV+GLC1RO!_hYxNdvFqUn;-A?a2}K40M>OGF3$<7b+z?Z-ZpI{>i=q}Ins6VETKwJ` zwK1+v-3M#bCfwM+7Q^cqV18Vcx+Sk9+#AsY=hdvmg2>7QBc$F3I2IU;a|jOf*8#wO zzSz6KJN|mx|GN~JYmNG_Xq`KdWPqWimQk&>+@Wi&QG4d0Q9XpzgMrh4F~A8xkCZ>P z1^65A1n`74YDpXo!w^!h0rskPFR5W$@=>QcLh6Hn@xU1*_sS5Ofl>aNCZt{j%mQXw zqiiG@ouQ`BKkZ*uG=$UxfXTpx;0HL@_Z|g{ zZ^jw?J3{JKV2U;Bqk?q+8ejk+bqSb&TW{FEX!#xJ16&785K`X=%&2D%V`?5SqzHK# z8GbQu?O^9t}sf4zcpKjblaobKC_3%MA;f5aXm&M!@}xVgaLSrh|a2W|uA zSfkdoztJ+f^|(@{q=0V%?^jBd)(yQr`T5FcCa&wCOJCsYzz=bum05TLIJToMok2*w z8mKzFjoJhJB=@1-=0Uze+qe`?f|QW)GMM3`kLLIdHr+>JM2JC^eOPcBY&)>S^2} z&wo;g8GvhR6rvbFNc~yTDYXnZ#v1in3_U`yM!f-y#I2l#GSRm=GqHNWjX>YPI_rQj zjf}3dM!knybz2))wJ)yCnaOMbA@v~Ks3n97E@pmVR{2@6MlAx)C1KU71{eCaXCg)q z7)SVoYl=1M@d&b`V2zp$+#Xo12d?dzh+%-!1IxdSTa4*y+=6pwgz&AbLNgh_cfl_O zR-0URsM!FlQ6J-iYC{+%q;AO~H){_#EwKC>z|4#?^W=V9IA#cAvIs2N0MlyCaJvG2 zH)H6x;EXIXQyaiLx<&_7*@6p@>gqg6n5*IhA$97-rYt>R7|#9MSzfe8y_-Q^Ay}h6 z0R9?KrJ3Xi^F*>3pe3;UtPHY>W_DotgVGAhVt~&DmVYLLtfKi-VENQp1hTAHg&H7> zFTQh>87E}x=)^Lm(g#huZFq3WvsWj1L;o8nd0=4qtrTT|HGZ6(Go|zE7O6maQ|}wa z=(}#WFI@hUYDKJ38->�Q+`QaB2f&c?E@ZyM_k9R-qr2%9I07ntpIXnUGm=>Q_(} z1B8SY#xp>v6fJhMc}qDdD?o?=LN;n|Ls6lL@zznxm6s#_R?^B=AoLW^WaRuR?%l51)Rk(8bi_tNA-atr9RO&y5ECvYa0pMnf|H>e58x}2^ya|^$Bo9Pj`P4n2s8UmQ)oX^=E+N1FCE$!-n?M2Jo(h zKL^Unw0cw!V+h;NV6yD6%sSb4GO+wrLh9Wz%FGR~+qHq!GP&8a8ek4#@id13x$Zd0 z$ON2@ouxv?RlZCHutvQDgt`W95K>poo6t!766>VEYV)m8p`*cVh~e)D?SlJ}K8iX| zZXkT`a^`^I7zTI{*c4djav}A(5oAX}NIe#pHX(#fxYW*>$ZP;>)Jou<6jkpNQa3y= zwUGK~T&z;4$MzoI_DsZbx!wY-4y@A)nC;WlGz1~_fw+(8?txWTgkLh8MQ)KhU@)U>JjuZfvGIO?*SHR@s92JN(53M>&) zU+Gf-M?py4)2C-%f=dvUmdAV>qmf6#rg6C0?+Z-D4OQ;|W~H6%_<72vpoEIqu#{jfqtYYnJIV_cecx$MF}i4 zajRcPK1)bF3%41rrAYY+tN^af`+Z-HLKC;P;gcv00ltqr3ae3k2wVjm)`*7>4a^pNIeZW54Z1jB=LJ^8TdPH3H3K! zWyfZc0gC=Uya(I~+$p5)kIQN`2KXv2H(VOl1JB|XUFJ0Kq1Rk(E47SjtvO8wgf(he z9vXEP?-f0YbVr!H+USGlyhE_o9B54sU?K438U;q+vRX9^e~Qywf9;4QB{NyrL~>kX z>K)*_*h-QC7BrE3RMps+83MZ-Lh3$1($?Ae^?HB+s_v!TMW>hoB&9rF(1gp6lN8^6 zv5-1*W~lClkopYV5^F6iu(<6w+e@e)Ty-BXu~CQJ>?rsc)2YBkb&6hUjhfMBfD-Tm z?!2ueRsfIV4|E3pUG$+hT@C;24&l=SozJ9x_LRTi+})M-N16}D4M{^jx|?w`%AReP91Tc8>~sHP8V>Ys(CF=aT`Sk=;|pS}XrJPb~T1dys{sdO&0YpQBSz*~us zcN*3-J_EnE1cxrXiq*F~jZje~rkAe3vf3>;eR)3?Ox=jK*jEU7Do|T`2NqP{56w(* zBAf)rvPB_7rsfeKd0^!CaR%BHUC$tsP9m8a!i@4&TxxzagzsYHJvblx4rRUu#0Jlz zclZJwdC}7S3BvwaIMTiwb!98zRf|zoya>NudJkDGgEYs=q*HmC)>GExofw=92}s;l z_YgKLUT5`<1RBwq{f)K~I%M=gRE6d)b5BP`8{u9x0-wsG%H)w^ zRU7n9FwtlfsZSjiSB(k8~Y5+O>dyoSI477Ly?|FR?m))C!ci%BtY!2Sst8Uri#|SFX&)8{_Ou2 z9r5p3Vz9_GY#%D>%huqp_>U}K45YGy__TE!HZA@bMxX~@{;>cGYRgH~Ih*vd7EgV7h6Pg$#$lH+5=^lj{W80p{{l+;{7_t5cv3xVUy zl_BY4ht1JH*EEeRS{VwTC(QFIVu8zF&P8O$gJsMgsSO35SVvBrX`Vah$Yz2-5T>-`4DJNH;N zlSSY8-mfty+|1~*;BtTwLz_w5 z+lRv)J28~G%ouyvca(@|{2->WsPii&79&nju7ITE6hMX4AQc{|KqZN#)aAvemg3IZ zCr}Y+!r}JU&^>U1C2WyZC<=47itSYQ`?$5{VH?mtFMFFExfYTsfqK%*WzH@Onc#i` zI@a|rm-WbKk{5my{mF}H>Duc$bit&yLAgFfqo2vVbm~?FeG#0F?dSP*kxSo0Ff!o@ z(C}B;r&6pa-NY4;y~5lX8g&*MYQ>yLGd^tDWC4(sGy$Ow-*!eh%xt;>ve|J1q$*w< zh;B#cz!6l2=5bkX#nJ9PJQ`ew8t>7z$bxqf*QB=l2_UB$hK|1EIfloN-jQ=qcwChF zYAkkyp=;FwcnUB3v0=*tMYMA(Hdyk4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(eqE_ISEDhIkx*JK2z{*+IZ{zvW@G=!&ibvz(t=WS00Vys*8*qO&%)X?ev; zr;ayzjR!-{l^p)Re#XyW#pt;`|Cl$hD`=cbzZw^qX#9A$b(out*Ov5@rN8IpxtcP2 z3q6#Klvr`PVS7QhhyUb;DHhrO%-h~{J5EdXIvTm%{NwYiobSk;eS-5mewdzmrXbt!pE1rY zfwT1Y)GtLqf2fwYMwFx^mZVxG7o`Fz1|tJQV_gGdT|=V~Lt`sr3o9cNZ39Cq0|S@x zQU??bx%nxXX_asd1{NVkKn<2whK3LgoZ7dHfEpx0HU#IVm6RtIr7}3Ck4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(eqE=6kw0hIkx*J7ptpivf@8{2ii~mLzluclb_BV4QG5C$C@rkxN(^)EL(WrHG{{N_hX>o|0AYJ z|G%0XI=#=d;`Vg4R<4cbJNml1^p5Z?Sdp2zGVt3Hjg~!EP6s;q9h%gTe~DWM4fsG@}- literal 0 HcmV?d00001 diff --git a/src/Android/Library/res/drawable-mdpi/ic_action_done_dark.png b/src/Android/Library/res/drawable-mdpi/ic_action_done_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..b8fb4f84207d0c1abb3fb57a2c91d25302c9d422 GIT binary patch literal 454 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(eqE9(%ethIkx*J9Q%;qoaVs^OhF2UYF{rPAda7LZ#*}2>!_&_`>DNqNmCp zC95tkxNwqnqQ{@3!5tB&=f-k%-dI~U>ATU)nP)9dq^o~Y{4ZYPJz>(SPlvv#y(nH% zS9?26VEVj}Bh#-|OS-(=bbN6^_sxg0-zr3|uF$pHfBY;fDVH>j_Z?;g~1gO{SUvTcJ!FK_V8KnElhO1BAQ#KqtPlF!5<^)*`gLbZOUQmFA}>n z*tUF#e|-M=fz+P!$5{BKRHkcY3(FKTeRJ~LWMusF{<->%f0`cfbZnAvzHshyAJDt1 zC9V-ADTyViR>?)FK#IZ0z|dINz*yJND8$g%%Gkon$Wq(D(8|C-b%96&iiX_$l+3hB zxCR4@5F?-lODjV|hz3sWTSh<)k{}y`^V3So6N^$A98>a>QWZRN6Vp?JQWH}u3s0un Q02MKKy85}Sb4q9e08uumk4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(eqE)_S@)hIkx*dvPJxAqSb`AM-yrbVt=NOg^a5l$fybH^(;B`wl$Y4zG*2 z>+G{(X4=Ih>BF*350WKZrg-1`-}R{O@8`X{dAt6;%;Kr7XjKh&($wF4V8deV$EwdH zgsg(r8LE7#`SEY|&Lo$^&%YR&E4})3di%|S#9Y-m_wK1|6XNoH_v!JQBRzAN4<48Q ztsBUyHpkMa;NkisU79mn?1d#)PO%q?_ABDMu;~5a?!PzQ#e|qy3Ync?1Ug)`#5JNM zC9x#cD!C{XNHG{07#iyu0FgzAk+GGrrImq+wt=CQfx)vUzS~hW3VtQ&&YGO)d;mK4RpdtoOS3j3^ HP6{XPn literal 0 HcmV?d00001 diff --git a/src/Android/Library/res/drawable-mdpi/ic_launcher.png b/src/Android/Library/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..9dc7f2185cc16b43440c84c6364209f03a4a6091 GIT binary patch literal 2645 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 literal 0 HcmV?d00001 diff --git a/src/Android/Library/res/drawable-xhdpi/ic_action_discard_light.png b/src/Android/Library/res/drawable-xhdpi/ic_action_discard_light.png new file mode 100644 index 0000000000000000000000000000000000000000..24256f15c99031d16bc6a0e6d8100e6fa66af508 GIT binary patch literal 684 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 + + + \ No newline at end of file diff --git a/src/Android/Library/res/layout/actionbar_custom_view_done_discard.xml b/src/Android/Library/res/layout/actionbar_custom_view_done_discard.xml new file mode 100644 index 0000000..0b61fb9 --- /dev/null +++ b/src/Android/Library/res/layout/actionbar_custom_view_done_discard.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/src/Android/Library/res/layout/actionbar_discard_button.xml b/src/Android/Library/res/layout/actionbar_discard_button.xml new file mode 100644 index 0000000..3e72461 --- /dev/null +++ b/src/Android/Library/res/layout/actionbar_discard_button.xml @@ -0,0 +1,33 @@ + + + + diff --git a/src/Android/Library/res/layout/actionbar_done_button.xml b/src/Android/Library/res/layout/actionbar_done_button.xml new file mode 100644 index 0000000..a6071c6 --- /dev/null +++ b/src/Android/Library/res/layout/actionbar_done_button.xml @@ -0,0 +1,34 @@ + + + + + + diff --git a/src/Android/Library/res/layout/multiselectorgrid.xml b/src/Android/Library/res/layout/multiselectorgrid.xml new file mode 100644 index 0000000..6e22b5f --- /dev/null +++ b/src/Android/Library/res/layout/multiselectorgrid.xml @@ -0,0 +1,33 @@ + + + + + \ No newline at end of file diff --git a/src/Android/Library/res/values-de/multiimagechooser_strings_de.xml b/src/Android/Library/res/values-de/multiimagechooser_strings_de.xml new file mode 100644 index 0000000..32123f1 --- /dev/null +++ b/src/Android/Library/res/values-de/multiimagechooser_strings_de.xml @@ -0,0 +1,7 @@ + + + MultiImageChooser + Free version - Images left: %d + There was an error opening the images database. Please report the problem. + Requesting thumbnails, please be patient + diff --git a/src/Android/Library/res/values-es/multiimagechooser_strings_es.xml b/src/Android/Library/res/values-es/multiimagechooser_strings_es.xml new file mode 100644 index 0000000..fe05862 --- /dev/null +++ b/src/Android/Library/res/values-es/multiimagechooser_strings_es.xml @@ -0,0 +1,7 @@ + + + MultiImageChooser + Solicitando miniaturas. Por favor, espere… + Versión gratuita - Imágenes restantes: %d + Error al abrir la base de datos de imágenes. + \ No newline at end of file diff --git a/src/Android/Library/res/values-fr/multiimagechooser_strings_fr.xml b/src/Android/Library/res/values-fr/multiimagechooser_strings_fr.xml new file mode 100644 index 0000000..964f190 --- /dev/null +++ b/src/Android/Library/res/values-fr/multiimagechooser_strings_fr.xml @@ -0,0 +1,6 @@ + + "MultiImageChooser" + "La version gratuite - gauche Images:%d" + "Il y avait une erreur d'ouvrir la base de données images. S'il vous plaît signaler le problème." + "Demande de vignettes, s'il vous plaît soyez patient" + \ No newline at end of file diff --git a/src/Android/Library/res/values-hu/multiimagechooser_strings_hu.xml b/src/Android/Library/res/values-hu/multiimagechooser_strings_hu.xml new file mode 100644 index 0000000..5bb897c --- /dev/null +++ b/src/Android/Library/res/values-hu/multiimagechooser_strings_hu.xml @@ -0,0 +1,8 @@ + + + MultiImageChooser + + Ingyenes verzió - hátralévő képek: %d + Képadatbázis megnyitási hiba történt. Kérjük, jelentse a problémát. + Miniatűrök lekérése, kérjük legyen türelemmel + \ No newline at end of file diff --git a/src/Android/Library/res/values-ja/multiimagechooser_strings_ja.xml b/src/Android/Library/res/values-ja/multiimagechooser_strings_ja.xml new file mode 100644 index 0000000..92f084a --- /dev/null +++ b/src/Android/Library/res/values-ja/multiimagechooser_strings_ja.xml @@ -0,0 +1,7 @@ + + + MultiImageChooser + 無料版 - 残りの画像: %d + 画像データベースを開く際にエラーがありました。問題を報告してください。 + サムネイルをリクエスト中です。お待ちください。 + diff --git a/src/Android/Library/res/values-ko/multiimagechooser_strings_ko.xml b/src/Android/Library/res/values-ko/multiimagechooser_strings_ko.xml new file mode 100644 index 0000000..4454379 --- /dev/null +++ b/src/Android/Library/res/values-ko/multiimagechooser_strings_ko.xml @@ -0,0 +1,7 @@ + + + MultiImageChooser + 무료 버전 - 남은 이미지: %d + 이미지 데이터베이스를 여는 데 오류가 발생했습니다. 문제를 보고하세요. + 썸네일 요청 중. 기다려주세요 + diff --git a/src/Android/Library/res/values/multiimagechooser_strings_en.xml b/src/Android/Library/res/values/multiimagechooser_strings_en.xml new file mode 100644 index 0000000..2566b2f --- /dev/null +++ b/src/Android/Library/res/values/multiimagechooser_strings_en.xml @@ -0,0 +1,9 @@ + + + MultiImageChooser + Free version - Images left: %d + There was an error opening the images database. Please report the problem. + Requesting thumbnails, please be patient + Cancel + OK + diff --git a/src/Android/Library/res/values/themes.xml b/src/Android/Library/res/values/themes.xml new file mode 100644 index 0000000..2ec73cf --- /dev/null +++ b/src/Android/Library/res/values/themes.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/Android/Library/src/ImageFetcher.java b/src/Android/Library/src/ImageFetcher.java new file mode 100644 index 0000000..f384862 --- /dev/null +++ b/src/Android/Library/src/ImageFetcher.java @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.synconset; + +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Handler; +import android.provider.MediaStore; +import android.util.Log; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.ImageView; + +/** + * This helper class download images from the Internet and binds those with the + * provided ImageView. + * + *

+ * It requires the INTERNET permission, which should be added to your + * application's manifest file. + *

+ * + * A local cache of downloaded images is maintained internally to improve + * performance. + */ +public class ImageFetcher { + + private int colWidth; + private long origId; + private ExecutorService executor; + + public ImageFetcher() { + executor = Executors.newCachedThreadPool(); + } + + public void fetch(Integer id, ImageView imageView, int colWidth) { + resetPurgeTimer(); + this.colWidth = colWidth; + this.origId = id; + Bitmap bitmap = getBitmapFromCache(id); + + if (bitmap == null) { + forceDownload(id, imageView); + } else { + cancelPotentialDownload(id, imageView); + imageView.setImageBitmap(bitmap); + } + } + + /** + * Same as download but the image is always downloaded and the cache is not + * used. Kept private at the moment as its interest is not clear. + */ + private void forceDownload(Integer position, ImageView imageView) { + if (position == null) { + imageView.setImageDrawable(null); + return; + } + + if (cancelPotentialDownload(position, imageView)) { + BitmapFetcherTask task = new BitmapFetcherTask(imageView.getContext(), imageView); + DownloadedDrawable downloadedDrawable = new DownloadedDrawable(imageView.getContext(), task, origId); + imageView.setImageDrawable(downloadedDrawable); + imageView.setMinimumHeight(colWidth); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + task.executeOnExecutor(executor, position); + } else { + try { + task.execute(position); + } catch (RejectedExecutionException e) { + // Oh :( + } + } + + } + } + + /** + * Returns true if the current download has been canceled or if there was no + * download in progress on this image view. Returns false if the download in + * progress deals with the same url. The download is not stopped in that + * case. + */ + private static boolean cancelPotentialDownload(Integer position, ImageView imageView) { + BitmapFetcherTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); + long origId = getOrigId(imageView); + + if (bitmapDownloaderTask != null) { + Integer bitmapPosition = bitmapDownloaderTask.position; + if ((bitmapPosition == null) || (!bitmapPosition.equals(position))) { + Log.d("DAVID", "Canceling..."); + MediaStore.Images.Thumbnails.cancelThumbnailRequest(imageView.getContext().getContentResolver(), + origId, 12345); + bitmapDownloaderTask.cancel(true); + } else { + return false; + } + } + return true; + } + + /** + * @param imageView + * Any imageView + * @return Retrieve the currently active download task (if any) associated + * with this imageView. null if there is no such task. + */ + private static BitmapFetcherTask getBitmapDownloaderTask(ImageView imageView) { + if (imageView != null) { + Drawable drawable = imageView.getDrawable(); + if (drawable instanceof DownloadedDrawable) { + DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable; + return downloadedDrawable.getBitmapDownloaderTask(); + } + } + return null; + } + + private static long getOrigId(ImageView imageView) { + if (imageView != null) { + Drawable drawable = imageView.getDrawable(); + if (drawable instanceof DownloadedDrawable) { + DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable; + return downloadedDrawable.getOrigId(); + } + } + return -1; + } + + /** + * The actual AsyncTask that will asynchronously download the image. + */ + class BitmapFetcherTask extends AsyncTask { + private Integer position; + private final WeakReference imageViewReference; + private final Context mContext; + + public BitmapFetcherTask(Context context, ImageView imageView) { + imageViewReference = new WeakReference(imageView); + mContext = context; + } + + /** + * Actual download method. + */ + @Override + protected Bitmap doInBackground(Integer... params) { + position = params[0]; + if (isCancelled()) { + return null; + } + Bitmap thumb = MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(), position, 12345, + MediaStore.Images.Thumbnails.MICRO_KIND, null); + if (isCancelled()) { + return null; + } + if (thumb == null) { + return null; + } else { + if (isCancelled()) { + return null; + } else { + return thumb; + } + } + + } + + private void setInvisible() { + Log.d("COLLAGE", "Setting something invisible..."); + if (imageViewReference != null) { + final ImageView imageView = imageViewReference.get(); + BitmapFetcherTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); + if (this == bitmapDownloaderTask) { + imageView.setVisibility(View.GONE); + imageView.setClickable(false); + imageView.setEnabled(false); + } + } + } + + /** + * Once the image is downloaded, associates it to the imageView + */ + @Override + protected void onPostExecute(Bitmap bitmap) { + if (isCancelled()) { + bitmap = null; + } + addBitmapToCache(position, bitmap); + if (imageViewReference != null) { + ImageView imageView = imageViewReference.get(); + BitmapFetcherTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); + if (this == bitmapDownloaderTask) { + imageView.setImageBitmap(bitmap); + Animation anim = AnimationUtils.loadAnimation(imageView.getContext(), android.R.anim.fade_in); + imageView.setAnimation(anim); + anim.start(); + } + } else { + setInvisible(); + } + } + } + + /** + * A fake Drawable that will be attached to the imageView while the download + * is in progress. + * + *

+ * Contains a reference to the actual download task, so that a download task + * can be stopped if a new binding is required, and makes sure that only the + * last started download process can bind its result, independently of the + * download finish order. + *

+ */ + static class DownloadedDrawable extends ColorDrawable { + private final WeakReference bitmapDownloaderTaskReference; + private long origId; + + public DownloadedDrawable(Context mContext, BitmapFetcherTask bitmapDownloaderTask, long origId) { + super(Color.TRANSPARENT); + bitmapDownloaderTaskReference = new WeakReference(bitmapDownloaderTask); + this.origId = origId; + } + + public long getOrigId() { + return origId; + } + + public BitmapFetcherTask getBitmapDownloaderTask() { + return bitmapDownloaderTaskReference.get(); + } + } + + /* + * Cache-related fields and methods. + * + * We use a hard and a soft cache. A soft reference cache is too aggressively cleared by the + * Garbage Collector. + */ + + private static final int HARD_CACHE_CAPACITY = 100; + private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds + + // Hard cache, with a fixed maximum capacity and a life duration + private final HashMap sHardBitmapCache = new LinkedHashMap( + HARD_CACHE_CAPACITY / 2, 0.75f, true) { + @Override + protected boolean removeEldestEntry(LinkedHashMap.Entry eldest) { + if (size() > HARD_CACHE_CAPACITY) { + // Entries push-out of hard reference cache are transferred to + // soft reference cache + sSoftBitmapCache.put(eldest.getKey(), new SoftReference(eldest.getValue())); + return true; + } else + return false; + } + }; + + // Soft cache for bitmaps kicked out of hard cache + private final static ConcurrentHashMap> sSoftBitmapCache = new ConcurrentHashMap>( + HARD_CACHE_CAPACITY / 2); + + private final Handler purgeHandler = new Handler(); + + private final Runnable purger = new Runnable() { + public void run() { + clearCache(); + } + }; + + /** + * Adds this bitmap to the cache. + * + * @param bitmap + * The newly downloaded bitmap. + */ + private void addBitmapToCache(Integer position, Bitmap bitmap) { + if (bitmap != null) { + synchronized (sHardBitmapCache) { + sHardBitmapCache.put(position, bitmap); + } + } + } + + /** + * @param position + * The URL of the image that will be retrieved from the cache. + * @return The cached bitmap or null if it was not found. + */ + private Bitmap getBitmapFromCache(Integer position) { + // First try the hard reference cache + synchronized (sHardBitmapCache) { + final Bitmap bitmap = sHardBitmapCache.get(position); + if (bitmap != null) { + Log.d("CACHE ****** ", "Hard hit!"); + // Bitmap found in hard cache + // Move element to first position, so that it is removed last + return bitmap; + } + } + + // Then try the soft reference cache + SoftReference bitmapReference = sSoftBitmapCache.get(position); + if (bitmapReference != null) { + final Bitmap bitmap = bitmapReference.get(); + if (bitmap != null) { + // Bitmap found in soft cache + Log.d("CACHE ****** ", "Soft hit!"); + return bitmap; + } else { + // Soft reference has been Garbage Collected + sSoftBitmapCache.remove(position); + } + } + + return null; + } + + /** + * Clears the image cache used internally to improve performance. Note that + * for memory efficiency reasons, the cache will automatically be cleared + * after a certain inactivity delay. + */ + public void clearCache() { + // sHardBitmapCache.clear(); + // sSoftBitmapCache.clear(); + } + + /** + * Allow a new delay before the automatic cache clear is done. + */ + private void resetPurgeTimer() { + // purgeHandler.removeCallbacks(purger); + // purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE); + } +} diff --git a/src/Android/Library/src/MultiImageChooserActivity.java b/src/Android/Library/src/MultiImageChooserActivity.java new file mode 100644 index 0000000..a7d0b3b --- /dev/null +++ b/src/Android/Library/src/MultiImageChooserActivity.java @@ -0,0 +1,395 @@ +package com.synconset; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +import com.wymsee.apps.synconset.R; +import android.app.Activity; +import android.app.ActionBar; +import android.app.LoaderManager; +import android.content.Context; +import android.content.CursorLoader; +import android.content.Intent; +import android.content.Loader; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.os.Bundle; +import android.provider.MediaStore; +import android.util.Log; +import android.util.SparseBooleanArray; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.TextView; + +public class MultiImageChooserActivity extends Activity implements OnItemClickListener, + LoaderManager.LoaderCallbacks { + private static final String TAG = "Collage"; + public static final String COL_WIDTH_KEY = "COL_WIDTH"; + public static final String FLURRY_EVENT_ADD_MULTIPLE_IMAGES = "Add multiple images"; + + // El tamaño por defecto es 100 porque los thumbnails MICRO_KIND son de + // 96x96 + private static final int DEFAULT_COLUMN_WIDTH = 120; + + public static final int NOLIMIT = -1; + public static final String MAX_IMAGES_KEY = "MAX_IMAGES"; + + private ImageAdapter ia; + + private Cursor imagecursor, actualimagecursor; + private int image_column_index, actual_image_column_index; + private int colWidth; + + private static final int CURSORLOADER_THUMBS = 0; + private static final int CURSORLOADER_REAL = 1; + + private Set fileNames = new HashSet(); + + private SparseBooleanArray checkStatus = new SparseBooleanArray(); + + private TextView freeLabel = null; + private int maxImages; + private boolean unlimitedImages = false; + + private GridView gridView; + + private final ImageFetcher fetcher = new ImageFetcher(); + + private int selectedColor = Color.GREEN; + private boolean shouldRequestThumb = true; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.multiselectorgrid); + fileNames.clear(); + + maxImages = getIntent().getIntExtra(MAX_IMAGES_KEY, NOLIMIT); + + unlimitedImages = maxImages == NOLIMIT; + if (!unlimitedImages) { + freeLabel = (TextView) findViewById(R.id.label_images_left); + freeLabel.setVisibility(View.VISIBLE); + updateLabel(); + } + + colWidth = getIntent().getIntExtra(COL_WIDTH_KEY, DEFAULT_COLUMN_WIDTH); + + Display display = getWindowManager().getDefaultDisplay(); + @SuppressWarnings("deprecation") + int width = display.getWidth(); + int testColWidth = width / 3; + + if (testColWidth > colWidth) { + colWidth = width / 4; + } + + // int bgColor = getIntent().getIntExtra("BG_COLOR", Color.BLACK); + + gridView = (GridView) findViewById(R.id.gridview); + gridView.setColumnWidth(colWidth); + gridView.setOnItemClickListener(this); + gridView.setOnScrollListener(new OnScrollListener() { + + private int lastFirstItem = 0; + private long timestamp = System.currentTimeMillis(); + + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + if (scrollState == SCROLL_STATE_IDLE) { + Log.d(TAG, "IDLE - Reload!"); + shouldRequestThumb = true; + ia.notifyDataSetChanged(); + } + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + float dt = System.currentTimeMillis() - timestamp; + if (firstVisibleItem != lastFirstItem) { + double speed = 1 / dt * 1000; + lastFirstItem = firstVisibleItem; + timestamp = System.currentTimeMillis(); + Log.d(TAG, "Speed: " + speed + " elements/second"); + + // Limitarlo si vamos a más de una página por segundo... + shouldRequestThumb = speed < visibleItemCount; + } + } + }); + selectedColor = 0xff32b2e1; + // selectedColor = Color.RED; + + // gridView.setBackgroundColor(bgColor); + // gridView.setBackgroundResource(R.drawable.grid_background); + + ia = new ImageAdapter(this); + gridView.setAdapter(ia); + + LoaderManager.enableDebugLogging(false); + getLoaderManager().initLoader(CURSORLOADER_THUMBS, null, this); + getLoaderManager().initLoader(CURSORLOADER_REAL, null, this); + setupHeader(); + updateAcceptButton(); + } + + private void setupHeader() { + // From Roman Nurik's code + // https://plus.google.com/113735310430199015092/posts/R49wVvcDoEW + // Inflate a "Done/Discard" custom action bar view. + LayoutInflater inflater = (LayoutInflater) getActionBar().getThemedContext().getSystemService( + LAYOUT_INFLATER_SERVICE); + final View customActionBarView = inflater.inflate(R.layout.actionbar_custom_view_done_discard, null); + customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // "Done" + selectClicked(null); + } + }); + customActionBarView.findViewById(R.id.actionbar_discard).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + // Show the custom action bar view and hide the normal Home icon and + // title. + final ActionBar actionBar = getActionBar(); + actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM + | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE); + actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + } + + private void updateLabel() { + if (freeLabel != null) { + String text = String.format(getString(R.string.free_version_label), maxImages); + freeLabel.setText(text); + if (maxImages == 0) { + freeLabel.setTextColor(Color.RED); + } else { + freeLabel.setTextColor(Color.WHITE); + } + } + } + + public class ImageAdapter extends BaseAdapter { + private final Bitmap mPlaceHolderBitmap; + + public ImageAdapter(Context c) { + Bitmap tmpHolderBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.loading_icon); + mPlaceHolderBitmap = Bitmap.createScaledBitmap(tmpHolderBitmap, colWidth, colWidth, false); + if (tmpHolderBitmap != mPlaceHolderBitmap) { + tmpHolderBitmap.recycle(); + tmpHolderBitmap = null; + } + } + + public int getCount() { + if (imagecursor != null) { + return imagecursor.getCount(); + } else { + return 0; + } + } + + public Object getItem(int position) { + return position; + } + + public long getItemId(int position) { + return position; + } + + // create a new ImageView for each item referenced by the Adapter + public View getView(int pos, View convertView, ViewGroup parent) { + + if (convertView == null) { + convertView = new ImageView(MultiImageChooserActivity.this); + } + + ImageView imageView = (ImageView) convertView; + imageView.setImageBitmap(null); + + final int position = pos; + + if (!imagecursor.moveToPosition(position)) { + return imageView; + } + + if (image_column_index == -1) { + return imageView; + } + + final int id = imagecursor.getInt(image_column_index); + if (isChecked(pos)) { + imageView.setBackgroundColor(selectedColor); + } else { + imageView.setBackgroundColor(Color.TRANSPARENT); + } + if (shouldRequestThumb) { + fetcher.fetch(Integer.valueOf(id), imageView, colWidth); + } + + return imageView; + } + } + + private String getImageName(int position) { + actualimagecursor.moveToPosition(position); + String name = null; + + try { + name = actualimagecursor.getString(actual_image_column_index); + } catch (Exception e) { + return null; + } + return name; + } + + private void setChecked(int position, boolean b) { + checkStatus.put(position, b); + } + + public boolean isChecked(int position) { + boolean ret = checkStatus.get(position); + return ret; + } + + public void cancelClicked(View ignored) { + setResult(RESULT_CANCELED); + finish(); + } + + public void selectClicked(View ignored) { + Intent data = new Intent(); + if (fileNames.isEmpty()) { + this.setResult(RESULT_CANCELED); + } else { + + ArrayList al = new ArrayList(); + al.addAll(fileNames); + Bundle res = new Bundle(); + res.putStringArrayList("MULTIPLEFILENAMES", al); + if (imagecursor != null) { + res.putInt("TOTALFILES", imagecursor.getCount()); + } + + data.putExtras(res); + this.setResult(RESULT_OK, data); + } + Log.d(TAG, "Returning " + fileNames.size() + " items"); + finish(); + } + + @Override + public void onItemClick(AdapterView arg0, View view, int position, long id) { + String name = getImageName(position); + + if (name == null) { + return; + } + boolean isChecked = !isChecked(position); + // PhotoMix.Log("DAVID", "Posicion " + position + " isChecked: " + + // isChecked); + if (!unlimitedImages && maxImages == 0 && isChecked) { + // PhotoMix.Log("DAVID", "Aquí no debería entrar..."); + isChecked = false; + } + + if (isChecked) { + // Solo se resta un slot si hemos introducido un + // filename de verdad... + if (fileNames.add(name)) { + maxImages--; + view.setBackgroundColor(selectedColor); + } + } else { + if (fileNames.remove(name)) { + // Solo incrementa los slots libres si hemos + // "liberado" uno... + maxImages++; + view.setBackgroundColor(Color.TRANSPARENT); + } + } + + setChecked(position, isChecked); + updateAcceptButton(); + updateLabel(); + + } + + private void updateAcceptButton() { + ((TextView) getActionBar().getCustomView().findViewById(R.id.actionbar_done_textview)) + .setEnabled(fileNames.size() != 0); + getActionBar().getCustomView().findViewById(R.id.actionbar_done).setEnabled(fileNames.size() != 0); + + } + + @Override + public Loader onCreateLoader(int cursorID, Bundle arg1) { + CursorLoader cl = null; + + ArrayList img = new ArrayList(); + switch (cursorID) { + + case CURSORLOADER_THUMBS: + img.add(MediaStore.Images.Media._ID); + break; + case CURSORLOADER_REAL: + img.add(MediaStore.Images.Thumbnails.DATA); + break; + default: + break; + } + + cl = new CursorLoader(MultiImageChooserActivity.this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + img.toArray(new String[img.size()]), null, null, null); + return cl; + } + + @Override + public void onLoadFinished(Loader loader, Cursor cursor) { + if (cursor == null) { + // NULL cursor. This usually means there's no image database yet.... + return; + } + + switch (loader.getId()) { + case CURSORLOADER_THUMBS: + imagecursor = cursor; + image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID); + ia.notifyDataSetChanged(); + break; + case CURSORLOADER_REAL: + actualimagecursor = cursor; + actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + break; + default: + break; + } + } + + @Override + public void onLoaderReset(Loader loader) { + if (loader.getId() == CURSORLOADER_THUMBS) { + imagecursor = null; + } else if (loader.getId() == CURSORLOADER_REAL) { + actualimagecursor = null; + } + } +} \ No newline at end of file diff --git a/src/Android/com/synconset/ImagePicker/ImagePicker.java b/src/Android/com/synconset/ImagePicker/ImagePicker.java new file mode 100644 index 0000000..46ac0bf --- /dev/null +++ b/src/Android/com/synconset/ImagePicker/ImagePicker.java @@ -0,0 +1,44 @@ +/** + * An Internal Storage Plugin for Cordova/PhoneGap. + */ +package com.synconset; + +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaPlugin; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.io.File; +import java.io.IOException; + +import android.app.Activity; +import android.content.Intent; +import android.util.Log; + +public class ImagePicker extends CordovaPlugin { + + public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { + if (action.equals("getPictures")) { + Intent intent = new Intent(cordova.getActivity(), MultiImageChooserActivity.class); + intent.putExtra("MAX_IMAGES", 20); + + if (this.cordova != null) { + this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0); + } + } + return true; + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + Log.d("PLUGIN", "result code = " + resultCode); + if (resultCode == 1 && data != null) { + ArrayList fileNames = data.getStringArrayListExtra("MULTIPLEFILNAMES"); + for (int i = 0; i < fileNames.size(); i++) { + Log.d("PLUGIN", fileNames.get(i)); + } + } + } +}