From aa855a5255d09663d60463f5cc6c02662411e7bf Mon Sep 17 00:00:00 2001 From: HendrikBoone Date: Sat, 5 Mar 2016 09:23:45 +0100 Subject: [PATCH 001/181] Dutch translations --- app/src/main/res/values-nl/strings.xml | 237 +++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 app/src/main/res/values-nl/strings.xml diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml new file mode 100644 index 000000000..72664ee1b --- /dev/null +++ b/app/src/main/res/values-nl/strings.xml @@ -0,0 +1,237 @@ + + + + + + Lightning + Nieuw Tabblad + Deel + Geschiedenis + Bladwijzers + Bladwijzer toevoegen + Kopieer link + Voorwaarts + Instellingen + Locatie toegang + Bewaar jouw paswoord + Gebruikersagent + Adobe Flash activeren + Startpagina + Volledig scherm modus + JavaScript activeren + Download naar locatie + Geavanceerde instellingen + Apache License 2.0 + Application versie + Wis cache bij beëindigen + Text herschikking activeren + Blokkeer afbeeldingen + Sta sites toe om in een nieuwe pagina te openen + Cookies activeren + Importeer bladwijzers van browser + Tekst grootte + Aanbevolen + Zoekmachine + Zoek + Gebruik wijde viewport + Laad pagina\'s in overzichtsweergave + Herstel tabbladen bij opstart + Ondersteunde browsers + Standaard browser + Geen standaard browser gevonden + standaard browser gevonden + Verberg status balk tijdens surfen + Wis browser cookies + Wis browser historiek + Wat wil je met deze afbeelding doen? + Download + Open + Wat wil je met deze link doen? + Deel deze pagina + Wat wil je met dit item doen? + Wat wil je met deze bladwijzer doen? + Verwijderen + Witte pagina + Standaard + Desktop + Mobile + Aangepast + Zoekmachine + OK + Wil je dit bestand downloaden? + Annuleer + Waarschuwing + Adobe Flash Player werd niet gevonden.\nGelieve Flash Player te installeren. + User Agent + Locatie downloaden + Aangepaste startpagina + Webpagina + Wis historiek + Wisk cookies + Wil je alle browser historiek wissen? + Wil je alle browser cookies wissen? + Ja + Nee + Tekst grootte + Grootst + Groot + Normaal + Smal + Smaller + Fout + Er werd geen browser gevonden om bladwijzers van te importeren. + Titel + URL + Wijzig bladwijzer + Wijzig + Nieuw incognito tabblad + Standaard + Terug + Vind in pagina + Download starten\u2026 + Kan alleen \"http\" of \"https\" URLs downloaden. + ongeldige URL gevonden, kan niet downloaden + Kan niet downloaden naar de bestemming + Geen SD kaart + USB opslag is vereist om bestand te downloaden. + USB opslag niet beschikbaar + Opslag is bezet. Om downloads toe te laten, gelieve USB opslag uit te zetten in het notificatiecentrum. + Cookies activeren in incognito modus + Adobe Flash + Manueel + Auto + Contacteer Mij + twitter.com/RestainoAnthony + Wis cache + Cache gewist + Bladwijzers zijn geïmporteerd + Historiek gewist + Cookies gewist + Maximum aantal tabbladen bereikt + Tekst gekopieerd naar klembord + Link gekopieerd naar klembord + Aangepaste URL + Lokaal bestand werd geblokkeerd + Open Source Licenses + Zoek voor + Blokkeer advertenties + Verbinding met deze site is niet veilig :\n%1$s\nToch doorgaan? + datum van certificaat is ongeldig + certificaat is vervallen + domein in certificaat komt niet overeen met site domein + certificaat is ongeldig + certificaat is nog niet geldig + certificaat wordt niet vertrouwd + Formulier herverzending + Wil je de gegevens opnieuw verzenden? + \nWil jouw locatie gebruiken + Toestaan + Niet toestaan + Inloggen + Gebruiksnaam + Paswoord + Zoeksuggesties + Ondersteund door Google + HTTP Proxy + + None + Orbot + I2P + Manual + + Manuele proxy + Host: + Poort: + Je lijkt Orbit te hebben geïnstalleerd. Wil je Tor gebruiken? + Je lijkt I2P te hebben geïnstalleerd. Wil je I2P gebruiken? + Gelieve Orbot te installeren om proxies te doen met Tor. + I2P draait niet. + I2P tunnels zijn niet klaar. + Ja + Nee + Wis cookies bij beëindigen + Wis geschiedenis bij beëindigen + Standaard + Aangepast + Geen titel + Mozilla Public License v. 2.0 + Freeware + Android Open Source Project + hpHosts Ad Server List + Oud tabblad heropend + Render modus + Omgekeerd + Zwart-wit + Omgkeerd zwart-wit + Contrast vergroten + Normaal + Synchroniseer geschiedenis met Google + Bestand kiezer + NetCipher + GNU Lesser General Public License + Exporteer bladwijzers naar backup + Importeer bladwijzers van backup + Bladwijzers geëxporteerd naar + Bladwijzer instellingen + Kon bladwijzers niet van bestand laden + Kies een bestand + Algemene instellingen + Scherm instellingen + Privacy instellingen + Over + Details over versie, auteur en licensie. + Sluit tabblad + Alle tabbladen sluiten + Alle andere tabbladen sluiten + Blokkeer derde partij cookies + Activeer kleurmodus + Leesmodus + Laden… + Kon niets van deze pagina laden. + Snacktory + jsoup: Java HTML Parser + MIT licensie + URL box inhoud + Tekst codering + + Domein (standaard) + URL + Titel + + Keer kleur om + Donker thema + Tabbladen + App thema + Licht thema + Zwart Thema (AMOLED) + Map naam + Map + Geef nieuwe naam + Geef map naam + Wat wil je met deze map doen? + Wis web opslag + Wis web opslag bij beëindigen + Web opslag gewist + Bron hosts bestand om advertenties te blokkeren + Advertentie blokkeer instellingen + Toon tabbladen in navigatie lade + Vraag \'Niet Volgen\' + Verwijder identificatie hoofden + Voeg aan startscherm toe + Snelkoppeling aan startscherm toegevoegd + Verwijder alle bladwijzers + From cd69b2779f3437ea139899c14c7ed614c228a047 Mon Sep 17 00:00:00 2001 From: HendrikBoone Date: Sat, 5 Mar 2016 09:39:00 +0100 Subject: [PATCH 002/181] New duckduckgo image --- app/src/main/assets/duckduckgo.png | Bin 20503 -> 29999 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/src/main/assets/duckduckgo.png b/app/src/main/assets/duckduckgo.png index a62119e5813079aea7061dce3397299b79711f9c..74091ee3ccb7c82d4d5e28cfaddbbbda2cfe6b6e 100644 GIT binary patch literal 29999 zcmZs?19T=qyDpk!V%v5mwrzZ|ZQIVocJjs6#I|i`VoYq?cm93$!9Dl(TGd_s_VapG zbyas&q@uhe0xT{p2nYy*w3L|gzw5-mk`E2}?+k#wPXPe|N3aqVRg@MLC02BHFt@Tb z0|DWRjaAdL#8*QX=yb6lBcD;RWeauvEr>vYkgU#D(9{vIwZ&l%l;&6`Ju!W{nn@p@ z;bQIlEKm?v^kqKFLLcgF{Y6auh_oTl#Fz?8vA#r1EztB5tauV#dY-|{nqk#ZzioEq zd!KWi>vPp^aSd_OUZDw0LeexkKm_G2no-}f-KNbBB0ePmjmNafb(e9 z*%2M^F_lYTc=Q`CA|CXnOl{H~)cY-wNbpRX@X7e3m04(r(YtNe zWM$Arz(3Z?{D5w6F#wNlR zLH>bbje95^z>rjgsKdCgXIFYMD+`asxkMz3dHxotoc}G>814M4RtvIHDJE87oxc6- z{8edq2Fo|kH8EM9KoDjF?nhh|=AzkcWvH$RnxH=&Czv254l(Ll z@T@+I^i!e}3n-~q6d&Lz8NUI|^!ja8##UUPk8}C6D~46MG)sJoyQwqZ@SF9goUY1B z6&+$r7}+GvJA_{M$B03_?kOFoQp+ArPKUx_zBEBJBj#>9X2KxXQ>jtZl{e0alQQz z|B%JfiG-%ZAesFR-`68}d-2Y&7uN&=#QzmIN@kBeI{~!~!F3<9-muY6kSOH~_jl>} z;;HwI#nb2!0*rRtdeS2HJXPVdgO>#~5*cO{5LYyfC}p0Aps;g`d|{sG2OO3MWV z1P<*#1r#JR8yf@!?1z=ArmH4Ej>p8oj={*(!Ptz!)6Vf98U%#TljmR6&dk+_*wfC| z-i61LpY*>FJpbzdAv2N^{};s7hM!auphzt0;A}?B&cMdNL@EGFOiaw@Y--MK4U@M@aF8MD2_U>lRu4c}} z|FkeL6H~J?)9^9=-^l-MG2eeg^N2dwIXauUxcu`>fSr%=|3mw~@e0mXX8&UJpGXKW z|2O{sr2RLZkMTcY`ai<0v$m^!l;Pl ztq3edf-!CPn$srg^LAyG|Hjn&=WMr&AN^#D>13Sgxs;2=(Ny`)YtMb^BL3pBJ{C0i z2v@7imb%SUw%LdhiTOs-6o*@AX=dNjdS3_$%Ail)d9aW} z_^$}k-|Sa@jj>o$xtB^r(H~oCj3w2sm)%*5S2Zk8Pp%!!{ocGx9gQE&BWKKZ6viZae1Y$M3s>7u38yqR6cLbsL&%26CD6n$O_( zB6As1N4kmO9cjA)=VT)5-`geUL6?{#YN~mRVDX9L{;m58 z;)f&|DnwL(k0BpveCnT;MtVYGUNo9bU_Mzdf4QkAC2eX;$m_NyvL-I3T;L%Yxj#2 zmYKvN`B?H01Opf0A|jF6DT^ZpA?0;3$9o>(rbP44LvljzG{@gDpW8P89c^RV<1yjK zs`*uh{R6)*g6k!1F?Iz6-{ZpN1cyV8A)5j^m*DmM>L*ynjrFJJ@o*qvY#><%FlI+2 ziZSt8CB&Bj!&H5yN~cl#bW&?C%n+Jz!S+dX#~~aUIsaW3iRCZE%KLdoVOh#EC#fdNr<$m@8TI0 zeaPw$mDTuX|3bFl!|EX`GE3Mc%F{lNA5>sTKIE7l0L38}m{|{NCgZ?C6zKJYha z3Z$q(!QU$gkMUmYl*(omHu#*Lv|OH|8OL$*fnFlY*%)S?3;d{(M^VA~fby6QUu2e5 zvEFVN@|_f?9E99!TbZ&Cf_f=yNtdB5&indi1WA!4H+GY#Ozj+h|9ajru5Dy!7tMs* zQDWcNBV6g8q6ooKx;S&t^s$lJFVdvL(=UKcJ%7clgr2#G;^Zof~onqOSeq~?%znRw-L0Dyi z&E5qAAzIX1Gck4%LfD}m4pXN@Mjvrkp=JoZjFmX7OI){b`G@y3tu@go^FOKcq+esk zOe4knb5Lj9=)#$g0{f7@sMgx<6prbc%4dM=Q}?Pp&nPmT%hM#to@O6j5j<-44_h@( z-zW@Dk#$?78B?;b&^8655>0n1FMMGJIoCW203YAidlIJ*Xq+Be-cz1rcR5^wwtnbY z7|5bBcrmO~1>BN3^t8x*ED|(ye5&BW#66g1N}+fsyo3Vx{obsX4P2c}PJ_G6qiz{a z*U*lX5B>HEZ*cKpSS(%njM_jZ$^kt&k)awHvz+K&D|w4E7#D|;XMet;EB1^m3^BRW zCiSQCfIK*ogyB!RGrAl#{vWy>7*1c;QGB&+?7U|d2o2O*TE!DmB+o?TUj_?tULP0j zw5`Kx8@c*}fWMEMw3CUPRce!OJJ-35bldHzh<&K4rq$Pxjq`N+dwNJIETQj+Sji{~rZPzGBY`yao}e4De>kCqB{o96Xkkd~x;_3J+lXT-R` z3@p30iLeWg1ZRJm1qQJm0=kw%E;QN0H>sgh$fz#<+y~klRKe3?w$3%-r$W&g3PS$a z#4W6P`ti*U)^p&MQC21ZY_z7)tnr6^Ia5QM5zp)0cG~ht_1w-t9UqevuSdMvv!)As z@LxVM?eW^){A2TC3OAy_pvrM^dSgTD&!hSvW?h)rA4xgg*@wO{M&s-BY=*dHpng_!l!s6v#5s$3p>kRb;K51Xn61`%)x07r_VPxNU6rc%K0P6~ z|D6S|U(J0_xAW)_Y}ci-PXZ%2E1peiTGHZLhfw^X|2JbtF2MFs8`MT005Db8%MtGx z){t+*E;uA8cH_=7R~74O^S09C3Pq7b?NUIWqQJC%VMfLRyX`if$e|1v`W@>zOLZ<- z@=W0$FhhHOP7}_wMcQ@fZ~uq~?JYayQiFzLQl;2W?@5ORc+XQrl)227ulQ5?QW$ z4Kg?8bmj{p^d4e_X|{I&Na6NE6mv{|<#BgoJH_K-w7#arD3*vJ{cjvWk~0Z=l8;B? zUC)RRP=QK2Xl~If6v%+?>pdG#vin@s^)m(ZaS>YTM)oDHpQO$l=0T zJJEGd8ar(sfV@^;VWaUhU1t9jv|EAbol!n?hPEnGW`iNhzepMPYdQpYZ6!Gjw4z`;J>weHoeP5G}e_4%)SXP>_? z5Ff&fGh$A4{6@I{5>MHnQ`3JQ4ut0qD^Q!i9}ZlXt0P?yNu;w@-X6G1+X4F{}=Zi~BYxH@w@c?E6{F739}6@ZpO?$g5j0&$TjeKbN*fgw z`SzkI?S&(c3pt_ga(uhL(NBzf1gY9wK9q4@RZc%vFzWsqZ(Hg`sJZn&cy|_KN!k~| zN4bN$ExF^ZPj`xzZNs|dHu-2#-*07tPn01pE54C2e&5q_K_?pyp&ds>Flxjcy(k1fT&e2?;WFDngpu?RlSbPBtaJJ@#w|}To z02c!l?F9pvkNb(pP49a%8c6RE@crTTX=CXvNxw zx}j};Y5$q14Y2_%wbbgW_-PG!^!`xJ4%Q^KO{_9a9N0tL93o=xH)Y5+GiGIE7p0P8 z`=k|qi$ngwEGvdqyhyoKx6{APXY`)i56=6f5hE%$2ZW0gLeol;gQLLqfd)wc)5InLOxBsV3_a_rdOpE8g^?rbEaRmVFqg<_ zWZ4JH)1_bag6VJV0W7D0Ng>)7b?JbsIa6WW@FBrKLSv!|J;YbFIHD%@;$F|~pk{4d z^F)JeoaUqVzDDh35sXwTZiY8~)>)!#4u@gCpT^i<;F!ZxMFU!Mo&BzZA0r z$>eU^v9hA>8QF*br~u|~lty9;+pxH3qe8Evpem%xVDu8Cvxa~G^I6eeW`y`{hlLFd z7K#jjmY5-F`pPUb$~sV_=v^?r>~mJm*ZQ%>7D28q<+iNPsW2cmDrmr zoyD1ZKQxgxP*-b!(ZP89gMQi1s^^LZgJZ5x>ksGr-)AQGzXerr_f2&ZMo|;j8_L_G zvp#3+rKP4m6BHV1JHJHkFZUuiD=_N8Do}k9!xEz@+RWm|W3sF!99|1?{I^3#qQ~@s z2Re4k*k7;awGtsdgdk=-4t^ z%~+nf+4ovz_?&E4FovY45?!TWN3%w5 z7AN1w7HR^AFh!(9bpk`?5qf=M^h<^*&9TVD!<+88+?d|Z;hpZ`?*y3mbz9k6v)I|$ zQGd^6$_=QGk<}+;Q4{zi22;!82&3Qb76D$Tq5(Vv%;RPX1&!z?B%8ujxhz{)Fw=Gwq2iuOH=+T4_9I~WwLfz+3E8el&9{n2;vd3s#+ zaF`O$E{}5Fjt-^bqE2pu_5F9L<1yBj-U7vtc$HBhr?mmNNgrC9$wacvvG5549O_-+ z}QF&B2OLY+#?@5*h1%1n3|gag+Mb zd!Fs(FlMtm3=`~bmYSsj2nfU$1ZiVC8dnPrZp0RPK42^AQOpc;oXc2ahi)zKOZ+jg zw$4GY2M;P^c&);mC}){4SQ(jr%wpRVl2$w+imB|1yPlRpHtv7>?XdNJWRG8L8!u!T zw8#w;Fu}O6cq4=RC=(0?z3j5AR>TN0+g(KwmH*c5|B$7Oi67nCS(u*^t8HXTftDzH z$ld|^cZ$^wv~ZUnUX@M_s9%*H=QOAPTcMrKBI24FmV&ss%~0`H(t&EV89lxhu z38_(^HH>iLd9WBQ&DaMke$<#(Nm{L$5z3%pf5B z#TX9E1ciJNdzh;25A}A9X{(GfW#VivV*<0F7dwQ=tr?tC)MSDa0eCU2w=ybDpFUH+ zDtByUpb$>$_~~6Hqpb-bxmQ&-3xjX$&ebz=dOsW%U&d-zQzK59NF{VagNyR=IbnxG zz#x@1Q9ri|Nx#4AXxa!8Ougr%{(c&6-p_<`T{uJVkOZEjbp~TxufR^$<;W|p$!j*~ ziN&F*$L-6kHUub|X-zM&VAlGxfF)Y;pi)l>VM{lPPJE@fw6e@ci47oxN(l^Z>zX7K znFU;u;){`=VB^|3Y*=ho3K&8LTzzLIUiUT3A1PEGTE(^v9~q|GlJ21 zH4H)8`A+?nMzmJVPxqg#@U-#s5LGE-RtK-Ua}^sd`++eI+4>VgchwQP;tPO2`jt$B z7%$h6u0KdL_|=0EcjR^}_q&_0mAVNvP0B5?!D3`ZPysfOTMsC#hD$gtWv!btH>*bILmz0rBGVAtsDIDL@co&I> zaJ5Z_fMi_(FUK?7(D}-%?(s)&5zrI$WH)8{<9YB#F@!es%^|Z8Pu91{sdQ`n@3m-2 zOxB#U?g(8Is{@lcSt)8xmg{)ljg;A*arl7>3Jaa>y-+{?T|tuiq3~F?;IFGeN^QT; z+pJYjanjv!ry$opHe$M~8A(WR9Y(~)&(Gw_T*$5fweZkr?V3HF&qzlX>@dbPAS}Q4 zOScA^O!eW_IzlL!aLj$YP!BqVGI9KgJnx@rPvb)sqoS0d$r{QjpZZ@kaw~W;HVR48 zlq%Y0o2@-7@aEp#fRLDus(|0%qbJ45mXw9o6=y(_r^nu1zY(hqk!pGS=;cwlT{7#C)}DWG2Beu$Is*H`M$} z{{0v_2BoJro{wfEo|0s3n5mv?I-XiSu&#bL5}!GR=q`LIk^G<(MTQN@a|Tv3P%m=| zH*ixv;tvOM*OgHD+a*Xfj5p9j1shV6Km{-4R^h071vTmy9T;*QX%8KvyjqPC+iM~w zwElk^`wc=S62RoyhVyXLirX4v^=1X{6*MF5y!TU%&1~HK z=Iby`{-;LE6Bpm|t|%eB5mae+tW%oxS}>t^GOrbwoyU(u_jxe-`;TU{pV=Yr?plU( zyhD2w?oM0^Hyi78$A+z`4T?=x^)S>4*k54 z6tR^AEUOC~biSL0)z(tbWjV#Dw2jNUJqG$jQy1HA+-75X*1s`5GEG`#hB$yU zkvYKIv`DMDpkLRcUsc8HQ*tWz`xyZZhm|0xeh_aoNl#;M)jdDixUl~I$#m$IBr#6~ zY>^?JT$1y#l_4q8Tg3yy2a0?e-sgupU@ zUIJ_7b==f{+JjO`&IEEYRxYPC)<|@{O#VyiY82mA=4Y(np)DFC14p9mb-JYgd?NHg zJQ5?Tti~0qXobx54GD$0fuG2v>GVVSpq#Yylrs?dlsCgiARf4k-k8LC#P5)28-`TL zMlsA>nhIflT;ttnrP3{}hRB|prfc*h=uKqvxKZUcWxl!=6GxVPhIBEhqJPtRZaqSW zKPl2?Akfuun$uVj06<~H!~Cd!$qd6tMe!Y&xF#yS9nB@Z*nO8bAxbSqh`&l z=Wg0!Dgl()WfE$Zoh zJCn^81EH=8EdQoR>)m4eddeEXqpw+z7&94fA`UJR901%Qx7YW_fB&LBw?3URhsu!T z(sO{)n^puDu`?AGvbZbEytSDAt<(4rl6G-ocC8wrFHLPU?M$kM;L@IcgI%1EY!V=LxoS5pbI#L;pcY0yT5vJ;1bQ|5qmvWA(vGBdy5Z=^< zn5WIZuvg~~NpY$6F07GMnp~d@`eb`&DL%y(q$@XZha?-jPS^7@)*AdBAq41%LK~RU zP~|SB(kO*D4!2?N9jYoS{wt!4Ips%#!|PRV={aH?n2N7IG6q9KBa7smrOg(rc6O{I z_sOm&Q6rJHR)m3!7<0gzRhfd{6ZGV;THPXklBZ!_G>>;y$LWO`oVWoyJQF^5Zz4EK zbo;JT2(t!U1tMniHFWs#x5$Tx$i4V|Nh5cf6BA=_k9zX?;{uPHJNlB;p+Y54IS`hU zO@Gs?^LO~Jz=(4kfj+7T35vxr<+#MTt}2LO#Y z_SDZPx`7Ih6$&u{M*`U+s8JM-a<0%Tp*JY#GS3CAQp@#MTYpe&wymQBE{sriTJ$;Q zG>kM;CM0tLAFCcQw99D>y)3uiq-boBEbxnq*WGc7u%J=u&dkd-ZKbX@D- z;TMskk%EKF>(_)&ob51r-0y0HeI>erS?Kbb8cO3=YjRFpQ%bw&;+&_WB0Y@J~L_ zkRq?fcMpW>d?vgVf6~q1g3HGxr^1~ycE_3RzJC^f8)MHYl!O-vNfv<+jURPY@Kx|B{B&EPXWJg4GD6dr94@@ zgSgs7qEh&ENhxG{3d&7;H3MQm%br7s?rwH#RC0Z%TDYLynWDGk$*Oq6-s7CzPAkA2 z?C3pFgFQo`)hEm|Q5;*J0w0`x>$#MfBF<5~s)Wny!I@6vuoh zLST2)?T}&n#7;TYx$PZSPAIrJG?Q*vSVWZ$lqf_9RBT%Q8se>Yy9CxEJTNfFnx#Vl zqA6tQbh(8V(%aUpW?25yH8V2oYIGo1O)0D|6<# z{#LO#yx!12Zg)2vo+;0&wb`0lL2l3AcUpa1Gjmcr*rOZve-ax>mlxA6i_wE0?Q=}R zdL8>CD&Pz@8>nJ1{m-nP^~I?}`%Ln7tT_yW760NtC^N-|T))U#Oi$*jq(>INDYZAc zIK>qaL{wbm{cBq+Mvuv+4g1^NVqYUiA+MJ|X4B)hUa3Wo=NN;NzwbOmr-S3^SeWUM zkL8JUG*jgTH)No9oP3_xZx_uWV~7m1kD6Xzvn_BoZ8=yiVwe#Q4Aiv13g9`n>+a>e zuNjta7u$(AEvAqBQVg_O#Auaf;bsn<1ZMsJc2vpU7#t27ZtK}eKxo1<{;Gk(OqMrIWY6wBhpR;ZvP;3KRJG-o+MIS=8fj#`iSwP#Z#@R z=N=iI*M0*ZUkY$jg&Le$VU)2zA|dbhh4DP5&a+6e=}V&Cls}m@Ykx4)Q81YAw{^@j zqi6Gm)TN%#;n2)BN6$HtMU0L=W>BLl$g1W_j&Jmye#slcJ^rEQe@9eS-jNgFT~J`2 zKHB?3Uo#mf?oAToDyvIDum;Wl;JQL9UaRRe?+BukolNdbi?c;fxg8Iql@*#jqr4J> zaWhExvWh2C9!N6v==^jA>Og+<>P|IQSV$TzdAS&8xl>&re(@54T3giEzVrQ3X?}lX zem{<+Zy2?|`|$C^9RHQe4he4VsMh}aGVQ>oLK)jM#A&P<;Br}Ibrh2r^QdSQdOz`w zBbm&}&bgqRo}iMxGZP9P*t!Ku6A0D!2S*CbJYi#nCa2==<71rT(u(k1;2>KrkeE8 zF9Cc#%uk~?W&jC<&Za`lKL);2^87R@{Gn;B8wK@!iaBelt-H@z$Go#mR~l{EP~HE@ zgy^V>*_z?+8&;C&-p7!$2|<}jr!ufqj#BKn>czs&}h zIgxHg+nU)@>`)pTo#oN}2}X;%#?`KGFgvZBfdeoZ#RZTnqG$&p z*hCMf-5b@5RL8>zX}oxHnUbLGJYebp8{La%YFSaNhc2XZyLPJKM3Etkpza@Qp)76m zbcvN-gz|a5zOaBPp+k$LR78(Wjq3zG+S9a6JtNPIZ4JHzNXD_-!Ln;542L@BejYmNhmBhF(Q#zb!{k7$wX1~I-WG{uS_EW@*9OSmhhm>+$qk9?MSFu{ixxEa0dU2GWSvAZO9!W1-DLIS{4gg+XDk6B ze$_w|)-U_8Z=hTR3)o!PHKyy{KQy55)b95p3Wh%~TE5?auAIR6^@LWgV=XMRxnilj zf#(S_Ke><|r9uf7I22wicY9MzgPXxN|7FZ5!|2nQ{>mrEG#3NY(NS0^m8jm|+#*{d+5LnoLKBjS)g}&-iG%#Q zjL=1F$>GvKI4_o|wVC^iC~T}i-sq>Er+TFgt`u#~?u?!FW>xOOx;0FRpNvQlowHf$ z*^Q4RKJ|zD120VlenFQ@F)qYFyE-C;Hz7m)ddi32W=c$jg>K345EPkm`5%|@H4M_0 zIxRsRL^Wa!7{7%s8N|FsZ<$Zo!_rgnw#t#sK~E0leg*Z4q;T}ih7Ff;=3`nkCom3C z71ip9gDdcu)^tzd3&Ph`S{Mk#!fF001UB90r%crC;+l;F*`BF_< zwJ?$8u;JvGsd7y|Z$_9byr1J;m+L(yKq|gwiu@pFn~2%2Q%3GSD&5MnXN>$=EJlOW zJ&;yzlyYttsRZecYh?WuWH?0GoK+o_uV9}H^uaN$Rt$;pSa`Td*saH~ro4f3ofyfM zQe?qOglCPCpZbcq7dqPYNm_>t_R~C>kQp*Gmxlg@2(OGwS$a(N4{9PfHUchIJ@k3) zMf$hH8Z%1Q{fu!na$Kn^O`bXTMqDpnrMKB=iipvzLXlrhmgUfDXecT&f9VP@vnp>S$>25fjX+t%cKX$R3rpBy$caox| zO^S%bffw`!w;>LbzesRCMF#ZVd;}fc*2!2T!+M}1KApip9b2J1nDKm{$usw#h@eV) z7xzH!5g!2c%)*!Y&cp%ilq7rIiGMf6+SloP=a^*(2*D0e(YG7ZTZTRPn z=~jAp?9;NwlY4RqlWJsrMJ*CC$9q5NRpNhPe>|BHE%Wd=&ndiYO?K(3YUxS1&cn-F$*~Y!Dpu%dI z1WdL5DE$R31E-^Fn zJ3k*z`%Ho)%)|9VXt$Q0wB%Ca=DK#;Hd?Xs^vKZYCKghBIy-$C1nu=)f09t7!Wi!u zNPQbA@%k$d7sFLzhB7c!JBE&|$kd_UBM=BEPf7VGh4C{{!-bF$=<`Ta{9!HM%9XZ_ zNFVBmkiJgd7QTy6)5m!Id2at>E|8^S2p9TE<*TKuHu=aBamtYti4P-;qiHk5V}2Qi zT3XyM3SCaQ(N*J=6;a*m5C6OKp47`hu_jJ`G)pj2b^ zV(#WKq2Hw21b;`&>j0>JH2b*UDLtE?j{BCny9rGC%NT0BRSg$`V7Qud4p?Q@nSdk= zo5;>c{yxJ9y%g_{f~FS2vKO;ki4yXDDSK;lbEAzNOiX>Z{*$e)ma$B`?p@-qzkOn1 zQM@+@zlt-u(no?)?IY@z;pd}n6&;ZG>!)fO@{yem?rG(^bn>(uj2Abgj?JL5tRc8( z323gX+HAYjM^qDfTRd!LsHp4z&FDzrXS~e1CDxt}LF~KN=qdtK8U@MW2j^q()~a}0 zlSm&f!#e8#Kub)g_Si?QIOi_!sA0pB=;87Y5ll?PVeGve`~mK>4mwG;^NX~(M&7H!8EUw~ zOyZQwtVVo@`STb25{(Y7vJ2amhfeae>`bZ^u>slyee;b~;%Xakl+d6%Bt}Ad%%9~q zNd^UQgJ*;t_{>&Qo06T2=-$0FK2|MG8aZ+arg=xl&CJ2e7Alt33?W!r^Yqb?qZ`D^(8Y5u z@Y$1c#<5d2nDt_H`_4wfWEdj^U$Y6H)N@u)(hZ2Ebq5bCW@y@g@AK8wIEp@D)B+VP zxV8AB6vSQhZH8sA&>tugHkf?kMJlCt3z)1YIkD!e;m=t{M5_)mrS*ycWy2a@$;qJW z<;-C{Ng$)^k*2@-hh`JFB4B!Wj)+a%~WNJ~}DblmOI9}-hLn>o0~-Z0a5f~`x_R9n5C(HYDJ z(+BKOkHk29dvnbdSQBb83}q_kYq>roQ4E-eR%dHqpgQ_RzXtXYyZy|2{43T zK-XyQZM}%>ZRi5k`hLBzS3L&5i#0oOfa^1530j_h2D_0k?ob_yi0LWfi%fxnVb$7T zA6Yi}G(3E489q_LZ$l9*40L0h7j;TnLBpi`9R!i&cwUgJ;enr_1@eSPfBhG;0OQz{ zzu1i5ws4roFA33b^mqyMfecQ(S{c>Nl__McS}T~<6Lp$!LBFs!sar%N1}W%cmu<|M z8&4XBz~`EdXhVm$!fo2;WT?FHF!Yb}$1jOotIZUkaf1C`nEkz?-9CI&v`l{~=l|5d(Hz)b^R`4!P zL@m--w9Axir4Da&E*6K!oH!!*l`U8kjqN2`4+Tn1Tcp$X5|~Eq;(yLCunb2?xVu1k zmWo^7@TjM9+=6OHghGd6W0*EXt z)#e!(Jqc(V<5$h)xGgALyhLvO@J?WdVrVnh^{T(ttza9|3g_oWUL-sspg*=~N%vcUn*>#2B&K zGN9euJM>KAqprC$$oSo6S0r5}0i~^GmZ>oUaFyCji34OVL_z^CWk^ki1L4iv zVd9j9oXg8coV~HaqD;V%L)mz_?di1g!o$_RyVo>C|{!D0QNNW>kz#$+TBQLV6!ts7Rk$#Fn?v~F$+R*>|gFjcu z&~ol412jo+5O&dUEj-4X%h~eE;)@GL3sdfP{A?h*5_y*drBq?rZ#;Pte=CzNdl$_I zmg!hIX3*Pc9HX7X3}Bjx`88RI`DFKxsgXPcwoXDC&gsfM%ISfhHuXuyNY+ttjWV6v z?Q=GC$BMgR_;O`wt0mpP=ph_sIlW7FQ&Afqd%n!iYu~a)(lqlS(wxZ0+>@lBM_3sB zga4*t&T5ri93&i-HY7QjJ^_x4PiR(|{;jkoAYY=@bvU3td$G;in9KC8X=3Y0%dJrU zE%YOwk4vTWDu*fZ6StZari0$3;?`Q?n(Cm1o#!h|35M-3H)rp%k1XV;$b4Us{QemS zl`Jm*uWU$o1gZ1jmkc}P8BBL^BNh|>cS9RoUv~mNo0sr1Ie3aK6H(mg_y{F1pc`^X zR1E_pkE!AUYc*cRdvmVUW7ZyJBb5ChP;8HnLl6Rk-fbZgq^exNk+6f9HHAJ3h?k?Z zcpz3&BKhR}E+(0^z#`4%Wsizko4nS=(C|9C95$s8R+B#|>HP zcg?d+Ur>yzvx2FX!jFER9bh#r^;Gw{f7=>c7f*xD;N#bBM}Kh+yT_8NoVevjWiV1B z03C0)E433TjDyR*^tCUdDXkpLrcRS`$qY1}^ zkvEJol5L)V(%0I1%(1uT=FnhvBD?YQ0DB7|{+_1?hDv;tQ?YcBvKwVh%dr}q@kq%%jxgy<(8kIIU)xk19eO%(eI*PH*sdYg zO8$R4Yb4Sy?hGI%^fo*GRs{mYL&ga0W!}yQ+j^44!d*v?wlCjog<9Qr&}eg$h}J^c z;ffx{c=NCP;-2dE(qwX{nx-Mvc}?y5%QGO}#^CwpbGKNC=#u zArf;7%Nh5CobOg1yy>t1G`h93IXmd}z~py}L2recAVjQ@Ep$ zucwD)=lm_#0>5^qtThSw_meF2Ce!ONjG(E{fV+2|Bjifenu+bUhG{dUOn)Pc<&`(m zoXaTM54x9VQE#jYaQoz7(g+g)5h7o*;BIxpT%v(ZBT21KA<2UtJm2!JQ6IlYr-n>P zPDn_c;w8)D=R~F=i5BQpbJ|s`y7ii8lZ^e z?8`laYP!fh-%GM8?<%mB>kn;Mrk>+<#A!O0Z-vsP%8US3qt|S?OrG*qCHsD*GBzB4 zp2c%H_q}>eUQp6M9W%2r-Rah+$m2kH6$W1?CoboEfF1RF9kwyPznu88)YMoZMmI7TEOK9Vc z3QwEMZ8<;-{s-v|n^scuPZQ+U?L4^SY?W4D{&3Fkq?{5lu_(!teYZ7KuE);U&Hx9X zB2RtjypqfGQ=g&s6gnVVgx&~(G$s36X+N(R#IW7)WQ-5#;vAdVi*M@9!J0C@RMtDZ z2Zb6ybwt6^FW~<2;f76#CFpxO|Ev$77Fs6lM0Y3r!ZQ;Hh0X_b4y*C4pV&n+RuW=y zK<}@|8>YURNUMX_ImK7HEs2hVH)fp610fwOCc5KulX9fxaz`%)+6X&4(G_xqc@`MS z7s3tVxKHh4sX;2lOp@1d^a^ zq%7XEYM7D#+Zi=j(UkHkB)8BvgTq+ME{2^JC0&V=SJo$p6>7@g=dCJrHsqAC-MB$L zr#t+Xj$X`YlGhbYFdzMh3JOI9yC7}Thrd9RYsK8@ZnI4NT15AY@xYkiSB3kO-!5Q zm&si)lV>Jl`cBJEf+GJdvrZ>4djdIONXvC*hj zHjWy1!bFno-i+g%W~tRdUEszy<*$`ZF^EQi!HEpjq$*oV&9o)%b&3sj%nxRs2cQ9}@?AaoSNe{9m|Yw%$gRp4&X8|; z*iokVHkQ|p`{YcoeR%TIxwBC@kuaM{m1!FDlWfx|dNteNu?HET5`3=51{e7au1&OH zzKnoj-x&j%>}cjXb49J?%mBz;)FxIk%}L3;Oz4Jq>+dnTI0+OsjpNyq)gj?LgFIa=@s`7!?pFc?#3bo$J6kozNn|l$JD)>(g zFI|J7esH{v;bapm8Z)0Xu3b7FnHm5(rYS&=W&Zky&y#`7p3SYMXVrVb$R2ZmmRp}z ziwAZOBPAjxlB}elbj98}>r5c*Z_oux9EI{+vVLX^RKE?vbUJgs*H_%gX^>3J%%%~t zia30;9M==!lf4FcQ}~gVFtWSHLX_n7gs$0l^ww6Mp`Uce)>R|^X#)FoU3F&Mi41_F7+1YfV&FEw_;z;k7TN@uzffhNI=&dK870x|K9GUG@I6 zAs6u%0hHOo?3tX1a{+Z69MegXlBO?yQ{w^o({sGfO!+s@^iMj34BdB3mFzHsas(<{ zEi3J7kG1~JOQRNsmW@7c&sKGozG<+rJlxJfj>cR}mIQI4#%!cB4&j)N5Rp0}H4y}| zEOqD9u^Y9DXk3ei;=tK#b6=`Qlx~8{={h~@Y0WOm{6y}{*-KVg6Gbm*=Nq>ptsI1V zUKA$qK2z;)97Wz%Uz?ReBZlTI3jB+)$0Ty}W^sCWWrVVjeouMbP8#!T@#+^d1ntJs(J~!#$Xtk!Bk($FiA5hRY)+f2|*<>shks?HI18X zp7W6cp4mWr#Y}#y9mQmj0M%f6V04eO$|XE2j}Awcg~vA-zIlq3rG0SW*x_!{#jUsU9myqh19W%f1{PsW>XgnSkDCp1wtr1?G!J^w@J@{jyD zZn;X3ngTP9Nc_2`6E(pb{CzJ`Y1yH7o4mP_pmHT!EAp$rImj?96Cc7wPy03x&AqLL zduqeNbVz_^ctFYou&XS$rEdDjp{QolgdTN5WV^Aze`Rb7&nh3R&PzNfljp)_8~xg2AxbkPl(S;Q60lW$~#WQa3sPBE)`K_1|kX9gfpT_Cbi z90IZT=Bz`694SSO(Z98?*1#99MF;fjh$`rc zj)AOooV0hM-{AtjeR2q|(=7|d%P^;jJThENF9Ya0j1Tt?EtIgx`^?@8(>$Cv_xl7D zH`|53>*uG+-QL0vn?$pFc&=p+$wIIvK*I8iAY<-HB1yU8YREL#ggc-nx|uoUeVUxG z48R+)@V#AK=h8NvQE9x`ARR?xa^FfWsI&UKvz{SmD|KF?Ih#iduQgSd-?{hpQb|$N z#>KvjZ6tqp*%`m(PJ~+R?J(@UZ(eRwDbR=m=;6!Nv)LWq?}Qc^Nd+kDCpC?YINXq@ zh+gS_;?<;GhKcOi>~1d!7iWK$FF$pd>1pAMv=DAmjd>^^sw}~Bt z&y?85Q7q1Ld3@E`d--*uDs+@pNKje|DU<%H$3yf97k|vBQm)k|x07dfJFC4w#fSZ3 z9PY-E8069%S>r`F{3pTXb-Tw_KaM#780QN%29S72qegEQr9;3<{9DR;FMQtDJZ#+Tl+8g2Fz`eJ&9^5-S{(&!t9ovAQjt+J%9uXiJ}G4uD zub1%2dkG^y|LM;pP4C~r{-i0M)>{>bF-h07ybqdA{CYjqS}91rP}y5Kr>a+=RIbbs zEW8UAWC4RZbA`r6APR*N15NNz$7%!C3(Fc-J{5VOMMxUnG49+rP8u)OD?WCNL>(w@ z5_Fshyiui=r&x<7$rOpCkRYbhp1Y)kREez#;Rd?ABZ_Bu@cSk7=WsaTxX!nX)Jd1D z&2&VlfZUVY*`r`ak~fLNJNG^0m63WZs36J5S6)^bKWZjIYtfLTQ^}y0QEzSi!bOeg zqs>K54y1P%MB(bf3p=)v$(w0otjf|J_27xP?ygv~mt|w~<41iX6rV7tKn~FIOr=YJ z6op$r8jR$Oo-+CieL*d2kwp6#E!UtiiPR!*tgjCq3vYUYqjrgG!vRFIs8ps-?1p46OnR1$}>GK9?94sf)Dl ze%Y}UuDI+<+z@O0plG5qb#{*32Q6-C;Z{^Zo*r3k6#vP!C-ZH(fSxkC$tk)*Gud=j z(;HzYxR*ZpCJ@p^R>Mj0P8ox@ZZB062~S*F!6fZ~{;>@af$VYSbV{su=`2QN=V2We=k-zr;yrQ&oWjpe-_t>8} zOQ+HQW0*~mW4U)3nbHbGIMLsLlHPtu%GZ2dFSpTMUV`c>=#u{WH=gIJ%aa07hQ#-_ z5<5@6irj=~Eedk>g;%Q`#nIFC9AUY1hfpmR9y9!GuM6QtR`2xjK`tb&Jnp_EUn0l0 zRUgTboWY!C0}ZR2{-$n;(qajWNU6d9DSODg&?rLo7C!)Vo9l0X7hYgu=V@Gu5q-#r z5J4A|;E|A<3!k8k%86%D$a_k)6t6X>nUr58ba>`wsk=pa{VoSEJ7m6@t1ug8Mmbnu zeiwXC%39-?mRHMV3VmXYA2UYXXkNLD+zv~Y*GYjNt(ogSBS}2%5kK!>@4d?>!tk>m zO{BTu2q9j*8P8-Ez2HLnWl6>V5qO zQcf1X5Gc?wD#n;)XVAOyrnCMP3L39$YngF;y|c-n+;mEqzb6+ro zkGx{4O^GH6A5c|1#rA~1oooN$^Z9(2>$ivoa3w}rd1N(>g-Q zENEKT0hsglxTE(sp_REFW30wj#-=0m&TD-i3Y1y|IIADVIS}fzTmI!bid`rVCGW|} zSvB*2eq5XR+Ck(Vimu=pk{RX9h;850onGnlB;qp95y7eqg~g@3BK!8$<5*6sH|G^syqF-$!w*J|s z7SS=MqV(8H^GEa=W<_xUW96RrJ8euhnqb8rk1mSeCm#QC>l~=GIOo-5;PBf%XCPM; zE1k(aUlIzURVAWKc?|o$)>T-n2;%bHKyW`3Qjk^}%=y~hm>&|<`ywaa-&VEF=5M>Z z&(K#c9MuuHti}q7gd^Y=KGJRc7Hf5QRA#9%55?By9%A}zmh)eg!u%y76O^Y>iZ|Rx z>>%o-4b8pvT2&D^!!%#YaFA{vnzcUMzK+9kI%84(i7-vl@?0p;;6UM)9TLX~A}bjP zgNkW8bfR~QF~2I0)9@N7Cgv7>_D(AL*t~GjuvS4JPmV~FJ7;@`4)V`d1>CPp693!c1CmZ=B~)1g(}qQ;S&mnr=#EIOFn7?WKv)(RA0NA3J|g3D`f^e)V5+0bMDa zhob58cI6!fUb#xjR?*?YVAphn+rw_?;gHRkI)uo9muL$>#edA-24v1TJy_)Ycn2s!lQk?Uok%b!^YkUA~D2>4mmcJc0MW%-c25!zIw3 z!mEX=Egr;94DqeazTcV5USR8h>(n=yiJ9m=on@0Zl<_J?X}g#0pXaOO3^PGH__Z44)wVWZ}!NHTID8ipZ@Z{oT8q30iS z$J7qR0a{OnM?D9sZFUYrckNAgg70x5bKI*~vgONm-?rv*!1peS zKpxefiBV^PwDYn0ImJmX^z8y6ch)3mWNc*Ehv}$rnwZRR*XqCS&k>2(L(pU_{E$Y! zfMqXQLc}MPyq9Uj1V4GCdY}u?kp*I+V`@>nE(X%b9!Qt97fbLZ>2)62epBsUB-M}u z5)8|5&o9Y>g%~8wbT-#K`scT+!s;5|t#GR54C>pL%v_wJX0WayN9C~c9#)gUj?6+& zY9-qG*cZxyfm9355~`AMXWq|rbh9WB>3xxSm%qx5qeA_oCcIDx!iRXrB9Z7|-s#Y0 zef(EZf1c2oTyL(hKMHO=TI>q0c)_a6;pY1*sz0xuiOWbKp1TORJy}bg5PDN+NbGfY z+TsfWfrRBrqh#+fb_Ch91{>y9S*L=Y^F6#LPD*utCND9);)%5;Ay83~w6p4Y-rAq?TyV z-cs9&hJ#{ zluL1?XTDIIn-4q@&z_;FB`a3k4o@AQvkeE~5Q>B2+*CRpRG9qOH&t#uvVP&+hhwO$*2EvpPWpmKQkNDcVB z_q+2$^4uW?YSn&->cU+n$ShdV1FxDXv$@l{U04Hl$8>bLcm{6H0p8p=7UhNU;Q?$} zBMxUbT?b~m_H%r)`B=-_PKLK_3mZsM{pP}N0Jb25_@SPK3K2p4kj_H{3Bf*y=Kp_H z-l$+7<@L|ytK8p{o5=pX3`=e>u!qz6d^%P4@t5WDc{t0ft2DVV-<@c>Ssp1al^hkd zGfI5TaL1atawV+DF7LT8j#EdlZYbNGu!wk$G8z3FMn3m5e2X4p*G}?b<%(foYe$po zBCuqp=c;4Npi_HFJ|4$wX~ncZ#P@}$Pv*|L9&)da6|Y{dSQWHc?(DXi4K5EOm{+Ri zT{o0ADu@^O%}wwX%nk98FUWZ0vnwCdtaEG_rlr#E>!4_%7fJ~r{FKJrV+@-e?G|h{ac6RvEzO7^2X!g-l53c@n7)|vuWy(>>$;sxAFdP#ITZJ<31eLOs zM_bPqOENJrF)a&XrGNig`Uv^OlYa_tH?&K34oO+E0F?IixI754?oPb^{LpgF*sg&f zl+T!zzXk6>hZNb7iB@WgiH)35k7G{A`cE?13KBfYhY}smvvbI_&ymlvDhPZ(Z|X)e z%|g>UG87#3Y;flX{Jb9t?%y>C9kmcWX#oFZ0Qa`S!5BHN`#N9m^&Kb6%o5ErT8_)K z)7}#I6r(6X4%u<6SsSt!d=Y>T=mQTNQ+h1(HVx4)& zH=JdOm+R;$)Cn<6J+^SRI?@>rP{vk2HyO`4dm6#$w+4suo0yiIpMszR#*0#Y-EL2( z1AZXAiLNE1r#R`LX2NWScuWu1-PqfkI+9+*V#xe|kF)XvzHa3Zd9JC&aN1O7aa_`{P9tfH2IcrXz?}m-Kqne+gZyru%vC(H;&o<}%R~evkR! z3$e#P_&Jhc;Q#KE?|oUR@gP8aPfLc@T4pSfKxA1eC;)OmNV$1d3QWF$ZhsugOa1>+EP@dajG$szq#C-;Kp8g2Jge)&_S)Ct$|zQ4dc zKVY`4>z^u|>p;<`4LAX_!ygQiJK>&?^vkDzK>0wQ;U4;;6c(D?fC{E2oV$98cn}uM z6PUqS08pp2A0rfq;~m1N?|Beb;C&E=>1r!z6r$r|Jlkv=rUE@$QrFwV*!H}{&>}0>eM!qw5QH{>fVrfv}9h~S>=l%!JlavIx z*B9Ck-~+QY8+Mb$2pLW$zrsXF5ogiiP~zgxfLVcLf0N9NQJ^Yu5XK)qXSA^?0kwxn zjP^H0&*jlrM6;jC_h82y?5r~6<{K5>AMwFlm}yaOIL?2Dygw8ibI`mUW{GpLDXxMO zJZP{Pru(`CO8Mj=A+h)H@{(pi)7YWFe*LX9!y|Yn5EyiOCWm8+kxu2uXFw#86~`A9 zUo83@-|-kG@xRv_bWOMDxk!d`f|K5j8^H^l!iv|nU=_&t)z}cu%nyK}x z)CZ|M4Z|NBj#?yWO`;M2bXmjR3ww+hRa$>bBWJV$(^nStl;S=@4~OfojHeeYMa&x z1XK~1@2W;Q9R+MfH7mI|B^YSqd}?`;RVP{N+{z3kfI@;VNATS)6D2=zfRh-srYNo@ z&8CP0Qlh8E?c36?R-(*!ff=kpYdpXLOY!W%z! z0xJjl6CYZwFCxSMIj-UY{rOD70OiVe=koT7pL&igF|nK;!?r7262{>%E#*Z)-DnGed;D-z;&pX)MD?Y`-=HaVto$jE+G}561!DDkna{&-(&}=`}dICfZ{6v^-${8epRBzU8Am*p{l?~<6C%VXlIOw{1@^Ht5 zyiEPESV=v#7wqAYbmuSuNLaq&SXP+}fRG0iyZl1dd%7^-x5z=!Ub(TwJ7<0&KF(sM zOVciKEd2cjdMrb`x4K}pS*vxsK!-dEfZ&tBYqC^g2;)_RRVj5A#{|NY9HB_Ir_JyV z6wYw49Q?vH+M^RC%}u@3J0t^B=O+c4*fPmBoabz7NG_S`Vb=z+Q(P1+O1aRjlFgwSxHUAp4DWXcRD zAnlvwT*Ma1rSYC;g)&&5C7#ANd>|h5BWR~Ki2s(ajMy12gMWdT*H>{(y7OtX-}!)V z-`eRH3u!Fk`MVnz7iY8yQR;&l)GI;Bn(k@_|3w&Sltl8#9}IvEtlGRn&$ok=*~Az( zIs^xF$7}9;%$vvq)Vu~+pcni$E0Z4s@_FsS3CNG>t2SvKSAZ30>Po{VI-vjzhR$cR zc|3hR-Yq+-^W{RBAwYjUc-lpZUpuM!a;~vV7DLdV;v}3qf!{fty*uBAv|H$n zxssHzf+~-z2S8rTLHs4V3&0NT<-=Sm0``R>2Y44!BJy>5SLDwn&hbQQz&SS=}rwV;^ z`vRw3S;$8n{|=l&{|S^h%eOV&YPHi5FdmMCfGN&*gvuJ@#_Ty#1Zo-zSG2_G%=9%? z&lM^g5%Zt^%)_6!e_jfBf!?&}=<2~~v^%&zD18Zbi zRoBmatJU|j-*grQ&>7^Hb0AG(C@?~p`O6v312|h&xJnqB zWSIEELv^9n6g~Sz@=W{CDphCU3@CCgT5>tDo7TWDG4|5fd3&twPSNQ?$vJ`z>Vng_ z4M{B^@Z}HA3B{u7`c@Pz$wJIxOa6A()&LmcQMbBsbVdh{AefvDQt^Kr zHeta-;dkD~5mCs|2tc>^x@K&z{K31x$m>oy+a4!XFdszW`A@2hEkxrQQH8GZWJ!|t>6vf8Iy{&}^i?eJca2^3Ffhaex1Dqu=13Vam{712P;RhO zw$`TO6s&kP&FSSb)Y4CfSH>=gqad>Gi45P(xMt5r z6-=?%Eh#bklR;WW6F81rGCKCbnV?2fgdA(4o$rIY7B+7YCo$vrs%$@xx>^T0p4_Jh zbsh($&}@~Qbescvs#7=@H>HfxAU;EER4*V;g(nnUKqt z4HL*updhdygFh2d>oTbgJe(&t5q9VE6oKj2Z@4F!Mo%#I^thu$tuDZCTOa7^PooTKJ8ZXMoc z&fT!sB%~~MG(3zs|81$E!uG;DVA{}CQCnBEnmnh`iTNA|PY9zzcsQ7*X23svQK(qpJ}UWn=l8{p0x-O06L$K; zz+K2)9Ujdg)ilRxWsJujQNbadMW^KBxc$}b_{A~xJAT*=Zh1%LW~^3Q`+h0mx{v`X z;yFuZdtUvGRPsPip~9iCo7(2gD#qj{p=m)8l5wL+O4ou?vnMb;c+=_=$_`R zC(ri(&ZRWO$=RD!QaR-{cOuF{N_(0!5LIRqnQjboH55|BelC ztV}{2k)!z$A8;n$=MlholV!jtscULa4c;}m83k?&px&%E3?0cjT+LvO<5se&R z@P*}jL*v0WHyR@^aK%RJU>D5>Iuzjw3%gw#Q!euVhsruR$NgbD$+CHZWKZqAVKu~j ziGl0ds58lc>pdVY4u2BmJDG8PjaDBbYGD|Fp{VZnKN#s^m5hVjcNvr?7Tk95w}(&jpmleyS!-YjGsk<1sFI;}aQ#SYk(nTPtxQPZWD ziS10)prFgIW)q~93Z&4Er`{9X)!6`u`nzJlM

Rq)NsZDV-U64=>n3&S7B$`e37X zKL;t-gpcxoaA}I12>hrrtV- zW|kKGK$;2X3|rEO@TW51js-!ohCWjiamEu8=`q(%@Xp2 zGj)rT81x%ZK4z=1JE0pRbsQIIKkwrEkK-cDv)|*{!N@&*DNjqAO7-wK{W2$B>j`?1 zzi;TaxZN<`QPnYjKqbdt3Z3v0wrw6txMfwGC_$%P#Ht5EAbD7NQ`J6_M8e^+RL2o> z9_%bTh8EuBiCMUZrk7?+M{U7v@ZksN7?%ohWA~NcqccZc{GvYfTu;4_oH7}i`g@VG zJc4iF3|gBMB?d&e2qRAA--`h0KQIBo{S|hlJbKCYjbR~-7pa4i6|uAn7P#*(!wPfb zBl1`yOpUm>xO$5PLEqNY5kA)eIYMW*_3Dadzk=ruw6@0+Vgrj3%%#idttf(Kq`K5=`%DUlh2WbWsH|O0KrFA-8 zT%b*m+=M$0B_xzXXFyMAG}CkPMY(DvON?5Lp}$^TH%>HqU&xW~>BaX(b;4LDv#XzH zfm@i}nM#Q%SIPJ#dr9ytCPf|2Z}$hcI^0KPcQCeV2A^hZBaaez->G`QuQqg~H*_Av z0^G1C-O+Scve{6TNBXHtCr@&zS7Mg*Te1-4;L8hC=dM!z9z_|mltVtiCovyahF5QG z4tu@7AbV|L#s!rGY6Ox9{nEHBuC70Qwv{In79 zxUIOO;=Uoh|BBK1e34vf0wpi}FX}m?sFVaKM-&6Dxyzwb)jnt3V!TkSMt#CMu)`nM z3Zc8o6-_j)p_FHMp~P>Iu;spw%PNhhcfWhxf-S3^gzW~Sq3{<~Yet5#&3zwKd|mxF zprxf01y+)79{cU~Ke~9ES{^)GyDO7kTYH?z7?S;NKBZGulw# zaBaY?>PR)RRu2wBP4=@Oz6Ce8AfBl`u(f6knV_>b#sL~hGwVyU_mr>h0p&l&8=amH zhkENjcF*?@WfA0*gDy~=EsMSGGy+`QXHbi0K~BKUfA;yLcel%AGCDP4-EHd-Armd; zU|c`CQ0{I8)H0Wj;hXxV9 zP5WPA`9F9?b5OjsUtsGPMLf9M3yr{ytD<$2Bb5#WAfPO;AIk@L6 zko>7eb=OTPPqGM#qsRpF(z>$SO+wH8Ao6+vMu>OQG=`l@+^g;k0V~7sJ}6m*GIOE; zcK7PRd;!Y6AjXR&`J9f3#`p9a%z14Ellga=Yd40Mzj-~~+p@h8sQd{Yl>O~!ICq{n3nmEMGljYQ!@3b|^1ki?bnT?jBR&Y(GV@pH z%#J~69%w3t&5bWKrpi&Q24f3Rfp;P$Mh;_pp!b`xnxo(JrKHTE@2NPT`muvL`)*!} z3hsQ-UYE$}8Vu`G{a*|Z%%MLm2?(j*ztIL4EWyGCAab;sn86$%+JHZ(l2!HlQJB*& z_qsCPm(!MdaWWH*kLFmtvX=ku>v-7&yj*vr zznEDZikKNp(Bw%ixVFF{Uj5+s%m+OFyro!?%?#&I+w5zrJAQxv`r?e+;*7&faW*T- zyCQTY?Z)5a8uChO^%E^kpjrS8iw;m+)+0lFiM_D-D%EqrF{2} zC~QcbaGg}S7nmU824`+xR6j_>dod1E1~_rN2{FCVI^*A1;2w!sgK*jORFTA+=m0Ec zpG@~rNu(03P9!G1>mP+jc>cs}TU2*ZrD~*SDxr)=c}1-%N`U@fh3=_5EVS_{{EJyU z1iD}1UIaY5He{^}HkqyS)QycSjMkDRe%Z2u3BcLDK-jzmX+Ed@pgBR?Pg>H8*5a{O zC@Ay|01?Mi+d4D<$mnRr^@Fhg2zb=>ks^3SbUOp_ZeQ<=QE1iqD#TZB9n7be;tt~x zBI&ggTLsYfca{hCLmzC1rZM8+lPM*xEk!yZg(1xjz4PsO&*U_PY7Xr&`yuX4Xl_!ED%Y(^emyeKCK{8QUx;N6Cy2dq)e*d>A;P1?k7D`xdh-*+MY!BEM^P_B8rnK6SX)Ky=m2AIAsM{@sHbQhBHM|6PP5-% z7@+o4aJS7Gu3%d8_;|kXd#e#f$NXzAj%rSR(ZfZ6-llU_Ms>0dxwk7XD(1&+mgalv zohe7qn|>&6xBhAmqO6y7>Z~@V}o6 NrNrb#YlRJi{|`Yah4%me literal 20503 zcmV*UKwH0wP)u&2%@4`5gQ;1Qbe)$Xsn4wQ;n&{nEX>Ti7m}oVw%18ZtRK((tGc{ z_j0|w|C_x%IF18B4ui?v=kxnq*}1*lnfIOd-puSC0RWew3SGWX2@J%py<2l0r|zN>r8n89yt{oMf04 z?QR(5?QHnqjJ@HpABP)$yVlz9m8lkn;|3WU_UvqEs6~H+N~eP%Y2V3^7#hl?rKLp{ zFJ7!^4>d?r2}+VkBqSpvgQTUUHA{)9X(Tc^jYOxUlcL-ly;oiAZ5A4mRlf`%zu&ec zezEo>KW{t{mpK!tK$W9PQN>OKickgPRf}$;WlGua(C^ZHwI zW=dYS?LbDf(;@~$;W1~<98J4wKvBO63k!*fi3!os(IEx~28~KbA8k?>rDs4a4GoNz zS{TefFx=okw39(niHo*`=SqOAvZ2(BCR?Ceko_ zlKST$a%53Y@^U9add}8>q5-9~KovRAbN1r}@G@xkUs4KBpOk!hWNmNu6 ziAhN#F-a*T=+7Ole(uKiOVBW@C&=;xOw1b>mPI3%8MrOJMx!sB+FewenMf;T@nBOSt0lAZb8-F^@8#* z779vU8zU^7ZY;`k)RNQyWXJyIQ;v&znkv@Q1h{nZ3EZ=3N_0XZiAhZ-(b3V&c`GV1 zGLj@DBoL`ossTl#29z2(g7@jn>t*A$q0~|46&Pb|NZ8BgVwjUNoW9o)7cCwntoZg- z0r&Fnd{KO`2so8u+^-bsKcuWAN}ov@EYIhP#RwDc+5vvW*42Wdr9%aIPP$_H+qolU z$I{rb(sL=nb1K8v+z%(+gZMxPO`B^#Y2FZVNxo6Vw$;1y9JGZ@kBtVEJFWpaD!?(p zKvc5UjmJ5?lP^k*7JyV*$MB_9kdSxlIKS$^CVn{@cdFdjMO6u%ioRui#oZrhY zeSb19->rj?fo9ZGj(;5M_3VhG{OcwAB?XzL8XM4n@>KC|9D2E6YR{Y;8#JD=jTjeh z%fXN;cMOpfuN=+iocfuE#w%3t08%tM5%2CPVa4}v@rz%x6BKxM73De*3H=^5V&-`S zYs{k=W38((vd?oyvSo+Mgyp4q6ZFJ|3;GI6Kba+{KC+cZ!!!^H#5KQNoJXPI6|Wh~ z&$ZW*FyC`%9C%tL-=kY0=fd7qxC@OvXh2cnMGCV_NEoU^@be zXl&%a4vJW$Rk{1)Zy2MdA(ov}&rRhqk7L0@4_m(D&7bkRdKysv zi=kF&LAT;}Ctb}N%J%$Yl|%s<%|Ie8dEb*KN{Zksgfje+jq`Xp4m#p2?3uIeRD8b; zDI3ExJWgr;yuO&X{3?(GBhE|^lx~>A!|jsnQ7jc(pPoA_W zCCWN~o^=#sjM2poWsI0+K8W&jdpu z_xhn4FM?ok3l%znzY#V)uHQzc3?ry!&Ulxf8n!m~CTKbR?r_ zN1?~#-Z?o>1IoWp-1}#zXWQvxw?Om29$r7Cz+fjheWy2?HNOn zmTZ{Ml~z{>Wl3%#zi_1kFLSWWkp8uhD0URogV^hfs!se=&3IEGUtGHB6$*<~WgW<1 z5pi#wn6IkN|Ni@L;^E;zX3d&KX3m_+C?zFD14>&JKluLmEXNKNnHX+m+A9h3k&K~4 zQoi#;j(pOP_xKt&+qJs@KbJxDUlJOB#$fC;zF5McYsn}u6@Pxs$+RI7x~*P$+VPCh zLkZ@GSGXs8C1wkTmz#Ncc<rh0&s8=5ADtmmVQbDBe7!4>d;yg)l zo>AVMfsq+D4L~x2NYMcJa!AT|t>>T@k*e%DS!JwUNTz&3W z9=oPjRQm0js`NoD1PwtlMm7PNH=!NmOf`kP1p^^}*$BvAJ{s~C4};vn{iA%nIwGzup>9%_1Sy97CcI^t@yS76@N)|}PDlRJ# z@Ig{q2%@A&;6Atj<$FJag4bOjYeFabn~;u%lrg&D-)NIU2-4}qs*913g+*F*ejgVB zlBhZtTIVI3SMOm!`TchdC~aAsyJu$8##PmjX@iKgZ0E;vNF=4(*K*S+Bu_DzOvY%m zAYpPZ@cU>5ggx|vDxn0L@{kneLiM%7P`Gw7?n@8S2ESmyu&`vg_23JW!kOXYioZ5< z@I2~wF0zgY1UHT>k4;S{yLRnjJj}RbGo;%o$ew`&iZ(3d%15`#fBTY4!AT#ZRJH+8gJD7`OY|;i3`rZ80k@(Y zn)48*L_^7z*CE5PJp)WrfBPR7tv?!uP3y}S=cO~Nk&8FK#-VjuuPn{g#&<3jCPxia zY@5WyMCMXs4Jgl1K|w((U3uZUnP+PnZ%nNrrqRUoL+9f<7mL#4tu&zg)1a`SSMk@Ye@(H*UTkz-VS_@^ zXUpXa93=(oW^t)Orj4mzwlUF$4_)B~L9ci~*g^*gUoe_c=t6r4UgiS+t7pLD4_1KJ zHygm~&wUVZ>oz3DB|%vw2bz@f3;9s^;ao`RkH0sfdB^sTh#unz9T7k10W)k|vUM#t zRaO0CT^D||;5Y+HQj!Lge+rb)m^cD)K@MrQTB5X(N{vJlZ%<2sq$HoYBC+E5PHxIT zB7Iilpou)4D`1`#g-LEE{TvM?y*K_YP4;cIAz}V7Ncw&Q6eh+u$+Ji~RZ#HW3`ifV z52@(EQZS56wQZZAFkXc&@tHMM*6Uqh#g8{&7uA5)vjy@zci|3aQ~Kmusm~SfkGL=mCYFy$n@X4uU8- z3S*K=rQ38h?IAAA0nUSqQ1sO+km1%HsHbF(dyM*zy+y*~NghC;_`A255RCii8W%wk zr;e&$KSi%Pdnd-nlIYl24JgkY6uoxj@sD3k$s4T;spw6Z24aPt1M=UQE*}b(U+zJ^Jj6ki&uP%*XJhzw^aF1E$Qn+CW zmjPR;9KAX+^rtTu(YsMk=3r z8>6EE8TV5Pr&#!XT>M(XkD{l`9W9J0VWI7|b|^O9ds zFge_hT+UO1Bn81qbL=9-o{gC^Df{C)4mO%p9mbH#LQ?SQ5;}tb|HuP>H~-yPkc7EG z%BVI33mwex=q->`R|qj&6r{VF2vTh7mZ3KQJk*msynFAy29(y))vH&@jvYJ5&Ye5S zk9&S42fz4e1cq25rZ-biBK0QQ-eY<;acO}t&CN`ZJgjb+XB9QhjCbd-3nKryhorn1 zGG`5eq`~SrFLjC5ed)eU)y#15-Y=`^d&TXvt?0z$(GBl7|FCBt)0W?V|2;W>{=5bh zb&3A#lj7qGWAbz1Xr;!&Mo6*mAQYx2Fy5r}x6K^o#(GxKk(>DGgQ2>#7}~;v7y1}d zM(8o;+-6{*L&I)nd}&pMNL+%Ql(UgA*`{upf-wZXHzfxZ+tS_LT?0yMfYM!;bP2X0 znHjY5N7RZ!QLvGjTm(sFnK0d>H$Qo3-7?Rj6ih_paX+aKZb4gml28 zK^sY`j>e}m&LQtEhDvB#4=J|_L$INcG^p)>Lc_s~SwpBt7Yh<1_{p|9BF5_}l%bKp zDr54729#C?4jp8h>sl5MRL2NKA7*`6n#H_2M!$WOGcTjp6r8#&HK2SOhE{i9G6 zl~%*a>tXQ2fk$xgLJ%Zn$U?yCTW3KX=c!I54j_{1`LIR9*aa#sUN zD}rLCM@%AYNC{nQq*(b0{Rot?E}s|ngipOo((slyI$f*ezr+KQsv7Cpr2y$UW$+{{ z9U|g$fy)!B6_UWnEO1=B7e+7m1w7aM1rt~Pfv|cimiO zeO<-HgS-Uv>~-oC+b(`M;q*5kRvJ)R2^1Q3(IMePTLsaC(XN9?n3>F2XyMlPx$*s! z$~>d!#NwSjyP%;I{<>Ej%y|1CW4JTlJ_M^iKMP;%x&_fm`D%egC=$bu2Ooh~UGQ46yRt4%fV5+eBhtaqcf*yl5K%g@#`_Z%yaP!!HVs z;`TIK=6~;V^$F?f?4|)lZJIiJF6mFm$W&^;HnMPw(J(44F+VPh`S+`$pFiWp_fgp1 z0?}(jd{@tf+ZpvQ#oCKu&%RTB&{iIjvSLV?UOBp#RSiZ&RySG>qI&S1@xYqP$FDqFpCp{E)h3o>g>V z->vQ6At-#6BVBFnQSE&b;s&Va+|{92^z4P-uV>n(V9PoleXqEk{zJe{V{&1f#-pfD z^Dsv_X+nZ%exeLY*-6RN~;RTYrzZUJ$F+6E}t7Lc)g0^?CCZ=B-CVxFS7orcj@%}M;!iSBwDP}HP17S1*H zvLMAYKZzg43S-{*K}5m}^J8M8;=P;sv6c$kTPW&LZv6TyTuZHPGoWnRdl&jm-UjAw z-@(ZFzrg$3u0lz9Z3vk2!9u3A_8+=JQ7iOBP zfr9&g_~m*y8e0JcRs2Scc*p*S3?$Tu`%c;hU+=lYe7^DLn@ldDj>mxufnedj1%}W0 znbCkLJD{i2W_Ww^#o7tT;sQu?>;~$rhZcd-n?TW?P0V}>9dwDYtPje~#qQr}Kv9#z z-=6ym4Jl%W)+!nsA^*E~8Bq91(ZaZ4+Tz&3b<4Cwv=M#QE`!6-Wsp?Vc%Jgo2gex0 zmG$=D!>o4>!KHiAFmcr%@Xfw^YFilTzVdelmVwj0XMh}p&riZL6ed(8kTPp1#PnBR zJ+ws82uAK_uQI(%(eAH!w9OQ^$6+0ZE_Xj7)_|fOkCL=z>S^jhltC%pzk_K6j{kiD z8iyoyh#EmbV+(r8366vnKu~7mcUW1n{v`DG+|GbPd;7sNetJfQrgW z4Ja*@06~eIY#k71C2L%{Xr))(yDYnj#Hrr|(H3>Lw^VdKB6g@QT)5^17voAmD3&(5 zc=5fhSD0j*dJ_6fL$N>3`aky}{(5bQ8^(H=X4YX0y~5FR0A1BB;RbsP@V$hAPF~0TX=h{>%d4u? z(SXv@&`TuJN}6IF8I6@5Gnf_a>8yy9)VhP;#NnlnLe}BLWLSu8_pLk@xJqx0Gv*$2S7D`bt=yN>%VOq zy^(|)?#IMKMZY5`y%e^qNpw^u)TJMs@K1$%$t7(B2Qj?`CO+i@@M8cfZvYf-18K%Q zG;T`-L0bk!vMkq7_8N_ef&wg96sVG&n4gT6d8e4c&rpYS0@$HDU&5&p2+|ToF@v?m z(bl!wY3HW_MSY;?ASiLlpx}EkC%}uxg2HPJP?+R*s6L#(;Ui1vCC_u&F!li)FM#~d zL7F}Xq$#c-O|rv~X$VN;5Qv!WXv}&bi69^emq{8)YI2RH!odI%CCgJF72k*ILfIZ2 zNS>?(k(Q(;H+h!&lYw9^0f|`3Pl)6rBqFAh(}2<{pb!KlydEfhiL~1H4&zZuj_&5S z1}KbIp$Yw;2b+}8t7nNYA5Z8HkR}cXsR9HH5GX18ETK?DYBOHoSq0H-NQT}=;H3+N zo3znz2}B?uk^Nd;ceKqCC-!AVy?9YULJY+uDnLm=Pz*Gnr~#D3Db~KU;i3lBDxx=$ zR@^!-8y>!NlpkSEq>9_srP$t>(0?XN=u?YZIiat<#{g0TMx;)odBn4*j`zU#l_zu{ zbF~)4VB#NPfq+=4ukIqTlS!Ik!_1>p`#ligdr8zlh3)uT@e|CV5ELy9C~5#D!PENh z2(0wTfwc-p4^nda4+fOVhd1~Ljzn?0xqCAuW! z#=bw9gua*~P#-1bXJz?_id>`)BnSrot`3y_hWbMXs?X~%$+tK}28euqL>#CK-0M0} zv;#fI!df`O+1%rKz@ZFE$;satP%_po;L~tf1t_0uKv5qkQ|T3s5!SV$@8c&95J-j0 zWrWg{6&`{x^SWi!rD)vmgZ1w+3H{TS+&9acpnv@l`D=gC?SJ62|ZHRbxZPJJ{56bC zv&9-v)CbC71VdD(A?WCgO?#0bD~%bm&H3hiUYKd?G&)^7^<=&)90@OkfQ&Nrfs*@S zqo7F9QwV)^A$lZZbajl7o3q z4Jhi6m;t2|8bek%?WGhHW|&`Mu-W4g1z4{qbj_FC_#j^jyT+^6+ofA^Z+fmaPcmji!A}3NKFa7xCEqey&D`7 zrU`lV1s$2k=-*04E%!{lWl~rDVW$O|>sK z&Wh}hckf3eoGJ|{>X4+WoaFEM<|PV-Vnx%QHrl~VAg(B9u1m>Wzls;yvz0(Wqk8!6 zYE0ls9%h@4f9hG^CBwQD=-qmJ|ntIVt>x;+y)33Z&ep0$ldnw z8cAgt0jX32in>&MVqd?Io`f4l0g=m!X?#hQ?|s=)mTRYZXb{pmWz;0PyyMA?v2Zjj z4}8-~)ja8lp?u~tkj4<%bs|yqVWIOU+#5QOvq2jYreM!+i^tVZX8a+&6omOqsHH5l zi5fv5&P@wamuf-Y7upO2{0Hoia!T!d3p2bNE&C1r0|aHDY~RmXS2U+em}SRYE6?ntpEyE?)FgXMHECEHO|w92NKyIz^A^sfRDWuD3@!gm>w2kxpe9p zoWX?tX*b1tmPh{YI~nkk=W9X99yIhP>`Z(LYv57r@)UNGkpU-3Va8srq`ID>p=I}q z@Nxgvfy5bF5Ny`Mx}sjL4-s=CgPHl0gn8q*s`iQJ`3HhRG@!H&C~izcC<^27(B4E` z9sGn1zs~TeTd!A64T`|H`sTK6a3r=Iaw>Rg2PJ3gdI;)H7-J2l%RT6&yeqUAk0J1` zHEPD=#5Di9lX?pzlVl4dGuLWE*Z|q@wzQ7uamUY;{qZa>F-8z(r7J>k>X$Pnb2Ol| z9w_axl9QDyJqTTU_T~>6%av4Bh@u@W1x&2o3ZQtcUJQq$OCc&x{eP&P_2pXTTxxz3 zL&#tgnej!?`ytQMg8a?e%#g7-hy^B<^&;_gJxHDPUvUcI7k-C^WE8%XMOyNF0aO|D zvna@jNDKbj$=u5z@0V|Q_+C}HJOrh?29(wVghrO*et4AeXsVE7oHe zpAImnD0>t^AsSFx7Zm3Z+9*m2>OrI>7mmqpv6>tw2p!N)L=8$+*=H5g!w)rtGj~Ja zYJ4$>)%=e_IY0al0*#t*EOeznZ<(7DSE3+-eY( zF_)DMGLwO(&U%rH9(%^dHyLkIe(xF&k58hq9{Z6Q8cT#4m7R zVq-cinYwN{k2aigxt5B~NnAdB22RG7LIqExR!|BK?S_D7J!U#8XMrH}lEDyY#=geS zf-Tiw5A{Uh>#HZ?#)LD&!bvM<@&bFPESrFB*iHjV>w`kDvfoo>C}<$!N}qd7QePeB z&kgRaEmXIWgkj^~`tl1Vq0cB)@4s=C-?<|55Pe@fQNUBzEn}`h;DiVAgDtg14b=VD zOdD!Ic`l%sAQ**AFRGwGjPH|PnZd2`D(@`i26V4mrlq1Y|6WUG!QrS92+daSrNP{| zD9jnOnXpQo$K2}bO>-UeCefkHBFNOWOSyrn>%9uw&PoHy^8izJ3jJ=M7F| zuprn{SELGd?8pvcSrTMKh`$~oc{??rJP%L?2ALC15DmE$6o6hOe$hm^SAon;A9DP= z)-BT#F-dfPeK>cW-s`Kl(VKTa%OhdwWC-Y?zT<6e1=3Niq1^?7>~zMPB(0vurD2$g za^j4QZ;Z*?{Vf9W70KPPfm8>2Yd~pLQ2OBW;PxcibL1aP(pn!DNy*jI@_*wJMmY54 z2b!wSIOxK}tG^v!E)6c>sP|r9IX`{{{@q?2P_Pq{=Kc0P<4wvR{LKqAA>trQB}lNo zq9)p$=BFpWF!uKE0L7A!5NiWceE!Iwkip%m0_o7FWvv1*kBD?0#HW*w%nkA`pW^x( z5lLY0y5*i#A=qQy`RIM-(%|GG_5N#ch0lEmK*MV8u`(-)&DC>$O%>KD#LjT!f>a^~ zu}B;}WenfHhf+B@64%E-RDAZ(7(r&L29)Ow3Kc&skz{UO|D#`*`i)3G%ldAEd{|17 z{Pq$qQ?5_T4TR2QKbq|hMjvsoLdhLK=Z|Vmt_Y3o~2rn^41Ij-E3axliX_0B@upT)9 zrfe@PS1;O|>4~d?eE96jVnMiFA3lx$>y(Rm8Lk*#oPF#ABL!LM86$3Ryj#9}^n z!^QxXz1|PH?->i7eshF#qdGu@SrlH{@d`RJjUo*--MXDaKHmWyzeQd7(FX3H7^&KbK40Vu8f9Z7skSzJ8#0Nq&vVB)xYB; zN6dxP>I?|wrNFJ5d*P(5He+<52<4Tj-C*6hu`tDFA~;`n0hVtB40_g5{f^#F= zGdJFNmh);*xIe!hL|k(9G*gGXq!@ni5Mu#;R9XfzBsyBL0nxD5H+Vz^Ow89s=7A0|JZ1;cJ3 z0GA!0+a)J3IPU_VzuXHheqagj2fD-ZC+;x&whK(S)&MAns8?};KgV~5h@Qf-Usa5}aWs@O||6+KFQP$odXvlF1} zaWv@t4xoQ<3`{}eck&$pBOi=_;dks|(BF>G=gK(fd44?TpK^wg_?@lM6X63tH(2@5 zrEyT$Jmp7^?ht9LK1k3*h;#RBWju*gC=kUhp2Ds1+zMqe+`>GjLj`(n+kcx~{p&!X zD!Foc4)q{@bQssXu6#NXh+jUFi{6K^Y(aLqINWKlzy~4nv#4LbF$G|cdSmmq%u3?y za@nQ9cQQ7>Pfr1*8wKTnGnkxrf?1&sF!9Ma82@M-jJh`-hTI$veXopXwskz|1ii5Q z*K8QqBv4Mc!lvmx8Bm&YE-Hmy)3+;;X7Bu_id_;UNqTz;m)2puveVuw?3{Erp? zMw|Lqg2Lo0+yD1Jl?}?mlJMF*4(%NoSaLE1ksc%Y4V7;Y6bv)&EqjT%G&mxsf&t}T z=I02CLz6+76XFOS4S-^J3Wa6YKXGN$Bv4Me!e?_#ACW6^14?zSZC6Dbzm;5%ebY} zFMwE7^A~fuzx_f2EIJbjm!kot&EH{?$1#YW<8te9Cz%1%g9Sg2eR(ohTv0A$<8N`w z`Zb)#hG-Byn*a(8P5O0!Gq(cZa-3|2-Zy7QlR>e-gne#k!=Q9QP;?N4R}qj;{hHxX zW3p*$AoSFmM$dEM334)-jzd_OCybus%xee| zn%9MnwT{B_rpooM0p$ghFfYp_+{Gr0!s2JHB6Pq84;tQ!kG*KkwY}A00sL^6p?vQS zG9zjb6ii@mezHM!udgzI=#r!GV~AaoJWB6IKrv;K`Ej6o*bzQ@G9BLYb%3R~zgc%( z8y_A%?g~G-cZYD}rbFU`p_Z?)wm5U^Mvi=tqdFpp7h-S4XF8Z(s_QJo&MJYQme@yC zoohgOK_$q`HVbnZ9^%dRj=p9JVvXgAslF(0|1Z_@i@xX@v9vGW=lK|EiywDU`VK3) zI`-b&DR3mR7$S2-kX(MXX&&X^1n79e5nTL+!#E#X81-Nz48A=IEU%3OqYJjs{?rIe z=EuX^e%}L6QU(6$7vS^XM#9`1PGEn3A`HCl24-hm>VtB40vsOGiMg$*s^hIA3@^Rg zqgNO|kXPaRP<}^0X~C)e9KYTjM9euW)fKHfZ$k=6|2SS+Qon}kTLa3A>{;@2jKe35 z@p;riwc+^mKqKf#B=Kt&a74w0HLDsc{JePK6K#3;J*kh8lHt&VeqQTnd{N$Lom>o zd`#<$f)q5uLRfO^GEcsklK!D;?w>n30YiES=yx9*%gWMT*{7E-oW1M?R}!irrz#fq zM7SU*F7-eedC3`!PmE?J9AER<3aM4O&Aa(TVk`ujc3{?k(F>%`*|vvI=b3@)$3wvU zM>}Tu%KSI`L$HwyhI;2_BJ&35DI~GWr*k>6k@D4?((*@l_`w)zJ!;=bz2JFA&KQ4R zSeS40w0hQn@^4t`A{6K(efZj53Iz2c^^5|0&c_&vd1E^#y!kR0lhvAqS=7^HY}v^5 zx9%!pfT5#H7@}PH<##w4R|Q$+1+YJ67HkT1W* z68w~n>llzJ2=uNq;TZab;xTxcYs1w6`taCH8=fc|dQX`LK|rKY^IU}G-go)(4geE& zLDC1SxR1LMF^W0&di6msR6~H`Ute@s!mT!FN*(9@`3ngepaJDyp`3l+zvE-1Bcul6 zYo@vfrbg-4zpF5N&o&M=dd(g0=!j6}jxRYuBg}-4u^MlzdYwt=Q;K+SG36cjpT8Zf zdpr(azBd|Py6X<#g>8no^28Qj)Wy$C13#;-H6D%eYNoPs7b?#l+V?G@^29K zu1RY6+Jw1&N?qR4S2x`u{_P@n-qC z;6KPjcC2(Tp|cF+N1ce&f3T4#{`G~z;;Ux`ipPf`lbAvt>SiPGLWsP(s6NNX@{R#P zj9xhD8b2%DOk*P&Q0m6jM}J@Oq+ge!hcx%VFy?Vj)uM(;%LLe%3eq-z!owuHw#R1e zlG-zklvs)6L(b}YWc=_gJkTc6Cw)7J!X}O8r~L0dUg@1{d~tc1;ti3dywoIN`t~n) zfg^hh9=4Yqdqd|%Ma%eDbSTgH?Web1g#T95fbtIsbAVp4E9aiXUKhL!(TntKSdY-d zJT#!au%0+_o*O^!$nQKsPL@y!8YbXj!4W7($O0s0A(FC^C`kTZ%u2+5moF+S5tKc+ z#TVw~h?IX1J*24M)IomKqRITnW(HzqW4sVK)d1LrP!J=Nq*Rq3%LX)+7JFhAEbJiVy`k^v}sZ`o}sLUBCW*u91lI`2S%O}Yj*LKPMYd6XIWedsp zakET2z9RhW42?Z#Kxt$Itgw(gHtj|p=n{fGG$XH0grFf3G_Ve+S5ZODGD<}mvG8F2 z^8kDQ2km7L-Pczwy6pjaiU%EJ-=W{7`*`Nx??EC^Z=ek6Ini@N?^i2*LLO)lQvTRm zV-Ffo8UdxakUX*OMzF^v7@pLs2Lp;++Gu3XUdH4Qs>F+WjgXh3P?La*{t618v= z3HP)k;nT*}C~Rt7g-%f^Bh;+0sg8Sm`Wl8KEWGCkh5!|X`VBQ7)#E;fjnOOSXxdc+ zO50V4yR-IPLM-nakXfirsEe3$MBURTr6?&1o>BC>Ww@^x+~*b4x2Ul`OurhaTC-HBuAPMiUR+M)9`>Tym!%&k@%TXVoHluz6Ez&w1NWt)wC{R~dutiV*}qrQ9vVm*`0YxK?G@xjt zkwzL&G}1@|ibfh~K+#Ae4JaCEqya@EjWnQWq>%=c7w$6N>MFvC4kMhH@Ot8+s$wH` z(o#|erlh70O-@Z6R-6#qnTMZON3)8;@5VDT)B2;z z#n(I)_01?2>s>)o-iv$JNRpG2LvnL-Nq&AlDJm)=B_$<#s19XiWrkGvx_xnRu{PaK z%gM_Y78ce>C~O=5(^v8M9`Q3G#NUh%zg~nqF{@R8DIvFe8+4mJ*&~1Q)T!V$eFp3q zYOy%jn2^UkW%BNZ-y7V62=lU;yBtb5RdrRZLY!&>l@+LR0#y}6itj~St~RH%iWGR0sPooshgfr6@6~8tbvD zN`>g>WvBvFF?NDnj#hqEo?%*fib*;r)hw+v)hI1D)gUb?m88a?Vo}McG*qf;rKF@V zHrs4a92^`rySlm__Vo0;J7dO-kU4YaB+i{XH*@~{`MFg1I(^oxS~4GjsEfq?O`H#j#5kEJ%NO-rSs*7A(kHJa2B+vbl2-*36vtWc_5f<3Bo${^0EJz9W75chwH+ z(~0<6btR7#^vG0?6yLtqwm|8FpkQ4EVjZm;JL;?()*r3I569Y`3F#@TV_N6_av>}M z<}4(rAOt32bWajB&H`mlqEQJ>=EMh|t$UjjQ*(1-t|()akvXv#V{Xys4fEIg?J_?( z;G#vi>7_2YT`uUCcfD*-+4Y=3N!KF=sa(;Hd1B$V%k^IbA zufmG)D3%7@(W4aAc$8rX3I)WZR?M~WUF*xMOIIMOWyI5uo*+`!9Shj50vxCB_ z80Ck$hB}QpiMoOcKo!Z$O+`aP?*r4OO_TKP+jskwD_3;r&Uic?;c~eRN+c4seNcKf zpt?7gVD8G|g?iGR>0yu4P=u`?J}Lrr8+DGY!}F+zs5F#BUXLEMSDrBwRyjL9yxglp zpC<_9L+rKhwL?&@|NB4*rs|83^dlt9ijbHAgxt4M0!51u-9_Y+_7@4SJ@&utFQYEh zs2CN3x{JDn@s_FI)SYCe}ae5x0tU-|m)CDyWb%ZsB8es7GECQovX=zFN^y#Bg z-Me=u2M!$gFMx8bkvcR$4M%;2%9htVJ(hVM?&;?(42Sr3{SSkpM|AW*A%{EMsRIZH zbpYj#>WU&t(n0k?E$MKR{Hni}bb213ywXS`D{2HPMA5?x95`^_(++Uw&Yk}SP%bvH z4r#~pXH7VZ-+yVMTio9!2F6|n|1nUsWcH!|0r|ZHhEM2C)-8xBh>Qw_rKQ~xQ0UNeR#p}xI&@9n^XX73 zO2kTB^Gt_YvrySY$f?rFym{H^jv487&r;vm$3j~-7#lFuMAnGS0mTPJfeTR3W8+o> zh3Yahpn}JR$0j;vq&uqo>N)kyf$;f6ke^Eg1$p%(M2S#RIvk#xMPF-Gl$3NXEh{ra znN$}SwU?F_6Jclo3FyiZp>;eDnB4?ZEd~5g9ra;YioNFbC`3-jvbrS=!Bs}LY6LF`mMda{V5k0mvh#G2F>r% zsUx{%)0rfU>`WqUJCpF?D109Qa}SL0JEQ{%vgx9K$Z^ozPdr^tET26yZrhqhu+x7A@X&NZhn}_53--nwoUq61tnT?La zkA6IU+&(VaSjn z+iH$UN5^2|#EGf1X3YXOH#fL^`SQC@17*#cH4*Oa?o22*aM0jy=zgxD>yD+Bi>^Bq zD>@1r;pCvMZcAMpBVF0y)`@gjn+|WwdS&pKI*n;aG~j|uR)$7&QtWAmC*-RNKeEsHu0X>+>%vJ)0>K-!^hR40oesom9jmtXndim+6pZ1I%JsKQc-C)_s z5nd1V(7^O-@86{;UtK~r4(PYp-pw7$yTZ%%qeH#u@U~ptWb*4m$aNEa(|7HLpQc0C zE>osr9eTo~Nww1h9{Aeb(-X!{p9xz>^j{F%M2`}I?+*<%oi%aVbg?Ub*A2@$&YW}Z zi?PFWqkGqa5{-J;pJ*BFB_aCPY9P7wERZw>6zzUwsKF1!x7|$wdiZ;K80P7nXGMpe zFQfiOogkH3GswI0?_IojQ7xcQ`O7`Z*s){pDuUwb>Y6%j+B6!L!KF)=ngU9AJy6hH z#|~h7A%tc3sJ?GtBS=t+$DYg%!~Vq%$p(62 zBL;4!=SPR1U!5>6l)1sUam|g!i9de#Y@aSR^E}+sXkNtD6IBU2tbGu57Uk&K(O~Cr^Y~e^o*eRqW(&2Pk` zMyuF|1?oOihQfs5Ael&3UOcHjP`1lKK_k!A)zvjr1q!+_1{5j#-+=U4F8W?97B>h= z0(ul5YXhVClP0En)b>>2D3gYc3qfI?8v`W>8$Sq*=R|)aCoEe%xpv=Q%J=h}Kp9sv z`h_8rudnaS)&PZ`!-tr2QBT7Do&Ytyv13C}2!cWy0)-Bm(2>T+7P_5YaU1XJR$CWz zlC=}F4;7#!qX&BbEwX|9U1PvyC=+#qqW=jw(4jU5DnMB`vY*bVaHi~40@{C&w2SvH z8mkMGZxleuM^L&bgF=O2*}Is-kYU4yH7E}ck8t^Lvmz*ISg}9a5BS7odYuNgYwWn1 z0!kzr&Q;4!{pU>b$nvP|1$QX!=Q)8gMhTR8>ITIZzjw~EvkiJofr8ik-_wrmX`qB* z-3FLxk$0WOoOP{jp8!P<)etBvKO)-|K*>QFJ_QIm>3Bh5cD`1ZQAdfl&KTlZ6LR$? z1DHw6OEtgoK@*^xDfe*g(A)KUulG82f%1a_C|L+fM`ci`;rHp&=iSBzB($`&2pUAV zyu2Kg8%*e>MP6}t3Y<8##+Xk&?YN!>%5Ou=U-B{4)>+~Y09383hqVwmsHb!Oj^d+Gw^m;xvf2ntarC^s>I ze>|jv<#bO^jzUkkxFw*_hW>S^#iEbKVi;1}z{gbW=Q)8gPYDz|btd!PSe~x_UE?(N zwnF}JwkgNf7$~3H+Z_CDnE4|5+EcdA43v4jeKZWp=L(=yG{KOKQ4y#tR2r*vlt{kb zOLuxLDEjNk(GE9j_W!UMq1<20chD2HJ5CDJ1xkPdD3{a?${noSYqs6TE954?&OJOc zD0Cmo+?<~vcp`;;-au*nL!f-F07@BxVyaG$LP5FTQ(O0CcbE7{(`xGRtCoO5N41u_ zIY-W!?2)4|xI!1!4rvA`E0mIX`==PN7OI_s^iiEqiK;*`*iIfPB=P&30m>&e$8?d1 z)d7kns!9Qr&sqbNOCx$rRp<$YDC?Gj!VX^w*?dR7?`{7OC^r>A@k3CEIzf4i9BC3Yo@}m?RzZ&h3cbPnWtR)B{BeLD@-y+Sks} z{M?LvzO5M2sRNX?^6#^t*fj#mx@QID@(AOJ3i%1J3o}~;3afWe8^&?UUwKxs~nazx>H(pn12_ln;~1D~%13c*GX zlN-K`jm__kfr8)bBU-wY~%1R1~Cz}(T zwCra0q+5MReDGLqn;3MP=i#0~Cr%pxW%i`HgChS^GbsI(&WXuao&pLr&V5Q=?#ZnbRN;5&V8$FZfH>`VM4TngTp<1 zrd~wCLh`r#`W6b{hMDCiv4mJ*(Mcpl$dn z^;VN)pu|4tp{=6?N}bV41<_%CUv?Gt754af2nruTv1%qLhU`r?fW6M9;v0t{wz0hl z327J<`ON#(24>#5tdYmEHgzX#DCe#h3?KE6_MSfg# zZ51?AX{cXNLs0bl#M9IBX`oQ!KBbiSGojeD+R3jQECkEtpbQyiv#)j@r3MtjCfS=B z0JughC^-m9=jMRIp4V6MbDl8S6F#*axXY&td+Q>4x0Eh2`5F@P&KTR{6X-37nqG&c zs7t8nC~bK?%H`zbM0|XFltH1#_NHRuPxBBuWb9G9;yHs|TuHrG70pHHaIoC-D1kyX zgS|Wf8j}m||GPnbW(0O3#2?T1tx?0zj>q$$*BGJBphyF9MDb`jXZMNlvh&y|?>@TS z!z^Ui6(wPtEd5XhithP(nv3#5iBTXIy>>*uVO8nhBtAOR$!Iw!dbHt3W`!5c_XjA_S!+z-zYy+1S$>{&x*c(h&qB=kD7q$h$3>WUcH*knKOrhr4dkQ zqiD0qav*EqQg&3tn+=_G*v7M`y%d6SZup3iZ)m9oMRERNE8AGwR-jOm8(}DyY4o+SExgO5;)eH z1Ugug092@*75V0+IjdHzdHp7q^+tuFV%YjiKt-dTpe~@cpyr}X73)x0^qTIFkPua% zP>p2=42s$FrAy@FP@CzJc(x2(vHL56bQ%-;UAIj2+S5c|1t{{K{|)xqlYF-RBy9c^ zkL`ML+T3|BU;OBuPN{1akYv=M|9!f4^S140w`|!$wH8Gh(P~<5>y|A?R<2!ldEdNA z(~?}RNbE#wlHqJkKG|+f`g>WE;kQ*v8#M~G0d>yy&cI;no4r#kZ}iOUbHgMB6^gos z`X03q)u-=66Vhv$3F+C%gqWC_5X=20q|Y7H4Vn7>ZQ9=CYL}JmWZtBR^&Hf@ Date: Wed, 16 Mar 2016 18:59:05 +0100 Subject: [PATCH 003/181] Update Serbian language --- app/src/main/res/values-sr/strings.xml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 4d624c7b9..6f1ed439a 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -42,7 +42,7 @@ Блокирај слике Дозволи сајтовима да отварају нове прозоре Омогући колачиће - Увези обележиваче из Прегледача + Увези обележиваче из прегледача Величина текста Препоручљиво Мотор претраге @@ -50,6 +50,8 @@ Широки приказ Учитај странице у режиму прегледа Врати изгубљене језичке по покретању + Подржани прегледачи + Уграђени прегледач Нема уграђеног прегледача Откривен подржани уграђени прегледач Сакриј траку стања током прегледања @@ -170,11 +172,12 @@ Фривер Андроид пројекат отвореног кôда hpHosts списак рекламних сервера - Поново отворени претходни језичци + Поново отворени претходни језичак Исцртавање Инверзно Сивило Инверзно сивило + Појачан контраст Нормално Синхронизуј историјат са Гуглом Бирач фајлова @@ -193,6 +196,7 @@ Детаљи о издању, аутору и лиценци. Затвори језичак Затвори све језичке + Затвори друге језичке Блокирај колачиће треће стране Режим боје Режим за читање @@ -225,4 +229,9 @@ Извор hosts фајла за блокирање реклама Поставке Адблока Језичци у фиоци навигације + Захтевај „Не прати ме“ + Уклони идентификујућа заглавља + Додај на почетни екран + Пречица додата на почетни екран + Обриши све обележиваче From 1079a6e95de9c0eb09df8eb73927b680ac7ad689 Mon Sep 17 00:00:00 2001 From: bebolint98 Date: Wed, 23 Mar 2016 20:25:05 +0100 Subject: [PATCH 004/181] Update strings.xml Update Hungarian string --- app/src/main/res/values-hu/strings.xml | 65 ++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index cd31452a8..98b403c84 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -50,6 +50,8 @@ Széles nézőport használata Oldalak betöltése áttekinthető módban Elvesztett lapok visszaállítása induláskor + Támogatott Böngészők + Gyári Böngésző Nincs gyári böngésző észlelve Támogatott gyári böngésző észlelve Állapotsáv elrejtése böngészés közben @@ -60,7 +62,8 @@ Megnyitás Mit szeretnél csinálni ezzel a linkkel? Oldal megosztása - Mit szeretnél csinálni ezzel a könyvjelzővel? + Mit szeretnél csinálni, ezzel az előzménnyel? + Mit szeretnél csinálni, ezzel a könyvjelzővel? Törlés Üres oldal Alapértelmezett @@ -101,6 +104,8 @@ Keresés az oldalon Letöltés elkezdése\u2026 Csak \"http\" vagy \"https\" URL-eket lehet letölteni. + Érvénytelen URL, nem sikerült a letöltés + Nem lehet letölteni a kiválasztott helyre Nincs SD kártya USB tárolóra van szükség a fájl letöltéséhez. USB-tár nem elérhető @@ -124,6 +129,13 @@ Nyílt forráskódú licencek Keresés Reklámok blokkolása + Kapcsolódás ehhez a weboldalhoz, nem biztonságos:\n%1$s\nFolytatja mindenképpen? + az tanúsítvány dátuma érvénytelen + a tanúsítvány lejárt + a domain a tanúsítványban, nem egyezik az domainjével + a tanúsítvány érvénytelen + a tanúsítvány, még nem érvényes + a tanúsítvány nem megbízható Űrlap újraküldése Szeretnél újból elküldi az adatokat? \nSzeretné használni a saját helyét? @@ -134,8 +146,21 @@ Jelszó Keresési javaslatok A Google támogatásával - Úgy tűnik, hogy önnek telepítve van az Orbot.Szeretné használni Tor-t? + HTTP Proxy + + Egyik sem + Orbot + I2P + Manuális + + Manuális proxy + Hoszt: + Port: + Úgy tűnik, hogy önnek telepítve van az Orbot. Szeretné használni a Tor-t? + Úgy tűnik, hogy önnek telepítve van az I2P. Szeretné használni az I2P-t? Kérjük telepítse az Orbot-ot annak érdekében, hogy működjön a proxy a Tor-ral. + I2P, nem fut. + I2P alagútak, nem állnak készen még. Igen Nem Cookie-ek törlése kilépéskor @@ -152,6 +177,7 @@ Negatív Szürkeárnyalatos Negatív szürkeárnyalatos + Kontraszt Növelése Normál Előzmények szinkronizálása Google-val Fájl választó @@ -170,6 +196,7 @@ Részletek az alkalmazás verziószámáról, a készítőről és a licencekről. Lap bezárása Összes lap bezárása + Másik lapok bezárása Harmadik féltől származó Cookie-k letiltása Színes mód engedélyezése Olvasó mód @@ -177,14 +204,34 @@ Nem sikerült semmit betölteni az oldalról. Snacktory jsoup: Java HTML Parser - MIT License + MIT Licenc URL doboz tartalma + Szöveg Kódolás - Domain (alapértelmezett) - URL - Cím + Domain (alapértelmezett) + URL + Cím - Negatív szín - Sötét téma - Lapok + Negatív szín + Sötét téma + Lapok + Alkalmazás Téma + Világos Téma + Fekete Téma (AMOLED) + Mappanév + Mappa + Átnevez + Mappa átnevezése + Mit szeretnél csinálni, ezzel a mappával? + Webtárhely törlése + Webtárhely törlése kilépéskor + Webtárhely törölve + Reklámblokkoló hosztfájl forrása + Reklámblokkoló beállítások + Oldalak mutatása a navigációs fiókban + \'Ne kövessen nyomon\' kérése + Azonosító fejléc eltávolítása + Hozzáadás a kezdőképernyőhöz + Parancsikon hozzáadva a kezdőképernyőhöz + Összes könyvjelző törlése From 62bbc85b3b7734320a3393f5e323333f9fe848d8 Mon Sep 17 00:00:00 2001 From: stellasythe Date: Sat, 27 Aug 2016 15:32:49 -0300 Subject: [PATCH 005/181] Portuguese-Brazilian translation --- .../main/res/values-pt-br/values-pt-br.xml | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 app/src/main/res/values-pt-br/values-pt-br.xml diff --git a/app/src/main/res/values-pt-br/values-pt-br.xml b/app/src/main/res/values-pt-br/values-pt-br.xml new file mode 100644 index 000000000..54f4735c0 --- /dev/null +++ b/app/src/main/res/values-pt-br/values-pt-br.xml @@ -0,0 +1,202 @@ + + + + + Lightning + Nova aba + Compartilhar + Histórico + Favoritos + Adicionar favoritos + Copiar link da página + Avançar + Configurações + Acesso de localização + Salvar senhas + Agente + Ativar Adobe Flash + Página inicial + Modo de tela completa + Ativar JavaScript + Pasta de download + Configurações avançadas + Apache License 2.0 + Versão da aplicação + Limpar cache ao sair + Ativar ajuste de texto + Bloquear imagens + Permitir que sites abram novas janelas + Ativar cookies + Importar favoritos do navegador + Tamanho do texto + Recomendado + Mecanismo de pesquisa + Pesquisa + Utilizar viewport amplo + Carregar páginas no modo panorâmico + Restaurar abas ao iniciar + Navegador não detectado + Navegador detetado + Ocultar barra de estado ao navegar + Limpar cookies + Limpar histórico + O que gostaria de fazer com esta imagem? + Salvar + Abrir + O que gostaria de fazer com este link? + Compartilhar esta página + O que gostaria de fazer com este favorito? + Remover + Página vazia + Padrão + Desktop + Mobile + Personalizado + Mecanismo de pesquisa + OK + Gostaria de transferir este arquivo? + Cancelar + Aviso + O Adobe Flash Player não foi detectado.\nNecessário instalar o Flash Player. + Agente de utilizador + Local das transferências + Página inicial personalizada + Página web + Limpar histórico + Limpar cookies + Gostaria de limpar todo o histórico do navegador? + Gostaria de limpar todos os cookies do navegador? + Sim + Não + Tamanho do texto + Maior + Grande + Normal + Pequeno + Menor + Erro + Não foi detectado qualquer navegador para importar os favoritos. + Título + URL + Editar favorito + Editar + Nova aba anônima + Padrão + Voltar + Localizar na página + A iniciar transferência\u2026 + Apenas possível para as URLs \"http\" ou \"https\". + Cartão SD não encontrado + Necessita-se de um cartão SD para salvar o arquivo transferido. + Cartão SD não disponível + O cartão SD está ocupado. Para poder transferir arquivos, desative a opção Desativar armazenamento USB na notificação. + Permitir cookies no modo anônimo + Adobe Flash + Manual + Automático + Contato + twitter.com/RestainoAnthony + Limpar cache + Cache limpo + Favoritos importados + Histórico removido + Cookies removidos + Atingido número máximo de abas + Texto copiado para a área de transferência + Link copiado para a área de transferência + URL personalizado + Bloqueado o carregamento do arquivo local + Licenças Open Source + Pesquisar por + Bloquear anúncios + Submissão de formulário + Gostaria de reenviar os dados? + \nGostaria de utilizar a sua localização + Sim + Não + Iniciar sessão + Usuário + Senha + Sugestões de pesquisa + Disponibilizado por Google + Proxy HTTP + + Não + Orbot + I2P + Manual + + Proxy manual + Servidor: + Porta: + Parece que você tem o Orbot instalado. Gostaria de utilizar a rede Tor? + Parece que você tem o I2P instalado. Gostaria de utilizar a rede I2P? + Por favor instale o Orbot para poder utilizar a rede Tor. + I2P não está em execução. + Os canais I2P ainda não estão prontos. + Sim + Não + Limpar cookies ao sair + Limpar histórico ao sair + Padrão + Personalizado + Sem título + Mozilla Public License v. 2.0 + Freeware + Projeto Android Open Source + hpHosts Ad Server List + Reabrir última aba + Modo de renderização + Invertido + Escala cinza + Escala cinza invertida + Normal + Sincronizar histórico com Google + Seletor de arquivos + NetCipher + GNU Lesser General Public License + Exportar favoritos para backup + Importar favoritos de um backup + Favoritos salvos em + Configurações de favoritos + Não foi possível importar os favoritos do arquivo + Escolha um arquivo + Configurações gerais + Configurações de exibição + Configurações de privacidade + Sobre + Detalhes da versão, do autor e da licença + Fechar aba + Fechar todas as abas + Bloquear cookies de terceiros + Ativar modo de cor + Modo de leitura + A carregar… + A página não foi carregada. + Snacktory + jsoup: Java HTML Parser + MIT License + Conteúdo da caixa do URL + + Domínio (padrão) + URL + Título + + Inverter cores + Tema escuro + Abas + \ No newline at end of file From 934456f5d1e393ccbf29b98579173d98a0e524f3 Mon Sep 17 00:00:00 2001 From: moon-dark Date: Mon, 19 Sep 2016 17:57:06 +0800 Subject: [PATCH 006/181] Append Chinese translations Append Chinese translations, zh-rCN and zh-rTW --- values-zh-rCN/strings.xml | 249 ++++++++++++++++++++++++++++++++++++++ values-zh-rTW/strings.xml | 249 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 498 insertions(+) create mode 100644 values-zh-rCN/strings.xml create mode 100644 values-zh-rTW/strings.xml diff --git a/values-zh-rCN/strings.xml b/values-zh-rCN/strings.xml new file mode 100644 index 000000000..a8c0bb982 --- /dev/null +++ b/values-zh-rCN/strings.xml @@ -0,0 +1,249 @@ + + + 闪电 + 新建标签 + 分享页面 + 历史记录 + 书签列表 + 添加书签 + 复制链接 + 前进 + 浏览器设置 + 允许站点访问地理位置 + 保存密码 + User Agent + 启用 Adobe Flash + 设置首页 + 启用全屏模式 + 启用 JavaScript + 下载目录 + 高级设置 + Apache License 2.0 + 当前版本 + 退出时清理缓存 + 启用文本重排 + 屏蔽网页图像 + 允许站点打开新窗口 + 启用 Cookies + 从浏览器中导入书签 + 页面文本尺寸 + (推荐) + 搜索引擎 + 搜索 + 使用宽视图 + 使用概览模式载入页面 + 启动时恢复丢失页面 + (尚未检测到已支持原生浏览器) + (已检测到受支持的原生浏览器) + 浏览时隐藏状态栏 + 清除浏览器 Cookies + 清除浏览历史 + 您希望对此图片进行什么操作? + 下载 + 打开 + 您希望对此链接进行什么操作? + 分享此页面 + 请问您要如何处理此书签? + 删除 + 空白页 + 默认 UA + 桌面访问 + 移动设备 + 自定义 UA + 搜索引擎 + 确认 + 您是否需要下载此文件? + 取消 + 警告 + "未检测到您的设备中安装了 Adobe Flash Player,请先安装 Adobe Flash Player 后再启用此选项。" + User Agent + 下载目录 + 自定义主页 + 网页 + 清除历史记录 + 清除 Cookies + 您是否确认清除所有浏览器历史记录? + 您是否确认清除所有浏览器历史记录 Cookies? + 确认 + 取消 + 文本大小 + 最大 + 较大 + 普通 + 较小 + 最小 + 错误 + 暂未检测到任何可导入书签的浏览器 + 标题 + URL + 编辑书签 + 编辑 + 新建隐身标签 + 默认页面 + 返回 + 页内搜索 + 正在开始下载… + 仅可下载以 \"http\" 或 \"https\" 开头的链接地址 + 未发现 SDCard + 为正常下载此文件需要 USB 存储设备。 + USB 存储不可用 + USB 存储设备目前正忙,为确保正常下载此文件请在通知栏中确认关闭 USB 大容量存储。 + 在隐身模式中启用 Cookies + Adobe Flash + 手工 + 自动 + 联系我 + twitter.com/ACRDevelopment + 清除缓存 + 缓存已清除 + 书签导入成功 + 历史已清除 + Cookies 已清除 + 达到最大标签数 + 文本已复制到剪贴板 + 链接已复制到剪贴板 + 自定义 URL + 本地文件已被阻止加载 + 开源许可 + 搜索目标 + 拦截广告 + 重新提交表单 + 你想重新发送数据吗? + \n你想使用你的位置吗? + 允许 + 不允许 + 登录 + 用户名 + 密码 + 搜索建议 + 由 Google 提供支持 + 看起来你已经安装了 Orbot. 你想要使用 Tor 吗? + 请安装 Orbot 以便通过 Tor 全使用代理。 + + + 退出时清除 cookies + 退出时清除历史 + 默认 + 自定义 + 未标题的 + Mozilla Public License v. 2.0 + 免费软件 + Android 开源项目 + hpHosts 广告服务器列表 + 重新打开老标签 + 渲染模式 + 反转 + 灰度 + 反转灰度 + 普通 + 与 Google 同步历史 + 文件选择器 + NetCipher + GNU Lesser General Public License + 导出书签到备份文件 + 从备份文件导入书签 + 书签已导出到 + 书签设置 + 无法从文件导入书签 + 选择一个文件 + 关闭所有标签 + 关闭标签 + 启用色彩模式 + 使用深色主题 + 反转颜色 + jsoup: Java HTML 解析器 + 正在加载… + 无法从页面上加载任何东西。 + MIT 许可 + 阅读模式 + 关于 + 关于版本,作者和许可的详细信息。 + 显示设置 + 常规设置 + + 域 (默认) + URL + 标题 + + 隐私设置 + 标签 + 阻止第三方 Cookies + URL 框内容 + + + 支持的浏览器 + 股票浏览器 + 你想对这条历史记录执行什么操作? + 非法的URL,不能下载 + 不能下载到指定的位置 + + 这个站点连接不安全:\n%1$s\n仍然执行? + 证书日期无效 + 证书过期 + 证书域名不匹配 + 证书无效 + 证书暂时无效 + 不受信任的证书 + + 由DuckDuckGo提供技术支持 + 关闭搜索建议 + HTTP代理 + + + Orbot + I2P + 手动 + + 手动代理 + 主机: + 端口: + 看上去你已经安装I2P。是否希望使用I2P? + I2P没有运行 + I2P隧道没有准备好。 + 增加对比度 + 关闭其他标签 + Snacktory + 文本编码 + + 应用风格 + 明亮主题 + 黑暗主题 (AMOLED) + 文件夹名 + 文件夹 + 重命名 + 重命名文件夹 + 你想对这个个文件夹做什么操作? + 清除Web存储 + 退出时清除Web存储 + 已经清除Web存储 + HOSTS文件禁止广告来源 + 禁止广告设置 + 在导航抽屉显示标签 + 书签和标签抽屉交换位置 + 请求 \'Do Not Track\' + 清除标志头 + 添加到主屏 + 快捷方式添加到主屏 + 删除所有书签 + + FAQ + 常见问题 + + + 调试设置 + LeakCanary + 重启APP以使设置生效 + + + 在新标签打开 + 在后台标签打开 + 在匿名标签打开 + 删除书签 + 编辑书签 + 从历史删除 + 下载图片 + 复制链接 + 重命名文件夹 + 删除文件夹 + 关闭浏览器 + diff --git a/values-zh-rTW/strings.xml b/values-zh-rTW/strings.xml new file mode 100644 index 000000000..7b2c221ac --- /dev/null +++ b/values-zh-rTW/strings.xml @@ -0,0 +1,249 @@ + + + 閃電 + 新建標籤 + 分享頁面 + 歷史記錄 + 書簽列表 + 添加書簽 + 複製鏈接 + 前進 + 瀏覽器設置 + 允許站點訪問地理位置 + 保存密碼 + User Agent + 啟用 Adobe Flash + 設置首頁 + 啟用全屏模式 + 啟用 JavaScript + 下載目錄 + 高級設置 + Apache License 2.0 + 當前版本 + 退出時清理緩存 + 啟用文本重排 + 遮罩網頁圖像 + 允許站點打開新窗口 + 啟用 Cookies + 從瀏覽器中導入書簽 + 頁面文本尺寸 + (推薦) + 搜索引擎 + 搜索 + 使用寬視圖 + 使用概覽模式載入頁面 + 啟動時恢復丟失頁面 + (尚未檢測到已支持原生瀏覽器) + (已檢測到受支持的原生瀏覽器) + 瀏覽時隱藏狀態欄 + 清除瀏覽器 Cookies + 清除瀏覽歷史 + 您希望對此圖片進行什麼操作? + 下載 + 打開 + 您希望對此鏈接進行什麼操作? + 分享此頁面 + 請問您要如何處理此書簽? + 刪除 + 空白頁 + 默認 UA + 桌面訪問 + 移動設備 + 自定義 UA + 搜索引擎 + 確認 + 您是否需要下載此檔? + 取消 + 警告 + "未檢測到您的設備中安裝了 Adobe Flash Player,請先安裝 Adobe Flash Player 後再啟用此選項。" + User Agent + 下載目錄 + 自定義主頁 + 網頁 + 清除歷史記錄 + 清除 Cookies + 您是否確認清除所有瀏覽器歷史記錄? + 您是否確認清除所有瀏覽器歷史記錄 Cookies? + 確認 + 取消 + 文本大小 + 最大 + 較大 + 普通 + 較小 + 最小 + 錯誤 + 暫未檢測到任何可導入書簽的瀏覽器 + 標題 + URL + 編輯書簽 + 編輯 + 新建隱身標籤 + 默認頁面 + 返回 + 頁內搜索 + 正在開始下載… + 僅可下載以 \"http\" 或 \"https\" 開頭的鏈接地址 + 未發現 SDCard + 為正常下載此檔需要 USB 存儲設備。 + USB 存儲不可用 + USB 存儲設備目前正忙,為確保正常下載此檔請在通知欄中確認關閉 USB 大容量存儲。 + 在隱身模式中啟用 Cookies + Adobe Flash + 手工 + 自動 + 聯繫我 + twitter.com/ACRDevelopment + 清除緩存 + 緩存已清除 + 書簽導入成功 + 歷史已清除 + Cookies 已清除 + 達到最大標籤數 + 文本已複製到剪貼板 + 鏈接已複製到剪貼板 + 自定義 URL + 本地檔已被阻止加載 + 開源許可 + 搜索目標 + 攔截廣告 + 重新提交表單 + 你想重新發送數據嗎? + \n你想使用你的位置嗎? + 允許 + 不允許 + 登錄 + 用戶名 + 密碼 + 搜索建議 + 由 Google 提供支持 + 看起來你已經安裝了 Orbot. 你想要使用 Tor 嗎? + 請安裝 Orbot 以便通過 Tor 全使用代理。 + + + 退出時清除 cookies + 退出時清除歷史 + 默認 + 自定義 + 未標題的 + Mozilla Public License v. 2.0 + 免費軟體 + Android 開源專案 + hpHosts 廣告伺服器列表 + 重新打開老標籤 + 渲染模式 + 反轉 + 灰度 + 反轉灰度 + 普通 + 與 Google 同步歷史 + 檔選擇器 + NetCipher + GNU Lesser General Public License + 導出書簽到備份檔 + 從備份檔導入書簽 + 書簽已導出到 + 書簽設置 + 無法從檔導入書簽 + 選擇一個檔 + 關閉所有標籤 + 關閉標籤 + 啟用色彩模式 + 使用深色主題 + 反轉顏色 + jsoup: Java HTML 解析器 + 正在加載… + 無法從頁面上加載任何東西。 + MIT 許可 + 閱讀模式 + 關於 + 關於版本,作者和許可的詳細資訊。 + 顯示設置 + 常規設置 + + 域 (默認) + URL + 標題 + + 隱私設置 + 標籤 + 阻止第三方 Cookies + URL 框內容 + + + 支持的瀏覽器 + 股票瀏覽器 + 你想對這條歷史記錄執行什麼操作? + 非法的URL,不能下載 + 不能下載到指定的位置 + + 這個站點連接不安全:\n%1$s\n仍然執行? + 證書日期無效 + 證書過期 + 證書功能變數名稱不匹配 + 證書無效 + 證書暫時無效 + 不受信任的證書 + + 由DuckDuckGo提供技術支持 + 關閉搜索建議 + HTTP代理 + + + Orbot + I2P + 手動 + + 手動代理 + 主機: + 端口: + 看上去你已經安裝I2P。是否希望使用I2P? + I2P沒有運行 + I2P隧道沒有準備好。 + 增加對比度 + 關閉其他標籤 + Snacktory + 文本編碼 + + 應用風格 + 明亮主題 + 黑暗主題 (AMOLED) + 檔夾名 + 檔夾 + 重命名 + 重命名檔夾 + 你想對這個個檔夾做什麼操作? + 清除Web存儲 + 退出時清除Web存儲 + 已經清除Web存儲 + HOSTS檔禁止廣告來源 + 禁止廣告設置 + 在導航抽屜顯示標籤 + 書簽和標籤抽屜交換位置 + 請求 \'Do Not Track\' + 清除標誌頭 + 添加到主屏 + 快捷方式添加到主屏 + 刪除所有書簽 + + FAQ + 常見問題 + + + 調試設置 + LeakCanary + 重啟APP以使設置生效 + + + 在新標籤打開 + 在後臺標籤打開 + 在匿名標籤打開 + 刪除書簽 + 編輯書簽 + 從歷史刪除 + 下載圖片 + 複製鏈接 + 重命名檔夾 + 刪除檔夾 + 關閉瀏覽器 + From 2f89b5549b27842b58485854d5cb9d315766a0d5 Mon Sep 17 00:00:00 2001 From: Andrei Conache Date: Thu, 27 Oct 2016 11:29:01 +0200 Subject: [PATCH 007/181] strings.xml: update italian translations --- app/src/main/res/values-it/strings.xml | 48 ++++++++++++++------------ 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 68adb044c..72340db59 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -22,15 +22,15 @@ Cronologia Segnalibri Aggiungi segnalibro - Copia Link + Copia link Avanti Impostazioni - Localizzazione + Posizione Salva password User Agent Abilita Adobe Flash - Home - Schermo Intero + Pagina iniziale + Schermo intero Abilita JavaScript Scegli un percorso Avanzate @@ -38,7 +38,7 @@ Versione App Cancella la cache in chiusura Abilità il reflow del testo - Blocca Immagini + Blocca immagini Consenti a siti di aprire nuove finestre Abilita Cookies Importa preferiti da browser @@ -48,7 +48,7 @@ Cerca Utilizza ampia finestra Carica le pagine in modalità panoramica - Restore lost tabs on start + Ripristina schede chiuse all\'avvio Nessun browser stock trovato Browser stock supportato trovato Nascondi la barra di stato mentre navighi @@ -66,7 +66,7 @@ Default Desktop Mobile - Custom + Personalizzato Motore di Ricerca OK Vuoi scaricarlo? @@ -101,10 +101,10 @@ Trova nella pagina Avvio download\u2026 Puoi scaricare solo da URLs \"http\" o \"https\". - Nessuna SD Card trovata. - USB storage is required to download the file. - USB storage unavailable - The storage is busy. To allow downloads, touch Turn Off USB Storage in the notification. + Nessuna memoria SD trovata. + Richiesta unità USB per scaricare il file. + Nessuna unità USB disponibile + Unità USB occupata. Per continuare il download, spegnere l\'unità USB dalla notifica. Abilita i cookies nella modalità incognito Adobe Flash Manuale @@ -120,11 +120,11 @@ Testo copiato negli appunti Link copiato negli appunti URL Personalizzato - Local file has been blocked from loading + Caricamento file locale bloccato Licenze Open Source Cerca Blocca Annunci - Reinvio Modulo + Reinvio modulo Vuoi inviare nuovamente i dati? \nVorrebbe usare la tua posizione Consenti @@ -154,14 +154,14 @@ Cancella i cookies in chiusura Cancella la cronologia in chiusura Default - Custom + Personalizzato Senza titolo Mozilla Public License v. 2.0 Freeware Android Open Source Project hpHosts Ad Server List Scheda precedente riaperta - Rendering Mode + Modalità Rendering Inverso Scala di grigi Scala di grigi invertita @@ -183,7 +183,7 @@ Informazioni sulla versione, l\'autore e licenze. Chiudi scheda Chiudi tutte le schede - Blocca cookies di terze parti. + Blocca cookies di terze parti Attiva modalità colore Modalità lettura Caricamento… @@ -209,14 +209,18 @@ Rinomina Rinomina la cartella Cosa vuoi fare con questa cartella? - Clear Web Storage - Clear web storage on exit - Web Storage Cleared + Cancella memoria siti + Cancella memoria siti in chiusura + Memoria siti cancellata Fonte file host Impostazioni di Ad Block Mostra le schede nel menù - \'Non tenere traccia\' + \"Non tenere traccia\" Rimuovi header di identificazione - Aggiungi a Homescreen - Scorciatoia Aggiunta + Aggiungi a schermata Home + Scorciatoia aggiunta + Cancella tutti i segnalibri + + FAQ + Domande più frequenti From b6a4b10a815d950ea7658f86fba619a653680314 Mon Sep 17 00:00:00 2001 From: Andrei Conache Date: Thu, 27 Oct 2016 14:57:34 +0200 Subject: [PATCH 008/181] BrowserActivity: close drawers on back/forward btns and update italian translations --- .../java/acr/browser/lightning/activity/BrowserActivity.java | 2 ++ app/src/main/res/values-it/strings.xml | 1 + 2 files changed, 3 insertions(+) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index b848b0a0f..e669a87fb 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -1884,6 +1884,7 @@ public void onBackButtonPressed() { if (currentTab != null) { if (currentTab.canGoBack()) { currentTab.goBack(); + closeDrawers(null); } else { mPresenter.deleteTab(mTabsManager.positionOf(currentTab)); } @@ -1896,6 +1897,7 @@ public void onForwardButtonPressed() { if (currentTab != null) { if (currentTab.canGoForward()) { currentTab.goForward(); + closeDrawers(null); } } } diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 72340db59..95a4d6ef6 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -220,6 +220,7 @@ Aggiungi a schermata Home Scorciatoia aggiunta Cancella tutti i segnalibri + Inverti pannello segnalibri con schede FAQ Domande più frequenti From 182757e2e67e753e2c478a55006c6862f5e523ef Mon Sep 17 00:00:00 2001 From: Andrei Conache Date: Thu, 27 Oct 2016 15:17:02 +0200 Subject: [PATCH 009/181] Inform people about flash player support .. and update italian translations again. --- .../lightning/fragment/GeneralSettingsFragment.java | 8 +++++++- app/src/main/res/values-it/strings.xml | 3 +++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java index 7714bab03..5507f02f4 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java @@ -152,7 +152,13 @@ private void initPrefs() { boolean enableJSBool = mPreferenceManager.getJavaScriptEnabled(); cbAds.setEnabled(Constants.FULL_VERSION); - cbFlash.setEnabled(API < Build.VERSION_CODES.KITKAT); + + if (API < Build.VERSION_CODES.KITKAT) { + cbFlash.setEnabled(true); + } else { + cbFlash.setEnabled(false); + cbFlash.setSummary(getResources().getString(R.string.flash_not_supported)); + } cbImages.setChecked(imagesBool); cbJsScript.setChecked(enableJSBool); diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 95a4d6ef6..5948c9169 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -183,6 +183,7 @@ Informazioni sulla versione, l\'autore e licenze. Chiudi scheda Chiudi tutte le schede + Chiudi le altre schede Blocca cookies di terze parti Attiva modalità colore Modalità lettura @@ -221,6 +222,8 @@ Scorciatoia aggiunta Cancella tutti i segnalibri Inverti pannello segnalibri con schede + Chiudi browser + Flash Player non è supportato dal tuo sistema! FAQ Domande più frequenti diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 516ff8a61..c021489e7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -237,6 +237,7 @@ Add to Homescreen Shortcut Added to Homescreen Delete all bookmarks + Flash Player is not supported by your system! FAQ Frequently Asked Questions From 6088e058a46c3bc69611bc68e8f614fe91abb20f Mon Sep 17 00:00:00 2001 From: Andrei Conache Date: Thu, 27 Oct 2016 16:03:42 +0200 Subject: [PATCH 010/181] improve image dialog handling and finish italian translation --- .../dialog/LightningDialogBuilder.java | 18 ++++++------------ app/src/main/res/values-it/strings.xml | 18 ++++++++++++++++-- app/src/main/res/values/strings.xml | 2 ++ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 5d45ad2a4..e868d7d6f 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -246,22 +246,22 @@ public void run() { public void showLongPressImageDialog(@NonNull final Activity activity, @NonNull final String url, @NonNull final String userAgent) { BrowserDialog.show(activity, url.replace(Constants.HTTP, ""), - new BrowserDialog.Item(R.string.dialog_open_new_tab) { + new BrowserDialog.Item(R.string.dialog_download_image) { @Override public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); + Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment"); } }, - new BrowserDialog.Item(R.string.dialog_open_background_tab) { + new BrowserDialog.Item(R.string.dialog_image_new_tab) { @Override public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); } }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { + new BrowserDialog.Item(R.string.dialog_image_background_tab) { @Override public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); } }, new BrowserDialog.Item(R.string.dialog_copy_link) { @@ -269,12 +269,6 @@ public void onClick() { public void onClick() { BrowserApp.copyToClipboard(activity, url); } - }, - new BrowserDialog.Item(R.string.dialog_download_image) { - @Override - public void onClick() { - Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment"); - } }); } diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 5948c9169..318e2dccd 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -22,7 +22,7 @@ Cronologia Segnalibri Aggiungi segnalibro - Copia link + Copia indirizzo link Avanti Impostazioni Posizione @@ -222,9 +222,23 @@ Scorciatoia aggiunta Cancella tutti i segnalibri Inverti pannello segnalibri con schede - Chiudi browser Flash Player non è supportato dal tuo sistema! FAQ Domande più frequenti + + + Apri in un\'altra scheda + Apri in una scheda in background + Apri in scheda in incognito + Rimuovi segnalibro + Modifica segnalibro + Rimuovi dalla cronologia + Apri immagine in nuova scheda + Apri immagine in background + Scarica immagine + Copia indirizzo link + Rinomina cartella + Rimuovi cartella + Chiudi browser diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c021489e7..0dd4e3c1f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -254,6 +254,8 @@ Remove bookmark Edit bookmark Remove from history + Open image in new tab + Open image in background tab Download image Copy link Rename folder From 28d169d3a27368144243deac3e786b095a00e92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Freddy=20Mor=C3=A1n=20Jr?= Date: Wed, 2 Nov 2016 07:56:27 -0600 Subject: [PATCH 011/181] Update strings.xml Added some missing translation strings --- app/src/main/res/values-es/strings.xml | 61 ++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 876d8ed6e..bf6011856 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -84,10 +84,10 @@ Buscar en la página Iniciando descarga\u2026 Sólo se puede descargar de URLs \"http\" o \"https\". - No hay tarjeta SD - Se requiere de almacenamiento USB para descargar el archivo. + No hay tarjeta SD + Se requiere de almacenamiento USB para descargar el archivo. Almacenamiento USB no disponible - El almacenamiento está ocupado. Para permitir las descargar, desactiva el almacenamiento USB desde el área de notificación. + El almacenamiento está ocupado. Para permitir las descargar, desactiva el almacenamiento USB desde el área de notificación. Habilitar cookies en el modo incógnito Adobe Flash Manual @@ -117,6 +117,18 @@ Contraseña Sugerencias de búsqueda Proporcionadas por Google + Proporcionadas por DuckDuckGo + Sin sugerencias de búsqueda + Proxy HTTP + + Ninguno + Orbot + I2P + Manual + + Proxy manual + Host: + Puerto: Parece que tienes Orbot instalado. ¿Quieres usar Tor? Por favor, instala Orbot para usar Tor. @@ -135,6 +147,7 @@ Invertido Escala de grises Escala de grises invertida + Aumentar contraste Normal Sincronizar historial con Google Selector de archivo @@ -162,6 +175,7 @@ jsoup: Java HTML Parser MIT License Contenido de la caja de la URL + Codificación de texto Dominio (por defecto) URL @@ -170,4 +184,45 @@ Invertir color Usar tema oscuro Pestañas + Tema de la app + Tema claro + Tema oscuro (AMOLED) + Nombre de la carpeta + Carpeta + Renombrar + Renombrar carpeta + ¿Qué te gustaría hacer con esta carpeta? + Borrar almacenamiento web + Borrar almacenamiento web al salir + Almacenamiento web borrado + Fuente de bloqueo de anuncios del archivo hosts + Ajustes de bloqueo de anuncios + Mostrar pestañas en el cajón de navegación + Cambiar marcador y tabuladores + Solicitar \'Do Not Track\' + Remover encabezados de identificación + Añadir a pantalla de inicio + Acceso directo añadido a la pantalla de inicio + Borrar todos los marcadores + + FAQ + Preguntas frecuentes + + + Ajustes de depuración + LeakCanary + Reinicia la aplicación para que el cambio tenga efecto. + + + Abrir en nueva pestaña + Abrir en pestaña de fondo + Abrir en pestaña incógnito + Remover marcador + Editar marcador + Remover del historial + Descargar imagen + Copiar enlace + Renombrar carpeta + Remover carpeta + Cerrar navegador From 6070885be53ecd745db6a6594409d28363358037 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Sun, 6 Nov 2016 11:30:06 -0500 Subject: [PATCH 012/181] Update Bonsai library to latest --- Bonsai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bonsai b/Bonsai index 53608c03b..68eb7eb37 160000 --- a/Bonsai +++ b/Bonsai @@ -1 +1 @@ -Subproject commit 53608c03b77d598aaebd17eb0acbedd8ffb1bf51 +Subproject commit 68eb7eb377803f7971baedb28144aa3b1c420cd0 From 92676ca5fe07d897d9c416322cfd667a55a0c207 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Sun, 6 Nov 2016 11:37:47 -0500 Subject: [PATCH 013/181] Update AnimatedProgressBar library --- AnimatedProgressBar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AnimatedProgressBar b/AnimatedProgressBar index 2d7f756be..e7d6ec28b 160000 --- a/AnimatedProgressBar +++ b/AnimatedProgressBar @@ -1 +1 @@ -Subproject commit 2d7f756be8f562b2cedca46de7d2ff24f9383040 +Subproject commit e7d6ec28baac7cc6909466fc0c8fc8c5e3de6f9d From d2ef1aaec4fb3370626695cd5183b4f12abbae0c Mon Sep 17 00:00:00 2001 From: Death Mask Salesman Date: Wed, 9 Nov 2016 12:52:55 +0100 Subject: [PATCH 014/181] Italian translation update #2 --- app/src/main/res/values-it/strings.xml | 193 +++++++++++++++---------- 1 file changed, 116 insertions(+), 77 deletions(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 68adb044c..c64317001 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,4 +1,5 @@ - + Impostazioni di debug + LeakCanary + Prego, riavvia la app per applicare le modifiche. + + + Apri in nuova scheda + Apri in secondo piano + Apri in scheda in incognito + Elimina segnalibro + Modifica segnalibro + Elimina dalla cronologia + Scarica immagine + Copia link + Rinomina cartella + Elimina cartella + Chiudi browser From 3774ce70b229e959d6bad80907035ec68dc2448c Mon Sep 17 00:00:00 2001 From: Penturon Date: Thu, 10 Nov 2016 15:16:37 +0100 Subject: [PATCH 015/181] Add files via upload --- app/src/main/res/values-de/strings.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 57ce8fb11..f484a81e4 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -169,6 +169,7 @@ Über Details über Version, Autor und Lizenz Tab schließen + Andere Tabs schließen Alle Tabs schließen Drittanbieter Cookies blockieren Farbmodus aktivieren @@ -202,6 +203,8 @@ Tabs App-Design Ordner umbenennen + Auf Startbildschirm legen + Verknüpfung auf dem Startbildschirm abgelegt HTTP-Proxy I2P läuft nicht. I2P Tunnel sind noch nicht bereit. @@ -216,4 +219,20 @@ Es sieht aus, als ob I2P installiert wäre. Möchten Sie es verwenden? Textcodierung Tabs in Drawer anzeigen + Alle Lesezeichen löschen + Lesezeichen und Tab Drawer umschalten + \'Nicht Verfolgen\' anfordern + \'Identifying Headers\' entfernen + + In neuem Tab öffnen + In Hintergrund Tab öffnen + In Inkognito Tab öffnen + Lesezeichen entfernen + Lesezeichen bearbeiten + Aus dem Verlauf löschen + Bilder herunterladen + Link kopieren + Ordner umbenennen + Ordner löschen + Browser schließen From 15cb950af368a474e880671e12656bbebb131dcf Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Sun, 13 Nov 2016 14:12:14 -0500 Subject: [PATCH 016/181] Fixed a memory leak --- .../acr/browser/lightning/search/SuggestionsManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java index 3ea94d7ed..48bde012d 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java @@ -1,5 +1,6 @@ package acr.browser.lightning.search; +import android.app.Application; import android.content.Context; import android.support.annotation.NonNull; @@ -26,13 +27,14 @@ static boolean isRequestInProgress() { } static Observable> getObservable(@NonNull final String query, @NonNull final Context context, @NonNull final Source source) { + final Application application = BrowserApp.get(context); return Observable.create(new Action>() { @Override public void onSubscribe(@NonNull final Subscriber> subscriber) { sIsTaskExecuting = true; switch (source) { case GOOGLE: - new GoogleSuggestionsTask(query, BrowserApp.get(context), new SuggestionsResult() { + new GoogleSuggestionsTask(query, application, new SuggestionsResult() { @Override public void resultReceived(@NonNull List searchResults) { subscriber.onNext(searchResults); @@ -41,7 +43,7 @@ public void resultReceived(@NonNull List searchResults) { }).run(); break; case DUCK: - new DuckSuggestionsTask(query, BrowserApp.get(context), new SuggestionsResult() { + new DuckSuggestionsTask(query, application, new SuggestionsResult() { @Override public void resultReceived(@NonNull List searchResults) { subscriber.onNext(searchResults); From 59df30dd0ce0293b58c0fb1e797694cd902fa462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Marques?= Date: Mon, 14 Nov 2016 23:21:48 +0000 Subject: [PATCH 017/181] Portuguese update --- app/src/main/res/values-pt/strings.xml | 88 +++++++++++++++++++++----- 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 5acdcff42..05fb451b7 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -32,35 +32,38 @@ Página inicial Modo de ecrã completo Ativar JavaScript - Local de transferências + Local para descargas Definições avançadas Apache License 2.0 Versão da aplicação Limpar cache ao sair Ativar ajuste de texto Bloquear imagens - Permitir que os sítios web abram novas janelas + Permitir que os sites abram novas janelas Ativar cookies Importar marcadores do navegador Tamanho do texto Recomendado - Mecanismo de pesquisa + Motor de pesquisa Pesquisa Utilizar viewport amplo Carregar páginas no modo panorâmico Restaurar separadores ao iniciar + Navegadores suportados + Navegador do sistema Navegador não detetado Navegador detetado Ocultar barra de estado ao navegar Limpar cookies Limpar histórico O que gostaria de fazer com esta imagem? - Transferir + Descarregar Abrir O que gostaria de fazer com esta ligação? Partilhar esta página + O que gostaria de fazer com este item do histórico? O que gostaria de fazer com este marcador? - Eliminar + Apagar Página vazia Padrão Desktop @@ -68,12 +71,12 @@ Personalizado Mecanismo de pesquisa OK - Gostaria de transferir este ficheiro? + Deseja descarregar este ficheiro? Cancelar Aviso O Adobe Flash Player não foi detetado.\nTem que instalar o Flash Player. Agente de utilizador - Local das transferências + Local para as descargas Página inicial personalizada Página web Limpar histórico @@ -98,12 +101,14 @@ Padrão Recuar Localizar na página - A iniciar transferência\u2026 + A iniciar descarga\u2026 Apenas possível para os URL \"http\" ou \"https\". + URL inválido e a descarga não é possível + Não é possível descarregar da localização especificada Cartão SD não encontrado - Necessita de um cartão SD para guardar o ficheiro transferido. + Necessita de um cartão SD para guardar o ficheiro descarregado. Cartão SD não disponível - O cartão SD está ocupado. Para poder transferir ficheiros, desative a opção Desativar armazenamento USB na notificação. + O cartão SD está ocupado. Para poder descarregar ficheiros, desative a opção Desativar armazenamento USB na notificação. Permitir cookies no modo incógnito Adobe Flash Manual @@ -115,7 +120,7 @@ Marcadores importados Histórico removido Cookies removidos - Atingido número máximo de separadores + Atingido o número máximo de separadores Texto copiado para a área de transferência Ligação copiada para a área de transferência URL personalizado @@ -123,6 +128,13 @@ Licenças Open Source Pesquisar por Bloquear anúncios + A ligação a este site não é segura:\n%1$s\nContinuar? + data de certificado inválida + certificado expirado + domínio do certificado não coincide com o domínio do site + certificado inválido + certificado ainda não válido + certificado não confiável Submissão de formulário Gostaria de reenviar os dados? \nGostaria de utilizar a sua localização @@ -132,7 +144,9 @@ Utilizador Palavra-passe Sugestões de pesquisa - Disponibilizado por Google + Disponibilizadas por Google + Disponibilizadas por DuckDuckGo + Sem sugestões de pesquisa Proxy HTTP Não @@ -153,7 +167,7 @@ Limpar cookies ao sair Limpar histórico ao sair Padrão - Personalizado + Personalizada Sem título Mozilla Public License v. 2.0 Freeware @@ -164,6 +178,7 @@ Invertido Escala de cinzento Escala de cinzento invertida + Aumentar contraste Normal Sincronizar histórico com Google Seletor de ficheiros @@ -178,10 +193,11 @@ Definições gerais Definições de exibição Definições de privacidade - Sobre + Acerca Detalhes da versão, do autor e da licença Fechar separador Fechar todos os separadores + Fechar os outros separadores Bloquear cookies de terceiros Ativar modo de cor Modo de leitura @@ -189,8 +205,9 @@ A página não foi carregada. Snacktory jsoup: Java HTML Parser - MIT License + Licença MIT Conteúdo da caixa do URL + Codificação do texto Domínio (padrão) URL @@ -199,4 +216,45 @@ Inverter cores Tema escuro Separadores + Tema da aplicação + Tema claro + Tema preto (AMOLED) + Nome da pasta + Pasta + Renomear + Renomear pasta + O que gostaria de fazer com esta pasta? + Limpar armazenamento web + Limpar armazenamento web ao sair + Armazenamento web removido + Fonte do ficheiro hosts para Ad Blocking + Definições AdBlock + Mostrar separadores no menu de navegação + Trocar menus de marcadores e separadores + Pedidos \'Do Not Track\' + Remover cabeçalhos de identificação + Adicionar ao ecrã + Atalho adicionado ao ecrã + Apagar todos os marcadores + + FAQ + Perguntas frequentes + + + Definições de depuração + LeakCanary + Reinicie a aplicação para aplicar as alterações. + + + Abrir em novo separador + Abrir em separador de fundo + Abrir em separador incógnito + Remover marcador + Editar marcador + Remover do histórico + Descarregar imagem + Copiar ligação + Renomear pasta + Remover pasta + Fechar navegador From dcde8fa348cf6b9f7c6d793e173656055e684f66 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Tue, 29 Nov 2016 19:57:37 -0500 Subject: [PATCH 018/181] Fixed bug where startpage logo wasn't showing up --- .../main/java/acr/browser/lightning/constant/StartPage.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/constant/StartPage.java b/app/src/main/java/acr/browser/lightning/constant/StartPage.java index abccc832c..e1e503d31 100644 --- a/app/src/main/java/acr/browser/lightning/constant/StartPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/StartPage.java @@ -127,13 +127,13 @@ private String getHomepage() { break; case 5: // STARTPAGE_SEARCH; - icon = "file:///android_asset/png"; + icon = "file:///android_asset/startpage.png"; // "https://com/graphics/startp_logo.gif"; searchUrl = Constants.STARTPAGE_SEARCH; break; case 6: // STARTPAGE_MOBILE - icon = "file:///android_asset/png"; + icon = "file:///android_asset/startpage.png"; // "https://com/graphics/startp_logo.gif"; searchUrl = Constants.STARTPAGE_MOBILE_SEARCH; break; From ed9fea1c8f53bd8303ea21f445a33eb896fa962d Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Tue, 29 Nov 2016 20:01:12 -0500 Subject: [PATCH 019/181] Update hosts file --- app/src/LightningPlus/assets/hosts.txt | 79 +++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/app/src/LightningPlus/assets/hosts.txt b/app/src/LightningPlus/assets/hosts.txt index 5377c6a1f..e9d12ca49 100644 --- a/app/src/LightningPlus/assets/hosts.txt +++ b/app/src/LightningPlus/assets/hosts.txt @@ -15,6 +15,7 @@ 127.0.0.1 007.go2cloud.org 127.0.0.1 0075-7112-e7eb-f9b9.reporo.net 127.0.0.1 008.free-counter.co.uk +127.0.0.1 00zasdf.pw 127.0.0.1 011i5.voluumtrk.com 127.0.0.1 0124498474f7c13ac9a2-6b191446002b31342189d56cabcf5227.r11.cf2.rackcdn.com 127.0.0.1 02gzx.voluumtrk.com @@ -1797,6 +1798,10 @@ 127.0.0.1 abandonglare.8m.com 127.0.0.1 abbie-surber.us 127.0.0.1 abbott.vo.llnwd.net +127.0.0.1 abbp1.pw +127.0.0.1 abbp1.science +127.0.0.1 abbp1.space +127.0.0.1 abbp1.website 127.0.0.1 abby-clowers.us 127.0.0.1 abc.apportium.com 127.0.0.1 abc.bnex.com @@ -18571,6 +18576,8 @@ 127.0.0.1 adspaes.ero-advertising.com 127.0.0.1 adspages.ero-advertising.com 127.0.0.1 adspaper.org +127.0.0.1 adspayformy.site +127.0.0.1 adspayformymortgage.win 127.0.0.1 adspcces.ero-advertising.com 127.0.0.1 adspdbl.com 127.0.0.1 adspeed.com @@ -24020,7 +24027,25 @@ 127.0.0.1 cdn1.tribalfusion.com 127.0.0.1 cdn10-ref.landing.comcontent.net 127.0.0.1 cdn11-ref.landing.comcontent.net +127.0.0.1 cdn11.00zasdf.pw +127.0.0.1 cdn11.abbp1.pw +127.0.0.1 cdn11.abbp1.science +127.0.0.1 cdn11.abbp1.space +127.0.0.1 cdn11.abbp1.website +127.0.0.1 cdn11.adspayformy.site +127.0.0.1 cdn11.adspayformymortgage.win 127.0.0.1 cdn11.contentabc.com +127.0.0.1 cdn11.monzta.pet +127.0.0.1 cdn11.oknplm.website +127.0.0.1 cdn11.olmknp.space +127.0.0.1 cdn11.pleasedontslaymy.download +127.0.0.1 cdn11.plmokn.pw +127.0.0.1 cdn11.poolnoodle.tech +127.0.0.1 cdn11.routehero.com +127.0.0.1 cdn11.tgbvfr.website +127.0.0.1 cdn11.yuiop.trade +127.0.0.1 cdn11.yuiout.online +127.0.0.1 cdn11.zxcvb.space 127.0.0.1 cdn12-ref.landing.comcontent.net 127.0.0.1 cdn13-ref.landing.comcontent.net 127.0.0.1 cdn14-ref.landing.comcontent.net @@ -26278,10 +26303,21 @@ 127.0.0.1 coxnetmasterglobal.112.2o7.net 127.0.0.1 coxnews.cimedia.com 127.0.0.1 coxpalmbeachpost.112.2o7.net +127.0.0.1 cp.abbp1.pw +127.0.0.1 cp.abbp1.science +127.0.0.1 cp.abbp1.space +127.0.0.1 cp.abbp1.website +127.0.0.1 cp.adspayformy.site 127.0.0.1 cp.doublepimp.com 127.0.0.1 cp.intl.match.com +127.0.0.1 cp.monzta.pet +127.0.0.1 cp.pleasedontslaymy.download +127.0.0.1 cp.poolnoodle.tech 127.0.0.1 cp.pushwoosh.com +127.0.0.1 cp.routehero.com 127.0.0.1 cp.surf-town.net +127.0.0.1 cp.yuiop.trade +127.0.0.1 cp.yuiout.online 127.0.0.1 cp1dk.voluumtrk.com 127.0.0.1 cpa.ly 127.0.0.1 cpaaltima.go2cloud.org @@ -29283,6 +29319,7 @@ 127.0.0.1 ftp01.dus.vmsn.de 127.0.0.1 ftpcontent.worldnow.com 127.0.0.1 ftr2.external.xerox.com +127.0.0.1 ftrackb.net 127.0.0.1 fu7fb.voluumtrk.com 127.0.0.1 fuauq.voluumtrk.com 127.0.0.1 fucktubenetwork.com @@ -29699,6 +29736,7 @@ 127.0.0.1 go-clicks.de 127.0.0.1 go.activengage.com 127.0.0.1 go.ad2up.com +127.0.0.1 go.ad2upapp.com 127.0.0.1 go.adify.com 127.0.0.1 go.adinfuse.com 127.0.0.1 go.adversal.com @@ -29707,6 +29745,7 @@ 127.0.0.1 go.by 127.0.0.1 go.coxds.com 127.0.0.1 go.cpmadvisors.com +127.0.0.1 go.deliverymodo.com 127.0.0.1 go.delnapb.com 127.0.0.1 go.feedxfeed.com 127.0.0.1 go.goroost.com @@ -33428,6 +33467,7 @@ 127.0.0.1 monitor01.con.vmsn.de 127.0.0.1 monster.gostats.com 127.0.0.1 monsterpops.com +127.0.0.1 monzta.pet 127.0.0.1 moo.go2cloud.org 127.0.0.1 mopo.ivwbox.de 127.0.0.1 mopub.web107-east.manage.com @@ -34350,6 +34390,7 @@ 127.0.0.1 oin.valuead.com 127.0.0.1 ojolink.com 127.0.0.1 ojrq.net +127.0.0.1 oknplm.website 127.0.0.1 okohp.voluumtrk.com 127.0.0.1 okpgn.voluumtrk.com 127.0.0.1 okrg0.voluumtrk.com @@ -34363,6 +34404,7 @@ 127.0.0.1 olivia-hermes.us 127.0.0.1 olivia-stanfield.us 127.0.0.1 olizyr.com +127.0.0.1 olmknp.space 127.0.0.1 om.1and1.co.uk 127.0.0.1 om.1und1.info 127.0.0.1 om.cbsi.com @@ -35207,6 +35249,7 @@ 127.0.0.1 playminigolf.com 127.0.0.1 playtomic.com 127.0.0.1 plb27.voluumtrk.com +127.0.0.1 pleasedontslaymy.download 127.0.0.1 plemedia.com 127.0.0.1 plemx.com 127.0.0.1 plenews.net @@ -35215,6 +35258,7 @@ 127.0.0.1 plex.r.worldssl.net 127.0.0.1 plex2.com 127.0.0.1 pll28.voluumtrk.com +127.0.0.1 plmokn.pw 127.0.0.1 plocia.com 127.0.0.1 ploko.voluumtrk.com 127.0.0.1 pls.webtype.com @@ -35274,10 +35318,12 @@ 127.0.0.1 pongoresume.com 127.0.0.1 pons.ivwbox.de 127.0.0.1 pontiflex.com +127.0.0.1 pool.admedo.com 127.0.0.1 pool.ads.netlog.com 127.0.0.1 pool.skyhookwireless.com 127.0.0.1 pool01.2cnt.net 127.0.0.1 pool02.2cnt.net +127.0.0.1 poolnoodle.tech 127.0.0.1 poopoo.freestats.com 127.0.0.1 pop.adcocktail.com 127.0.0.1 pop.adconjure.com @@ -36366,6 +36412,7 @@ 127.0.0.1 rotator.tradetracker.nl 127.0.0.1 rotator.trafficstars.com 127.0.0.1 rotrk.com +127.0.0.1 routehero.com 127.0.0.1 router.adlure.net 127.0.0.1 router.revmob.com 127.0.0.1 router.tlvmedia.com @@ -36476,7 +36523,6 @@ 127.0.0.1 rwbd0.voluumtrk.com 127.0.0.1 rwnkj.voluumtrk.com 127.0.0.1 rxdja.voluumtrk.com -127.0.0.1 rxf.answcdn.com 127.0.0.1 ry7c5.directadsopt.com 127.0.0.1 ryan-lietz.us 127.0.0.1 rydium.us.intellitxt.com @@ -38900,6 +38946,7 @@ 127.0.0.1 tfp.2ref.co 127.0.0.1 tga.acs86.com 127.0.0.1 tga.csbew.com +127.0.0.1 tgbvfr.website 127.0.0.1 tgp.buzzsession.com 127.0.0.1 tgp.pornsponsors.com 127.0.0.1 thaliaat02.webtrekk.net @@ -39310,6 +39357,7 @@ 127.0.0.1 track.scorpiointeractive.com 127.0.0.1 track.searchignite.com 127.0.0.1 track.sexchangegirl.com +127.0.0.1 track.sharktrkr.xyz 127.0.0.1 track.shop2market.com 127.0.0.1 track.sigfig.com 127.0.0.1 track.slideshare.net @@ -44537,7 +44585,6 @@ 127.0.0.1 webtrack-brickstreetconnect-mkt-prd.hsbc.com.hk 127.0.0.1 webtrack.jwgrant.co.uk 127.0.0.1 webtracker.educationconnection.com -127.0.0.1 webtracker.tnt.com 127.0.0.1 webtrackerplus.com 127.0.0.1 webtracking.touchclarity.com 127.0.0.1 webtraffic.ttinet.com @@ -44736,9 +44783,27 @@ 127.0.0.1 wrestling.searchwho.com 127.0.0.1 ws-eu.amazon-adsystem.com 127.0.0.1 ws-na.amazon-adsystem.com +127.0.0.1 ws.00zasdf.pw +127.0.0.1 ws.abbp1.pw +127.0.0.1 ws.abbp1.science +127.0.0.1 ws.abbp1.space +127.0.0.1 ws.abbp1.website +127.0.0.1 ws.adspayformy.site +127.0.0.1 ws.adspayformymortgage.win 127.0.0.1 ws.amazon.com +127.0.0.1 ws.monzta.pet +127.0.0.1 ws.oknplm.website +127.0.0.1 ws.olmknp.space +127.0.0.1 ws.pleasedontslaymy.download +127.0.0.1 ws.plmokn.pw +127.0.0.1 ws.poolnoodle.tech +127.0.0.1 ws.routehero.com 127.0.0.1 ws.sharethis.com 127.0.0.1 ws.tapjoyads.com +127.0.0.1 ws.tgbvfr.website +127.0.0.1 ws.yuiop.trade +127.0.0.1 ws.yuiout.online +127.0.0.1 ws.zxcvb.space 127.0.0.1 ws1.surf-town.net 127.0.0.1 ws10.surf-town.net 127.0.0.1 ws11.surf-town.net @@ -44782,6 +44847,7 @@ 127.0.0.1 wsc1.webspectator.com 127.0.0.1 wsc4.webspectator.com 127.0.0.1 wsclick.infospace.com +127.0.0.1 wsg.abbp1.pw 127.0.0.1 wsi1.surf-town.net 127.0.0.1 wsod.com 127.0.0.1 wsp1.surf-town.net @@ -44953,6 +45019,7 @@ 127.0.0.1 www.ad-lite.com 127.0.0.1 www.ad-maker.net 127.0.0.1 www.ad-media.org +127.0.0.1 www.ad-rev.in 127.0.0.1 www.ad-search.com 127.0.0.1 www.ad-solutions.com 127.0.0.1 www.ad-space.net @@ -45085,6 +45152,7 @@ 127.0.0.1 www.adsniper.ru 127.0.0.1 www.adsoogle.com 127.0.0.1 www.adspaces.ero-advertising.com +127.0.0.1 www.adspayformy.site 127.0.0.1 www.adsphinx.com 127.0.0.1 www.adspics.com 127.0.0.1 www.adspinner.com @@ -45880,6 +45948,7 @@ 127.0.0.1 www.freeviral.com 127.0.0.1 www.freewha.com 127.0.0.1 www.friendlyduck.com +127.0.0.1 www.ftrackb.net 127.0.0.1 www.fucktubenetwork.com 127.0.0.1 www.fuel451.com 127.0.0.1 www.fullqurandownload.com @@ -46682,6 +46751,7 @@ 127.0.0.1 www.pixetrk.com 127.0.0.1 www.placehold.it 127.0.0.1 www.platinscience.com +127.0.0.1 www.pleasedontslaymy.download 127.0.0.1 www.plocia.com 127.0.0.1 www.plug-media.com 127.0.0.1 www.plus500.com @@ -47727,6 +47797,8 @@ 127.0.0.1 ysm.hauchi.com.tw 127.0.0.1 ytubevideoqualitymanager.com 127.0.0.1 yuilop.com +127.0.0.1 yuiop.trade +127.0.0.1 yuiout.online 127.0.0.1 yume.com 127.0.0.1 yuppy.2cnt.net 127.0.0.1 yvap.query.yahoo.com @@ -47894,6 +47966,7 @@ 127.0.0.1 zw.zeroredirect1.com 127.0.0.1 zww.ero-advertising.com 127.0.0.1 zx.zeroredirect1.com +127.0.0.1 zxcvb.space 127.0.0.1 zxypenguin.people-group.su 127.0.0.1 zy.zeroredirect1.com 127.0.0.1 zyngawithfriends.com @@ -47901,4 +47974,4 @@ 127.0.0.1 zz.zeroredirect1.com 127.0.0.1 zzz.clickbank.net 127.0.0.1 _thums.ero-advertising.com -# Hosts: 47893 \ No newline at end of file +# Hosts: 47966 \ No newline at end of file From e4a46b66b188d120faf2fdf3bcaf76bfffd5f5f7 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Tue, 29 Nov 2016 20:16:20 -0500 Subject: [PATCH 020/181] Minor bugfix bump --- app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2ae1a3c3b..40950bb54 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 24 - versionName "4.4.1" + versionName "4.4.2" vectorDrawables.useSupportLibrary = true } @@ -36,13 +36,13 @@ android { lightningPlus { buildConfigField "boolean", "FULL_VERSION", "true" applicationId "acr.browser.lightning" - versionCode 90 + versionCode 91 } lightningLite { buildConfigField "boolean", "FULL_VERSION", "false" applicationId "acr.browser.barebones" - versionCode 92 + versionCode 93 } } From 1eb6d680721f69a126269f577eb959c6b8b07d58 Mon Sep 17 00:00:00 2001 From: valentind44 Date: Tue, 6 Dec 2016 16:09:57 +0100 Subject: [PATCH 021/181] Added new strings to the French translation. --- app/src/main/res/values-fr/strings.xml | 44 ++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0ac4949fe..bc668427f 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -16,7 +16,8 @@ --> - + + Lightning Nouvel onglet Partager @@ -28,7 +29,7 @@ Paramètres Accéder à ma position Enregistrer les mots de passe - User Agent + Agent utilisateur Activer Adobe Flash Page d\'accueil Mode plein écran @@ -50,6 +51,8 @@ Utiliser large fenêtre d\'affichage Charger les pages en mode aperçu Restaurer les onglets perdus au démarrage + Navigateurs pris en charge + Navigateur par défaut Aucun navigateur détecté Navigateur compatible détecté Masquer la barre d\'état lors de la navigation @@ -74,7 +77,7 @@ Annuler Avertissement Adobe Flash Player n\'a pas été détecté.\nVeuillez installer Flash Player. - User Agent + Agent utilisateur Téléchargement Page d\'accueil personnalisée Page internet @@ -144,6 +147,8 @@ Mot de passe Suggestions de recherche Proposé par Google + Propulsé par DuckDuckGo + Pas de suggestions de recherche Proxy HTTP Aucun @@ -175,6 +180,7 @@ Inversé Niveaux de gris Niveaux de gris inversés + Augmenter le contraste Normal Synchroniser l\'historique avec Google Explorateur de fichiers @@ -193,6 +199,7 @@ En savoir plus sur la version, l\'auteur et la licence. Fermer l\'onglet Fermer tous les onglets + Fermer les autres onglets Bloquer les cookies tiers Activer le mode couleur Mode lecteur @@ -208,9 +215,9 @@ Adresse Titre - Inverser la couleur - Thème sombre - Onglets + Inverser les couleurs + Thème sombre + Onglets Thème Thème clair Thème noir (AMOLED) @@ -225,6 +232,31 @@ Fichier Hosts source de blocage des publicités Blocage des publicités Afficher les onglets dans le volet de navigation + Échanger les favoris et les onglets Demander de \'Ne pas pister\' Supprimer les en-têtes d\'dentification + Ajouter à l\'écran d\'accueil + Ajouté à l\'écran d\'accueil + Supprimer tous les favoris + + FAQ + Questions fréquemment posées + + + Paramètres de déboggage + LeakCanary + Veuillez redémarrer l\'application pour prendre en compte les changements. + + + Ouvrir dans un nouvel onglet + Ouvrir en arrière plan + Ouvrir dans un onglet incognito + Supprimer le favori + Éditer le favori + Supprimer de l\'historique + Télécharger l\'image + Copier le lien + Renommer de dossier + Supprimer le dossier + Fermer le navigateur From 47ff7e28e61a9611f402db3b01b7d27ac4d48f63 Mon Sep 17 00:00:00 2001 From: zygimantus Date: Sun, 18 Dec 2016 23:04:33 +0200 Subject: [PATCH 022/181] Lithuanian language added --- app/src/main/res/values-lt/strings.xml | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 app/src/main/res/values-lt/strings.xml diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml new file mode 100644 index 000000000..2f05a20f7 --- /dev/null +++ b/app/src/main/res/values-lt/strings.xml @@ -0,0 +1,42 @@ + + + Lightning + Pridėti žymę + Pridėti į pradžios langą + Leisti + Atgal + Tuščias puslapis + Žymės + Atšaukti + Kopijuoti nuorodą + Ištrinti + Neleisti + Atsiųsti + Aplankas + Susisiekti + Nauja kortelė + Nauja privati kortelė + Vadovas + Ne + Gerai + Atidaryti + Istorija + Numatytasis + Pirmyn + Keisti + Rasti puslapyje + Pervadinti + Dalintis + Tinklalapis + Taip + Naudotojo agentas + + + + + Taip + Skaitymo rėžimas + Ne + Normalus + Portas: + \ No newline at end of file From 19166f8dfbe20cacb5a92130fc736ae0894175e5 Mon Sep 17 00:00:00 2001 From: Zoraver Kang Date: Sun, 18 Dec 2016 23:59:09 -0500 Subject: [PATCH 023/181] Added basic keyboard shortcut support. --- .../lightning/activity/BrowserActivity.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index b848b0a0f..d3db8e4d3 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -712,6 +712,50 @@ public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { return super.onKeyUp(keyCode, event); } + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + // Keyboard shortcuts + if (event.isCtrlPressed() && event.getAction() == KeyEvent.ACTION_DOWN) { + switch(event.getKeyCode()) { + case KeyEvent.KEYCODE_T: + // Open new tab + newTab(null, true); + return true; + case KeyEvent.KEYCODE_W: + // Close current tab + mPresenter.deleteTab(mTabsManager.indexOfCurrentTab()); + return true; + case KeyEvent.KEYCODE_Q: + // Close browser + closeBrowser(); + return true; + case KeyEvent.KEYCODE_R: + // Refresh current tab + mTabsManager.getCurrentTab().reload(); + return true; + case KeyEvent.KEYCODE_TAB: + int nextIndex = 0; + if(event.isShiftPressed()) { + // Go back one tab + if(mTabsManager.indexOfCurrentTab() > 0) nextIndex = mTabsManager.indexOfCurrentTab() - 1; + else nextIndex = mTabsManager.last(); + } else { + // Go forward one tab + if(mTabsManager.indexOfCurrentTab() < mTabsManager.last()) nextIndex = mTabsManager.indexOfCurrentTab() + 1; + else nextIndex = 0; + } + mPresenter.tabChanged(nextIndex); + return true; + } + } else if(event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_SEARCH) { + // Highlight search field + mSearch.requestFocus(); + mSearch.selectAll(); + return true; + } + return super.dispatchKeyEvent(event); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { final LightningView currentView = mTabsManager.getCurrentTab(); From d74c3199633d825ef1a30277ecc3efdcfdbe2a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Mill=C3=A1n=20Soto?= Date: Fri, 23 Dec 2016 20:13:37 +0100 Subject: [PATCH 024/181] Show realm in HTTP auth dialog Display realm when an HTTP authentication is requested. The term "Server message" is used instead of realm as not all users would understand what realm means. --- .../java/acr/browser/lightning/view/LightningWebClient.java | 4 ++++ app/src/main/res/values/strings.xml | 1 + 2 files changed, 5 insertions(+) diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index e5f24f88f..0c3f12f74 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -26,6 +26,7 @@ import android.webkit.WebViewClient; import android.widget.EditText; import android.widget.LinearLayout; +import android.widget.TextView; import java.io.ByteArrayInputStream; import java.net.URISyntaxException; @@ -125,11 +126,14 @@ public void onReceivedHttpAuthRequest(final WebView view, @NonNull final HttpAut final String host, final String realm) { AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); + final TextView realmLabel = new TextView(mActivity); final EditText name = new EditText(mActivity); final EditText password = new EditText(mActivity); LinearLayout passLayout = new LinearLayout(mActivity); passLayout.setOrientation(LinearLayout.VERTICAL); + realmLabel.setText(mActivity.getString(R.string.label_realm, realm)); + passLayout.addView(realmLabel); passLayout.addView(name); passLayout.addView(password); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 516ff8a61..d040dcde6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -142,6 +142,7 @@ Allow Don\'t Allow Sign In + Server message: %s Username Password Search Suggestions From f51d38598deba2d2d5bd193a77002bcd3b65ff03 Mon Sep 17 00:00:00 2001 From: Dennis Date: Mon, 16 Jan 2017 21:42:28 +0100 Subject: [PATCH 025/181] German Translations updated. --- Lightning-Browser.iml | 2 +- app/src/main/res/values-de/strings.xml | 50 ++++++++++++++++++++------ app/src/main/res/values/strings.xml | 2 +- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Lightning-Browser.iml b/Lightning-Browser.iml index 1f7c20064..8a90bdfb3 100644 --- a/Lightning-Browser.iml +++ b/Lightning-Browser.iml @@ -13,7 +13,7 @@ - + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 57ce8fb11..6006ab5b5 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -79,8 +79,8 @@ Webseite Verlauf löschen Cookies löschen - Möchten Sie den gesamten Verlauf sicher löschen? - Möchten Sie alle Cookies sicher löschen? + Möchten Sie den gesamten Verlauf löschen? + Möchten Sie alle Cookies löschen? Ja Nein Textgröße @@ -103,7 +103,7 @@ Herunterladen nur bei \"http\" oder \"https\" URLs möglich! Keine SD-Karte USB-Speicher ist für das Herunterladen der Datei notwendig! - USB-Speicher nicht verfügbar! + USB-Speicher nicht verfügbar Speicher aktiv. Um ein Herunterladen zu ermöglichen, schalten Sie den USB-Speicher in der Benachrichtigung aus. Cookies im Inkognito-Modus aktivieren Adobe Flash @@ -120,7 +120,7 @@ Text in Zwischenablage kopiert Link in Zwischenablage kopiert Benutzerdefinierte URL - Lokale Datei wurde beim Laden blockiert! + Lokale Datei wurde beim Laden blockiert Open Source-Lizenzen Suche nach Werbung blockieren @@ -157,18 +157,17 @@ Dateiauswahl NetCipher GNU Lesser General Public License - Exportiere Backup - Importiere Backup + Exportiere Datensicherung + Importiere Lesezeichen aus Datensicherung Lesezeichen exportiert nach - Lesezeichen - Lesezeichen konnten nicht imprortiert werden + Lesezeichen Einstellungen + Lesezeichen konnten nicht importiert werden Wähle Datei aus Allgemein - Display Privatsphäre Über Details über Version, Autor und Lizenz - Tab schließen + Aktuellen Tab schließen Alle Tabs schließen Drittanbieter Cookies blockieren Farbmodus aktivieren @@ -216,4 +215,35 @@ Es sieht aus, als ob I2P installiert wäre. Möchten Sie es verwenden? Textcodierung Tabs in Drawer anzeigen + Zum Homescreen hinzufügen + Alle Lesezeichen löschen + Bitte schließen Sie die App um die Änderungen anzuwenden. + Ordner löschen + Lesezeichen löschen + In neuem Tab öffnen + In Inkognito-Tab öffnen + Lesezeichen bearbeiten + Andere Tabs schließen + Debug Einstellungen + Link kopieren + Bild herunterladen + In Hintergrund-Tab öffnen + Aus dem Verlauf entfernen + Ordner umbenennen + Browser schließen + \"Nicht verfolgen\"-Funktion anfordern + FAQ + Häufige Fragen + Lesezeichen zum Homescreen hinzugefügt + Kontrast erhöhen + Unterstützt durch DuckDuckGo + Identifizierbare Header entfernen + Keine Suchvorschläge + Werbeblocker + Unterstützte Browser + Lesezeichen und Tab-Drawer wechseln + Standardbrowser + Host: + Quelle für Werbeblocker + Anzeige diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 516ff8a61..4e41fab89 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -225,7 +225,7 @@ Rename Rename Folder What would you like to do with this folder? - Clear Web Storage + Clear web storage Clear web storage on exit Web storage cleared Hosts File Ad Blocking Source From c9308d26aed35a47b5549c5e7634e8e1038b1484 Mon Sep 17 00:00:00 2001 From: Roboe Date: Sun, 28 Feb 2016 01:04:51 +0100 Subject: [PATCH 026/181] [Spanish l10n] Update strings and add new ones --- app/src/main/res/values-es/strings.xml | 105 ++++++++++++++++--------- 1 file changed, 68 insertions(+), 37 deletions(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 876d8ed6e..569b4dd51 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,5 +1,4 @@ - Lightning Nueva pestaña Compartir @@ -9,19 +8,19 @@ Copiar enlace Adelante Ajustes - Acceder a tu ubicación - Almacenar contraseñas + Acceso a tu ubicación + Almacenar tus contraseñas Agente de usuario Habilitar Adobe Flash Página de inicio - Habilitar pantalla completa + Modo de pantalla completa Habilitar JavaScript Ruta de descargas Ajustes avanzados - Apache License 2.0 + Licencia Apache 2.0 Versión Vaciar caché al salir - Activar el Text Reflow + Activar la recolocación dinámica de texto Bloquear imágenes Permitir a los sitios abrir nuevas ventanas Habilitar cookies @@ -30,11 +29,11 @@ (Recomendado) Motor de búsqueda Buscar - Utilizar viewport normal + Utilizar ventana de visualización normal Visualizar la página de lejos al cargar Restaurar pestañas cerradas al iniciar - (No se detecta navegador de sistema) - (Detectado navegador de sistema soportado) + Navegador de sistema no detectado + Detectado navegador de sistema soportado Ocultar barra de estado al navegar Limpiar cookies Limpiar historial @@ -57,7 +56,7 @@ Aviso No se detecta Adobe Flash Player.\nPor favor, instálalo. Agente de usuario - Ruta de descargas + Ruta para las descargas Página de inicio personalizada Página web Borrar historial @@ -67,27 +66,27 @@ No Tamaño de la tipografía - Más grande + Muy grande Grande Normal Pequeño - Más pequeño + Muy pequeño Error No se ha detectado navegador del cual importar marcadores. Título - URL + Dirección URL Editar marcador Editar - Nueva pestaña privada + Nueva pestaña de incógnito Por defecto Atrás Buscar en la página Iniciando descarga\u2026 - Sólo se puede descargar de URLs \"http\" o \"https\". - No hay tarjeta SD - Se requiere de almacenamiento USB para descargar el archivo. + Sólo se puede descargar de direcciones \"http\" o \"https\". + No hay tarjeta SD + Se requiere de almacenamiento USB para descargar el archivo. Almacenamiento USB no disponible - El almacenamiento está ocupado. Para permitir las descargar, desactiva el almacenamiento USB desde el área de notificación. + El almacenamiento está ocupado. Para permitir las descargar, desactiva el almacenamiento USB desde el área de notificación. Habilitar cookies en el modo incógnito Adobe Flash Manual @@ -95,14 +94,14 @@ Contáctame twitter.com/RestainoAnthony Limpiar caché - La caché se ha borrado - Los marcadores se han importado - El historial se ha borrado - Las cookies se han borrado + La caché ha sido borrada + Se han importado los marcadores + El historial ha sido borrado + Las cookies han sido borradas Se ha alcanzado el máximo de pestañas - El texto se ha copiado al portapapeles + El texto ha sido copiado al portapapeles El enlace se ha copiado al portapapeles - URL personalizada + Dirección personalizada Se ha bloqueado la carga del archivo local Licencias de código abierto (open source) Buscar @@ -113,7 +112,7 @@ Permitir No permitir Iniciar sesión - Usuario + Nombre de usuario Contraseña Sugerencias de búsqueda Proporcionadas por Google @@ -127,7 +126,7 @@ Personalizado Sin título Mozilla Public License v. 2.0 - Freeware + Software gratuito Android Open Source Project hpHosts Ad Server List Pestaña reabierta @@ -137,15 +136,15 @@ Escala de grises invertida Normal Sincronizar historial con Google - Selector de archivo + Selector de archivos NetCipher GNU Lesser General Public License - Exportar marcadores a la copia de seguridad - Importar marcadores a una copia de seguridad + Exportar marcadores a una copia de seguridad + Importar marcadores desde una copia de seguridad Marcadores exportados a Ajustes de marcadores No se pudo importar los marcadores del archivo - Elija un archivo + Elige un archivo Ajustes generales Ajustes de pantalla Ajustes de privacidad @@ -157,17 +156,49 @@ Habilitar modo de color Modo de lectura Cargando… - No se pudo extraer contenido de la página. + No se pudo cargar de la página. Snacktory jsoup: Java HTML Parser - MIT License - Contenido de la caja de la URL + Licencia MIT + Contenido de la caja de la dirección - Dominio (por defecto) - URL - Título + Dominio (por defecto) + Dirección URL + Título Invertir color - Usar tema oscuro + Tema oscuro Pestañas + Carpeta + Renombrar + Tema negro (AMOLED) + Vaciar almacenamiento web + Vaciar almacenamiento web al salir + ¿Qué quieres hacer con esta carpeta? + ¿Qué quieres hacer con este elemento del historial? + Nombre de la carpeta + Fichero hosts para filtrado de anuncios + Proxy HTTP + I2P no está corriendo. + Los túneles I2P no están preparados aún. + Tema claro + Proxy manual + la fecha del certificado no es válida + el dominio en el certificado no corresponde al dominio del sitio + el certificado expiró + el certificado no es válido + el certificado no es válido todavía + el certificado no es confiable + La conexión a este sitio no es segura:\n%1$s\n¿Continuar en cualquier caso? + El almacenamiento web ha sido borrado + Puerto: + La dirección no es válida, no se pudo descargar + No se pudo descargar en la localización específica + Ajustes del bloqueo de anuncios + Mostrar pestañas en el menú lateral + Codificación del texto + Tema gráfico de la aplicación + Renombrar carpeta + Parece que tienes I2P instalado. ¿Quieres usar I2P? + Servidor: From 8d9e44eccd3c4eb916bfd833e9e6651ee3b12d2a Mon Sep 17 00:00:00 2001 From: stellasythe Date: Sun, 22 Jan 2017 18:17:40 -0300 Subject: [PATCH 027/181] Add files via upload --- app/src/main/res/values-br/values-pt-br.xml | 202 ++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 app/src/main/res/values-br/values-pt-br.xml diff --git a/app/src/main/res/values-br/values-pt-br.xml b/app/src/main/res/values-br/values-pt-br.xml new file mode 100644 index 000000000..54f4735c0 --- /dev/null +++ b/app/src/main/res/values-br/values-pt-br.xml @@ -0,0 +1,202 @@ + + + + + Lightning + Nova aba + Compartilhar + Histórico + Favoritos + Adicionar favoritos + Copiar link da página + Avançar + Configurações + Acesso de localização + Salvar senhas + Agente + Ativar Adobe Flash + Página inicial + Modo de tela completa + Ativar JavaScript + Pasta de download + Configurações avançadas + Apache License 2.0 + Versão da aplicação + Limpar cache ao sair + Ativar ajuste de texto + Bloquear imagens + Permitir que sites abram novas janelas + Ativar cookies + Importar favoritos do navegador + Tamanho do texto + Recomendado + Mecanismo de pesquisa + Pesquisa + Utilizar viewport amplo + Carregar páginas no modo panorâmico + Restaurar abas ao iniciar + Navegador não detectado + Navegador detetado + Ocultar barra de estado ao navegar + Limpar cookies + Limpar histórico + O que gostaria de fazer com esta imagem? + Salvar + Abrir + O que gostaria de fazer com este link? + Compartilhar esta página + O que gostaria de fazer com este favorito? + Remover + Página vazia + Padrão + Desktop + Mobile + Personalizado + Mecanismo de pesquisa + OK + Gostaria de transferir este arquivo? + Cancelar + Aviso + O Adobe Flash Player não foi detectado.\nNecessário instalar o Flash Player. + Agente de utilizador + Local das transferências + Página inicial personalizada + Página web + Limpar histórico + Limpar cookies + Gostaria de limpar todo o histórico do navegador? + Gostaria de limpar todos os cookies do navegador? + Sim + Não + Tamanho do texto + Maior + Grande + Normal + Pequeno + Menor + Erro + Não foi detectado qualquer navegador para importar os favoritos. + Título + URL + Editar favorito + Editar + Nova aba anônima + Padrão + Voltar + Localizar na página + A iniciar transferência\u2026 + Apenas possível para as URLs \"http\" ou \"https\". + Cartão SD não encontrado + Necessita-se de um cartão SD para salvar o arquivo transferido. + Cartão SD não disponível + O cartão SD está ocupado. Para poder transferir arquivos, desative a opção Desativar armazenamento USB na notificação. + Permitir cookies no modo anônimo + Adobe Flash + Manual + Automático + Contato + twitter.com/RestainoAnthony + Limpar cache + Cache limpo + Favoritos importados + Histórico removido + Cookies removidos + Atingido número máximo de abas + Texto copiado para a área de transferência + Link copiado para a área de transferência + URL personalizado + Bloqueado o carregamento do arquivo local + Licenças Open Source + Pesquisar por + Bloquear anúncios + Submissão de formulário + Gostaria de reenviar os dados? + \nGostaria de utilizar a sua localização + Sim + Não + Iniciar sessão + Usuário + Senha + Sugestões de pesquisa + Disponibilizado por Google + Proxy HTTP + + Não + Orbot + I2P + Manual + + Proxy manual + Servidor: + Porta: + Parece que você tem o Orbot instalado. Gostaria de utilizar a rede Tor? + Parece que você tem o I2P instalado. Gostaria de utilizar a rede I2P? + Por favor instale o Orbot para poder utilizar a rede Tor. + I2P não está em execução. + Os canais I2P ainda não estão prontos. + Sim + Não + Limpar cookies ao sair + Limpar histórico ao sair + Padrão + Personalizado + Sem título + Mozilla Public License v. 2.0 + Freeware + Projeto Android Open Source + hpHosts Ad Server List + Reabrir última aba + Modo de renderização + Invertido + Escala cinza + Escala cinza invertida + Normal + Sincronizar histórico com Google + Seletor de arquivos + NetCipher + GNU Lesser General Public License + Exportar favoritos para backup + Importar favoritos de um backup + Favoritos salvos em + Configurações de favoritos + Não foi possível importar os favoritos do arquivo + Escolha um arquivo + Configurações gerais + Configurações de exibição + Configurações de privacidade + Sobre + Detalhes da versão, do autor e da licença + Fechar aba + Fechar todas as abas + Bloquear cookies de terceiros + Ativar modo de cor + Modo de leitura + A carregar… + A página não foi carregada. + Snacktory + jsoup: Java HTML Parser + MIT License + Conteúdo da caixa do URL + + Domínio (padrão) + URL + Título + + Inverter cores + Tema escuro + Abas + \ No newline at end of file From 3318d09a23d2c372b7e5c472b1431e1b99a13cd8 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 18 Mar 2017 21:46:08 -0400 Subject: [PATCH 028/181] Updating gradle plugin, updating sex count plugin, upgrading target version, updating support library versions --- app/build.gradle | 18 +++++++++--------- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 40950bb54..a73edc0a3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,12 +3,12 @@ apply plugin: 'com.neenbedankt.android-apt' apply plugin: 'com.getkeepsafe.dexcount' android { - compileSdkVersion 24 - buildToolsVersion "24.0.3" + compileSdkVersion 25 + buildToolsVersion '25.0.2' defaultConfig { minSdkVersion 14 - targetSdkVersion 24 + targetSdkVersion 25 versionName "4.4.2" vectorDrawables.useSupportLibrary = true } @@ -58,7 +58,7 @@ android { dexcount { includeClasses = false includeFieldCount = false - printAsTree = true + format = "tree" orderByMethodCount = true verbose = false } @@ -66,11 +66,11 @@ dexcount { dependencies { // support libraries - compile 'com.android.support:palette-v7:24.2.1' - compile 'com.android.support:appcompat-v7:24.2.1' - compile 'com.android.support:design:24.2.1' - compile 'com.android.support:recyclerview-v7:24.2.1' - compile 'com.android.support:support-v4:24.2.1' + compile 'com.android.support:palette-v7:25.2.0' + compile 'com.android.support:appcompat-v7:25.2.0' + compile 'com.android.support:design:25.2.0' + compile 'com.android.support:recyclerview-v7:25.2.0' + compile 'com.android.support:support-v4:25.2.0' // html parsing for reading mode compile 'org.jsoup:jsoup:1.9.2' diff --git a/build.gradle b/build.gradle index 9f7466eaf..d32499436 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,9 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.2' + classpath 'com.android.tools.build:gradle:2.3.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7' - classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.2.1' + classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.3' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9d020539c..665e5ab4b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Aug 15 21:33:52 EDT 2016 +#Sat Mar 18 21:36:34 EDT 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip From 5bdc9294db9bc446642cf7e2a884630a1bb76332 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 18 Mar 2017 21:59:41 -0400 Subject: [PATCH 029/181] Update to latest progress bar library code --- AnimatedProgressBar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AnimatedProgressBar b/AnimatedProgressBar index e7d6ec28b..c23593345 160000 --- a/AnimatedProgressBar +++ b/AnimatedProgressBar @@ -1 +1 @@ -Subproject commit e7d6ec28baac7cc6909466fc0c8fc8c5e3de6f9d +Subproject commit c23593345996115c44305aab9780a7d4c307896a From 77a2f61df3a991f22e1b12b273283655ef421743 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 18 Mar 2017 22:20:57 -0400 Subject: [PATCH 030/181] Updating bonsai --- Bonsai | 2 +- .../lightning/activity/BrowserActivity.java | 3 +- .../lightning/activity/IncognitoActivity.java | 13 +-- .../lightning/activity/MainActivity.java | 13 +-- .../lightning/activity/ReadingActivity.java | 20 ++--- .../lightning/activity/TabsManager.java | 37 +++++---- .../lightning/browser/BrowserPresenter.java | 23 +++-- .../lightning/database/BookmarkLocalSync.java | 15 ++-- .../fragment/BookmarkSettingsFragment.java | 10 +-- .../lightning/fragment/BookmarksFragment.java | 30 +++---- .../lightning/search/SuggestionsAdapter.java | 83 +++++++++---------- .../lightning/search/SuggestionsManager.java | 16 ++-- .../browser/lightning/view/LightningView.java | 80 ++++++++---------- build.gradle | 10 +++ 14 files changed, 179 insertions(+), 176 deletions(-) diff --git a/Bonsai b/Bonsai index 68eb7eb37..d47c9626c 160000 --- a/Bonsai +++ b/Bonsai @@ -1 +1 @@ -Subproject commit 68eb7eb377803f7971baedb28144aa3b1c420cd0 +Subproject commit d47c9626c2583b09a1102a980186f9ca51bc4e29 diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index b848b0a0f..87625e0cb 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -80,6 +80,7 @@ import android.widget.TextView.OnEditorActionListener; import android.widget.VideoView; +import com.anthonycr.bonsai.Completable; import com.anthonycr.bonsai.Observable; import com.anthonycr.bonsai.Schedulers; import com.anthonycr.grant.PermissionsManager; @@ -225,7 +226,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements public abstract void updateHistory(@Nullable final String title, @NonNull final String url); - abstract Observable updateCookiePreference(); + abstract Completable updateCookiePreference(); @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java b/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java index e939e5ad8..a6ab3a8cd 100644 --- a/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java @@ -8,19 +8,20 @@ import android.webkit.CookieManager; import android.webkit.CookieSyncManager; +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; + import acr.browser.lightning.R; -import com.anthonycr.bonsai.Action; -import com.anthonycr.bonsai.Observable; -import com.anthonycr.bonsai.Subscriber; @SuppressWarnings("deprecation") public class IncognitoActivity extends BrowserActivity { @Override - public Observable updateCookiePreference() { - return Observable.create(new Action() { + public Completable updateCookiePreference() { + return Completable.create(new CompletableAction() { @Override - public void onSubscribe(@NonNull Subscriber subscriber) { + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { CookieManager cookieManager = CookieManager.getInstance(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { CookieSyncManager.createInstance(IncognitoActivity.this); diff --git a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java index 982bec75e..a4f6c3528 100644 --- a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java @@ -8,19 +8,20 @@ import android.webkit.CookieManager; import android.webkit.CookieSyncManager; +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; + import acr.browser.lightning.R; -import com.anthonycr.bonsai.Action; -import com.anthonycr.bonsai.Observable; -import com.anthonycr.bonsai.Subscriber; @SuppressWarnings("deprecation") public class MainActivity extends BrowserActivity { @Override - public Observable updateCookiePreference() { - return Observable.create(new Action() { + public Completable updateCookiePreference() { + return Completable.create(new CompletableAction() { @Override - public void onSubscribe(@NonNull Subscriber subscriber) { + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { CookieManager cookieManager = CookieManager.getInstance(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { CookieSyncManager.createInstance(MainActivity.this); diff --git a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java index 90b943edd..e04abbe39 100644 --- a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java @@ -30,11 +30,11 @@ import acr.browser.lightning.constant.Constants; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.preference.PreferenceManager; -import com.anthonycr.bonsai.Action; -import com.anthonycr.bonsai.Observable; -import com.anthonycr.bonsai.OnSubscribe; -import com.anthonycr.bonsai.Subscriber; import com.anthonycr.bonsai.Schedulers; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleOnSubscribe; +import com.anthonycr.bonsai.SingleSubscriber; import com.anthonycr.bonsai.Subscription; import acr.browser.lightning.reading.HtmlFetcher; import acr.browser.lightning.reading.JResult; @@ -152,7 +152,7 @@ private boolean loadPage(Intent intent) { getSupportActionBar().setTitle(Utils.getDomainName(mUrl)); mPageLoaderSubscription = loadPage(mUrl).subscribeOn(Schedulers.worker()) .observeOn(Schedulers.main()) - .subscribe(new OnSubscribe() { + .subscribe(new SingleOnSubscribe() { @Override public void onStart() { mProgressDialog = new ProgressDialog(ReadingActivity.this); @@ -165,7 +165,7 @@ public void onStart() { } @Override - public void onNext(@Nullable ReaderInfo item) { + public void onItem(@Nullable ReaderInfo item) { if (item == null || item.getTitle().isEmpty() || item.getBody().isEmpty()) { setText(getString(R.string.untitled), getString(R.string.loading_failed)); } else { @@ -193,14 +193,14 @@ public void onComplete() { return true; } - private static Observable loadPage(@NonNull final String url) { - return Observable.create(new Action() { + private static Single loadPage(@NonNull final String url) { + return Single.create(new SingleAction() { @Override - public void onSubscribe(@NonNull Subscriber subscriber) { + public void onSubscribe(@NonNull SingleSubscriber subscriber) { HtmlFetcher fetcher = new HtmlFetcher(); try { JResult result = fetcher.fetchAndExtract(url, 2500, true); - subscriber.onNext(new ReaderInfo(result.getTitle(), result.getText())); + subscriber.onItem(new ReaderInfo(result.getTitle(), result.getText())); } catch (Exception e) { subscriber.onError(new Throwable("Encountered exception")); Log.e(TAG, "Error parsing page", e); diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 08c85a62a..7e5eefa26 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -14,6 +14,14 @@ import android.util.Log; import android.webkit.WebView; +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; +import com.anthonycr.bonsai.ObservableSubscriber; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleOnSubscribe; +import com.anthonycr.bonsai.SingleSubscriber; import com.squareup.otto.Bus; import java.util.ArrayList; @@ -32,11 +40,7 @@ import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.preference.PreferenceManager; -import com.anthonycr.bonsai.Action; -import com.anthonycr.bonsai.Observable; -import com.anthonycr.bonsai.OnSubscribe; import com.anthonycr.bonsai.Schedulers; -import com.anthonycr.bonsai.Subscriber; import acr.browser.lightning.utils.FileUtils; import acr.browser.lightning.utils.UrlUtils; @@ -108,13 +112,12 @@ private synchronized void finishInitialization() { * @param intent the intent that started the browser activity. * @param incognito whether or not we are in incognito mode. */ - public synchronized Observable initializeTabs(@NonNull final Activity activity, - @Nullable final Intent intent, - final boolean incognito) { - return Observable.create(new Action() { + public synchronized Completable initializeTabs(@NonNull final Activity activity, + @Nullable final Intent intent, + final boolean incognito) { + return Completable.create(new CompletableAction() { @Override - public void onSubscribe(@NonNull final Subscriber subscriber) { - + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { // Make sure we start with a clean tab list shutdown(); @@ -150,12 +153,12 @@ public void onSubscribe(@NonNull final Subscriber subscriber) { } private void restoreLostTabs(@Nullable final String url, @NonNull final Activity activity, - @NonNull final Subscriber subscriber) { + @NonNull final CompletableSubscriber subscriber) { restoreState().subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()).subscribe(new OnSubscribe() { + .observeOn(Schedulers.main()).subscribe(new SingleOnSubscribe() { @Override - public void onNext(Bundle item) { + public void onItem(@Nullable Bundle item) { LightningView tab = newTab(activity, "", false); String url = item.getString(URL_KEY); if (url != null && tab.getWebView() != null) { @@ -477,16 +480,16 @@ public void clearSavedState() { * and will delete the saved instance file when * restoration is complete. */ - private Observable restoreState() { - return Observable.create(new Action() { + private Single restoreState() { + return Single.create(new SingleAction() { @Override - public void onSubscribe(@NonNull Subscriber subscriber) { + public void onSubscribe(@NonNull SingleSubscriber subscriber) { Bundle savedState = FileUtils.readBundleFromStorage(mApp, BUNDLE_STORAGE); if (savedState != null) { Log.d(Constants.TAG, "Restoring previous WebView state now"); for (String key : savedState.keySet()) { if (key.startsWith(BUNDLE_KEY)) { - subscriber.onNext(savedState.getBundle(key)); + subscriber.onItem(savedState.getBundle(key)); } } } diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java index 2c19fbf31..e6a2c9350 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java @@ -7,6 +7,7 @@ import android.support.annotation.Nullable; import android.util.Log; +import com.anthonycr.bonsai.CompletableOnSubscribe; import com.anthonycr.bonsai.Schedulers; import com.squareup.otto.Bus; @@ -19,8 +20,6 @@ import acr.browser.lightning.controller.UIController; import acr.browser.lightning.preference.PreferenceManager; -import com.anthonycr.bonsai.OnSubscribe; - import acr.browser.lightning.utils.UrlUtils; import acr.browser.lightning.view.LightningView; @@ -64,16 +63,16 @@ public void tabNumberChanged(int newNumber) { */ public void setupTabs(@Nullable Intent intent) { mTabsModel.initializeTabs((Activity) mView, intent, mIsIncognito) - .subscribeOn(Schedulers.main()) - .subscribe(new OnSubscribe() { - @Override - public void onComplete() { - // At this point we always have at least a tab in the tab manager - mView.notifyTabViewInitialized(); - mView.updateTabNumber(mTabsModel.size()); - tabChanged(mTabsModel.last()); - } - }); + .subscribeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + // At this point we always have at least a tab in the tab manager + mView.notifyTabViewInitialized(); + mView.updateTabNumber(mTabsModel.size()); + tabChanged(mTabsModel.last()); + } + }); } /** diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java index bf15463a1..f2be1709f 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java @@ -8,12 +8,13 @@ import android.support.annotation.WorkerThread; import android.util.Log; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; + import java.util.ArrayList; import java.util.List; -import com.anthonycr.bonsai.Action; -import com.anthonycr.bonsai.Observable; -import com.anthonycr.bonsai.Subscriber; import acr.browser.lightning.utils.Utils; public class BookmarkLocalSync { @@ -89,10 +90,10 @@ private Cursor getBrowserCursor(String contentUri) { } @NonNull - public Observable> getSupportedBrowsers() { - return Observable.create(new Action>() { + public Single> getSupportedBrowsers() { + return Single.create(new SingleAction>() { @Override - public void onSubscribe(@NonNull Subscriber> subscriber) { + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { List sources = new ArrayList<>(1); if (isBrowserSupported(STOCK_BOOKMARKS_CONTENT)) { sources.add(Source.STOCK); @@ -106,7 +107,7 @@ public void onSubscribe(@NonNull Subscriber> subscriber) { if (isBrowserSupported(CHROME_DEV_BOOKMARKS_CONTENT)) { sources.add(Source.CHROME_DEV); } - subscriber.onNext(sources); + subscriber.onItem(sources); subscriber.onComplete(); } }); diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index deeb8a421..088181e5b 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -21,6 +21,7 @@ import android.util.Log; import android.widget.ArrayAdapter; +import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.grant.PermissionsManager; import com.anthonycr.grant.PermissionsResultAction; @@ -40,7 +41,6 @@ import acr.browser.lightning.database.BookmarkLocalSync.Source; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; -import com.anthonycr.bonsai.OnSubscribe; import com.anthonycr.bonsai.Schedulers; import acr.browser.lightning.dialog.BrowserDialog; @@ -213,14 +213,14 @@ public void onDenied(String permission) { return true; case SETTINGS_IMPORT_BROWSER: getSync().getSupportedBrowsers().subscribeOn(Schedulers.worker()) - .observeOn(Schedulers.main()).subscribe(new OnSubscribe>() { + .observeOn(Schedulers.main()).subscribe(new SingleOnSubscribe>() { @Override - public void onNext(@Nullable List items) { + public void onItem(@Nullable List item) { Activity activity = getActivity(); - if (items == null || activity == null) { + if (item == null || activity == null) { return; } - List titles = buildTitleList(activity, items); + List titles = buildTitleList(activity, item); showChooserDialog(activity, titles); } }); diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 494ce06bb..4da841431 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -27,11 +27,11 @@ import android.widget.ListView; import android.widget.TextView; -import com.anthonycr.bonsai.Action; -import com.anthonycr.bonsai.Observable; -import com.anthonycr.bonsai.OnSubscribe; import com.anthonycr.bonsai.Schedulers; -import com.anthonycr.bonsai.Subscriber; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleOnSubscribe; +import com.anthonycr.bonsai.SingleSubscriber; import com.squareup.otto.Bus; import com.squareup.otto.Subscribe; @@ -96,15 +96,15 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, private boolean mIsIncognito; - private Observable initBookmarkManager() { - return Observable.create(new Action() { + private Single initBookmarkManager() { + return Single.create(new SingleAction() { @Override - public void onSubscribe(@NonNull Subscriber subscriber) { + public void onSubscribe(@NonNull SingleSubscriber subscriber) { Context context = getContext(); if (context != null) { mBookmarkAdapter = new BookmarkViewAdapter(context, mBookmarks); setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); - subscriber.onNext(mBookmarkAdapter); + subscriber.onItem(mBookmarkAdapter); } subscriber.onComplete(); } @@ -191,13 +191,13 @@ public void onClick(View v) { setupNavigationButton(view, R.id.action_toggle_desktop, R.id.icon_desktop); initBookmarkManager().subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new OnSubscribe() { - @Override - public void onNext(@Nullable BookmarkViewAdapter item) { - mBookmarksListView.setAdapter(mBookmarkAdapter); - } - }); + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable BookmarkViewAdapter item) { + mBookmarksListView.setAdapter(mBookmarkAdapter); + } + }); return view; } diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index f1dfc1647..263fb29a5 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -15,12 +15,15 @@ import android.widget.ImageView; import android.widget.TextView; -import com.anthonycr.bonsai.Action; -import com.anthonycr.bonsai.Observable; -import com.anthonycr.bonsai.OnSubscribe; +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; import com.anthonycr.bonsai.Scheduler; import com.anthonycr.bonsai.Schedulers; -import com.anthonycr.bonsai.Subscriber; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleOnSubscribe; +import com.anthonycr.bonsai.SingleSubscriber; import java.io.File; import java.io.FilenameFilter; @@ -98,16 +101,15 @@ public void clearCache() { } public void refreshBookmarks() { - Observable.create(new Action() { + Completable.create(new CompletableAction() { @Override - public void onSubscribe(@NonNull Subscriber subscriber) { + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { mAllBookmarks.clear(); mAllBookmarks.addAll(mBookmarkManager.getAllBookmarks(true)); subscriber.onComplete(); } - }).subscribeOn(Schedulers.io()) - .subscribe(); + }).subscribeOn(Schedulers.io()).subscribe(); } @Override @@ -200,25 +202,25 @@ private synchronized void publishResults(List list) { } private void clearSuggestions() { - Observable.create(new Action() { + Completable.create(new CompletableAction() { @Override - public void onSubscribe(@NonNull Subscriber subscriber) { + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { mBookmarks.clear(); mHistory.clear(); mSuggestions.clear(); subscriber.onComplete(); } }).subscribeOn(FILTER_SCHEDULER) - .observeOn(Schedulers.main()) - .subscribe(); + .observeOn(Schedulers.main()) + .subscribe(); } private void combineResults(final @Nullable List bookmarkList, final @Nullable List historyList, final @Nullable List suggestionList) { - Observable.create(new Action>() { + Single.create(new SingleAction>() { @Override - public void onSubscribe(@NonNull Subscriber> subscriber) { + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { List list = new ArrayList<>(5); if (bookmarkList != null) { mBookmarks.clear(); @@ -251,25 +253,24 @@ public void onSubscribe(@NonNull Subscriber> subscriber) { } Collections.sort(list, mFilterComparator); - subscriber.onNext(list); + subscriber.onItem(list); subscriber.onComplete(); } }).subscribeOn(FILTER_SCHEDULER) .observeOn(Schedulers.main()) - .subscribe(new OnSubscribe>() { - @Override - public void onNext(@Nullable List item) { - publishResults(item); - } - }); - + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + publishResults(item); + } + }); } @NonNull - private Observable> getBookmarksForQuery(@NonNull final String query) { - return Observable.create(new Action>() { + private Single> getBookmarksForQuery(@NonNull final String query) { + return Single.create(new SingleAction>() { @Override - public void onSubscribe(@NonNull Subscriber> subscriber) { + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { List bookmarks = new ArrayList<>(5); int counter = 0; for (int n = 0; n < mAllBookmarks.size(); n++) { @@ -285,36 +286,30 @@ public void onSubscribe(@NonNull Subscriber> subscriber) { counter++; } } - subscriber.onNext(bookmarks); + subscriber.onItem(bookmarks); subscriber.onComplete(); } }); } @NonNull - private Observable> getSuggestionsForQuery(@NonNull final String query) { + private Single> getSuggestionsForQuery(@NonNull final String query) { if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_GOOGLE) { return SuggestionsManager.getObservable(query, mContext, SuggestionsManager.Source.GOOGLE); } else if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_DUCK) { return SuggestionsManager.getObservable(query, mContext, SuggestionsManager.Source.DUCK); } else { - return Observable.create(new Action>() { - @Override - public void onSubscribe(@NonNull Subscriber> subscriber) { - //TODO add an Observable.empty() method to generate an empty Observable - subscriber.onComplete(); - } - }); + return Single.empty(); } } @NonNull - private Observable> getHistoryForQuery(@NonNull final String query) { - return Observable.create(new Action>() { + private Single> getHistoryForQuery(@NonNull final String query) { + return Single.create(new SingleAction>() { @Override - public void onSubscribe(@NonNull Subscriber> subscriber) { + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { List historyList = mDatabaseHandler.findItemsContaining(query); - subscriber.onNext(historyList); + subscriber.onItem(historyList); subscriber.onComplete(); } }); @@ -345,9 +340,9 @@ protected FilterResults performFiltering(CharSequence constraint) { mSuggestionsAdapter.getSuggestionsForQuery(query) .subscribeOn(Schedulers.worker()) .observeOn(Schedulers.main()) - .subscribe(new OnSubscribe>() { + .subscribe(new SingleOnSubscribe>() { @Override - public void onNext(@Nullable List item) { + public void onItem(@Nullable List item) { mSuggestionsAdapter.combineResults(null, null, item); } }); @@ -356,9 +351,9 @@ public void onNext(@Nullable List item) { mSuggestionsAdapter.getBookmarksForQuery(query) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) - .subscribe(new OnSubscribe>() { + .subscribe(new SingleOnSubscribe>() { @Override - public void onNext(@Nullable List item) { + public void onItem(@Nullable List item) { mSuggestionsAdapter.combineResults(item, null, null); } }); @@ -366,9 +361,9 @@ public void onNext(@Nullable List item) { mSuggestionsAdapter.getHistoryForQuery(query) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) - .subscribe(new OnSubscribe>() { + .subscribe(new SingleOnSubscribe>() { @Override - public void onNext(@Nullable List item) { + public void onItem(@Nullable List item) { mSuggestionsAdapter.combineResults(null, item, null); } }); diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java index 48bde012d..4eaccdea9 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java @@ -4,9 +4,9 @@ import android.content.Context; import android.support.annotation.NonNull; -import com.anthonycr.bonsai.Action; -import com.anthonycr.bonsai.Observable; -import com.anthonycr.bonsai.Subscriber; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; import java.util.List; @@ -26,18 +26,18 @@ static boolean isRequestInProgress() { return sIsTaskExecuting; } - static Observable> getObservable(@NonNull final String query, @NonNull final Context context, @NonNull final Source source) { + static Single> getObservable(@NonNull final String query, @NonNull final Context context, @NonNull final Source source) { final Application application = BrowserApp.get(context); - return Observable.create(new Action>() { + return Single.create(new SingleAction>() { @Override - public void onSubscribe(@NonNull final Subscriber> subscriber) { + public void onSubscribe(@NonNull final SingleSubscriber> subscriber) { sIsTaskExecuting = true; switch (source) { case GOOGLE: new GoogleSuggestionsTask(query, application, new SuggestionsResult() { @Override public void resultReceived(@NonNull List searchResults) { - subscriber.onNext(searchResults); + subscriber.onItem(searchResults); subscriber.onComplete(); } }).run(); @@ -46,7 +46,7 @@ public void resultReceived(@NonNull List searchResults) { new DuckSuggestionsTask(query, application, new SuggestionsResult() { @Override public void resultReceived(@NonNull List searchResults) { - subscriber.onNext(searchResults); + subscriber.onItem(searchResults); subscriber.onComplete(); } }).run(); diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index e7b0785d4..f96201430 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -32,6 +32,10 @@ import android.webkit.WebSettings.PluginState; import android.webkit.WebView; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleOnSubscribe; +import com.anthonycr.bonsai.SingleSubscriber; import com.squareup.otto.Bus; import java.io.File; @@ -51,11 +55,7 @@ import acr.browser.lightning.download.LightningDownloadListener; import acr.browser.lightning.preference.PreferenceManager; -import com.anthonycr.bonsai.Action; -import com.anthonycr.bonsai.Observable; import com.anthonycr.bonsai.Schedulers; -import com.anthonycr.bonsai.Subscriber; -import com.anthonycr.bonsai.OnSubscribe; import acr.browser.lightning.utils.ProxyUtils; import acr.browser.lightning.utils.UrlUtils; @@ -405,59 +405,51 @@ private void initializeSettings() { settings.setAllowUniversalAccessFromFileURLs(false); } - getPathObservable("appcache") - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new OnSubscribe() { - @Override - public void onNext(File item) { - settings.setAppCachePath(item.getPath()); - } - - @Override - public void onComplete() {} - }); - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - getPathObservable("geolocation") - .subscribeOn(Schedulers.io()) + getPathObservable("appcache").subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) - .subscribe(new OnSubscribe() { + .subscribe(new SingleOnSubscribe() { @Override - public void onNext(File item) { - //noinspection deprecation - settings.setGeolocationDatabasePath(item.getPath()); + public void onItem(@Nullable File item) { + settings.setAppCachePath(item.getPath()); } - - @Override - public void onComplete() {} }); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + getPathObservable("geolocation").subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable File item) { + //noinspection deprecation + settings.setGeolocationDatabasePath(item.getPath()); + } + }); } - getPathObservable("databases") - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new OnSubscribe() { - @Override - public void onNext(File item) { - if (API < Build.VERSION_CODES.KITKAT) { - //noinspection deprecation - settings.setDatabasePath(item.getPath()); + getPathObservable("databases").subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable File item) { + if (API < Build.VERSION_CODES.KITKAT) { + //noinspection deprecation + settings.setDatabasePath(item.getPath()); + } } - } - @Override - public void onComplete() {} - }); + @Override + public void onComplete() { + } + }); } - private Observable getPathObservable(final String subFolder) { - return Observable.create(new Action() { + private Single getPathObservable(final String subFolder) { + return Single.create(new SingleAction() { @Override - public void onSubscribe(@NonNull Subscriber subscriber) { + public void onSubscribe(@NonNull SingleSubscriber subscriber) { File file = BrowserApp.get(mActivity).getDir(subFolder, 0); - subscriber.onNext(file); + subscriber.onItem(file); subscriber.onComplete(); } }); diff --git a/build.gradle b/build.gradle index d32499436..19604f82f 100644 --- a/build.gradle +++ b/build.gradle @@ -15,3 +15,13 @@ allprojects { mavenCentral() } } + +ext { + // Necessary for Bonsai submodule + versionCode = 1 + versionName = '1.0' + + minSdkVersion = 14 + targetSdkVersion = 25 + buildToolsVersion = '25.0.2' +} From 14ef8c70770d7c666dffd695a198328d2582b235 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 18 Mar 2017 22:39:23 -0400 Subject: [PATCH 031/181] Moving to net cipher 2.0.0-alpha away from submodule --- .gitmodules | 4 ---- app/build.gradle | 7 +++---- .../main/java/acr/browser/lightning/utils/ProxyUtils.java | 2 +- settings.gradle | 2 -- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/.gitmodules b/.gitmodules index 40622c5db..75ddd20e9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ -[submodule "external/netcipher"] - path = external/netcipher - url = https://github.com/guardianproject/NetCipher.git - branch = master [submodule "Bonsai"] path = Bonsai url = https://github.com/anthonycr/Bonsai.git diff --git a/app/build.gradle b/app/build.gradle index a73edc0a3..e942159f5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -92,10 +92,9 @@ dependencies { // proxy support compile 'net.i2p.android:client:0.8' - // Use the following code to update the libnetcipher submodule - // git submodule foreach git reset --hard - // git submodule update --remote - compile project(':libnetcipher') + // tor proxy + compile 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1' + compile 'info.guardianproject.netcipher:netcipher-webkit:2.0.0-alpha1' compile project(':bonsai') diff --git a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java index a444ea40a..f3ce53600 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java @@ -20,7 +20,7 @@ import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.preference.PreferenceManager; import info.guardianproject.netcipher.proxy.OrbotHelper; -import info.guardianproject.netcipher.web.WebkitProxy; +import info.guardianproject.netcipher.webkit.WebkitProxy; @Singleton public class ProxyUtils { diff --git a/settings.gradle b/settings.gradle index 463d0c1bd..440e7fcf1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,8 +1,6 @@ include ':app' -include ':libnetcipher' include ':bonsai' include ':animated-progress-bar' -project(':libnetcipher').projectDir = new File(rootProject.projectDir, 'external/netcipher/libnetcipher') project(':bonsai').projectDir = new File(rootProject.projectDir, 'Bonsai/library') project(':animated-progress-bar').projectDir = new File(rootProject.projectDir, 'AnimatedProgressBar/library') \ No newline at end of file From f48320153eb9e7cd539a8ce78ff35c8b44a2abb2 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 18 Mar 2017 22:42:50 -0400 Subject: [PATCH 032/181] Moving new Chinese translations to correct folder --- app/src/main/res/values-zh-rCN/strings.xml | 423 ++++++++++++--------- app/src/main/res/values-zh-rTW/strings.xml | 344 ++++++++++++----- values-zh-rCN/strings.xml | 249 ------------ values-zh-rTW/strings.xml | 249 ------------ 4 files changed, 498 insertions(+), 767 deletions(-) delete mode 100644 values-zh-rCN/strings.xml delete mode 100644 values-zh-rTW/strings.xml diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 420e51ff7..a404db0cf 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,174 +1,249 @@ - - - Lightning - 新建标签 - 分享页面 - 历史记录 - 书签列表 - 添加书签 - 复制链接 - 前进 - 浏览器设置 - 允许站点访问地理位置 - 保存密码 - - User Agent - 启用 Adobe Flash - 设置首页 - 启用全屏模式 - 启用 JavaScript - 下载目录 - 高级设置 - Apache License 2.0 - 当前版本 - 退出时清理缓存 - 启用文本重排 - 屏蔽网页图像 - 允许站点打开新窗口 - 启用 Cookies - 从浏览器中导入书签 - 页面文本尺寸 - (推荐) - 搜索引擎 - 搜索 - 使用宽视图 - 使用概览模式载入页面 - 启动时恢复丢失页面 - (尚未检测到已支持原生浏览器) - (已检测到受支持的原生浏览器) - 浏览时隐藏状态栏 - 清除浏览器 Cookies - Clear Browser History - 您希望对此图片进行什么操作? - 下载 - 打开 - 您希望对此链接进行什么操作? - 分享此页面 - 请问您要如何处理此书签? - 删除 - 空白页 - 默认 UA - 桌面访问 - 移动设备 - 自定义 UA - 搜索引擎 - 确认 - 您是否需要下载此文件? - 取消 - 警告 - "未检测到您的设备中安装了 Adobe Flash Player,请先安装 Adobe Flash Player 后再启用此选项。" - User Agent - 下载目录 - 自定义主页 - 网页 - 清除历史记录 - 清除 Cookies - 您是否确认清除所有浏览器历史记录? - 您是否确认清除所有浏览器历史记录 Cookies? - 确认 - 取消 - 文本大小 - 最大 - 较大 - 普通 - 较小 - 最小 - 错误 - 暂未检测到任何可导入书签的浏览器 - 标题 - URL - 编辑书签 - 编辑 - 新建隐身标签 - 默认页面 - 返回 - 页内搜索 - 正在开始下载… - 仅可下载以 \"http\" 或 \"https\" 开头的链接地址 - 未发现 SDCard - 为正常下载此文件需要 USB 存储设备。 - USB 存储不可用 - USB 存储设备目前正忙,为确保正常下载此文件请在通知栏中确认关闭 USB 大容量存储。 - 在隐身模式中启用 Cookies - Adobe Flash - 手工 - 自动 - 联系我 - twitter.com/ACRDevelopment - 清除缓存 - 缓存已清除 - 书签导入成功 - 历史已清除 - Cookies 已清除 - 达到最大标签数 - 文本已复制到剪贴板 - 链接已复制到剪贴板 - 自定义 URL - 本地文件已被阻止加载 - 开源许可 - 搜索目标 - 拦截广告 - 重新提交表单 - 你想重新发送数据吗? - \n你想使用你的位置吗? - 允许 - 不允许 - 登录 - 用户名 - 密码 - 搜索建议 - 由 Google 提供支持 - 看起来你已经安装了 Orbot. 你想要使用 Tor 吗? - 请安装 Orbot 以便通过 Tor 全使用代理。 - - - 退出时清除 cookies - 退出时清除历史 - 默认 - 自定义 - 未标题的 - Mozilla Public License v. 2.0 - 免费软件 - Android 开源项目 - hpHosts 广告服务器列表 - 重新打开老标签 - 渲染模式 - 反转 - 灰度 - 反转灰度 - 普通 - 与 Google 同步历史 - 文件选择器 - NetCipher - GNU Lesser General Public License - 导出书签到备份文件 - 从备份文件导入书签 - 书签已导出到 - 书签设置 - 无法从文件导入书签 - 选择一个文件 - 关闭所有标签 - 关闭标签 - 启用色彩模式 - 使用深色主题 - 反转颜色 - jsoup: Java HTML 解析器 - 正在加载… - 无法从页面上加载任何东西。 - MIT 许可 - 阅读模式 - 关于 - 关于版本,作者和许可的详细信息。 - 显示设置 - 常规设置 - - 域 (默认) - URL - 标题 - - 隐私设置 - 标签 - 阻止第三方 Cookies - URL 框内容 - - + + + 闪电 + 新建标签 + 分享页面 + 历史记录 + 书签列表 + 添加书签 + 复制链接 + 前进 + 浏览器设置 + 允许站点访问地理位置 + 保存密码 + User Agent + 启用 Adobe Flash + 设置首页 + 启用全屏模式 + 启用 JavaScript + 下载目录 + 高级设置 + Apache License 2.0 + 当前版本 + 退出时清理缓存 + 启用文本重排 + 屏蔽网页图像 + 允许站点打开新窗口 + 启用 Cookies + 从浏览器中导入书签 + 页面文本尺寸 + (推荐) + 搜索引擎 + 搜索 + 使用宽视图 + 使用概览模式载入页面 + 启动时恢复丢失页面 + (尚未检测到已支持原生浏览器) + (已检测到受支持的原生浏览器) + 浏览时隐藏状态栏 + 清除浏览器 Cookies + 清除浏览历史 + 您希望对此图片进行什么操作? + 下载 + 打开 + 您希望对此链接进行什么操作? + 分享此页面 + 请问您要如何处理此书签? + 删除 + 空白页 + 默认 UA + 桌面访问 + 移动设备 + 自定义 UA + 搜索引擎 + 确认 + 您是否需要下载此文件? + 取消 + 警告 + "未检测到您的设备中安装了 Adobe Flash Player,请先安装 Adobe Flash Player 后再启用此选项。" + User Agent + 下载目录 + 自定义主页 + 网页 + 清除历史记录 + 清除 Cookies + 您是否确认清除所有浏览器历史记录? + 您是否确认清除所有浏览器历史记录 Cookies? + 确认 + 取消 + 文本大小 + 最大 + 较大 + 普通 + 较小 + 最小 + 错误 + 暂未检测到任何可导入书签的浏览器 + 标题 + URL + 编辑书签 + 编辑 + 新建隐身标签 + 默认页面 + 返回 + 页内搜索 + 正在开始下载… + 仅可下载以 \"http\" 或 \"https\" 开头的链接地址 + 未发现 SDCard + 为正常下载此文件需要 USB 存储设备。 + USB 存储不可用 + USB 存储设备目前正忙,为确保正常下载此文件请在通知栏中确认关闭 USB 大容量存储。 + 在隐身模式中启用 Cookies + Adobe Flash + 手工 + 自动 + 联系我 + twitter.com/ACRDevelopment + 清除缓存 + 缓存已清除 + 书签导入成功 + 历史已清除 + Cookies 已清除 + 达到最大标签数 + 文本已复制到剪贴板 + 链接已复制到剪贴板 + 自定义 URL + 本地文件已被阻止加载 + 开源许可 + 搜索目标 + 拦截广告 + 重新提交表单 + 你想重新发送数据吗? + \n你想使用你的位置吗? + 允许 + 不允许 + 登录 + 用户名 + 密码 + 搜索建议 + 由 Google 提供支持 + 看起来你已经安装了 Orbot. 你想要使用 Tor 吗? + 请安装 Orbot 以便通过 Tor 全使用代理。 + + + 退出时清除 cookies + 退出时清除历史 + 默认 + 自定义 + 未标题的 + Mozilla Public License v. 2.0 + 免费软件 + Android 开源项目 + hpHosts 广告服务器列表 + 重新打开老标签 + 渲染模式 + 反转 + 灰度 + 反转灰度 + 普通 + 与 Google 同步历史 + 文件选择器 + NetCipher + GNU Lesser General Public License + 导出书签到备份文件 + 从备份文件导入书签 + 书签已导出到 + 书签设置 + 无法从文件导入书签 + 选择一个文件 + 关闭所有标签 + 关闭标签 + 启用色彩模式 + 使用深色主题 + 反转颜色 + jsoup: Java HTML 解析器 + 正在加载… + 无法从页面上加载任何东西。 + MIT 许可 + 阅读模式 + 关于 + 关于版本,作者和许可的详细信息。 + 显示设置 + 常规设置 + + 域 (默认) + URL + 标题 + + 隐私设置 + 标签 + 阻止第三方 Cookies + URL 框内容 + + + 支持的浏览器 + 股票浏览器 + 你想对这条历史记录执行什么操作? + 非法的URL,不能下载 + 不能下载到指定的位置 + + 这个站点连接不安全:\n%1$s\n仍然执行? + 证书日期无效 + 证书过期 + 证书域名不匹配 + 证书无效 + 证书暂时无效 + 不受信任的证书 + + 由DuckDuckGo提供技术支持 + 关闭搜索建议 + HTTP代理 + + + Orbot + I2P + 手动 + + 手动代理 + 主机: + 端口: + 看上去你已经安装I2P。是否希望使用I2P? + I2P没有运行 + I2P隧道没有准备好。 + 增加对比度 + 关闭其他标签 + Snacktory + 文本编码 + + 应用风格 + 明亮主题 + 黑暗主题 (AMOLED) + 文件夹名 + 文件夹 + 重命名 + 重命名文件夹 + 你想对这个个文件夹做什么操作? + 清除Web存储 + 退出时清除Web存储 + 已经清除Web存储 + HOSTS文件禁止广告来源 + 禁止广告设置 + 在导航抽屉显示标签 + 书签和标签抽屉交换位置 + 请求 \'Do Not Track\' + 清除标志头 + 添加到主屏 + 快捷方式添加到主屏 + 删除所有书签 + + FAQ + 常见问题 + + + 调试设置 + LeakCanary + 重启APP以使设置生效 + + + 在新标签打开 + 在后台标签打开 + 在匿名标签打开 + 删除书签 + 编辑书签 + 从历史删除 + 下载图片 + 复制链接 + 重命名文件夹 + 删除文件夹 + 关闭浏览器 + diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 5472476c7..7b2c221ac 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,95 +1,249 @@ - - - Lightning - 新分頁 - 分享 - 記錄 - 書籤 - 新增書籤 - 複製連結 - 下一頁 - 設定 - 存取地理資訊 - 儲存密碼 - - User Agent - 啟用 Adobe Flash - 首頁 - 全螢幕模式 - 啟用 JavaScript - 下載資料夾位置 - 進階設定 - Apache License 2.0 - 應用程式版本 - 離開時清除快取 - 啟動文字自動重新排列 - 封鎖圖片 - 允許網站開啟新分頁 - 啟用 Cookies - 從其它瀏覽器匯入書籤 - 文字尺寸 - (建議) - 搜尋引擎 - 搜尋 - 自定 URL - 使用寬廣 viewport - 與總覽模式載入網頁 - 重新啟動時還原分頁 - (沒有偵測到支援的內建瀏覽器) - (偵測到支援的內建瀏覽器) - 與瀏覽時隱藏狀態列 - 清除瀏覽器 cookies - Clear Browser History - 您想要對這張圖片執行什麼動作? - 下載 - 開啟 - 您想要對這個連結執行什麼動作? - 分享連結 - 您想要對這個書籤執行什麼動作? - 刪除 - 空白頁 - 預設 - 桌上型電腦 - 行動裝置 - 自定 - 搜尋引擎 - OK - 您是否想要下載這個檔案? - 取消 - 警告 - 沒有偵測到 Adobe Flash Player。\n請安裝 Flash Player。 - User Agent - 下載資料夾位置 - 自定首頁 - 網頁 - 清除記錄 - 清除 Cookies - 您是否要清除所有瀏覽記錄? - 您是否要清除所有 cookies? - - - 文字尺寸 - 最大 - - 普通 - - 最小 - 錯誤 - 沒有偵測到任何瀏覽器以匯入書籤。 - 標題 - URL - 編輯書籤 - 編輯 - 新無痕式分頁 - 預設 - 上一頁 - 於頁面中搜尋 - 開始下載\u2026 - 儘可下載 \"http\" 或是 \"https\" URLs. - 沒有偵測到 SD 記憶卡 - 若要下載檔案,USB 儲存裝置是必須的。 - USB 儲存裝置無法使用 - 儲存裝置忙碌中。若是要下載檔案,請停止掛載 USB 儲存裝置。 - 預設 - 自定 - + + + 閃電 + 新建標籤 + 分享頁面 + 歷史記錄 + 書簽列表 + 添加書簽 + 複製鏈接 + 前進 + 瀏覽器設置 + 允許站點訪問地理位置 + 保存密碼 + User Agent + 啟用 Adobe Flash + 設置首頁 + 啟用全屏模式 + 啟用 JavaScript + 下載目錄 + 高級設置 + Apache License 2.0 + 當前版本 + 退出時清理緩存 + 啟用文本重排 + 遮罩網頁圖像 + 允許站點打開新窗口 + 啟用 Cookies + 從瀏覽器中導入書簽 + 頁面文本尺寸 + (推薦) + 搜索引擎 + 搜索 + 使用寬視圖 + 使用概覽模式載入頁面 + 啟動時恢復丟失頁面 + (尚未檢測到已支持原生瀏覽器) + (已檢測到受支持的原生瀏覽器) + 瀏覽時隱藏狀態欄 + 清除瀏覽器 Cookies + 清除瀏覽歷史 + 您希望對此圖片進行什麼操作? + 下載 + 打開 + 您希望對此鏈接進行什麼操作? + 分享此頁面 + 請問您要如何處理此書簽? + 刪除 + 空白頁 + 默認 UA + 桌面訪問 + 移動設備 + 自定義 UA + 搜索引擎 + 確認 + 您是否需要下載此檔? + 取消 + 警告 + "未檢測到您的設備中安裝了 Adobe Flash Player,請先安裝 Adobe Flash Player 後再啟用此選項。" + User Agent + 下載目錄 + 自定義主頁 + 網頁 + 清除歷史記錄 + 清除 Cookies + 您是否確認清除所有瀏覽器歷史記錄? + 您是否確認清除所有瀏覽器歷史記錄 Cookies? + 確認 + 取消 + 文本大小 + 最大 + 較大 + 普通 + 較小 + 最小 + 錯誤 + 暫未檢測到任何可導入書簽的瀏覽器 + 標題 + URL + 編輯書簽 + 編輯 + 新建隱身標籤 + 默認頁面 + 返回 + 頁內搜索 + 正在開始下載… + 僅可下載以 \"http\" 或 \"https\" 開頭的鏈接地址 + 未發現 SDCard + 為正常下載此檔需要 USB 存儲設備。 + USB 存儲不可用 + USB 存儲設備目前正忙,為確保正常下載此檔請在通知欄中確認關閉 USB 大容量存儲。 + 在隱身模式中啟用 Cookies + Adobe Flash + 手工 + 自動 + 聯繫我 + twitter.com/ACRDevelopment + 清除緩存 + 緩存已清除 + 書簽導入成功 + 歷史已清除 + Cookies 已清除 + 達到最大標籤數 + 文本已複製到剪貼板 + 鏈接已複製到剪貼板 + 自定義 URL + 本地檔已被阻止加載 + 開源許可 + 搜索目標 + 攔截廣告 + 重新提交表單 + 你想重新發送數據嗎? + \n你想使用你的位置嗎? + 允許 + 不允許 + 登錄 + 用戶名 + 密碼 + 搜索建議 + 由 Google 提供支持 + 看起來你已經安裝了 Orbot. 你想要使用 Tor 嗎? + 請安裝 Orbot 以便通過 Tor 全使用代理。 + + + 退出時清除 cookies + 退出時清除歷史 + 默認 + 自定義 + 未標題的 + Mozilla Public License v. 2.0 + 免費軟體 + Android 開源專案 + hpHosts 廣告伺服器列表 + 重新打開老標籤 + 渲染模式 + 反轉 + 灰度 + 反轉灰度 + 普通 + 與 Google 同步歷史 + 檔選擇器 + NetCipher + GNU Lesser General Public License + 導出書簽到備份檔 + 從備份檔導入書簽 + 書簽已導出到 + 書簽設置 + 無法從檔導入書簽 + 選擇一個檔 + 關閉所有標籤 + 關閉標籤 + 啟用色彩模式 + 使用深色主題 + 反轉顏色 + jsoup: Java HTML 解析器 + 正在加載… + 無法從頁面上加載任何東西。 + MIT 許可 + 閱讀模式 + 關於 + 關於版本,作者和許可的詳細資訊。 + 顯示設置 + 常規設置 + + 域 (默認) + URL + 標題 + + 隱私設置 + 標籤 + 阻止第三方 Cookies + URL 框內容 + + + 支持的瀏覽器 + 股票瀏覽器 + 你想對這條歷史記錄執行什麼操作? + 非法的URL,不能下載 + 不能下載到指定的位置 + + 這個站點連接不安全:\n%1$s\n仍然執行? + 證書日期無效 + 證書過期 + 證書功能變數名稱不匹配 + 證書無效 + 證書暫時無效 + 不受信任的證書 + + 由DuckDuckGo提供技術支持 + 關閉搜索建議 + HTTP代理 + + + Orbot + I2P + 手動 + + 手動代理 + 主機: + 端口: + 看上去你已經安裝I2P。是否希望使用I2P? + I2P沒有運行 + I2P隧道沒有準備好。 + 增加對比度 + 關閉其他標籤 + Snacktory + 文本編碼 + + 應用風格 + 明亮主題 + 黑暗主題 (AMOLED) + 檔夾名 + 檔夾 + 重命名 + 重命名檔夾 + 你想對這個個檔夾做什麼操作? + 清除Web存儲 + 退出時清除Web存儲 + 已經清除Web存儲 + HOSTS檔禁止廣告來源 + 禁止廣告設置 + 在導航抽屜顯示標籤 + 書簽和標籤抽屜交換位置 + 請求 \'Do Not Track\' + 清除標誌頭 + 添加到主屏 + 快捷方式添加到主屏 + 刪除所有書簽 + + FAQ + 常見問題 + + + 調試設置 + LeakCanary + 重啟APP以使設置生效 + + + 在新標籤打開 + 在後臺標籤打開 + 在匿名標籤打開 + 刪除書簽 + 編輯書簽 + 從歷史刪除 + 下載圖片 + 複製鏈接 + 重命名檔夾 + 刪除檔夾 + 關閉瀏覽器 + diff --git a/values-zh-rCN/strings.xml b/values-zh-rCN/strings.xml deleted file mode 100644 index a8c0bb982..000000000 --- a/values-zh-rCN/strings.xml +++ /dev/null @@ -1,249 +0,0 @@ - - - 闪电 - 新建标签 - 分享页面 - 历史记录 - 书签列表 - 添加书签 - 复制链接 - 前进 - 浏览器设置 - 允许站点访问地理位置 - 保存密码 - User Agent - 启用 Adobe Flash - 设置首页 - 启用全屏模式 - 启用 JavaScript - 下载目录 - 高级设置 - Apache License 2.0 - 当前版本 - 退出时清理缓存 - 启用文本重排 - 屏蔽网页图像 - 允许站点打开新窗口 - 启用 Cookies - 从浏览器中导入书签 - 页面文本尺寸 - (推荐) - 搜索引擎 - 搜索 - 使用宽视图 - 使用概览模式载入页面 - 启动时恢复丢失页面 - (尚未检测到已支持原生浏览器) - (已检测到受支持的原生浏览器) - 浏览时隐藏状态栏 - 清除浏览器 Cookies - 清除浏览历史 - 您希望对此图片进行什么操作? - 下载 - 打开 - 您希望对此链接进行什么操作? - 分享此页面 - 请问您要如何处理此书签? - 删除 - 空白页 - 默认 UA - 桌面访问 - 移动设备 - 自定义 UA - 搜索引擎 - 确认 - 您是否需要下载此文件? - 取消 - 警告 - "未检测到您的设备中安装了 Adobe Flash Player,请先安装 Adobe Flash Player 后再启用此选项。" - User Agent - 下载目录 - 自定义主页 - 网页 - 清除历史记录 - 清除 Cookies - 您是否确认清除所有浏览器历史记录? - 您是否确认清除所有浏览器历史记录 Cookies? - 确认 - 取消 - 文本大小 - 最大 - 较大 - 普通 - 较小 - 最小 - 错误 - 暂未检测到任何可导入书签的浏览器 - 标题 - URL - 编辑书签 - 编辑 - 新建隐身标签 - 默认页面 - 返回 - 页内搜索 - 正在开始下载… - 仅可下载以 \"http\" 或 \"https\" 开头的链接地址 - 未发现 SDCard - 为正常下载此文件需要 USB 存储设备。 - USB 存储不可用 - USB 存储设备目前正忙,为确保正常下载此文件请在通知栏中确认关闭 USB 大容量存储。 - 在隐身模式中启用 Cookies - Adobe Flash - 手工 - 自动 - 联系我 - twitter.com/ACRDevelopment - 清除缓存 - 缓存已清除 - 书签导入成功 - 历史已清除 - Cookies 已清除 - 达到最大标签数 - 文本已复制到剪贴板 - 链接已复制到剪贴板 - 自定义 URL - 本地文件已被阻止加载 - 开源许可 - 搜索目标 - 拦截广告 - 重新提交表单 - 你想重新发送数据吗? - \n你想使用你的位置吗? - 允许 - 不允许 - 登录 - 用户名 - 密码 - 搜索建议 - 由 Google 提供支持 - 看起来你已经安装了 Orbot. 你想要使用 Tor 吗? - 请安装 Orbot 以便通过 Tor 全使用代理。 - - - 退出时清除 cookies - 退出时清除历史 - 默认 - 自定义 - 未标题的 - Mozilla Public License v. 2.0 - 免费软件 - Android 开源项目 - hpHosts 广告服务器列表 - 重新打开老标签 - 渲染模式 - 反转 - 灰度 - 反转灰度 - 普通 - 与 Google 同步历史 - 文件选择器 - NetCipher - GNU Lesser General Public License - 导出书签到备份文件 - 从备份文件导入书签 - 书签已导出到 - 书签设置 - 无法从文件导入书签 - 选择一个文件 - 关闭所有标签 - 关闭标签 - 启用色彩模式 - 使用深色主题 - 反转颜色 - jsoup: Java HTML 解析器 - 正在加载… - 无法从页面上加载任何东西。 - MIT 许可 - 阅读模式 - 关于 - 关于版本,作者和许可的详细信息。 - 显示设置 - 常规设置 - - 域 (默认) - URL - 标题 - - 隐私设置 - 标签 - 阻止第三方 Cookies - URL 框内容 - - - 支持的浏览器 - 股票浏览器 - 你想对这条历史记录执行什么操作? - 非法的URL,不能下载 - 不能下载到指定的位置 - - 这个站点连接不安全:\n%1$s\n仍然执行? - 证书日期无效 - 证书过期 - 证书域名不匹配 - 证书无效 - 证书暂时无效 - 不受信任的证书 - - 由DuckDuckGo提供技术支持 - 关闭搜索建议 - HTTP代理 - - - Orbot - I2P - 手动 - - 手动代理 - 主机: - 端口: - 看上去你已经安装I2P。是否希望使用I2P? - I2P没有运行 - I2P隧道没有准备好。 - 增加对比度 - 关闭其他标签 - Snacktory - 文本编码 - - 应用风格 - 明亮主题 - 黑暗主题 (AMOLED) - 文件夹名 - 文件夹 - 重命名 - 重命名文件夹 - 你想对这个个文件夹做什么操作? - 清除Web存储 - 退出时清除Web存储 - 已经清除Web存储 - HOSTS文件禁止广告来源 - 禁止广告设置 - 在导航抽屉显示标签 - 书签和标签抽屉交换位置 - 请求 \'Do Not Track\' - 清除标志头 - 添加到主屏 - 快捷方式添加到主屏 - 删除所有书签 - - FAQ - 常见问题 - - - 调试设置 - LeakCanary - 重启APP以使设置生效 - - - 在新标签打开 - 在后台标签打开 - 在匿名标签打开 - 删除书签 - 编辑书签 - 从历史删除 - 下载图片 - 复制链接 - 重命名文件夹 - 删除文件夹 - 关闭浏览器 - diff --git a/values-zh-rTW/strings.xml b/values-zh-rTW/strings.xml deleted file mode 100644 index 7b2c221ac..000000000 --- a/values-zh-rTW/strings.xml +++ /dev/null @@ -1,249 +0,0 @@ - - - 閃電 - 新建標籤 - 分享頁面 - 歷史記錄 - 書簽列表 - 添加書簽 - 複製鏈接 - 前進 - 瀏覽器設置 - 允許站點訪問地理位置 - 保存密碼 - User Agent - 啟用 Adobe Flash - 設置首頁 - 啟用全屏模式 - 啟用 JavaScript - 下載目錄 - 高級設置 - Apache License 2.0 - 當前版本 - 退出時清理緩存 - 啟用文本重排 - 遮罩網頁圖像 - 允許站點打開新窗口 - 啟用 Cookies - 從瀏覽器中導入書簽 - 頁面文本尺寸 - (推薦) - 搜索引擎 - 搜索 - 使用寬視圖 - 使用概覽模式載入頁面 - 啟動時恢復丟失頁面 - (尚未檢測到已支持原生瀏覽器) - (已檢測到受支持的原生瀏覽器) - 瀏覽時隱藏狀態欄 - 清除瀏覽器 Cookies - 清除瀏覽歷史 - 您希望對此圖片進行什麼操作? - 下載 - 打開 - 您希望對此鏈接進行什麼操作? - 分享此頁面 - 請問您要如何處理此書簽? - 刪除 - 空白頁 - 默認 UA - 桌面訪問 - 移動設備 - 自定義 UA - 搜索引擎 - 確認 - 您是否需要下載此檔? - 取消 - 警告 - "未檢測到您的設備中安裝了 Adobe Flash Player,請先安裝 Adobe Flash Player 後再啟用此選項。" - User Agent - 下載目錄 - 自定義主頁 - 網頁 - 清除歷史記錄 - 清除 Cookies - 您是否確認清除所有瀏覽器歷史記錄? - 您是否確認清除所有瀏覽器歷史記錄 Cookies? - 確認 - 取消 - 文本大小 - 最大 - 較大 - 普通 - 較小 - 最小 - 錯誤 - 暫未檢測到任何可導入書簽的瀏覽器 - 標題 - URL - 編輯書簽 - 編輯 - 新建隱身標籤 - 默認頁面 - 返回 - 頁內搜索 - 正在開始下載… - 僅可下載以 \"http\" 或 \"https\" 開頭的鏈接地址 - 未發現 SDCard - 為正常下載此檔需要 USB 存儲設備。 - USB 存儲不可用 - USB 存儲設備目前正忙,為確保正常下載此檔請在通知欄中確認關閉 USB 大容量存儲。 - 在隱身模式中啟用 Cookies - Adobe Flash - 手工 - 自動 - 聯繫我 - twitter.com/ACRDevelopment - 清除緩存 - 緩存已清除 - 書簽導入成功 - 歷史已清除 - Cookies 已清除 - 達到最大標籤數 - 文本已複製到剪貼板 - 鏈接已複製到剪貼板 - 自定義 URL - 本地檔已被阻止加載 - 開源許可 - 搜索目標 - 攔截廣告 - 重新提交表單 - 你想重新發送數據嗎? - \n你想使用你的位置嗎? - 允許 - 不允許 - 登錄 - 用戶名 - 密碼 - 搜索建議 - 由 Google 提供支持 - 看起來你已經安裝了 Orbot. 你想要使用 Tor 嗎? - 請安裝 Orbot 以便通過 Tor 全使用代理。 - - - 退出時清除 cookies - 退出時清除歷史 - 默認 - 自定義 - 未標題的 - Mozilla Public License v. 2.0 - 免費軟體 - Android 開源專案 - hpHosts 廣告伺服器列表 - 重新打開老標籤 - 渲染模式 - 反轉 - 灰度 - 反轉灰度 - 普通 - 與 Google 同步歷史 - 檔選擇器 - NetCipher - GNU Lesser General Public License - 導出書簽到備份檔 - 從備份檔導入書簽 - 書簽已導出到 - 書簽設置 - 無法從檔導入書簽 - 選擇一個檔 - 關閉所有標籤 - 關閉標籤 - 啟用色彩模式 - 使用深色主題 - 反轉顏色 - jsoup: Java HTML 解析器 - 正在加載… - 無法從頁面上加載任何東西。 - MIT 許可 - 閱讀模式 - 關於 - 關於版本,作者和許可的詳細資訊。 - 顯示設置 - 常規設置 - - 域 (默認) - URL - 標題 - - 隱私設置 - 標籤 - 阻止第三方 Cookies - URL 框內容 - - - 支持的瀏覽器 - 股票瀏覽器 - 你想對這條歷史記錄執行什麼操作? - 非法的URL,不能下載 - 不能下載到指定的位置 - - 這個站點連接不安全:\n%1$s\n仍然執行? - 證書日期無效 - 證書過期 - 證書功能變數名稱不匹配 - 證書無效 - 證書暫時無效 - 不受信任的證書 - - 由DuckDuckGo提供技術支持 - 關閉搜索建議 - HTTP代理 - - - Orbot - I2P - 手動 - - 手動代理 - 主機: - 端口: - 看上去你已經安裝I2P。是否希望使用I2P? - I2P沒有運行 - I2P隧道沒有準備好。 - 增加對比度 - 關閉其他標籤 - Snacktory - 文本編碼 - - 應用風格 - 明亮主題 - 黑暗主題 (AMOLED) - 檔夾名 - 檔夾 - 重命名 - 重命名檔夾 - 你想對這個個檔夾做什麼操作? - 清除Web存儲 - 退出時清除Web存儲 - 已經清除Web存儲 - HOSTS檔禁止廣告來源 - 禁止廣告設置 - 在導航抽屜顯示標籤 - 書簽和標籤抽屜交換位置 - 請求 \'Do Not Track\' - 清除標誌頭 - 添加到主屏 - 快捷方式添加到主屏 - 刪除所有書簽 - - FAQ - 常見問題 - - - 調試設置 - LeakCanary - 重啟APP以使設置生效 - - - 在新標籤打開 - 在後臺標籤打開 - 在匿名標籤打開 - 刪除書簽 - 編輯書簽 - 從歷史刪除 - 下載圖片 - 複製鏈接 - 重命名檔夾 - 刪除檔夾 - 關閉瀏覽器 - From 96cd20a0b3a48b3936125db409e3446b5fb693d5 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 18 Mar 2017 22:56:30 -0400 Subject: [PATCH 033/181] Updating jsoup and leak canary --- app/build.gradle | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e942159f5..c7f812cef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,21 +66,23 @@ dexcount { dependencies { // support libraries - compile 'com.android.support:palette-v7:25.2.0' - compile 'com.android.support:appcompat-v7:25.2.0' - compile 'com.android.support:design:25.2.0' - compile 'com.android.support:recyclerview-v7:25.2.0' - compile 'com.android.support:support-v4:25.2.0' + def supportLibVersion = '25.2.0' + compile "com.android.support:palette-v7:$supportLibVersion" + compile "com.android.support:appcompat-v7:$supportLibVersion" + compile "com.android.support:design:$supportLibVersion" + compile "com.android.support:recyclerview-v7:$supportLibVersion" + compile "com.android.support:support-v4:$supportLibVersion" // html parsing for reading mode - compile 'org.jsoup:jsoup:1.9.2' + compile 'org.jsoup:jsoup:1.10.2' // event bus compile 'com.squareup:otto:1.3.8' // dependency injection - compile 'com.google.dagger:dagger:2.0.2' - apt 'com.google.dagger:dagger-compiler:2.0.2' + def daggerVersion = '2.0.2' + compile "com.google.dagger:dagger:$daggerVersion" + apt "com.google.dagger:dagger-compiler:$daggerVersion" provided 'javax.annotation:jsr250-api:1.0' // view binding @@ -93,14 +95,16 @@ dependencies { compile 'net.i2p.android:client:0.8' // tor proxy - compile 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1' - compile 'info.guardianproject.netcipher:netcipher-webkit:2.0.0-alpha1' + def netcipherVersion = '2.0.0-alpha1' + compile "info.guardianproject.netcipher:netcipher:$netcipherVersion" + compile "info.guardianproject.netcipher:netcipher-webkit:$netcipherVersion" compile project(':bonsai') compile project(':animated-progress-bar') // memory leak analysis - debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4' - releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4' + def leakCanaryVersion = '1.5' + debugCompile "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion" + releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion" } \ No newline at end of file From 1042ddc96c62795cff91daef8fe1a119fcc0609f Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 18 Mar 2017 23:23:12 -0400 Subject: [PATCH 034/181] removed netcipher submodule correctly --- external/netcipher | 1 - 1 file changed, 1 deletion(-) delete mode 160000 external/netcipher diff --git a/external/netcipher b/external/netcipher deleted file mode 160000 index 7727f0402..000000000 --- a/external/netcipher +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7727f0402ce43489e5ebf4ee42dcacddad37c491 From ccb82d9a73fa5eb19463c2c64d7fdb29d69c80bf Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 19 Mar 2017 08:14:30 -0400 Subject: [PATCH 035/181] Updating travis build configuration --- .travis.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1fc5f7032..b929ee7ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,8 @@ jdk: android: components: - tools - - build-tools-24.0.3 - - build-tools-23.0.3 - - build-tools-22.0.1 - - android-24 - - android-23 - - android-22 + - build-tools-25.0.2 + - android-25 - extra-android-support - extra-android-m2repository licenses: From e1ffe3b7fbfffcca6c127c9e9245bb9a701d12c2 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 19 Mar 2017 08:43:07 -0400 Subject: [PATCH 036/181] Giving gradlew proper privileges --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From 54115b55b021587c7fbf6c5872acdc6f23f47c16 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 20 Mar 2017 19:41:22 -0400 Subject: [PATCH 037/181] removing animated progress bar submodule --- .gitmodules | 3 --- AnimatedProgressBar | 1 - app/build.gradle | 2 +- settings.gradle | 4 +--- 4 files changed, 2 insertions(+), 8 deletions(-) delete mode 160000 AnimatedProgressBar diff --git a/.gitmodules b/.gitmodules index 75ddd20e9..e128a6e37 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "Bonsai"] path = Bonsai url = https://github.com/anthonycr/Bonsai.git -[submodule "AnimatedProgressBar"] - path = AnimatedProgressBar - url = https://github.com/anthonycr/AnimatedProgressBar.git diff --git a/AnimatedProgressBar b/AnimatedProgressBar deleted file mode 160000 index c23593345..000000000 --- a/AnimatedProgressBar +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c23593345996115c44305aab9780a7d4c307896a diff --git a/app/build.gradle b/app/build.gradle index c7f812cef..84b46c487 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -101,7 +101,7 @@ dependencies { compile project(':bonsai') - compile project(':animated-progress-bar') + compile 'com.anthonycr.progress:animated-progress:1.0' // memory leak analysis def leakCanaryVersion = '1.5' diff --git a/settings.gradle b/settings.gradle index 440e7fcf1..595cbb6c4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,4 @@ include ':app' include ':bonsai' -include ':animated-progress-bar' -project(':bonsai').projectDir = new File(rootProject.projectDir, 'Bonsai/library') -project(':animated-progress-bar').projectDir = new File(rootProject.projectDir, 'AnimatedProgressBar/library') \ No newline at end of file +project(':bonsai').projectDir = new File(rootProject.projectDir, 'Bonsai/library') \ No newline at end of file From 11d0d221a3d4c09b1817a308d2425535941b609f Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 20 Mar 2017 19:42:53 -0400 Subject: [PATCH 038/181] removing bonsai submodule --- .gitmodules | 3 --- Bonsai | 1 - app/build.gradle | 2 +- settings.gradle | 5 +---- 4 files changed, 2 insertions(+), 9 deletions(-) delete mode 160000 Bonsai diff --git a/.gitmodules b/.gitmodules index e128a6e37..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "Bonsai"] - path = Bonsai - url = https://github.com/anthonycr/Bonsai.git diff --git a/Bonsai b/Bonsai deleted file mode 160000 index d47c9626c..000000000 --- a/Bonsai +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d47c9626c2583b09a1102a980186f9ca51bc4e29 diff --git a/app/build.gradle b/app/build.gradle index 84b46c487..2b1e54ed0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,7 +99,7 @@ dependencies { compile "info.guardianproject.netcipher:netcipher:$netcipherVersion" compile "info.guardianproject.netcipher:netcipher-webkit:$netcipherVersion" - compile project(':bonsai') + compile 'com.anthonycr.bonsai:bonsai:1.0' compile 'com.anthonycr.progress:animated-progress:1.0' diff --git a/settings.gradle b/settings.gradle index 595cbb6c4..9d495b34f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1 @@ -include ':app' -include ':bonsai' - -project(':bonsai').projectDir = new File(rootProject.projectDir, 'Bonsai/library') \ No newline at end of file +include ':app' \ No newline at end of file From 9adc86ea472bae846c0e2de1e08a0d5e137087a7 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Mon, 20 Mar 2017 19:58:59 -0400 Subject: [PATCH 039/181] Fix formatting of redme --- README.md | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 411e2cc30..d8b0384f4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -#Lightning Browser [![Build Status](https://travis-ci.org/anthonycr/Lightning-Browser.svg?branch=master)](https://travis-ci.org/anthonycr/Lightning-Browser) -####Speed, Simplicity, Security -#![](ic_launcher_small.png) -####Download +# Lightning Browser [![Build Status](https://travis-ci.org/anthonycr/Lightning-Browser.svg?branch=master)](https://travis-ci.org/anthonycr/Lightning-Browser) + +#### Speed, Simplicity, Security +![](ic_launcher_small.png) + +#### Download * [Download APK from here](https://github.com/anthonycr/Lightning-Browser/releases) * [Download from F-Droid](https://f-droid.org/repository/browse/?fdfilter=lightning&fdid=acr.browser.lightning) @@ -10,13 +12,13 @@ * [Download Paid from Google Play](https://play.google.com/store/apps/details?id=acr.browser.lightning) -####Master Branch +#### Master Branch * [![Build Status](https://travis-ci.org/anthonycr/Lightning-Browser.svg?branch=master)](https://travis-ci.org/anthonycr/Lightning-Browser) -####Dev Branch +#### Dev Branch * [![Build Status](https://travis-ci.org/anthonycr/Lightning-Browser.svg?branch=dev)](https://travis-ci.org/anthonycr/Lightning-Browser) -####Features +#### Features * Bookmarks * History @@ -33,7 +35,7 @@ * Orbot Proxy support and I2P support -####Permissions +#### Permissions * ````INTERNET````: For accessing the web @@ -45,11 +47,11 @@ * ````ACCESS_NETWORK_STATE````: Required for the WebView to function by some OEM versions of WebKit -####The Code +#### The Code * Please contribute code back if you can. The code isn't perfect. * Please add translations/translation fixes as you see need -####Contributing +#### Contributing * [The Trello Board](https://trello.com/b/Gwjx8MC3/lightning-browser) * Contributions are always welcome * If you want a feature and can code, feel free to fork and add the change yourself and make a pull request @@ -60,15 +62,15 @@ * Prefix static member variables with 's' * Use 4 spaces instead of a tab (\t) -####Setting Up the Project +#### Setting Up the Project Due to the inclusion of the netcipher library for Orbot proxy support, importing the project will show you some errors. To fix this, first run the following git command in your project folder (NOTE: You need the git command installed to use this): -```` +``` git submodule update --init --recursive -```` +``` Once you run that command, the IDE should automatically import netcipher and a couple submodules in as separate projects. Than you need to set the netcipher library project as a libary of the browser project however your IDE makes you do that. Once those steps are done, the project should be all set up and ready to go. [Please read this tutorial for more information on git submodules](http://www.vogella.com/tutorials/Git/article.html#submodules) -####License -```` +#### License +``` Copyright 2014 Anthony Restaino Lightning Browser @@ -78,7 +80,4 @@ Lightning Browser was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/ -```` -This means that you MUST provide attribution in your application to Lightning Browser for the use of this code. The way you can do this is to provide a separate screen in settings showing what open-source libraries and/or apps (this one) you used in your application. You must also open-source any files that you use from this repository and if you use any code at all from this repository, the file you put it in must be open-sourced according the the MPL 2.0 license. To put it simply, if you create a fork of this browser, your browser must be open-source, no exceptions. The only way to avoid open-sourcing a file is to completely write all the code yourself and to not use any code from Lightning. This is in order to provide a way for companies to utilize the code without making private server code public. For further explanation, please email me, or seek legal counsel :-P - -If you have any questions regarding the open-source license, please contact me at [anthonyrestaino11@gmail.com](mailto:anthonyrestaino11@gmail.com) +``` From e26bd61c403948edc497a2b8f77700113ce37d64 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Tue, 21 Mar 2017 22:06:19 -0400 Subject: [PATCH 040/181] Update support library version (#542) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 2b1e54ed0..f0f3227bf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,7 +66,7 @@ dexcount { dependencies { // support libraries - def supportLibVersion = '25.2.0' + def supportLibVersion = '25.3.0' compile "com.android.support:palette-v7:$supportLibVersion" compile "com.android.support:appcompat-v7:$supportLibVersion" compile "com.android.support:design:$supportLibVersion" From 8ef2f9099aef7ecbf11e6eacd107ba2f2ae7ce60 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Tue, 21 Mar 2017 22:07:45 -0400 Subject: [PATCH 041/181] Removing bit about submodules --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index d8b0384f4..43a7f3bab 100644 --- a/README.md +++ b/README.md @@ -62,13 +62,6 @@ * Prefix static member variables with 's' * Use 4 spaces instead of a tab (\t) -#### Setting Up the Project -Due to the inclusion of the netcipher library for Orbot proxy support, importing the project will show you some errors. To fix this, first run the following git command in your project folder (NOTE: You need the git command installed to use this): -``` -git submodule update --init --recursive -``` -Once you run that command, the IDE should automatically import netcipher and a couple submodules in as separate projects. Than you need to set the netcipher library project as a libary of the browser project however your IDE makes you do that. Once those steps are done, the project should be all set up and ready to go. [Please read this tutorial for more information on git submodules](http://www.vogella.com/tutorials/Git/article.html#submodules) - #### License ``` Copyright 2014 Anthony Restaino From 3e6c228bba986fbe630293eadab675c32a7c73ae Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 26 Mar 2017 20:08:07 -0400 Subject: [PATCH 042/181] Cleaning up lint warnings caused by appcompat upgrade --- .../lightning/activity/BrowserActivity.java | 1 - .../fragment/anim/HorizontalItemAnimator.java | 14 +++++++++-- .../fragment/anim/VerticalItemAnimator.java | 14 +++++++++-- .../browser/lightning/utils/ThemeUtils.java | 25 +++++++++++++------ .../browser/lightning/view/SearchView.java | 4 +-- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 87625e0cb..f4cd8e2f6 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -81,7 +81,6 @@ import android.widget.VideoView; import com.anthonycr.bonsai.Completable; -import com.anthonycr.bonsai.Observable; import com.anthonycr.bonsai.Schedulers; import com.anthonycr.grant.PermissionsManager; import com.anthonycr.progress.AnimatedProgressBar; diff --git a/app/src/main/java/acr/browser/lightning/fragment/anim/HorizontalItemAnimator.java b/app/src/main/java/acr/browser/lightning/fragment/anim/HorizontalItemAnimator.java index 197d36445..732cf9652 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/anim/HorizontalItemAnimator.java +++ b/app/src/main/java/acr/browser/lightning/fragment/anim/HorizontalItemAnimator.java @@ -15,7 +15,8 @@ */ package acr.browser.lightning.fragment.anim; -import android.support.v4.animation.AnimatorCompatHelper; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorCompat; import android.support.v4.view.ViewPropertyAnimatorListener; @@ -54,6 +55,8 @@ public class HorizontalItemAnimator extends SimpleItemAnimator { private final ArrayList mRemoveAnimations = new ArrayList<>(); private final ArrayList mChangeAnimations = new ArrayList<>(); + private TimeInterpolator mDefaultInterpolator; + private static class MoveInfo { public final ViewHolder holder; public final int fromX; @@ -544,10 +547,17 @@ public void endAnimation(ViewHolder item) { } private void resetAnimation(ViewHolder holder) { - AnimatorCompatHelper.clearInterpolator(holder.itemView); + clearInterpolator(holder.itemView); endAnimation(holder); } + private void clearInterpolator(View view) { + if (mDefaultInterpolator == null) { + mDefaultInterpolator = new ValueAnimator().getInterpolator(); + } + view.animate().setInterpolator(mDefaultInterpolator); + } + @Override public boolean isRunning() { return (!mPendingAdditions.isEmpty() || diff --git a/app/src/main/java/acr/browser/lightning/fragment/anim/VerticalItemAnimator.java b/app/src/main/java/acr/browser/lightning/fragment/anim/VerticalItemAnimator.java index 228637ad6..4a2f5eedb 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/anim/VerticalItemAnimator.java +++ b/app/src/main/java/acr/browser/lightning/fragment/anim/VerticalItemAnimator.java @@ -15,7 +15,8 @@ */ package acr.browser.lightning.fragment.anim; -import android.support.v4.animation.AnimatorCompatHelper; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorCompat; import android.support.v4.view.ViewPropertyAnimatorListener; @@ -54,6 +55,8 @@ public class VerticalItemAnimator extends SimpleItemAnimator { private final ArrayList mRemoveAnimations = new ArrayList<>(); private final ArrayList mChangeAnimations = new ArrayList<>(); + private TimeInterpolator mDefaultInterpolator; + private static class MoveInfo { public final ViewHolder holder; public final int fromX; @@ -543,10 +546,17 @@ public void endAnimation(ViewHolder item) { } private void resetAnimation(ViewHolder holder) { - AnimatorCompatHelper.clearInterpolator(holder.itemView); + clearInterpolator(holder.itemView); endAnimation(holder); } + private void clearInterpolator(View view) { + if (mDefaultInterpolator == null) { + mDefaultInterpolator = new ValueAnimator().getInterpolator(); + } + view.animate().setInterpolator(mDefaultInterpolator); + } + @Override public boolean isRunning() { return (!mPendingAdditions.isEmpty() || diff --git a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java index 593fc5fa4..9bbb0a029 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java @@ -12,13 +12,14 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; import android.support.annotation.AttrRes; import android.support.annotation.ColorInt; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; -import android.support.v7.widget.AppCompatDrawableManager; import android.util.TypedValue; import android.widget.ImageView; @@ -69,7 +70,15 @@ public static void themeImageView(@NonNull ImageView icon, @NonNull Context cont @NonNull private static Drawable getVectorDrawable(@NonNull Context context, int drawableId) { - Drawable drawable = AppCompatDrawableManager.get().getDrawable(context, drawableId); + Drawable drawable; + if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { + drawable = context.getDrawable(drawableId); + } else { + drawable = context.getResources().getDrawable(drawableId); + } + + Preconditions.checkNonNull(drawable); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { drawable = (DrawableCompat.wrap(drawable)).mutate(); } @@ -81,8 +90,8 @@ private static Drawable getVectorDrawable(@NonNull Context context, int drawable private static Bitmap getBitmapFromVectorDrawable(@NonNull Context context, int drawableId) { Drawable drawable = getVectorDrawable(context, drawableId); - Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), - drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), + Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); @@ -94,7 +103,8 @@ private static Bitmap getBitmapFromVectorDrawable(@NonNull Context context, int public static Bitmap getThemedBitmap(@NonNull Context context, @DrawableRes int res, boolean dark) { int color = dark ? getIconDarkThemeColor(context) : getIconLightThemeColor(context); Bitmap sourceBitmap = getBitmapFromVectorDrawable(context, res); - Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight(), Bitmap.Config.ARGB_8888); + Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight(), + Bitmap.Config.ARGB_8888); Paint p = new Paint(); ColorFilter filter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN); p.setColorFilter(filter); @@ -115,8 +125,9 @@ public static Drawable getThemedDrawable(@NonNull Context context, @DrawableRes @NonNull public static ColorDrawable getSelectedBackground(@NonNull Context context, boolean dark) { - @ColorInt final int color = (dark) ? ContextCompat.getColor(context, R.color.selected_dark) : - ContextCompat.getColor(context, R.color.selected_light); + @ColorInt final int color = + (dark) ? ContextCompat.getColor(context, R.color.selected_dark) : ContextCompat.getColor( + context, R.color.selected_light); return new ColorDrawable(color); } diff --git a/app/src/main/java/acr/browser/lightning/view/SearchView.java b/app/src/main/java/acr/browser/lightning/view/SearchView.java index 4551c051e..025fa0db9 100644 --- a/app/src/main/java/acr/browser/lightning/view/SearchView.java +++ b/app/src/main/java/acr/browser/lightning/view/SearchView.java @@ -2,12 +2,12 @@ import android.content.Context; import android.support.annotation.Nullable; +import android.support.v7.widget.AppCompatAutoCompleteTextView; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.ViewConfiguration; -import android.widget.AutoCompleteTextView; -public class SearchView extends AutoCompleteTextView { +public class SearchView extends AppCompatAutoCompleteTextView { public interface PreFocusListener { void onPreFocus(); From 826ca9118ede39695a9d5c0d9f7cecc88e114e04 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 26 Mar 2017 20:08:22 -0400 Subject: [PATCH 043/181] Fixing nullable problems --- .../java/acr/browser/lightning/database/BookmarkManager.java | 2 +- .../main/java/acr/browser/lightning/database/HistoryItem.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java index e8e48ca6b..82ffad818 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java @@ -447,7 +447,7 @@ public boolean isRootFolder() { * * @return the current folder */ - @Nullable + @NonNull public String getCurrentFolder() { return mCurrentFolder; } diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryItem.java b/app/src/main/java/acr/browser/lightning/database/HistoryItem.java index c0c662689..137f29518 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryItem.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryItem.java @@ -63,7 +63,7 @@ public void setImageId(int id) { this.mImageId = id; } - public void setBitmap(Bitmap image) { + public void setBitmap(@Nullable Bitmap image) { mBitmap = image; } From 1f1d1e7f3252f0b95de4efdf0952b65799b9679c Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 26 Mar 2017 20:08:36 -0400 Subject: [PATCH 044/181] Fixing crash on restore caused by bonsai upgrade --- .../browser/lightning/activity/TabsManager.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 7e5eefa26..6167eddac 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -17,11 +17,14 @@ import com.anthonycr.bonsai.Completable; import com.anthonycr.bonsai.CompletableAction; import com.anthonycr.bonsai.CompletableSubscriber; -import com.anthonycr.bonsai.ObservableSubscriber; import com.anthonycr.bonsai.Single; import com.anthonycr.bonsai.SingleAction; import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.bonsai.SingleSubscriber; +import com.anthonycr.bonsai.Stream; +import com.anthonycr.bonsai.StreamAction; +import com.anthonycr.bonsai.StreamOnSubscribe; +import com.anthonycr.bonsai.StreamSubscriber; import com.squareup.otto.Bus; import java.util.ArrayList; @@ -156,9 +159,9 @@ private void restoreLostTabs(@Nullable final String url, @NonNull final Activity @NonNull final CompletableSubscriber subscriber) { restoreState().subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()).subscribe(new SingleOnSubscribe() { + .observeOn(Schedulers.main()).subscribe(new StreamOnSubscribe() { @Override - public void onItem(@Nullable Bundle item) { + public void onNext(@Nullable Bundle item) { LightningView tab = newTab(activity, "", false); String url = item.getString(URL_KEY); if (url != null && tab.getWebView() != null) { @@ -480,16 +483,16 @@ public void clearSavedState() { * and will delete the saved instance file when * restoration is complete. */ - private Single restoreState() { - return Single.create(new SingleAction() { + private Stream restoreState() { + return Stream.create(new StreamAction() { @Override - public void onSubscribe(@NonNull SingleSubscriber subscriber) { + public void onSubscribe(@NonNull StreamSubscriber subscriber) { Bundle savedState = FileUtils.readBundleFromStorage(mApp, BUNDLE_STORAGE); if (savedState != null) { Log.d(Constants.TAG, "Restoring previous WebView state now"); for (String key : savedState.keySet()) { if (key.startsWith(BUNDLE_KEY)) { - subscriber.onItem(savedState.getBundle(key)); + subscriber.onNext(savedState.getBundle(key)); } } } From 8e0d3c1b524e3cfbdfb36a907f5a69fd310266d5 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Fri, 7 Apr 2017 20:45:59 -0400 Subject: [PATCH 045/181] Moving away from raw query and cleaned up query code --- .../lightning/database/HistoryDatabase.java | 149 ++++++++---------- 1 file changed, 70 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java index 64d7327fe..790e140f1 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java @@ -11,6 +11,7 @@ import android.database.sqlite.SQLiteOpenHelper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.WorkerThread; import java.util.ArrayList; import java.util.List; @@ -19,8 +20,9 @@ import javax.inject.Singleton; import acr.browser.lightning.R; -import acr.browser.lightning.app.BrowserApp; +@SuppressWarnings("unused") +@WorkerThread @Singleton public class HistoryDatabase extends SQLiteOpenHelper { @@ -40,31 +42,21 @@ public class HistoryDatabase extends SQLiteOpenHelper { private static final String KEY_TITLE = "title"; private static final String KEY_TIME_VISITED = "time"; - @Nullable private SQLiteDatabase mDatabase; + @Nullable + private SQLiteDatabase mDatabase; @Inject public HistoryDatabase(@NonNull Context context) { super(context.getApplicationContext(), DATABASE_NAME, null, DATABASE_VERSION); - initialize(); - } - - private void initialize() { - BrowserApp.getTaskThread().execute(new Runnable() { - @Override - public void run() { - synchronized (HistoryDatabase.this) { - mDatabase = HistoryDatabase.this.getWritableDatabase(); - } - } - }); + mDatabase = HistoryDatabase.this.getWritableDatabase(); } // Creating Tables @Override public void onCreate(@NonNull SQLiteDatabase db) { String CREATE_HISTORY_TABLE = "CREATE TABLE " + TABLE_HISTORY + '(' + KEY_ID - + " INTEGER PRIMARY KEY," + KEY_URL + " TEXT," + KEY_TITLE + " TEXT," - + KEY_TIME_VISITED + " INTEGER" + ')'; + + " INTEGER PRIMARY KEY," + KEY_URL + " TEXT," + KEY_TITLE + " TEXT," + + KEY_TIME_VISITED + " INTEGER" + ')'; db.execSQL(CREATE_HISTORY_TABLE); } @@ -77,13 +69,6 @@ public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion onCreate(db); } - public synchronized void deleteHistory() { - mDatabase = openIfNecessary(); - mDatabase.delete(TABLE_HISTORY, null, null); - mDatabase.close(); - mDatabase = this.getWritableDatabase(); - } - @Override public synchronized void close() { if (mDatabase != null) { @@ -93,6 +78,7 @@ public synchronized void close() { super.close(); } + @WorkerThread @NonNull private SQLiteDatabase openIfNecessary() { if (mDatabase == null || !mDatabase.isOpen()) { @@ -101,26 +87,40 @@ private SQLiteDatabase openIfNecessary() { return mDatabase; } + @WorkerThread + public synchronized void deleteHistory() { + mDatabase = openIfNecessary(); + mDatabase.delete(TABLE_HISTORY, null, null); + mDatabase.close(); + mDatabase = this.getWritableDatabase(); + } + + @WorkerThread public synchronized void deleteHistoryItem(@NonNull String url) { mDatabase = openIfNecessary(); mDatabase.delete(TABLE_HISTORY, KEY_URL + " = ?", new String[]{url}); } + @WorkerThread public synchronized void visitHistoryItem(@NonNull String url, @Nullable String title) { mDatabase = openIfNecessary(); ContentValues values = new ContentValues(); values.put(KEY_TITLE, title == null ? "" : title); values.put(KEY_TIME_VISITED, System.currentTimeMillis()); - Cursor q = mDatabase.query(false, TABLE_HISTORY, new String[]{KEY_URL}, - KEY_URL + " = ?", new String[]{url}, null, null, null, "1"); - if (q.getCount() > 0) { + + Cursor cursor = mDatabase.query(false, TABLE_HISTORY, new String[]{KEY_URL}, + KEY_URL + " = ?", new String[]{url}, null, null, null, "1"); + + if (cursor.getCount() > 0) { mDatabase.update(TABLE_HISTORY, values, KEY_URL + " = ?", new String[]{url}); } else { addHistoryItem(new HistoryItem(url, title == null ? "" : title)); } - q.close(); + + cursor.close(); } + @WorkerThread private synchronized void addHistoryItem(@NonNull HistoryItem item) { mDatabase = openIfNecessary(); ContentValues values = new ContentValues(); @@ -130,11 +130,12 @@ private synchronized void addHistoryItem(@NonNull HistoryItem item) { mDatabase.insert(TABLE_HISTORY, null, values); } + @WorkerThread @Nullable synchronized String getHistoryItem(@NonNull String url) { mDatabase = openIfNecessary(); Cursor cursor = mDatabase.query(TABLE_HISTORY, new String[]{KEY_ID, KEY_URL, KEY_TITLE}, - KEY_URL + " = ?", new String[]{url}, null, null, null, null); + KEY_URL + " = ?", new String[]{url}, null, null, null, "1"); String m = null; if (cursor != null) { cursor.moveToFirst(); @@ -145,6 +146,7 @@ synchronized String getHistoryItem(@NonNull String url) { return m; } + @WorkerThread @NonNull public synchronized List findItemsContaining(@Nullable String search) { mDatabase = openIfNecessary(); @@ -152,79 +154,68 @@ public synchronized List findItemsContaining(@Nullable String searc if (search == null) { return itemList; } - search = DatabaseUtils.sqlEscapeString('%' + search + '%'); - - String selectQuery = "SELECT * FROM " + TABLE_HISTORY + " WHERE " + KEY_TITLE + " LIKE " - + search + " OR " + KEY_URL + " LIKE " + search + " ORDER BY " - + KEY_TIME_VISITED + " DESC LIMIT 5"; - Cursor cursor = mDatabase.rawQuery(selectQuery, null); - - int n = 0; - if (cursor.moveToFirst()) { - do { - HistoryItem item = new HistoryItem(); - item.setUrl(cursor.getString(1)); - item.setTitle(cursor.getString(2)); - item.setImageId(R.drawable.ic_history); - itemList.add(item); - n++; - } while (cursor.moveToNext() && n < 5); + + search = '%' + search + '%'; + + Cursor cursor = mDatabase.query(TABLE_HISTORY, null, KEY_TITLE + " LIKE ? OR " + KEY_URL + " LIKE ?", + new String[]{search, search}, null, null, KEY_TIME_VISITED + " DESC", "5"); + + while (cursor.moveToNext()) { + HistoryItem item = new HistoryItem(); + item.setUrl(cursor.getString(1)); + item.setTitle(cursor.getString(2)); + item.setImageId(R.drawable.ic_history); + itemList.add(item); } + cursor.close(); + return itemList; } + @WorkerThread @NonNull public synchronized List getLastHundredItems() { mDatabase = openIfNecessary(); List itemList = new ArrayList<>(100); - String selectQuery = "SELECT * FROM " + TABLE_HISTORY + " ORDER BY " + KEY_TIME_VISITED - + " DESC"; - - Cursor cursor = mDatabase.rawQuery(selectQuery, null); - int counter = 0; - if (cursor.moveToFirst()) { - do { - HistoryItem item = new HistoryItem(); - item.setUrl(cursor.getString(1)); - item.setTitle(cursor.getString(2)); - item.setImageId(R.drawable.ic_history); - itemList.add(item); - counter++; - } while (cursor.moveToNext() && counter < 100); + Cursor cursor = mDatabase.query(TABLE_HISTORY, null, null, null, null, null, KEY_TIME_VISITED + " DESC", "100"); + + while (cursor.moveToNext()) { + HistoryItem item = new HistoryItem(); + item.setUrl(cursor.getString(1)); + item.setTitle(cursor.getString(2)); + item.setImageId(R.drawable.ic_history); + itemList.add(item); } + cursor.close(); + return itemList; } + @WorkerThread @NonNull public synchronized List getAllHistoryItems() { mDatabase = openIfNecessary(); List itemList = new ArrayList<>(); - String selectQuery = "SELECT * FROM " + TABLE_HISTORY + " ORDER BY " + KEY_TIME_VISITED - + " DESC"; - - Cursor cursor = mDatabase.rawQuery(selectQuery, null); - - if (cursor.moveToFirst()) { - do { - HistoryItem item = new HistoryItem(); - item.setUrl(cursor.getString(1)); - item.setTitle(cursor.getString(2)); - item.setImageId(R.drawable.ic_history); - itemList.add(item); - } while (cursor.moveToNext()); + + Cursor cursor = mDatabase.query(TABLE_HISTORY, null, null, null, null, null, KEY_TIME_VISITED + " DESC"); + + while (cursor.moveToNext()) { + HistoryItem item = new HistoryItem(); + item.setUrl(cursor.getString(1)); + item.setTitle(cursor.getString(2)); + item.setImageId(R.drawable.ic_history); + itemList.add(item); } + cursor.close(); + return itemList; } - public synchronized int getHistoryItemsCount() { - mDatabase = openIfNecessary(); - String countQuery = "SELECT * FROM " + TABLE_HISTORY; - Cursor cursor = mDatabase.rawQuery(countQuery, null); - int n = cursor.getCount(); - cursor.close(); - return n; + @WorkerThread + public synchronized long getHistoryItemsCount() { + return DatabaseUtils.queryNumEntries(mDatabase, TABLE_HISTORY); } } From 4ced7178aaf265583a4788f51c0256098640440a Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Fri, 7 Apr 2017 22:34:28 -0400 Subject: [PATCH 046/181] Updating grade --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 19604f82f..8911568a9 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:2.3.1' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7' classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.3' } From bed8163399ccd3bd90da8c358432238d924fd914 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 9 Apr 2017 15:29:37 -0400 Subject: [PATCH 047/181] Moving to asynchronous consumption of the HistoryDatabase --- app/build.gradle | 2 +- .../lightning/activity/BrowserActivity.java | 192 +++++----- .../lightning/activity/TabsManager.java | 135 +++---- .../acr/browser/lightning/app/BrowserApp.java | 38 +- .../lightning/constant/HistoryPage.java | 121 +++--- .../lightning/database/HistoryDatabase.java | 70 ++-- .../lightning/database/HistoryModel.java | 84 +++++ .../dialog/LightningDialogBuilder.java | 350 +++++++++--------- .../fragment/PrivacySettingsFragment.java | 7 +- .../lightning/search/SuggestionsAdapter.java | 63 ++-- .../acr/browser/lightning/utils/WebUtils.java | 10 +- build.gradle | 4 - 12 files changed, 577 insertions(+), 499 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/database/HistoryModel.java diff --git a/app/build.gradle b/app/build.gradle index f0f3227bf..19720c770 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,7 +99,7 @@ dependencies { compile "info.guardianproject.netcipher:netcipher:$netcipherVersion" compile "info.guardianproject.netcipher:netcipher-webkit:$netcipherVersion" - compile 'com.anthonycr.bonsai:bonsai:1.0' + compile 'com.anthonycr.bonsai:bonsai:1.1.0' compile 'com.anthonycr.progress:animated-progress:1.0' diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index f4cd8e2f6..9a4a346f5 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -13,7 +13,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; -import android.database.sqlite.SQLiteException; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PorterDuff; @@ -81,7 +80,9 @@ import android.widget.VideoView; import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableOnSubscribe; import com.anthonycr.bonsai.Schedulers; +import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.grant.PermissionsManager; import com.anthonycr.progress.AnimatedProgressBar; import com.squareup.otto.Bus; @@ -105,8 +106,8 @@ import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.controller.UIController; import acr.browser.lightning.database.BookmarkManager; -import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.database.HistoryModel; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.fragment.BookmarksFragment; @@ -115,6 +116,7 @@ import acr.browser.lightning.receiver.NetworkReceiver; import acr.browser.lightning.search.SuggestionsAdapter; import acr.browser.lightning.utils.DrawableUtils; +import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.ProxyUtils; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.utils.UrlUtils; @@ -197,8 +199,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private TabsManager mTabsManager; - @Inject HistoryDatabase mHistoryDatabase; - // Image private Bitmap mWebpageBitmap; private final ColorDrawable mBackground = new ColorDrawable(); @@ -215,9 +215,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private static final int API = android.os.Build.VERSION.SDK_INT; private static final String NETWORK_BROADCAST_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; private static final LayoutParams MATCH_PARENT = new LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT); + LayoutParams.MATCH_PARENT); private static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); protected abstract boolean isIncognito(); @@ -249,7 +249,7 @@ private synchronized void initialize(Bundle savedInstanceState) { mDarkTheme = mPreferences.getUseTheme() != 0 || isIncognito(); mIconColor = mDarkTheme ? ThemeUtils.getIconDarkThemeColor(this) : ThemeUtils.getIconLightThemeColor(this); mDisabledIconColor = mDarkTheme ? ContextCompat.getColor(this, R.color.icon_dark_theme_disabled) : - ContextCompat.getColor(this, R.color.icon_light_theme_disabled); + ContextCompat.getColor(this, R.color.icon_light_theme_disabled); mShowTabsInDrawer = mPreferences.getShowTabsInDrawer(!isTablet()); mSwapBookmarksAndTabs = mPreferences.getBookmarksAndTabsSwapped(); @@ -307,10 +307,10 @@ public void onDrawerStateChanged(int newState) { final FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager - .beginTransaction() - .replace(getTabsFragmentViewId(), tabsFragment, TAG_TABS_FRAGMENT) - .replace(getBookmarksFragmentViewId(), bookmarksFragment, TAG_BOOKMARK_FRAGMENT) - .commit(); + .beginTransaction() + .replace(getTabsFragmentViewId(), tabsFragment, TAG_TABS_FRAGMENT) + .replace(getBookmarksFragmentViewId(), bookmarksFragment, TAG_BOOKMARK_FRAGMENT) + .commit(); if (mShowTabsInDrawer) { mToolbarLayout.removeView(findViewById(R.id.tabs_toolbar_container)); } @@ -432,7 +432,7 @@ void panicClean() { } private class SearchListenerClass implements OnKeyListener, OnEditorActionListener, - OnFocusChangeListener, OnTouchListener, SearchView.PreFocusListener { + OnFocusChangeListener, OnTouchListener, SearchView.PreFocusListener { @Override public boolean onKey(View searchView, int keyCode, KeyEvent keyEvent) { @@ -458,10 +458,10 @@ public boolean onEditorAction(TextView arg0, int actionId, KeyEvent arg2) { // hide the keyboard and search the web when the enter key // button is pressed if (actionId == EditorInfo.IME_ACTION_GO || actionId == EditorInfo.IME_ACTION_DONE - || actionId == EditorInfo.IME_ACTION_NEXT - || actionId == EditorInfo.IME_ACTION_SEND - || actionId == EditorInfo.IME_ACTION_SEARCH - || (arg2.getAction() == KeyEvent.KEYCODE_ENTER)) { + || actionId == EditorInfo.IME_ACTION_NEXT + || actionId == EditorInfo.IME_ACTION_SEND + || actionId == EditorInfo.IME_ACTION_SEARCH + || (arg2.getAction() == KeyEvent.KEYCODE_ENTER)) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(mSearch.getWindowToken(), 0); searchTheWeb(mSearch.getText().toString()); @@ -498,7 +498,7 @@ public void onFocusChange(final View v, final boolean hasFocus) { public boolean onTouch(View v, MotionEvent event) { if (mSearch.getCompoundDrawables()[2] != null) { boolean tappedX = event.getX() > (mSearch.getWidth() - - mSearch.getPaddingRight() - mIcon.getIntrinsicWidth()); + - mSearch.getPaddingRight() - mIcon.getIntrinsicWidth()); if (tappedX) { if (event.getAction() == MotionEvent.ACTION_UP) { if (mSearch.hasFocus()) { @@ -566,23 +566,23 @@ private void setNavigationDrawerWidth() { } if (width > maxWidth) { DrawerLayout.LayoutParams params = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerLeft - .getLayoutParams(); + .getLayoutParams(); params.width = maxWidth; mDrawerLeft.setLayoutParams(params); mDrawerLeft.requestLayout(); DrawerLayout.LayoutParams paramsRight = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerRight - .getLayoutParams(); + .getLayoutParams(); paramsRight.width = maxWidth; mDrawerRight.setLayoutParams(paramsRight); mDrawerRight.requestLayout(); } else { DrawerLayout.LayoutParams params = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerLeft - .getLayoutParams(); + .getLayoutParams(); params.width = width; mDrawerLeft.setLayoutParams(params); mDrawerLeft.requestLayout(); DrawerLayout.LayoutParams paramsRight = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerRight - .getLayoutParams(); + .getLayoutParams(); paramsRight.width = width; mDrawerRight.setLayoutParams(paramsRight); mDrawerRight.requestLayout(); @@ -622,7 +622,7 @@ private void initializePreferences() { case 0: mSearchText = mPreferences.getSearchUrl(); if (!mSearchText.startsWith(Constants.HTTP) - && !mSearchText.startsWith(Constants.HTTPS)) { + && !mSearchText.startsWith(Constants.HTTPS)) { mSearchText = Constants.GOOGLE_SEARCH; } break; @@ -676,8 +676,8 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { searchTheWeb(mSearch.getText().toString()); } } else if ((keyCode == KeyEvent.KEYCODE_MENU) - && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) - && (Build.MANUFACTURER.compareTo("LGE") == 0)) { + && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) + && (Build.MANUFACTURER.compareTo("LGE") == 0)) { // Workaround for stupid LG devices that crash return true; } else if (keyCode == KeyEvent.KEYCODE_BACK) { @@ -698,8 +698,8 @@ public void run() { @Override public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_MENU) - && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) - && (Build.MANUFACTURER.compareTo("LGE") == 0)) { + && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) + && (Build.MANUFACTURER.compareTo("LGE") == 0)) { // Workaround for stupid LG devices that crash openOptionsMenu(); return true; @@ -796,8 +796,8 @@ public boolean onOptionsItemSelected(MenuItem item) { // By using a manager, adds a bookmark and notifies third parties about that private void addBookmark(final String title, final String url) { final HistoryItem item = !mBookmarkManager.isBookmark(url) - ? new HistoryItem(url, title) - : null; + ? new HistoryItem(url, title) + : null; if (item != null && mBookmarkManager.addBookmark(item)) { mSuggestionsAdapter.refreshBookmarks(); mBookmarksView.handleUpdatedUrl(url); @@ -806,8 +806,8 @@ private void addBookmark(final String title, final String url) { private void deleteBookmark(final String title, final String url) { final HistoryItem item = mBookmarkManager.isBookmark(url) - ? new HistoryItem(url, title) - : null; + ? new HistoryItem(url, title) + : null; if (item != null && mBookmarkManager.deleteBookmark(item)) { mSuggestionsAdapter.refreshBookmarks(); mBookmarksView.handleUpdatedUrl(url); @@ -852,17 +852,17 @@ private void setWebViewTranslation(float translation) { */ private void findInPage() { BrowserDialog.showEditText(this, - R.string.action_find, - R.string.search_hint, - R.string.search_hint, new BrowserDialog.EditorListener() { - @Override - public void onClick(String text) { - if (!TextUtils.isEmpty(text)) { - mPresenter.findInPage(text); - showFindInPageControls(text); + R.string.action_find, + R.string.search_hint, + R.string.search_hint, new BrowserDialog.EditorListener() { + @Override + public void onClick(String text) { + if (!TextUtils.isEmpty(text)) { + mPresenter.findInPage(text); + showFindInPageControls(text); + } } - } - }); + }); } private void showFindInPageControls(@NonNull String text) { @@ -892,24 +892,24 @@ public void showCloseDialog(final int position) { return; } BrowserDialog.show(this, R.string.dialog_title_close_browser, - new BrowserDialog.Item(R.string.close_tab) { - @Override - public void onClick() { - mPresenter.deleteTab(position); - } - }, - new BrowserDialog.Item(R.string.close_other_tabs) { - @Override - public void onClick() { - mPresenter.closeAllOtherTabs(); - } - }, - new BrowserDialog.Item(R.string.close_all_tabs) { - @Override - public void onClick() { - closeBrowser(); - } - }); + new BrowserDialog.Item(R.string.close_tab) { + @Override + public void onClick() { + mPresenter.deleteTab(position); + } + }, + new BrowserDialog.Item(R.string.close_other_tabs) { + @Override + public void onClick() { + mPresenter.closeAllOtherTabs(); + } + }, + new BrowserDialog.Item(R.string.close_all_tabs) { + @Override + public void onClick() { + closeBrowser(); + } + }); } @Override @@ -1016,11 +1016,11 @@ public void run() { public void showBlockedLocalFileDialog(DialogInterface.OnClickListener listener) { AlertDialog.Builder builder = new AlertDialog.Builder(this); Dialog dialog = builder.setCancelable(true) - .setTitle(R.string.title_warning) - .setMessage(R.string.message_blocked_local) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(R.string.action_open, listener) - .show(); + .setTitle(R.string.title_warning) + .setMessage(R.string.message_blocked_local) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(R.string.action_open, listener) + .show(); BrowserDialog.setDialogSize(this, dialog); } @@ -1139,7 +1139,7 @@ void performExitCleanUp() { Log.d(TAG, "Cache Cleared"); } if (mPreferences.getClearHistoryExitEnabled() && !isIncognito()) { - WebUtils.clearHistory(this, mHistoryDatabase); + WebUtils.clearHistory(this); Log.d(TAG, "History Cleared"); } if (mPreferences.getClearCookiesExitEnabled() && !isIncognito()) { @@ -1280,11 +1280,6 @@ protected void onDestroy() { mPresenter.shutdown(); - if (mHistoryDatabase != null) { - mHistoryDatabase.close(); - mHistoryDatabase = null; - } - super.onDestroy(); } @@ -1402,7 +1397,7 @@ public void run() { mCurrentUiColor = color; mToolbarLayout.setBackgroundColor(color); mSearchBackground.getBackground().setColorFilter(DrawableUtils.mixColor(interpolatedTime, - startSearchColor, finalSearchColor), PorterDuff.Mode.SRC_IN); + startSearchColor, finalSearchColor), PorterDuff.Mode.SRC_IN); } }; animation.setDuration(300); @@ -1467,7 +1462,7 @@ public void updateUrl(@Nullable String url, boolean shortUrl) { public void updateTabNumber(int number) { if (mArrowImage != null && mShowTabsInDrawer) { mArrowImage.setImageBitmap(DrawableUtils.getRoundedNumberImage(number, Utils.dpToPx(24), - Utils.dpToPx(24), ThemeUtils.getIconThemeColor(this, mDarkTheme), Utils.dpToPx(2.5f))); + Utils.dpToPx(24), ThemeUtils.getIconThemeColor(this, mDarkTheme), Utils.dpToPx(2.5f))); } } @@ -1481,20 +1476,15 @@ void addItemToHistory(@Nullable final String title, @NonNull final String url) { if (UrlUtils.isSpecialUrl(url)) { return; } - BrowserApp.getIOThread().execute(new Runnable() { - @Override - public void run() { - try { - mHistoryDatabase.visitHistoryItem(url, title); - } catch (IllegalStateException e) { - Log.e(TAG, "IllegalStateException in updateHistory", e); - } catch (NullPointerException e) { - Log.e(TAG, "NullPointerException in updateHistory", e); - } catch (SQLiteException e) { - Log.e(TAG, "SQLiteException in updateHistory", e); - } - } - }); + + HistoryModel.visitHistoryItem(url, title) + .subscribeOn(Schedulers.io()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onError(@NonNull Throwable throwable) { + Log.e(TAG, "Exception while updating history", throwable); + } + }); } /** @@ -1543,7 +1533,19 @@ public void onItemClick(AdapterView adapterView, View view, int pos, long l) * function that opens the HTML history page in the browser */ private void openHistory() { - new HistoryPage(mTabsManager.getCurrentTab(), getApplication(), mHistoryDatabase).load(); + HistoryPage.getHistoryPage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + LightningView view = mTabsManager.getCurrentTab(); + if (view != null) { + view.loadUrl(item); + } + } + }); } private View getBookmarkDrawer() { @@ -1855,7 +1857,7 @@ public void onHideCustomView() { } private class VideoCompletionListener implements MediaPlayer.OnCompletionListener, - MediaPlayer.OnErrorListener { + MediaPlayer.OnErrorListener { @Override public boolean onError(MediaPlayer mp, int what, int extra) { @@ -1928,16 +1930,16 @@ private void setFullscreen(boolean enabled, boolean immersive) { if (enabled) { if (immersive) { decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } else { decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); } window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); + WindowManager.LayoutParams.FLAG_FULLSCREEN); } else { window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); @@ -2190,7 +2192,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis @Subscribe public void loadHistory(final BrowserEvents.OpenHistoryInCurrentTab event) { - new HistoryPage(mTabsManager.getCurrentTab(), getApplication(), mHistoryDatabase).load(); + openHistory(); } /** @@ -2239,7 +2241,7 @@ public void bookmarkDeleted(final BookmarkEvents.Deleted event) { private void handleBookmarksChange() { final LightningView currentTab = mTabsManager.getCurrentTab(); if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) - && currentTab.getUrl().endsWith(BookmarkPage.FILENAME)) { + && currentTab.getUrl().endsWith(BookmarkPage.FILENAME)) { currentTab.loadBookmarkpage(); } if (currentTab != null) { diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 6167eddac..f0a7478bd 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -17,10 +17,7 @@ import com.anthonycr.bonsai.Completable; import com.anthonycr.bonsai.CompletableAction; import com.anthonycr.bonsai.CompletableSubscriber; -import com.anthonycr.bonsai.Single; -import com.anthonycr.bonsai.SingleAction; import com.anthonycr.bonsai.SingleOnSubscribe; -import com.anthonycr.bonsai.SingleSubscriber; import com.anthonycr.bonsai.Stream; import com.anthonycr.bonsai.StreamAction; import com.anthonycr.bonsai.StreamOnSubscribe; @@ -39,13 +36,13 @@ import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.constant.StartPage; import acr.browser.lightning.database.BookmarkManager; -import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.preference.PreferenceManager; import com.anthonycr.bonsai.Schedulers; import acr.browser.lightning.utils.FileUtils; +import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.UrlUtils; import acr.browser.lightning.view.LightningView; @@ -70,7 +67,6 @@ public class TabsManager { @Inject PreferenceManager mPreferenceManager; @Inject BookmarkManager mBookmarkManager; - @Inject HistoryDatabase mHistoryManager; @Inject Bus mEventBus; @Inject Application mApp; @@ -116,8 +112,8 @@ private synchronized void finishInitialization() { * @param incognito whether or not we are in incognito mode. */ public synchronized Completable initializeTabs(@NonNull final Activity activity, - @Nullable final Intent intent, - final boolean incognito) { + @Nullable final Intent intent, + final boolean incognito) { return Completable.create(new CompletableAction() { @Override public void onSubscribe(@NonNull CompletableSubscriber subscriber) { @@ -158,68 +154,79 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) { private void restoreLostTabs(@Nullable final String url, @NonNull final Activity activity, @NonNull final CompletableSubscriber subscriber) { - restoreState().subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()).subscribe(new StreamOnSubscribe() { - @Override - public void onNext(@Nullable Bundle item) { - LightningView tab = newTab(activity, "", false); - String url = item.getString(URL_KEY); - if (url != null && tab.getWebView() != null) { - if (UrlUtils.isBookmarkUrl(url)) { - new BookmarkPage(tab, activity, mBookmarkManager).load(); - } else if (UrlUtils.isStartPageUrl(url)) { - new StartPage(tab, mApp).load(); - } else if (UrlUtils.isHistoryUrl(url)) { - new HistoryPage(tab, mApp, mHistoryManager).load(); + restoreState() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new StreamOnSubscribe() { + @Override + public void onNext(@Nullable Bundle item) { + final LightningView tab = newTab(activity, "", false); + String url = item.getString(URL_KEY); + if (url != null && tab.getWebView() != null) { + if (UrlUtils.isBookmarkUrl(url)) { + new BookmarkPage(tab, activity, mBookmarkManager).load(); + } else if (UrlUtils.isStartPageUrl(url)) { + new StartPage(tab, mApp).load(); + } else if (UrlUtils.isHistoryUrl(url)) { + HistoryPage.getHistoryPage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + tab.loadUrl(item); + } + }); + } + } else if (tab.getWebView() != null) { + tab.getWebView().restoreState(item); + } } - } else if (tab.getWebView() != null) { - tab.getWebView().restoreState(item); - } - } - @Override - public void onComplete() { - if (url != null) { - if (url.startsWith(Constants.FILE)) { - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - Dialog dialog = builder.setCancelable(true) - .setTitle(R.string.title_warning) - .setMessage(R.string.message_blocked_local) - .setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - if (mTabList.isEmpty()) { - newTab(activity, null, false); - } - finishInitialization(); - subscriber.onComplete(); - } - }) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(R.string.action_open, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - newTab(activity, url, false); + @Override + public void onComplete() { + if (url != null) { + if (url.startsWith(Constants.FILE)) { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + Dialog dialog = builder.setCancelable(true) + .setTitle(R.string.title_warning) + .setMessage(R.string.message_blocked_local) + .setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + if (mTabList.isEmpty()) { + newTab(activity, null, false); + } + finishInitialization(); + subscriber.onComplete(); + } + }) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(R.string.action_open, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + newTab(activity, url, false); + } + }).show(); + BrowserDialog.setDialogSize(activity, dialog); + } else { + newTab(activity, url, false); + if (mTabList.isEmpty()) { + newTab(activity, null, false); } - }).show(); - BrowserDialog.setDialogSize(activity, dialog); - } else { - newTab(activity, url, false); - if (mTabList.isEmpty()) { - newTab(activity, null, false); + finishInitialization(); + subscriber.onComplete(); + } + } else { + if (mTabList.isEmpty()) { + newTab(activity, null, false); + } + finishInitialization(); + subscriber.onComplete(); } - finishInitialization(); - subscriber.onComplete(); } - } else { - if (mTabList.isEmpty()) { - newTab(activity, null, false); - } - finishInitialization(); - subscriber.onComplete(); - } - } - }); + }); } /** diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index 6bf6d734c..cf30a595a 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -8,6 +8,7 @@ import android.os.Build; import android.os.StrictMode; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import android.webkit.WebView; @@ -23,30 +24,38 @@ import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.FileUtils; import acr.browser.lightning.utils.MemoryLeakUtils; +import acr.browser.lightning.utils.Preconditions; public class BrowserApp extends Application { private static final String TAG = BrowserApp.class.getSimpleName(); - private static AppComponent mAppComponent; + @Nullable private static Application sApplication; + @Nullable private static AppComponent sAppComponent; private static final Executor mIOThread = Executors.newSingleThreadExecutor(); private static final Executor mTaskThread = Executors.newCachedThreadPool(); @Inject Bus mBus; @Inject PreferenceManager mPreferenceManager; + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + sApplication = this; + } + @Override public void onCreate() { super.onCreate(); if (BuildConfig.DEBUG) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); + .detectAll() + .penaltyLog() + .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); + .detectAll() + .penaltyLog() + .build()); } final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); @@ -67,8 +76,8 @@ public void uncaughtException(Thread thread, Throwable ex) { } }); - mAppComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); - mAppComponent.inject(this); + sAppComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); + sAppComponent.inject(this); if (mPreferenceManager.getUseLeakCanary() && !isRelease()) { LeakCanary.install(this); @@ -86,13 +95,21 @@ public void onActivityDestroyed(Activity activity) { }); } + @NonNull + public static Application getApplication() { + Preconditions.checkNonNull(sApplication); + return sApplication; + } + @NonNull public static BrowserApp get(@NonNull Context context) { return (BrowserApp) context.getApplicationContext(); } + @NonNull public static AppComponent getAppComponent() { - return mAppComponent; + Preconditions.checkNonNull(sAppComponent); + return sAppComponent; } @NonNull @@ -105,6 +122,7 @@ public static Executor getTaskThread() { return mTaskThread; } + @NonNull public static Bus getBus(@NonNull Context context) { return get(context).mBus; } diff --git a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java index 44c3ca8f3..4d93b9967 100644 --- a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java @@ -4,26 +4,29 @@ package acr.browser.lightning.constant; import android.app.Application; -import android.os.AsyncTask; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleOnSubscribe; +import com.anthonycr.bonsai.SingleSubscriber; + import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.lang.ref.WeakReference; import java.util.Iterator; import java.util.List; import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.database.HistoryModel; +import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.Utils; -import acr.browser.lightning.view.LightningView; -public class HistoryPage extends AsyncTask { +public class HistoryPage { private static final String TAG = HistoryPage.class.getSimpleName(); @@ -43,70 +46,54 @@ public class HistoryPage extends AsyncTask { private static final String END = ""; - @NonNull private final WeakReference mTabReference; - @NonNull private final Application mApp; - @NonNull private final String mTitle; - private final HistoryDatabase mHistoryDatabase; - - @Nullable private String mHistoryUrl = null; - - public HistoryPage(LightningView tab, @NonNull Application app, HistoryDatabase database) { - mTabReference = new WeakReference<>(tab); - mApp = app; - mTitle = app.getString(R.string.action_history); - mHistoryDatabase = database; - } - - @Nullable - @Override - protected Void doInBackground(Void... params) { - mHistoryUrl = getHistoryPage(); - return null; - } - - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - LightningView tab = mTabReference.get(); - if (tab != null && mHistoryUrl != null) { - tab.loadUrl(mHistoryUrl); - } - } + private HistoryPage() {} @NonNull - private String getHistoryPage() { - StringBuilder historyBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2); - List historyList = mHistoryDatabase.getLastHundredItems(); - Iterator it = historyList.iterator(); - HistoryItem helper; - while (it.hasNext()) { - helper = it.next(); - historyBuilder.append(PART1); - historyBuilder.append(helper.getUrl()); - historyBuilder.append(PART2); - historyBuilder.append(helper.getTitle()); - historyBuilder.append(PART3); - historyBuilder.append(helper.getUrl()); - historyBuilder.append(PART4); - } - - historyBuilder.append(END); - File historyWebPage = new File(mApp.getFilesDir(), FILENAME); - FileWriter historyWriter = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - historyWriter = new FileWriter(historyWebPage, false); - historyWriter.write(historyBuilder.toString()); - } catch (IOException e) { - Log.e(TAG, "Unable to write history page to disk", e); - } finally { - Utils.close(historyWriter); - } - return Constants.FILE + historyWebPage; - } - - public void load() { - executeOnExecutor(BrowserApp.getIOThread()); + public static Single getHistoryPage() { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull final SingleSubscriber subscriber) { + final String title = BrowserApp.getApplication().getString(R.string.action_history); + final StringBuilder historyBuilder = new StringBuilder(HEADING_1 + title + HEADING_2); + + HistoryModel.lastHundredVisitedHistoryItems() + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + + Preconditions.checkNonNull(item); + Iterator it = item.iterator(); + HistoryItem helper; + while (it.hasNext()) { + helper = it.next(); + historyBuilder.append(PART1); + historyBuilder.append(helper.getUrl()); + historyBuilder.append(PART2); + historyBuilder.append(helper.getTitle()); + historyBuilder.append(PART3); + historyBuilder.append(helper.getUrl()); + historyBuilder.append(PART4); + } + + historyBuilder.append(END); + File historyWebPage = new File(BrowserApp.getApplication().getFilesDir(), FILENAME); + FileWriter historyWriter = null; + try { + //noinspection IOResourceOpenedButNotSafelyClosed + historyWriter = new FileWriter(historyWebPage, false); + historyWriter.write(historyBuilder.toString()); + } catch (IOException e) { + Log.e(TAG, "Unable to write history page to disk", e); + } finally { + Utils.close(historyWriter); + } + + subscriber.onItem(Constants.FILE + historyWebPage); + subscriber.onComplete(); + } + }); + } + }); } /** diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java index 790e140f1..4d4c3c927 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java @@ -4,7 +4,6 @@ package acr.browser.lightning.database; import android.content.ContentValues; -import android.content.Context; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; @@ -16,15 +15,11 @@ import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; -import javax.inject.Singleton; - import acr.browser.lightning.R; +import acr.browser.lightning.app.BrowserApp; -@SuppressWarnings("unused") @WorkerThread -@Singleton -public class HistoryDatabase extends SQLiteOpenHelper { +class HistoryDatabase extends SQLiteOpenHelper { // All Static variables // Database Version @@ -42,15 +37,24 @@ public class HistoryDatabase extends SQLiteOpenHelper { private static final String KEY_TITLE = "title"; private static final String KEY_TIME_VISITED = "time"; - @Nullable - private SQLiteDatabase mDatabase; + @Nullable private SQLiteDatabase mDatabase; + + @Nullable private static HistoryDatabase sInstance; - @Inject - public HistoryDatabase(@NonNull Context context) { - super(context.getApplicationContext(), DATABASE_NAME, null, DATABASE_VERSION); + private HistoryDatabase() { + super(BrowserApp.getApplication(), DATABASE_NAME, null, DATABASE_VERSION); mDatabase = HistoryDatabase.this.getWritableDatabase(); } + @NonNull + public synchronized static HistoryDatabase getInstance() { + if (sInstance == null) { + sInstance = new HistoryDatabase(); + } + + return sInstance; + } + // Creating Tables @Override public void onCreate(@NonNull SQLiteDatabase db) { @@ -78,6 +82,16 @@ public synchronized void close() { super.close(); } + @NonNull + private static HistoryItem fromCursor(@NonNull Cursor cursor) { + HistoryItem historyItem = new HistoryItem(); + historyItem.setUrl(cursor.getString(1)); + historyItem.setTitle(cursor.getString(2)); + historyItem.setImageId(R.drawable.ic_history); + + return historyItem; + } + @WorkerThread @NonNull private SQLiteDatabase openIfNecessary() { @@ -88,7 +102,7 @@ private SQLiteDatabase openIfNecessary() { } @WorkerThread - public synchronized void deleteHistory() { + synchronized void deleteHistory() { mDatabase = openIfNecessary(); mDatabase.delete(TABLE_HISTORY, null, null); mDatabase.close(); @@ -96,13 +110,13 @@ public synchronized void deleteHistory() { } @WorkerThread - public synchronized void deleteHistoryItem(@NonNull String url) { + synchronized void deleteHistoryItem(@NonNull String url) { mDatabase = openIfNecessary(); mDatabase.delete(TABLE_HISTORY, KEY_URL + " = ?", new String[]{url}); } @WorkerThread - public synchronized void visitHistoryItem(@NonNull String url, @Nullable String title) { + synchronized void visitHistoryItem(@NonNull String url, @Nullable String title) { mDatabase = openIfNecessary(); ContentValues values = new ContentValues(); values.put(KEY_TITLE, title == null ? "" : title); @@ -148,7 +162,7 @@ synchronized String getHistoryItem(@NonNull String url) { @WorkerThread @NonNull - public synchronized List findItemsContaining(@Nullable String search) { + synchronized List findItemsContaining(@Nullable String search) { mDatabase = openIfNecessary(); List itemList = new ArrayList<>(5); if (search == null) { @@ -161,11 +175,7 @@ public synchronized List findItemsContaining(@Nullable String searc new String[]{search, search}, null, null, KEY_TIME_VISITED + " DESC", "5"); while (cursor.moveToNext()) { - HistoryItem item = new HistoryItem(); - item.setUrl(cursor.getString(1)); - item.setTitle(cursor.getString(2)); - item.setImageId(R.drawable.ic_history); - itemList.add(item); + itemList.add(fromCursor(cursor)); } cursor.close(); @@ -175,17 +185,13 @@ public synchronized List findItemsContaining(@Nullable String searc @WorkerThread @NonNull - public synchronized List getLastHundredItems() { + synchronized List getLastHundredItems() { mDatabase = openIfNecessary(); List itemList = new ArrayList<>(100); Cursor cursor = mDatabase.query(TABLE_HISTORY, null, null, null, null, null, KEY_TIME_VISITED + " DESC", "100"); while (cursor.moveToNext()) { - HistoryItem item = new HistoryItem(); - item.setUrl(cursor.getString(1)); - item.setTitle(cursor.getString(2)); - item.setImageId(R.drawable.ic_history); - itemList.add(item); + itemList.add(fromCursor(cursor)); } cursor.close(); @@ -195,18 +201,14 @@ public synchronized List getLastHundredItems() { @WorkerThread @NonNull - public synchronized List getAllHistoryItems() { + synchronized List getAllHistoryItems() { mDatabase = openIfNecessary(); List itemList = new ArrayList<>(); Cursor cursor = mDatabase.query(TABLE_HISTORY, null, null, null, null, null, KEY_TIME_VISITED + " DESC"); while (cursor.moveToNext()) { - HistoryItem item = new HistoryItem(); - item.setUrl(cursor.getString(1)); - item.setTitle(cursor.getString(2)); - item.setImageId(R.drawable.ic_history); - itemList.add(item); + itemList.add(fromCursor(cursor)); } cursor.close(); @@ -215,7 +217,7 @@ public synchronized List getAllHistoryItems() { } @WorkerThread - public synchronized long getHistoryItemsCount() { + synchronized long getHistoryItemsCount() { return DatabaseUtils.queryNumEntries(mDatabase, TABLE_HISTORY); } } diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryModel.java b/app/src/main/java/acr/browser/lightning/database/HistoryModel.java new file mode 100644 index 000000000..c04a341e9 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/database/HistoryModel.java @@ -0,0 +1,84 @@ +package acr.browser.lightning.database; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; + +import java.util.List; + +/** + * A model class providing reactive bindings + * with the underlying history database. + */ +public final class HistoryModel { + + private HistoryModel() {} + + @NonNull + public static Completable deleteHistory() { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + HistoryDatabase.getInstance().deleteHistory(); + + subscriber.onComplete(); + } + }); + } + + @NonNull + public static Completable deleteHistoryItem(@NonNull final String url) { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + HistoryDatabase.getInstance().deleteHistoryItem(url); + + subscriber.onComplete(); + } + }); + } + + @NonNull + public static Completable visitHistoryItem(@NonNull final String url, @Nullable final String title) { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + HistoryDatabase.getInstance().visitHistoryItem(url, title); + + subscriber.onComplete(); + } + }); + } + + @NonNull + public static Single> findHistoryItemsContaining(@NonNull final String query) { + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { + List result = HistoryDatabase.getInstance().findItemsContaining(query); + + subscriber.onItem(result); + subscriber.onComplete(); + } + }); + } + + @NonNull + public static Single> lastHundredVisitedHistoryItems() { + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { + List result = HistoryDatabase.getInstance().getLastHundredItems(); + + subscriber.onItem(result); + subscriber.onComplete(); + } + }); + } +} diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 5d45ad2a4..969b6a2db 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -12,6 +12,7 @@ import android.widget.AutoCompleteTextView; import android.widget.EditText; +import com.anthonycr.bonsai.CompletableOnSubscribe; import com.anthonycr.bonsai.Schedulers; import com.squareup.otto.Bus; @@ -27,8 +28,8 @@ import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.database.BookmarkManager; -import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.database.HistoryModel; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Utils; @@ -41,7 +42,6 @@ public class LightningDialogBuilder { @Inject BookmarkManager mBookmarkManager; @Inject PreferenceManager mPreferenceManager; - @Inject HistoryDatabase mHistoryDatabase; @Inject Bus mEventBus; @Inject @@ -82,44 +82,44 @@ public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity context, public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity activity, @NonNull final HistoryItem item) { BrowserDialog.show(activity, R.string.action_bookmarks, - new BrowserDialog.Item(R.string.dialog_open_new_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl(), BrowserEvents.OpenUrlInNewTab.Location.NEW_TAB)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_background_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl(), BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl(), BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); - } - }, - new BrowserDialog.Item(R.string.dialog_copy_link) { - @Override - public void onClick() { - BrowserApp.copyToClipboard(activity, item.getUrl()); - } - }, - new BrowserDialog.Item(R.string.dialog_remove_bookmark) { - @Override - public void onClick() { - if (mBookmarkManager.deleteBookmark(item)) { - mEventBus.post(new BookmarkEvents.Deleted(item)); + new BrowserDialog.Item(R.string.dialog_open_new_tab) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl(), BrowserEvents.OpenUrlInNewTab.Location.NEW_TAB)); + } + }, + new BrowserDialog.Item(R.string.dialog_open_background_tab) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl(), BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); + } + }, + new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl(), BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); + } + }, + new BrowserDialog.Item(R.string.dialog_copy_link) { + @Override + public void onClick() { + BrowserApp.copyToClipboard(activity, item.getUrl()); } - } - }, - new BrowserDialog.Item(R.string.dialog_edit_bookmark) { - @Override - public void onClick() { - showEditBookmarkDialog(activity, item); - } - }); + }, + new BrowserDialog.Item(R.string.dialog_remove_bookmark) { + @Override + public void onClick() { + if (mBookmarkManager.deleteBookmark(item)) { + mEventBus.post(new BookmarkEvents.Deleted(item)); + } + } + }, + new BrowserDialog.Item(R.string.dialog_edit_bookmark) { + @Override + public void onClick() { + showEditBookmarkDialog(activity, item); + } + }); } private void showEditBookmarkDialog(@NonNull final Activity activity, @NonNull final HistoryItem item) { @@ -131,29 +131,29 @@ private void showEditBookmarkDialog(@NonNull final Activity activity, @NonNull f final EditText getUrl = (EditText) dialogLayout.findViewById(R.id.bookmark_url); getUrl.setText(item.getUrl()); final AutoCompleteTextView getFolder = - (AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder); + (AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder); getFolder.setHint(R.string.folder); getFolder.setText(item.getFolder()); final List folders = mBookmarkManager.getFolderTitles(); final ArrayAdapter suggestionsAdapter = new ArrayAdapter<>(activity, - android.R.layout.simple_dropdown_item_1line, folders); + android.R.layout.simple_dropdown_item_1line, folders); getFolder.setThreshold(1); getFolder.setAdapter(suggestionsAdapter); editBookmarkDialog.setView(dialogLayout); editBookmarkDialog.setPositiveButton(activity.getString(R.string.action_ok), - new DialogInterface.OnClickListener() { + new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - HistoryItem editedItem = new HistoryItem(); - editedItem.setTitle(getTitle.getText().toString()); - editedItem.setUrl(getUrl.getText().toString()); - editedItem.setUrl(getUrl.getText().toString()); - editedItem.setFolder(getFolder.getText().toString()); - mBookmarkManager.editBookmark(item, editedItem); - mEventBus.post(new BookmarkEvents.BookmarkChanged(item, editedItem)); - } - }); + @Override + public void onClick(DialogInterface dialog, int which) { + HistoryItem editedItem = new HistoryItem(); + editedItem.setTitle(getTitle.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setFolder(getFolder.getText().toString()); + mBookmarkManager.editBookmark(item, editedItem); + mEventBus.post(new BookmarkEvents.BookmarkChanged(item, editedItem)); + } + }); Dialog dialog = editBookmarkDialog.show(); BrowserDialog.setDialogSize(activity, dialog); } @@ -161,149 +161,145 @@ public void onClick(DialogInterface dialog, int which) { public void showBookmarkFolderLongPressedDialog(@NonNull final Activity activity, @NonNull final HistoryItem item) { BrowserDialog.show(activity, R.string.action_folder, - new BrowserDialog.Item(R.string.dialog_rename_folder) { - @Override - public void onClick() { - showRenameFolderDialog(activity, item); - } - }, - new BrowserDialog.Item(R.string.dialog_remove_folder) { - @Override - public void onClick() { - mBookmarkManager.deleteFolder(item.getTitle()); - mEventBus.post(new BookmarkEvents.Deleted(item)); - } - }); + new BrowserDialog.Item(R.string.dialog_rename_folder) { + @Override + public void onClick() { + showRenameFolderDialog(activity, item); + } + }, + new BrowserDialog.Item(R.string.dialog_remove_folder) { + @Override + public void onClick() { + mBookmarkManager.deleteFolder(item.getTitle()); + mEventBus.post(new BookmarkEvents.Deleted(item)); + } + }); } private void showRenameFolderDialog(@NonNull final Activity activity, @NonNull final HistoryItem item) { BrowserDialog.showEditText(activity, R.string.title_rename_folder, - R.string.hint_title, item.getTitle(), - R.string.action_ok, new BrowserDialog.EditorListener() { - @Override - public void onClick(String text) { - if (!TextUtils.isEmpty(text)) { - final String oldTitle = item.getTitle(); - final HistoryItem editedItem = new HistoryItem(); - editedItem.setTitle(text); - editedItem.setUrl(Constants.FOLDER + text); - editedItem.setFolder(item.getFolder()); - editedItem.setIsFolder(true); - mBookmarkManager.renameFolder(oldTitle, text); - mEventBus.post(new BookmarkEvents.BookmarkChanged(item, editedItem)); + R.string.hint_title, item.getTitle(), + R.string.action_ok, new BrowserDialog.EditorListener() { + @Override + public void onClick(String text) { + if (!TextUtils.isEmpty(text)) { + final String oldTitle = item.getTitle(); + final HistoryItem editedItem = new HistoryItem(); + editedItem.setTitle(text); + editedItem.setUrl(Constants.FOLDER + text); + editedItem.setFolder(item.getFolder()); + editedItem.setIsFolder(true); + mBookmarkManager.renameFolder(oldTitle, text); + mEventBus.post(new BookmarkEvents.BookmarkChanged(item, editedItem)); + } } - } - }); + }); } public void showLongPressedHistoryLinkDialog(@NonNull final Activity activity, @NonNull final String url) { BrowserDialog.show(activity, R.string.action_history, - new BrowserDialog.Item(R.string.dialog_open_new_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_background_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); - } - }, - new BrowserDialog.Item(R.string.dialog_copy_link) { - @Override - public void onClick() { - BrowserApp.copyToClipboard(activity, url); - } - }, - new BrowserDialog.Item(R.string.dialog_remove_from_history) { - @Override - public void onClick() { - BrowserApp.getIOThread().execute(new Runnable() { - @Override - public void run() { - mHistoryDatabase.deleteHistoryItem(url); - // openHistory(); - Schedulers.main().execute(new Runnable() { - @Override - public void run() { - mEventBus.post(new BrowserEvents.OpenHistoryInCurrentTab()); - } - }); - } - }); - } - }); + new BrowserDialog.Item(R.string.dialog_open_new_tab) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); + } + }, + new BrowserDialog.Item(R.string.dialog_open_background_tab) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); + } + }, + new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); + } + }, + new BrowserDialog.Item(R.string.dialog_copy_link) { + @Override + public void onClick() { + BrowserApp.copyToClipboard(activity, url); + } + }, + new BrowserDialog.Item(R.string.dialog_remove_from_history) { + @Override + public void onClick() { + HistoryModel.deleteHistoryItem(url) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + mEventBus.post(new BrowserEvents.OpenHistoryInCurrentTab()); + } + }); + } + }); } // TODO There should be a way in which we do not need an activity reference to dowload a file public void showLongPressImageDialog(@NonNull final Activity activity, @NonNull final String url, @NonNull final String userAgent) { BrowserDialog.show(activity, url.replace(Constants.HTTP, ""), - new BrowserDialog.Item(R.string.dialog_open_new_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_background_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); - } - }, - new BrowserDialog.Item(R.string.dialog_copy_link) { - @Override - public void onClick() { - BrowserApp.copyToClipboard(activity, url); - } - }, - new BrowserDialog.Item(R.string.dialog_download_image) { - @Override - public void onClick() { - Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment"); - } - }); + new BrowserDialog.Item(R.string.dialog_open_new_tab) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); + } + }, + new BrowserDialog.Item(R.string.dialog_open_background_tab) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); + } + }, + new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); + } + }, + new BrowserDialog.Item(R.string.dialog_copy_link) { + @Override + public void onClick() { + BrowserApp.copyToClipboard(activity, url); + } + }, + new BrowserDialog.Item(R.string.dialog_download_image) { + @Override + public void onClick() { + Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment"); + } + }); } public void showLongPressLinkDialog(@NonNull final Activity activity, final String url) { BrowserDialog.show(activity, url, - new BrowserDialog.Item(R.string.dialog_open_new_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_background_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); - } - }, - new BrowserDialog.Item(R.string.dialog_copy_link) { - @Override - public void onClick() { - BrowserApp.copyToClipboard(activity, url); - } - }); + new BrowserDialog.Item(R.string.dialog_open_new_tab) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); + } + }, + new BrowserDialog.Item(R.string.dialog_open_background_tab) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); + } + }, + new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { + @Override + public void onClick() { + mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); + } + }, + new BrowserDialog.Item(R.string.dialog_copy_link) { + @Override + public void onClick() { + BrowserApp.copyToClipboard(activity, url); + } + }); } } diff --git a/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java index 5d1ca65bf..425556bcc 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java @@ -16,11 +16,8 @@ import android.support.v7.app.AlertDialog; import android.webkit.WebView; -import javax.inject.Inject; - import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.utils.Utils; import acr.browser.lightning.utils.WebUtils; @@ -45,8 +42,6 @@ public class PrivacySettingsFragment extends LightningPreferenceFragment impleme private Activity mActivity; private Handler mMessageHandler; - @Inject HistoryDatabase mHistoryDatabase; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -200,7 +195,7 @@ private void clearCache() { } private void clearHistory() { - WebUtils.clearHistory(getActivity(), mHistoryDatabase); + WebUtils.clearHistory(getActivity()); mMessageHandler.sendEmptyMessage(1); } diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index 263fb29a5..02b67ad8c 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -40,8 +40,8 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.BookmarkManager; -import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.database.HistoryModel; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.ThemeUtils; @@ -65,7 +65,6 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable { private final Comparator mFilterComparator = new SuggestionsComparator(); - @Inject HistoryDatabase mDatabaseHandler; @Inject BookmarkManager mBookmarkManager; @Inject PreferenceManager mPreferenceManager; @@ -257,7 +256,7 @@ public void onSubscribe(@NonNull SingleSubscriber> subscriber) subscriber.onComplete(); } }).subscribeOn(FILTER_SCHEDULER) - .observeOn(Schedulers.main()) + .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable List item) { @@ -278,7 +277,7 @@ public void onSubscribe(@NonNull SingleSubscriber> subscriber) break; } if (mAllBookmarks.get(n).getTitle().toLowerCase(Locale.getDefault()) - .startsWith(query)) { + .startsWith(query)) { bookmarks.add(mAllBookmarks.get(n)); counter++; } else if (mAllBookmarks.get(n).getUrl().contains(query)) { @@ -303,18 +302,6 @@ private Single> getSuggestionsForQuery(@NonNull final String q } } - @NonNull - private Single> getHistoryForQuery(@NonNull final String query) { - return Single.create(new SingleAction>() { - @Override - public void onSubscribe(@NonNull SingleSubscriber> subscriber) { - List historyList = mDatabaseHandler.findItemsContaining(query); - subscriber.onItem(historyList); - subscriber.onComplete(); - } - }); - } - private boolean shouldRequestNetwork() { return !mIsIncognito && mSuggestionChoice != PreferenceManager.Suggestion.SUGGESTION_NONE; } @@ -338,35 +325,35 @@ protected FilterResults performFiltering(CharSequence constraint) { if (mSuggestionsAdapter.shouldRequestNetwork() && !SuggestionsManager.isRequestInProgress()) { mSuggestionsAdapter.getSuggestionsForQuery(query) - .subscribeOn(Schedulers.worker()) + .subscribeOn(Schedulers.worker()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + mSuggestionsAdapter.combineResults(null, null, item); + } + }); + } + + mSuggestionsAdapter.getBookmarksForQuery(query) + .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable List item) { - mSuggestionsAdapter.combineResults(null, null, item); + mSuggestionsAdapter.combineResults(item, null, null); } }); - } - - mSuggestionsAdapter.getBookmarksForQuery(query) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe>() { - @Override - public void onItem(@Nullable List item) { - mSuggestionsAdapter.combineResults(item, null, null); - } - }); - mSuggestionsAdapter.getHistoryForQuery(query) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe>() { - @Override - public void onItem(@Nullable List item) { - mSuggestionsAdapter.combineResults(null, item, null); - } - }); + HistoryModel.findHistoryItemsContaining(query) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + mSuggestionsAdapter.combineResults(null, item, null); + } + }); results.count = 1; return results; } diff --git a/app/src/main/java/acr/browser/lightning/utils/WebUtils.java b/app/src/main/java/acr/browser/lightning/utils/WebUtils.java index 1d165d40e..790566472 100644 --- a/app/src/main/java/acr/browser/lightning/utils/WebUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/WebUtils.java @@ -11,7 +11,9 @@ import android.webkit.WebView; import android.webkit.WebViewDatabase; -import acr.browser.lightning.database.HistoryDatabase; +import com.anthonycr.bonsai.Schedulers; + +import acr.browser.lightning.database.HistoryModel; /** * Copyright 8/4/2015 Anthony Restaino @@ -34,8 +36,10 @@ public static void clearWebStorage() { WebStorage.getInstance().deleteAllData(); } - public static void clearHistory(@NonNull Context context, @NonNull HistoryDatabase historyDatabase) { - historyDatabase.deleteHistory(); + public static void clearHistory(@NonNull Context context) { + HistoryModel.deleteHistory() + .subscribeOn(Schedulers.io()) + .subscribe(); WebViewDatabase m = WebViewDatabase.getInstance(context); m.clearFormData(); m.clearHttpAuthUsernamePassword(); diff --git a/build.gradle b/build.gradle index 8911568a9..b02baf915 100644 --- a/build.gradle +++ b/build.gradle @@ -17,10 +17,6 @@ allprojects { } ext { - // Necessary for Bonsai submodule - versionCode = 1 - versionName = '1.0' - minSdkVersion = 14 targetSdkVersion = 25 buildToolsVersion = '25.0.2' From 0819d357110ea6505af960efbc76512ea6f19875 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 9 Apr 2017 21:17:21 -0400 Subject: [PATCH 048/181] Making html page generation reactive --- .../lightning/activity/BrowserActivity.java | 4 +- .../lightning/activity/TabsManager.java | 24 +- .../browser/lightning/app/AppComponent.java | 6 + .../lightning/constant/BookmarkPage.java | 93 ++++--- .../lightning/constant/HistoryPage.java | 48 +++- .../browser/lightning/constant/StartPage.java | 244 ++++++++---------- .../browser/lightning/view/LightningView.java | 47 ++-- 7 files changed, 249 insertions(+), 217 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 9a4a346f5..8fdb36d2d 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -423,7 +423,7 @@ void panicClean() { mTabsManager.newTab(this, "", false); mTabsManager.switchToTab(0); mTabsManager.clearSavedState(); - HistoryPage.deleteHistoryPage(getApplication()); + new HistoryPage().deleteHistoryPage().subscribe(); closeBrowser(); // System exit needed in the case of receiving // the panic intent since finish() isn't completely @@ -1533,7 +1533,7 @@ public void onItemClick(AdapterView adapterView, View view, int pos, long l) * function that opens the HTML history page in the browser */ private void openHistory() { - HistoryPage.getHistoryPage() + new HistoryPage().getHistoryPage() .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe() { diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index f0a7478bd..1164bb38c 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -164,11 +164,29 @@ public void onNext(@Nullable Bundle item) { String url = item.getString(URL_KEY); if (url != null && tab.getWebView() != null) { if (UrlUtils.isBookmarkUrl(url)) { - new BookmarkPage(tab, activity, mBookmarkManager).load(); + new BookmarkPage(activity).getBookmarkPage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + tab.loadUrl(item); + } + }); } else if (UrlUtils.isStartPageUrl(url)) { - new StartPage(tab, mApp).load(); + new StartPage().getHomepage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + tab.loadUrl(item); + } + }); } else if (UrlUtils.isHistoryUrl(url)) { - HistoryPage.getHistoryPage() + new HistoryPage().getHistoryPage() .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe() { diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index c28da576e..c807078ba 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -8,6 +8,8 @@ import acr.browser.lightning.activity.ThemableBrowserActivity; import acr.browser.lightning.activity.ThemableSettingsActivity; import acr.browser.lightning.browser.BrowserPresenter; +import acr.browser.lightning.constant.BookmarkPage; +import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.constant.StartPage; import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.download.LightningDownloadListener; @@ -62,6 +64,10 @@ public interface AppComponent { void inject(StartPage startPage); + void inject(HistoryPage historyPage); + + void inject(BookmarkPage bookmarkPage); + void inject(BrowserPresenter presenter); void inject(TabsManager manager); diff --git a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java index c6d64ddf0..b44d561ca 100644 --- a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java @@ -6,27 +6,30 @@ import android.app.Activity; import android.app.Application; import android.graphics.Bitmap; -import android.os.AsyncTask; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; + import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; -import java.lang.ref.WeakReference; import java.util.List; +import javax.inject.Inject; + import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.utils.Utils; -import acr.browser.lightning.view.LightningView; -public final class BookmarkPage extends AsyncTask { +public final class BookmarkPage { /** * The bookmark page standard suffix @@ -34,25 +37,25 @@ public final class BookmarkPage extends AsyncTask { public static final String FILENAME = "bookmarks.html"; private static final String HEADING_1 = "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - ""; + "<head>\n" + + "<meta content=en-us http-equiv=Content-Language />\n" + + "<meta content='text/html; charset=utf-8' http-equiv=Content-Type />\n" + + "<meta name=viewport content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>\n" + + "<title>"; private static final String HEADING_2 = "\n" + - "\n" + - "\n" + - "

"; + "\n" + + "\n" + + "
"; private static final String PART1 = "
\n" + - "
\n" + - "
\n" + - "

\n" + - " { private File mFilesDir; private File mCacheDir; - private final Application mApp; - private final BookmarkManager mManager; - @NonNull private final WeakReference mTabReference; + @Inject Application mApp; + @Inject BookmarkManager mManager; + private final Bitmap mFolderIcon; @NonNull private final String mTitle; - public BookmarkPage(LightningView tab, @NonNull Activity activity, BookmarkManager manager) { - mApp = BrowserApp.get(activity); - final Bitmap folderIcon = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, false); + public BookmarkPage(@NonNull Activity activity) { + BrowserApp.getAppComponent().inject(this); + mFolderIcon = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, false); mTitle = mApp.getString(R.string.action_bookmarks); - mManager = manager; - mTabReference = new WeakReference<>(tab); - mFolderIcon = folderIcon; } - @Override - protected Void doInBackground(Void... params) { - mCacheDir = mApp.getCacheDir(); - mFilesDir = mApp.getFilesDir(); - cacheDefaultFolderIcon(); - buildBookmarkPage(null, mManager); - return null; - } + @NonNull + public Single getBookmarkPage() { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + mCacheDir = mApp.getCacheDir(); + mFilesDir = mApp.getFilesDir(); + cacheDefaultFolderIcon(); + buildBookmarkPage(null); - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - LightningView tab = mTabReference.get(); - if (tab != null) { - File bookmarkWebPage = new File(mFilesDir, FILENAME); - tab.loadUrl(Constants.FILE + bookmarkWebPage); - } + File bookmarkWebPage = new File(mFilesDir, FILENAME); + + subscriber.onItem(Constants.FILE + bookmarkWebPage); + subscriber.onComplete(); + } + }); } private void cacheDefaultFolderIcon() { @@ -115,8 +114,8 @@ private void cacheDefaultFolderIcon() { } } - private void buildBookmarkPage(@Nullable final String folder, @NonNull final BookmarkManager manager) { - final List list = manager.getBookmarksCopyFromFolder(folder, true); + private void buildBookmarkPage(@Nullable final String folder) { + final List list = mManager.getBookmarksCopyFromFolder(folder, true); final File bookmarkWebPage; if (folder == null || folder.isEmpty()) { bookmarkWebPage = new File(mFilesDir, FILENAME); @@ -134,7 +133,7 @@ private void buildBookmarkPage(@Nullable final String folder, @NonNull final Boo bookmarkBuilder.append(Constants.FILE).append(folderPage); bookmarkBuilder.append(PART2); bookmarkBuilder.append(folderIconPath); - buildBookmarkPage(item.getTitle(), manager); + buildBookmarkPage(item.getTitle()); } else { bookmarkBuilder.append(item.getUrl()); bookmarkBuilder.append(PART2).append(PART3); @@ -157,8 +156,4 @@ private void buildBookmarkPage(@Nullable final String folder, @NonNull final Boo } } - public void load() { - executeOnExecutor(BrowserApp.getIOThread()); - } - } diff --git a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java index 4d93b9967..265366484 100644 --- a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java @@ -8,6 +8,9 @@ import android.support.annotation.Nullable; import android.util.Log; +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; import com.anthonycr.bonsai.Single; import com.anthonycr.bonsai.SingleAction; import com.anthonycr.bonsai.SingleOnSubscribe; @@ -19,6 +22,8 @@ import java.util.Iterator; import java.util.List; +import javax.inject.Inject; + import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.HistoryItem; @@ -46,15 +51,21 @@ public class HistoryPage { private static final String END = "

"; - private HistoryPage() {} + @NonNull private final String mTitle; + + @Inject Application mApp; + + public HistoryPage() { + BrowserApp.getAppComponent().inject(this); + mTitle = mApp.getString(R.string.action_history); + } @NonNull - public static Single getHistoryPage() { + public Single getHistoryPage() { return Single.create(new SingleAction() { @Override public void onSubscribe(@NonNull final SingleSubscriber subscriber) { - final String title = BrowserApp.getApplication().getString(R.string.action_history); - final StringBuilder historyBuilder = new StringBuilder(HEADING_1 + title + HEADING_2); + final StringBuilder historyBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2); HistoryModel.lastHundredVisitedHistoryItems() .subscribe(new SingleOnSubscribe>() { @@ -76,7 +87,7 @@ public void onItem(@Nullable List item) { } historyBuilder.append(END); - File historyWebPage = new File(BrowserApp.getApplication().getFilesDir(), FILENAME); + File historyWebPage = new File(mApp.getFilesDir(), FILENAME); FileWriter historyWriter = null; try { //noinspection IOResourceOpenedButNotSafelyClosed @@ -97,17 +108,26 @@ public void onItem(@Nullable List item) { } /** - * Use this method to immediately delete the history - * page on the current thread. This will clear the - * cached history page that was stored on file. + * Use this observable to immediately delete the history + * page. This will clear the cached history page that was + * stored on file. * - * @param application the application object needed to get the file. + * @return a completable that deletes the history page + * when subscribed. */ - public static void deleteHistoryPage(@NonNull Application application) { - File historyWebPage = new File(application.getFilesDir(), FILENAME); - if (historyWebPage.exists()) { - historyWebPage.delete(); - } + @NonNull + public Completable deleteHistoryPage() { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + File historyWebPage = new File(mApp.getFilesDir(), FILENAME); + if (historyWebPage.exists()) { + historyWebPage.delete(); + } + + subscriber.onComplete(); + } + }); } } \ No newline at end of file diff --git a/app/src/main/java/acr/browser/lightning/constant/StartPage.java b/app/src/main/java/acr/browser/lightning/constant/StartPage.java index e1e503d31..b422ab163 100644 --- a/app/src/main/java/acr/browser/lightning/constant/StartPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/StartPage.java @@ -4,14 +4,15 @@ package acr.browser.lightning.constant; import android.app.Application; -import android.os.AsyncTask; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.lang.ref.WeakReference; import javax.inject.Inject; @@ -19,9 +20,8 @@ import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Utils; -import acr.browser.lightning.view.LightningView; -public class StartPage extends AsyncTask { +public class StartPage { public static final String FILENAME = "homepage.html"; @@ -55,142 +55,118 @@ public class StartPage extends AsyncTask { private static final String END = "\" + document.getElementById(\"search_input\").value;document.getElementById(\"search_input\").value = \"\";}return false;}"; @NonNull private final String mTitle; - @NonNull private final Application mApp; - @NonNull private final WeakReference mTabReference; + @Inject Application mApp; @Inject PreferenceManager mPreferenceManager; - private String mStartpageUrl; - - public StartPage(LightningView tab, @NonNull Application app) { + public StartPage() { BrowserApp.getAppComponent().inject(this); - mTitle = app.getString(R.string.home); - mApp = app; - mTabReference = new WeakReference<>(tab); - } - - @Nullable - @Override - protected Void doInBackground(Void... params) { - mStartpageUrl = getHomepage(); - return null; + mTitle = mApp.getString(R.string.home); } - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - LightningView tab = mTabReference.get(); - if (tab != null) { - tab.loadUrl(mStartpageUrl); - } - } - - /** - * This method builds the homepage and returns the local URL to be loaded - * when it finishes building. - * - * @return the URL to load - */ @NonNull - private String getHomepage() { - StringBuilder homepageBuilder = new StringBuilder(HEAD_1 + mTitle + HEAD_2); - String icon; - String searchUrl; - switch (mPreferenceManager.getSearchChoice()) { - case 0: - // CUSTOM SEARCH - icon = "file:///android_asset/lightning.png"; - searchUrl = mPreferenceManager.getSearchUrl(); - break; - case 1: - // GOOGLE_SEARCH; - icon = "file:///android_asset/google.png"; - // "https://www.google.com/images/srpr/logo11w.png"; - searchUrl = Constants.GOOGLE_SEARCH; - break; - case 2: - // ANDROID SEARCH; - icon = "file:///android_asset/ask.png"; - searchUrl = Constants.ASK_SEARCH; - break; - case 3: - // BING_SEARCH; - icon = "file:///android_asset/bing.png"; - // "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Bing_logo_%282013%29.svg/500px-Bing_logo_%282013%29.svg.png"; - searchUrl = Constants.BING_SEARCH; - break; - case 4: - // YAHOO_SEARCH; - icon = "file:///android_asset/yahoo.png"; - // "http://upload.wikimedia.org/wikipedia/commons/thumb/2/24/Yahoo%21_logo.svg/799px-Yahoo%21_logo.svg.png"; - searchUrl = Constants.YAHOO_SEARCH; - break; - case 5: - // STARTPAGE_SEARCH; - icon = "file:///android_asset/startpage.png"; - // "https://com/graphics/startp_logo.gif"; - searchUrl = Constants.STARTPAGE_SEARCH; - break; - case 6: - // STARTPAGE_MOBILE - icon = "file:///android_asset/startpage.png"; - // "https://com/graphics/startp_logo.gif"; - searchUrl = Constants.STARTPAGE_MOBILE_SEARCH; - break; - case 7: - // DUCK_SEARCH; - icon = "file:///android_asset/duckduckgo.png"; - // "https://duckduckgo.com/assets/logo_homepage.normal.v101.png"; - searchUrl = Constants.DUCK_SEARCH; - break; - case 8: - // DUCK_LITE_SEARCH; - icon = "file:///android_asset/duckduckgo.png"; - // "https://duckduckgo.com/assets/logo_homepage.normal.v101.png"; - searchUrl = Constants.DUCK_LITE_SEARCH; - break; - case 9: - // BAIDU_SEARCH; - icon = "file:///android_asset/baidu.png"; - // "http://www.baidu.com/img/bdlogo.gif"; - searchUrl = Constants.BAIDU_SEARCH; - break; - case 10: - // YANDEX_SEARCH; - icon = "file:///android_asset/yandex.png"; - // "http://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Yandex.svg/600px-Yandex.svg.png"; - searchUrl = Constants.YANDEX_SEARCH; - break; - default: - // DEFAULT GOOGLE_SEARCH; - icon = "file:///android_asset/google.png"; - searchUrl = Constants.GOOGLE_SEARCH; - break; - - } - - homepageBuilder.append(icon); - homepageBuilder.append(MIDDLE); - homepageBuilder.append(searchUrl); - homepageBuilder.append(END); - - File homepage = new File(mApp.getFilesDir(), FILENAME); - FileWriter hWriter = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - hWriter = new FileWriter(homepage, false); - hWriter.write(homepageBuilder.toString()); - } catch (IOException e) { - e.printStackTrace(); - } finally { - Utils.close(hWriter); - } - - return Constants.FILE + homepage; - } - - public void load() { - executeOnExecutor(BrowserApp.getIOThread()); + public Single getHomepage() { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + + StringBuilder homepageBuilder = new StringBuilder(HEAD_1 + mTitle + HEAD_2); + String icon; + String searchUrl; + switch (mPreferenceManager.getSearchChoice()) { + case 0: + // CUSTOM SEARCH + icon = "file:///android_asset/lightning.png"; + searchUrl = mPreferenceManager.getSearchUrl(); + break; + case 1: + // GOOGLE_SEARCH; + icon = "file:///android_asset/google.png"; + // "https://www.google.com/images/srpr/logo11w.png"; + searchUrl = Constants.GOOGLE_SEARCH; + break; + case 2: + // ANDROID SEARCH; + icon = "file:///android_asset/ask.png"; + searchUrl = Constants.ASK_SEARCH; + break; + case 3: + // BING_SEARCH; + icon = "file:///android_asset/bing.png"; + // "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Bing_logo_%282013%29.svg/500px-Bing_logo_%282013%29.svg.png"; + searchUrl = Constants.BING_SEARCH; + break; + case 4: + // YAHOO_SEARCH; + icon = "file:///android_asset/yahoo.png"; + // "http://upload.wikimedia.org/wikipedia/commons/thumb/2/24/Yahoo%21_logo.svg/799px-Yahoo%21_logo.svg.png"; + searchUrl = Constants.YAHOO_SEARCH; + break; + case 5: + // STARTPAGE_SEARCH; + icon = "file:///android_asset/startpage.png"; + // "https://com/graphics/startp_logo.gif"; + searchUrl = Constants.STARTPAGE_SEARCH; + break; + case 6: + // STARTPAGE_MOBILE + icon = "file:///android_asset/startpage.png"; + // "https://com/graphics/startp_logo.gif"; + searchUrl = Constants.STARTPAGE_MOBILE_SEARCH; + break; + case 7: + // DUCK_SEARCH; + icon = "file:///android_asset/duckduckgo.png"; + // "https://duckduckgo.com/assets/logo_homepage.normal.v101.png"; + searchUrl = Constants.DUCK_SEARCH; + break; + case 8: + // DUCK_LITE_SEARCH; + icon = "file:///android_asset/duckduckgo.png"; + // "https://duckduckgo.com/assets/logo_homepage.normal.v101.png"; + searchUrl = Constants.DUCK_LITE_SEARCH; + break; + case 9: + // BAIDU_SEARCH; + icon = "file:///android_asset/baidu.png"; + // "http://www.baidu.com/img/bdlogo.gif"; + searchUrl = Constants.BAIDU_SEARCH; + break; + case 10: + // YANDEX_SEARCH; + icon = "file:///android_asset/yandex.png"; + // "http://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Yandex.svg/600px-Yandex.svg.png"; + searchUrl = Constants.YANDEX_SEARCH; + break; + default: + // DEFAULT GOOGLE_SEARCH; + icon = "file:///android_asset/google.png"; + searchUrl = Constants.GOOGLE_SEARCH; + break; + + } + + homepageBuilder.append(icon); + homepageBuilder.append(MIDDLE); + homepageBuilder.append(searchUrl); + homepageBuilder.append(END); + + File homepage = new File(mApp.getFilesDir(), FILENAME); + FileWriter hWriter = null; + try { + //noinspection IOResourceOpenedButNotSafelyClosed + hWriter = new FileWriter(homepage, false); + hWriter.write(homepageBuilder.toString()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + Utils.close(hWriter); + } + + subscriber.onItem(Constants.FILE + homepage); + + } + }); } } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index f96201430..34db90472 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -57,6 +57,7 @@ import com.anthonycr.bonsai.Schedulers; +import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.ProxyUtils; import acr.browser.lightning.utils.UrlUtils; import acr.browser.lightning.utils.Utils; @@ -81,16 +82,16 @@ public class LightningView { private static String sDefaultUserAgent; private static float sMaxFling; private static final float[] sNegativeColorArray = { - -1.0f, 0, 0, 0, 255, // red - 0, -1.0f, 0, 0, 255, // green - 0, 0, -1.0f, 0, 255, // blue - 0, 0, 0, 1.0f, 0 // alpha + -1.0f, 0, 0, 0, 255, // red + 0, -1.0f, 0, 0, 255, // green + 0, 0, -1.0f, 0, 255, // blue + 0, 0, 0, 1.0f, 0 // alpha }; private static final float[] sIncreaseContrastColorArray = { - 2.0f, 0, 0, 0, -160.f, // red - 0, 2.0f, 0, 0, -160.f, // green - 0, 0, 2.0f, 0, -160.f, // blue - 0, 0, 0, 1.0f, 0 // alpha + 2.0f, 0, 0, 0, -160.f, // red + 0, 2.0f, 0, 0, -160.f, // green + 0, 0, 2.0f, 0, -160.f, // blue + 0, 0, 0, 1.0f, 0 // alpha }; @NonNull private final LightningViewTitle mTitle; @@ -213,7 +214,16 @@ public void loadHomepage() { * UI thread. */ private void loadStartpage() { - new StartPage(this, BrowserApp.get(mActivity)).load(); + new StartPage().getHomepage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + loadUrl(item); + } + }); } /** @@ -222,9 +232,16 @@ private void loadStartpage() { * UI thread. It also caches the default folder icon locally. */ public void loadBookmarkpage() { - if (mWebView == null) - return; - new BookmarkPage(this, mActivity, mBookmarkManager).load(); + new BookmarkPage(mActivity).getBookmarkPage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + loadUrl(item); + } + }); } /** @@ -353,7 +370,7 @@ public synchronized void initializePreferences(@NonNull Context context) { } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { CookieManager.getInstance().setAcceptThirdPartyCookies(mWebView, - !mPreferences.getBlockThirdPartyCookiesEnabled()); + !mPreferences.getBlockThirdPartyCookiesEnabled()); } } @@ -695,7 +712,7 @@ private void setColorMode(int mode) { break; case 1: ColorMatrixColorFilter filterInvert = new ColorMatrixColorFilter( - sNegativeColorArray); + sNegativeColorArray); mPaint.setColorFilter(filterInvert); setHardwareRendering(); @@ -724,7 +741,7 @@ private void setColorMode(int mode) { case 4: ColorMatrixColorFilter IncreaseHighContrast = new ColorMatrixColorFilter( - sIncreaseContrastColorArray); + sIncreaseContrastColorArray); mPaint.setColorFilter(IncreaseHighContrast); setHardwareRendering(); break; From 3c133748e910124d9827d2b1e81518f30b35102f Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 11 Apr 2017 22:38:15 -0400 Subject: [PATCH 049/181] Dropping async task for bonsai in image downloading --- app/build.gradle | 2 +- .../browser/lightning/app/AppComponent.java | 3 + .../lightning/async/AsyncExecutor.java | 53 ------- .../lightning/fragment/BookmarksFragment.java | 37 ++++- .../ImageDownloader.java} | 142 +++++++++--------- 5 files changed, 108 insertions(+), 129 deletions(-) delete mode 100644 app/src/main/java/acr/browser/lightning/async/AsyncExecutor.java rename app/src/main/java/acr/browser/lightning/{async/ImageDownloadTask.java => view/ImageDownloader.java} (51%) diff --git a/app/build.gradle b/app/build.gradle index 19720c770..161c19469 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,7 +66,7 @@ dexcount { dependencies { // support libraries - def supportLibVersion = '25.3.0' + def supportLibVersion = '25.3.1' compile "com.android.support:palette-v7:$supportLibVersion" compile "com.android.support:appcompat-v7:$supportLibVersion" compile "com.android.support:design:$supportLibVersion" diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index c807078ba..fd2b20428 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -7,6 +7,7 @@ import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.activity.ThemableBrowserActivity; import acr.browser.lightning.activity.ThemableSettingsActivity; +import acr.browser.lightning.view.ImageDownloader; import acr.browser.lightning.browser.BrowserPresenter; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.HistoryPage; @@ -76,4 +77,6 @@ public interface AppComponent { void inject(SuggestionsAdapter suggestionsAdapter); + void inject(ImageDownloader imageDownloader); + } diff --git a/app/src/main/java/acr/browser/lightning/async/AsyncExecutor.java b/app/src/main/java/acr/browser/lightning/async/AsyncExecutor.java deleted file mode 100644 index 7dea22476..000000000 --- a/app/src/main/java/acr/browser/lightning/async/AsyncExecutor.java +++ /dev/null @@ -1,53 +0,0 @@ -package acr.browser.lightning.async; - -import android.support.annotation.NonNull; -import android.util.Log; - -import java.util.ArrayDeque; -import java.util.Queue; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; - -/** - * Created 9/27/2015 Anthony Restaino - */ -public class AsyncExecutor implements Executor { - - private static final String TAG = AsyncExecutor.class.getSimpleName(); - private static final AsyncExecutor INSTANCE = new AsyncExecutor(); - private final Queue mQueue = new ArrayDeque<>(1); - private final ExecutorService mExecutor = Executors.newFixedThreadPool(4); - - private AsyncExecutor() {} - - @NonNull - public static AsyncExecutor getInstance() { - return INSTANCE; - } - - public synchronized void notifyThreadFinish() { - if (mQueue.isEmpty()) { - return; - } - Runnable runnable = mQueue.remove(); - execute(runnable); - } - - @Override - protected void finalize() throws Throwable { - mExecutor.shutdownNow(); - super.finalize(); - } - - @Override - public void execute(@NonNull Runnable command) { - try { - mExecutor.execute(command); - } catch (RejectedExecutionException ignored) { - mQueue.add(command); - Log.d(TAG, "Thread was enqueued"); - } - } -} diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 4da841431..ed0680565 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -35,6 +35,7 @@ import com.squareup.otto.Bus; import com.squareup.otto.Subscribe; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -44,8 +45,7 @@ import acr.browser.lightning.activity.ReadingActivity; import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.async.AsyncExecutor; -import acr.browser.lightning.async.ImageDownloadTask; +import acr.browser.lightning.view.ImageDownloader; import acr.browser.lightning.browser.BookmarksView; import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.constant.Constants; @@ -74,6 +74,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @Inject PreferenceManager mPreferenceManager; + private ImageDownloader mImageDownloader; + private TabsManager mTabsManager; private UIController mUiController; @@ -124,7 +126,9 @@ public void onCreate(@Nullable Bundle savedInstanceState) { mWebpageBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme); mFolderBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_folder, darkTheme); mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(context) : - ThemeUtils.getIconLightThemeColor(context); + ThemeUtils.getIconLightThemeColor(context); + + mImageDownloader = new ImageDownloader(mWebpageBitmap); } private TabsManager getTabsManager() { @@ -222,7 +226,9 @@ public void reinitializePreferences() { mWebpageBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_webpage, darkTheme); mFolderBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, darkTheme); mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(activity) : - ThemeUtils.getIconLightThemeColor(activity); + ThemeUtils.getIconLightThemeColor(activity); + + mImageDownloader = new ImageDownloader(mWebpageBitmap); } private void updateBookmarkIndicator(final String url) { @@ -389,14 +395,31 @@ public View getView(int position, View convertView, @NonNull ViewGroup parent) { ViewCompat.jumpDrawablesToCurrentState(row); - HistoryItem web = mBookmarks.get(position); + final HistoryItem web = mBookmarks.get(position); holder.txtTitle.setText(web.getTitle()); if (web.isFolder()) { holder.favicon.setImageBitmap(mFolderBitmap); } else if (web.getBitmap() == null) { holder.favicon.setImageBitmap(mWebpageBitmap); - new ImageDownloadTask(holder.favicon, web, mWebpageBitmap, BrowserApp.get(context)) - .executeOnExecutor(AsyncExecutor.getInstance()); + holder.favicon.setTag(web.getUrl().hashCode()); + + final String url = web.getUrl(); + final WeakReference imageViewReference = new WeakReference<>(holder.favicon); + mImageDownloader.newImageRequest(url) + .subscribeOn(Schedulers.worker()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Bitmap item) { + ImageView imageView = imageViewReference.get(); + Object tag = imageView != null ? imageView.getTag() : null; + if (tag != null && tag.equals(url.hashCode())) { + imageView.setImageBitmap(item); + } + + web.setBitmap(item); + } + }); } else { holder.favicon.setImageBitmap(web.getBitmap()); } diff --git a/app/src/main/java/acr/browser/lightning/async/ImageDownloadTask.java b/app/src/main/java/acr/browser/lightning/view/ImageDownloader.java similarity index 51% rename from app/src/main/java/acr/browser/lightning/async/ImageDownloadTask.java rename to app/src/main/java/acr/browser/lightning/view/ImageDownloader.java index 60cd9bfd4..61378c70a 100644 --- a/app/src/main/java/acr/browser/lightning/async/ImageDownloadTask.java +++ b/app/src/main/java/acr/browser/lightning/view/ImageDownloader.java @@ -1,69 +1,91 @@ -package acr.browser.lightning.async; +package acr.browser.lightning.view; import android.app.Application; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; -import android.os.AsyncTask; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; -import android.widget.ImageView; -import com.anthonycr.bonsai.Schedulers; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; -import java.lang.ref.WeakReference; import java.net.HttpURLConnection; import java.net.URL; +import javax.inject.Inject; + +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; -import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.utils.Utils; -public class ImageDownloadTask extends AsyncTask { - - private static final String TAG = ImageDownloadTask.class.getSimpleName(); - @NonNull private final WeakReference mFaviconImage; - @NonNull private final Application mContext; - @NonNull private final HistoryItem mWeb; - private final String mUrl; - @NonNull private final Bitmap mDefaultBitmap; - - public ImageDownloadTask(@NonNull ImageView bmImage, - @NonNull HistoryItem web, - @NonNull Bitmap defaultBitmap, - @NonNull Application context) { - // Set a tag on the ImageView so we know if the view - // has gone out of scope and should not be used - bmImage.setTag(web.getUrl().hashCode()); - this.mFaviconImage = new WeakReference<>(bmImage); - this.mWeb = web; - this.mUrl = web.getUrl(); - this.mDefaultBitmap = defaultBitmap; - this.mContext = context; +/** + * An ImageDownloader that creates image + * loading requests on demand. + */ +public class ImageDownloader { + + private static final String TAG = "ImageDownloader"; + + @Inject Application mApp; + + @NonNull private Bitmap mDefaultBitmap; + + public ImageDownloader(@NonNull Bitmap defaultBitmap) { + mDefaultBitmap = defaultBitmap; + BrowserApp.getAppComponent().inject(this); + } + + /** + * Creates a new image request for the given url. + * Emits the bitmap associated with that url, or + * the default bitmap if none was found. + * + * @param url the url for which to retrieve the bitmap. + * @return a single that emits the bitmap that was found. + */ + @NonNull + public Single newImageRequest(@Nullable final String url) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + Bitmap favicon = retrieveBitmap(mApp, mDefaultBitmap, url); + + Bitmap paddedFavicon = Utils.padFavicon(favicon); + + subscriber.onItem(paddedFavicon); + subscriber.onComplete(); + } + }); } @NonNull - @Override - protected Bitmap doInBackground(Void... params) { - Bitmap mIcon = null; + private static Bitmap retrieveBitmap(@NonNull Application app, + @NonNull Bitmap defaultBitmap, + @Nullable String url) { + // unique path for each url that is bookmarked. - if (mUrl == null) { - return mDefaultBitmap; + if (url == null) { + return defaultBitmap; } - File cache = mContext.getCacheDir(); - final Uri uri = Uri.parse(mUrl); - if (uri.getHost() == null || uri.getScheme() == null) { - return mDefaultBitmap; + + Bitmap icon = null; + File cache = app.getCacheDir(); + final Uri uri = Uri.parse(url); + + if (uri.getHost() == null || uri.getScheme() == null || Constants.FILE.startsWith(uri.getScheme())) { + return defaultBitmap; } + final String hash = String.valueOf(uri.getHost().hashCode()); final File image = new File(cache, hash + ".png"); final String urlDisplay = uri.getScheme() + "://" + uri.getHost() + "/favicon.ico"; - if (Constants.FILE.startsWith(uri.getScheme())) { - return mDefaultBitmap; - } + // checks to see if the image exists if (!image.exists()) { FileOutputStream fos = null; @@ -79,12 +101,12 @@ protected Bitmap doInBackground(Void... params) { in = connection.getInputStream(); if (in != null) { - mIcon = BitmapFactory.decodeStream(in); + icon = BitmapFactory.decodeStream(in); } // ...and cache it - if (mIcon != null) { + if (icon != null) { fos = new FileOutputStream(image); - mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos); + icon.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); Log.d(Constants.TAG, "Downloaded: " + urlDisplay); } @@ -97,9 +119,10 @@ protected Bitmap doInBackground(Void... params) { } } else { // if it exists, retrieve it from the cache - mIcon = BitmapFactory.decodeFile(image.getPath()); + icon = BitmapFactory.decodeFile(image.getPath()); } - if (mIcon == null) { + + if (icon == null) { InputStream in = null; FileOutputStream fos = null; try { @@ -113,12 +136,12 @@ protected Bitmap doInBackground(Void... params) { in = connection.getInputStream(); if (in != null) { - mIcon = BitmapFactory.decodeStream(in); + icon = BitmapFactory.decodeStream(in); } // ...and cache it - if (mIcon != null) { + if (icon != null) { fos = new FileOutputStream(image); - mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos); + icon.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); } @@ -129,28 +152,11 @@ protected Bitmap doInBackground(Void... params) { Utils.close(fos); } } - if (mIcon == null) { - return mDefaultBitmap; - } else { - return mIcon; - } - } - @Override - protected void onPostExecute(Bitmap bitmap) { - super.onPostExecute(bitmap); - AsyncExecutor.getInstance().notifyThreadFinish(); - final Bitmap fav = Utils.padFavicon(bitmap); - final ImageView view = mFaviconImage.get(); - if (view != null && view.getTag().equals(mWeb.getUrl().hashCode())) { - Schedulers.main().execute(new Runnable() { - @Override - public void run() { - view.setImageBitmap(fav); - } - }); + if (icon == null) { + return defaultBitmap; + } else { + return icon; } - mWeb.setBitmap(fav); } - } From 1d6ef194d14804ff3d6f1cedaa7016303e648db4 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 12 Apr 2017 22:30:55 -0400 Subject: [PATCH 050/181] Reducing code duplication in image downloader --- .../lightning/view/ImageDownloader.java | 144 ++++++++---------- 1 file changed, 67 insertions(+), 77 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/view/ImageDownloader.java b/app/src/main/java/acr/browser/lightning/view/ImageDownloader.java index 61378c70a..93c78f796 100644 --- a/app/src/main/java/acr/browser/lightning/view/ImageDownloader.java +++ b/app/src/main/java/acr/browser/lightning/view/ImageDownloader.java @@ -14,6 +14,7 @@ import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; @@ -34,11 +35,12 @@ public class ImageDownloader { @Inject Application mApp; - @NonNull private Bitmap mDefaultBitmap; + @NonNull private final Bitmap mDefaultBitmap; + @NonNull private final BitmapFactory.Options mLoaderOptions = new BitmapFactory.Options(); public ImageDownloader(@NonNull Bitmap defaultBitmap) { - mDefaultBitmap = defaultBitmap; BrowserApp.getAppComponent().inject(this); + mDefaultBitmap = defaultBitmap; } /** @@ -54,7 +56,7 @@ public Single newImageRequest(@Nullable final String url) { return Single.create(new SingleAction() { @Override public void onSubscribe(@NonNull SingleSubscriber subscriber) { - Bitmap favicon = retrieveBitmap(mApp, mDefaultBitmap, url); + Bitmap favicon = retrieveFaviconForUrl(url); Bitmap paddedFavicon = Utils.padFavicon(favicon); @@ -65,98 +67,86 @@ public void onSubscribe(@NonNull SingleSubscriber subscriber) { } @NonNull - private static Bitmap retrieveBitmap(@NonNull Application app, - @NonNull Bitmap defaultBitmap, - @Nullable String url) { + private Bitmap retrieveFaviconForUrl(@Nullable String url) { // unique path for each url that is bookmarked. if (url == null) { - return defaultBitmap; + return mDefaultBitmap; } - Bitmap icon = null; - File cache = app.getCacheDir(); - final Uri uri = Uri.parse(url); + Bitmap icon; + File cache = mApp.getCacheDir(); + Uri uri = Uri.parse(url); if (uri.getHost() == null || uri.getScheme() == null || Constants.FILE.startsWith(uri.getScheme())) { - return defaultBitmap; + return mDefaultBitmap; } - final String hash = String.valueOf(uri.getHost().hashCode()); - final File image = new File(cache, hash + ".png"); - final String urlDisplay = uri.getScheme() + "://" + uri.getHost() + "/favicon.ico"; - - // checks to see if the image exists - if (!image.exists()) { - FileOutputStream fos = null; - InputStream in = null; - try { - // if not, download it... - final URL urlDownload = new URL(urlDisplay); - final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); - connection.setDoInput(true); - connection.setConnectTimeout(1000); - connection.setReadTimeout(1000); - connection.connect(); - in = connection.getInputStream(); - - if (in != null) { - icon = BitmapFactory.decodeStream(in); - } - // ...and cache it - if (icon != null) { - fos = new FileOutputStream(image); - icon.compress(Bitmap.CompressFormat.PNG, 100, fos); - fos.flush(); - Log.d(Constants.TAG, "Downloaded: " + urlDisplay); - } - - } catch (Exception ignored) { - Log.d(TAG, "Could not download: " + urlDisplay); - } finally { - Utils.close(in); - Utils.close(fos); - } - } else { - // if it exists, retrieve it from the cache + String hash = String.valueOf(uri.getHost().hashCode()); + File image = new File(cache, hash + ".png"); + String urlDisplay = uri.getScheme() + "://" + uri.getHost() + "/favicon.ico"; + + if (image.exists()) { + // If image exists, pull it from the cache icon = BitmapFactory.decodeFile(image.getPath()); + } else { + // Otherwise, load it from network + icon = retrieveBitmapFromUrl(urlDisplay); } if (icon == null) { - InputStream in = null; - FileOutputStream fos = null; - try { - // if not, download it... - final URL urlDownload = new URL("https://www.google.com/s2/favicons?domain_url=" + uri.toString()); - final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); - connection.setDoInput(true); - connection.setConnectTimeout(1000); - connection.setReadTimeout(1000); - connection.connect(); - in = connection.getInputStream(); - - if (in != null) { - icon = BitmapFactory.decodeStream(in); - } - // ...and cache it - if (icon != null) { - fos = new FileOutputStream(image); - icon.compress(Bitmap.CompressFormat.PNG, 100, fos); - fos.flush(); - } - - } catch (Exception e) { - Log.d(TAG, "Could not download Google favicon"); - } finally { - Utils.close(in); - Utils.close(fos); - } + String googleFaviconUrl = "https://www.google.com/s2/favicons?domain_url=" + uri.toString(); + icon = retrieveBitmapFromUrl(googleFaviconUrl); } if (icon == null) { - return defaultBitmap; + return mDefaultBitmap; } else { + cacheBitmap(image, icon); + return icon; } } + + private void cacheBitmap(@NonNull File cacheFile, @NonNull Bitmap imageToCache) { + FileOutputStream fos = null; + + try { + fos = new FileOutputStream(cacheFile); + imageToCache.compress(Bitmap.CompressFormat.PNG, 100, fos); + fos.flush(); + } catch (IOException e) { + Log.e(TAG, "Could not cache icon"); + } finally { + Utils.close(fos); + } + } + + @Nullable + private Bitmap retrieveBitmapFromUrl(@NonNull String url) { + InputStream in = null; + Bitmap icon = null; + + try { + final URL urlDownload = new URL(url); + final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); + connection.setDoInput(true); + connection.setConnectTimeout(1000); + connection.setReadTimeout(1000); + connection.connect(); + in = connection.getInputStream(); + + if (in != null) { + icon = BitmapFactory.decodeStream(in, null, mLoaderOptions); + } + } catch (Exception ignored) { + Log.d(TAG, "Could not download icon from: " + url); + } finally { + Utils.close(in); + } + + return icon; + } + + } From cca39aa3d2d7082cb2623d9883d720d1053cbdd9 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Fri, 14 Apr 2017 22:47:42 -0400 Subject: [PATCH 051/181] Cleaning up image request logic --- .../browser/lightning/app/AppComponent.java | 3 - .../lightning/favicon/FaviconModel.java | 139 ++++++++++++++++ .../lightning/favicon/FaviconUtils.java | 33 ++++ .../lightning/favicon/ImageFetcher.java | 81 ++++++++++ .../lightning/fragment/BookmarksFragment.java | 11 +- .../acr/browser/lightning/utils/Utils.java | 54 +++++-- .../browser/lightning/view/IconCacheTask.java | 42 ----- .../lightning/view/ImageDownloader.java | 152 ------------------ .../lightning/view/LightningChromeClient.java | 23 ++- 9 files changed, 314 insertions(+), 224 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java create mode 100644 app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java create mode 100644 app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java delete mode 100644 app/src/main/java/acr/browser/lightning/view/IconCacheTask.java delete mode 100644 app/src/main/java/acr/browser/lightning/view/ImageDownloader.java diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index fd2b20428..c807078ba 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -7,7 +7,6 @@ import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.activity.ThemableBrowserActivity; import acr.browser.lightning.activity.ThemableSettingsActivity; -import acr.browser.lightning.view.ImageDownloader; import acr.browser.lightning.browser.BrowserPresenter; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.HistoryPage; @@ -77,6 +76,4 @@ public interface AppComponent { void inject(SuggestionsAdapter suggestionsAdapter); - void inject(ImageDownloader imageDownloader); - } diff --git a/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java new file mode 100644 index 000000000..3b5110465 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java @@ -0,0 +1,139 @@ +package acr.browser.lightning.favicon; + +import android.app.Application; +import android.graphics.Bitmap; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.util.Log; + +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import acr.browser.lightning.app.BrowserApp; +import acr.browser.lightning.utils.Utils; + +/** + * Reactive model that can fetch favicons + * from URLs and also cache them. + */ +public class FaviconModel { + + private static final String TAG = "FaviconModel"; + + private final ImageFetcher mImageFetcher; + + public FaviconModel() { + mImageFetcher = new ImageFetcher(); + } + + @NonNull + private static File createFaviconCacheFile(@NonNull Application app, @NonNull Uri uri) { + FaviconUtils.assertUriSafe(uri); + + String hash = String.valueOf(uri.getHost().hashCode()); + + return new File(app.getCacheDir(), hash + ".png"); + } + + + @NonNull + public Single faviconForUrl(@NonNull final String url, + @NonNull final Bitmap defaultFavicon, + final boolean allowGoogleService) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + Uri uri = FaviconUtils.safeUri(url); + + if (uri == null) { + + Bitmap newFavicon = Utils.padFavicon(defaultFavicon); + + subscriber.onItem(newFavicon); + subscriber.onComplete(); + + return; + } + + Application app = BrowserApp.getApplication(); + + File faviconCacheFile = createFaviconCacheFile(app, uri); + + Bitmap favicon = null; + + if (faviconCacheFile.exists()) { + favicon = mImageFetcher.retrieveFaviconFromCache(faviconCacheFile); + } + + if (favicon == null) { + favicon = mImageFetcher.retrieveBitmapFromDomain(uri); + } else { + Bitmap newFavicon = Utils.padFavicon(favicon); + + subscriber.onItem(newFavicon); + subscriber.onComplete(); + + return; + } + + if (favicon == null && allowGoogleService) { + favicon = mImageFetcher.retrieveBitmapFromGoogle(uri); + } + + if (favicon != null) { + cacheFaviconForUrl(favicon, url).subscribe(); + } + + if (favicon == null) { + favicon = defaultFavicon; + } + + Bitmap newFavicon = Utils.padFavicon(favicon); + + subscriber.onItem(newFavicon); + subscriber.onComplete(); + } + }); + } + + @NonNull + public Completable cacheFaviconForUrl(@NonNull final Bitmap favicon, + @NonNull final String url) { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + Uri uri = FaviconUtils.safeUri(url); + + if (uri == null) { + subscriber.onComplete(); + return; + } + + Application app = BrowserApp.getApplication(); + + Log.d(TAG, "Caching icon for " + uri.getHost()); + FileOutputStream fos = null; + + try { + File image = createFaviconCacheFile(app, uri); + fos = new FileOutputStream(image); + favicon.compress(Bitmap.CompressFormat.PNG, 100, fos); + fos.flush(); + } catch (IOException e) { + Log.e(TAG, "Unable to cache favicon", e); + } finally { + Utils.close(fos); + } + } + }); + } + +} diff --git a/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java b/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java new file mode 100644 index 000000000..9dbfea7c4 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java @@ -0,0 +1,33 @@ +package acr.browser.lightning.favicon; + +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +/** + * Created by anthonycr on 4/13/17. + */ + +class FaviconUtils { + @Nullable + static Uri safeUri(@NonNull String url) { + if (TextUtils.isEmpty(url)) { + return null; + } + + Uri uri = Uri.parse(url); + + if (uri.getHost() == null || uri.getScheme() == null) { + return null; + } + + return uri; + } + + static void assertUriSafe(@Nullable Uri uri) { + if (uri == null || TextUtils.isEmpty(uri.getScheme()) || TextUtils.isEmpty(uri.getHost())) { + throw new RuntimeException("Unsafe uri provided"); + } + } +} diff --git a/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java b/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java new file mode 100644 index 000000000..d9150262e --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java @@ -0,0 +1,81 @@ +package acr.browser.lightning.favicon; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; + +import java.io.File; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import acr.browser.lightning.utils.Utils; + +/** + * An image fetcher that creates image + * loading requests on demand. + */ +class ImageFetcher { + + private static final String TAG = "ImageFetcher"; + + @NonNull private final BitmapFactory.Options mLoaderOptions = new BitmapFactory.Options(); + + ImageFetcher() { + } + + @Nullable + Bitmap retrieveFaviconFromCache(@NonNull File cacheFile) { + return BitmapFactory.decodeFile(cacheFile.getPath(), mLoaderOptions); + } + + @Nullable + Bitmap retrieveBitmapFromDomain(@NonNull Uri uri) { + FaviconUtils.assertUriSafe(uri); + + String faviconUrlGuess = uri.getScheme() + "://" + uri.getHost() + "/favicon.ico"; + + return retrieveBitmapFromUrl(faviconUrlGuess); + } + + @Nullable + Bitmap retrieveBitmapFromGoogle(@NonNull Uri uri) { + FaviconUtils.assertUriSafe(uri); + + String googleFaviconUrl = "https://www.google.com/s2/favicons?domain_url=" + uri.toString(); + + return retrieveBitmapFromUrl(googleFaviconUrl); + } + + + @Nullable + private Bitmap retrieveBitmapFromUrl(@NonNull String url) { + InputStream in = null; + Bitmap icon = null; + + try { + final URL urlDownload = new URL(url); + final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); + connection.setDoInput(true); + connection.setConnectTimeout(1000); + connection.setReadTimeout(1000); + connection.connect(); + in = connection.getInputStream(); + + if (in != null) { + icon = BitmapFactory.decodeStream(in, null, mLoaderOptions); + } + } catch (Exception ignored) { + Log.d(TAG, "Could not download icon from: " + url); + } finally { + Utils.close(in); + } + + return icon; + } + + +} diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index ed0680565..9de7337c3 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -45,7 +45,7 @@ import acr.browser.lightning.activity.ReadingActivity; import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.view.ImageDownloader; +import acr.browser.lightning.favicon.FaviconModel; import acr.browser.lightning.browser.BookmarksView; import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.constant.Constants; @@ -74,7 +74,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @Inject PreferenceManager mPreferenceManager; - private ImageDownloader mImageDownloader; + private FaviconModel mFaviconModel; private TabsManager mTabsManager; @@ -128,7 +128,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(context) : ThemeUtils.getIconLightThemeColor(context); - mImageDownloader = new ImageDownloader(mWebpageBitmap); + mFaviconModel = new FaviconModel(); } private TabsManager getTabsManager() { @@ -228,7 +228,7 @@ public void reinitializePreferences() { mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(activity) : ThemeUtils.getIconLightThemeColor(activity); - mImageDownloader = new ImageDownloader(mWebpageBitmap); + mFaviconModel = new FaviconModel(); } private void updateBookmarkIndicator(final String url) { @@ -405,7 +405,8 @@ public View getView(int position, View convertView, @NonNull ViewGroup parent) { final String url = web.getUrl(); final WeakReference imageViewReference = new WeakReference<>(holder.favicon); - mImageDownloader.newImageRequest(url) + + mFaviconModel.faviconForUrl(url, mWebpageBitmap, true) .subscribeOn(Schedulers.worker()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe() { diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index bb18d6469..7ce25c886 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -14,6 +14,7 @@ import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; @@ -74,7 +75,7 @@ public static boolean doesSupportHeaders() { public static void downloadFile(final Activity activity, final PreferenceManager manager, final String url, final String userAgent, final String contentDisposition) { PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsResultAction() { + Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsResultAction() { @Override public void onGranted() { String fileName = URLUtil.guessFileName(url, null, null); @@ -124,13 +125,13 @@ public static void createInformativeDialog(@NonNull Activity activity, @StringRe AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle(title); builder.setMessage(message) - .setCancelable(true) - .setPositiveButton(activity.getResources().getString(R.string.action_ok), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - } - }); + .setCancelable(true) + .setPositiveButton(activity.getResources().getString(R.string.action_ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + } + }); AlertDialog alert = builder.create(); alert.show(); BrowserDialog.setDialogSize(activity, alert); @@ -259,7 +260,7 @@ public static Bitmap padFavicon(@NonNull Bitmap bitmap) { int padding = Utils.dpToPx(4); Bitmap paddedBitmap = Bitmap.createBitmap(bitmap.getWidth() + padding, bitmap.getHeight() - + padding, Bitmap.Config.ARGB_8888); + + padding, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(paddedBitmap); canvas.drawARGB(0x00, 0x00, 0x00, 0x00); // this represents white color @@ -303,10 +304,10 @@ public static File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + '_'; File storageDir = Environment - .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); return File.createTempFile(imageFileName, /* prefix */ - ".jpg", /* suffix */ - storageDir /* directory */ + ".jpg", /* suffix */ + storageDir /* directory */ ); } @@ -380,9 +381,9 @@ public static void drawTrapezoid(@NonNull Canvas canvas, int color, boolean with paint.setDither(true); if (withShader) { paint.setShader(new LinearGradient(0, 0.9f * canvas.getHeight(), - 0, canvas.getHeight(), - color, mixTwoColors(Color.BLACK, color, 0.5f), - Shader.TileMode.CLAMP)); + 0, canvas.getHeight(), + color, mixTwoColors(Color.BLACK, color, 0.5f), + Shader.TileMode.CLAMP)); } else { paint.setShader(null); } @@ -431,4 +432,27 @@ public static void createShortcut(@NonNull Activity activity, @NonNull HistoryIt Utils.showSnackbar(activity, R.string.message_added_to_homescreen); } + public static int calculateInSampleSize(@NonNull BitmapFactory.Options options, + int reqWidth, int reqHeight) { + // Raw height and width of image + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + // Calculate the largest inSampleSize value that is a power of 2 and keeps both + // height and width larger than the requested height and width. + while ((halfHeight / inSampleSize) >= reqHeight + && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + + return inSampleSize; + } + } diff --git a/app/src/main/java/acr/browser/lightning/view/IconCacheTask.java b/app/src/main/java/acr/browser/lightning/view/IconCacheTask.java deleted file mode 100644 index ec4018860..000000000 --- a/app/src/main/java/acr/browser/lightning/view/IconCacheTask.java +++ /dev/null @@ -1,42 +0,0 @@ -package acr.browser.lightning.view; - -import android.app.Application; -import android.graphics.Bitmap; -import android.net.Uri; -import android.util.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - -import acr.browser.lightning.constant.Constants; -import acr.browser.lightning.utils.Utils; - -class IconCacheTask implements Runnable { - private final Uri uri; - private final Bitmap icon; - private final Application app; - - public IconCacheTask(final Uri uri, final Bitmap icon, final Application app) { - this.uri = uri; - this.icon = icon; - this.app = app; - } - - @Override - public void run() { - String hash = String.valueOf(uri.getHost().hashCode()); - Log.d(Constants.TAG, "Caching icon for " + uri.getHost()); - FileOutputStream fos = null; - try { - File image = new File(app.getCacheDir(), hash + ".png"); - fos = new FileOutputStream(image); - icon.compress(Bitmap.CompressFormat.PNG, 100, fos); - fos.flush(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - Utils.close(fos); - } - } -} diff --git a/app/src/main/java/acr/browser/lightning/view/ImageDownloader.java b/app/src/main/java/acr/browser/lightning/view/ImageDownloader.java deleted file mode 100644 index 93c78f796..000000000 --- a/app/src/main/java/acr/browser/lightning/view/ImageDownloader.java +++ /dev/null @@ -1,152 +0,0 @@ -package acr.browser.lightning.view; - -import android.app.Application; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; - -import com.anthonycr.bonsai.Single; -import com.anthonycr.bonsai.SingleAction; -import com.anthonycr.bonsai.SingleSubscriber; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; - -import javax.inject.Inject; - -import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.constant.Constants; -import acr.browser.lightning.utils.Utils; - -/** - * An ImageDownloader that creates image - * loading requests on demand. - */ -public class ImageDownloader { - - private static final String TAG = "ImageDownloader"; - - @Inject Application mApp; - - @NonNull private final Bitmap mDefaultBitmap; - @NonNull private final BitmapFactory.Options mLoaderOptions = new BitmapFactory.Options(); - - public ImageDownloader(@NonNull Bitmap defaultBitmap) { - BrowserApp.getAppComponent().inject(this); - mDefaultBitmap = defaultBitmap; - } - - /** - * Creates a new image request for the given url. - * Emits the bitmap associated with that url, or - * the default bitmap if none was found. - * - * @param url the url for which to retrieve the bitmap. - * @return a single that emits the bitmap that was found. - */ - @NonNull - public Single newImageRequest(@Nullable final String url) { - return Single.create(new SingleAction() { - @Override - public void onSubscribe(@NonNull SingleSubscriber subscriber) { - Bitmap favicon = retrieveFaviconForUrl(url); - - Bitmap paddedFavicon = Utils.padFavicon(favicon); - - subscriber.onItem(paddedFavicon); - subscriber.onComplete(); - } - }); - } - - @NonNull - private Bitmap retrieveFaviconForUrl(@Nullable String url) { - - // unique path for each url that is bookmarked. - if (url == null) { - return mDefaultBitmap; - } - - Bitmap icon; - File cache = mApp.getCacheDir(); - Uri uri = Uri.parse(url); - - if (uri.getHost() == null || uri.getScheme() == null || Constants.FILE.startsWith(uri.getScheme())) { - return mDefaultBitmap; - } - - String hash = String.valueOf(uri.getHost().hashCode()); - File image = new File(cache, hash + ".png"); - String urlDisplay = uri.getScheme() + "://" + uri.getHost() + "/favicon.ico"; - - if (image.exists()) { - // If image exists, pull it from the cache - icon = BitmapFactory.decodeFile(image.getPath()); - } else { - // Otherwise, load it from network - icon = retrieveBitmapFromUrl(urlDisplay); - } - - if (icon == null) { - String googleFaviconUrl = "https://www.google.com/s2/favicons?domain_url=" + uri.toString(); - icon = retrieveBitmapFromUrl(googleFaviconUrl); - } - - if (icon == null) { - return mDefaultBitmap; - } else { - cacheBitmap(image, icon); - - return icon; - } - } - - private void cacheBitmap(@NonNull File cacheFile, @NonNull Bitmap imageToCache) { - FileOutputStream fos = null; - - try { - fos = new FileOutputStream(cacheFile); - imageToCache.compress(Bitmap.CompressFormat.PNG, 100, fos); - fos.flush(); - } catch (IOException e) { - Log.e(TAG, "Could not cache icon"); - } finally { - Utils.close(fos); - } - } - - @Nullable - private Bitmap retrieveBitmapFromUrl(@NonNull String url) { - InputStream in = null; - Bitmap icon = null; - - try { - final URL urlDownload = new URL(url); - final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); - connection.setDoInput(true); - connection.setConnectTimeout(1000); - connection.setReadTimeout(1000); - connection.connect(); - in = connection.getInputStream(); - - if (in != null) { - icon = BitmapFactory.decodeStream(in, null, mLoaderOptions); - } - } catch (Exception ignored) { - Log.d(TAG, "Could not download icon from: " + url); - } finally { - Utils.close(in); - } - - return icon; - } - - -} diff --git a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java index d28cdde47..1ab5694b7 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java @@ -2,7 +2,6 @@ import android.Manifest; import android.app.Activity; -import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; import android.graphics.Bitmap; @@ -19,13 +18,14 @@ import android.webkit.WebChromeClient; import android.webkit.WebView; +import com.anthonycr.bonsai.Schedulers; import com.anthonycr.grant.PermissionsManager; import com.anthonycr.grant.PermissionsResultAction; import acr.browser.lightning.R; -import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.controller.UIController; import acr.browser.lightning.dialog.BrowserDialog; +import acr.browser.lightning.favicon.FaviconModel; import acr.browser.lightning.utils.Preconditions; class LightningChromeClient extends WebChromeClient { @@ -37,6 +37,7 @@ class LightningChromeClient extends WebChromeClient { @NonNull private final Activity mActivity; @NonNull private final LightningView mLightningView; @NonNull private final UIController mUIController; + @NonNull private final FaviconModel mFaviconModel; LightningChromeClient(@NonNull Activity activity, @NonNull LightningView lightningView) { Preconditions.checkNonNull(activity); @@ -44,6 +45,7 @@ class LightningChromeClient extends WebChromeClient { mActivity = activity; mUIController = (UIController) activity; mLightningView = lightningView; + mFaviconModel = new FaviconModel(); } @Override @@ -57,7 +59,7 @@ public void onProgressChanged(WebView view, int newProgress) { public void onReceivedIcon(@NonNull WebView view, Bitmap icon) { mLightningView.getTitleInfo().setFavicon(icon); mUIController.tabChanged(mLightningView); - cacheFavicon(view.getUrl(), icon, mActivity); + cacheFavicon(view.getUrl(), icon); } /** @@ -65,13 +67,20 @@ public void onReceivedIcon(@NonNull WebView view, Bitmap icon) { * * @param icon the icon to cache */ - private static void cacheFavicon(@Nullable final String url, @Nullable final Bitmap icon, @NonNull final Context context) { - if (icon == null || url == null) return; - final Uri uri = Uri.parse(url); + private void cacheFavicon(@Nullable final String url, @Nullable final Bitmap icon) { + if (icon == null || url == null) { + return; + } + + Uri uri = Uri.parse(url); + if (uri.getHost() == null) { return; } - BrowserApp.getIOThread().execute(new IconCacheTask(uri, icon, BrowserApp.get(context))); + + mFaviconModel.cacheFaviconForUrl(icon, url) + .subscribeOn(Schedulers.io()) + .subscribe(); } From 268e0351fb4a5201fe94ecd2a3610f6332ca9054 Mon Sep 17 00:00:00 2001 From: Roberto MF Date: Sat, 15 Apr 2017 17:15:07 +0200 Subject: [PATCH 052/181] [Spanish l10n] Update strings --- app/src/main/res/values-es/strings.xml | 82 +++++++++++++++++++------- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 569b4dd51..ae3c18208 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -8,7 +8,7 @@ Copiar enlace Adelante Ajustes - Acceso a tu ubicación + Permitir acceso a tu ubicación Almacenar tus contraseñas Agente de usuario Habilitar Adobe Flash @@ -29,9 +29,11 @@ (Recomendado) Motor de búsqueda Buscar - Utilizar ventana de visualización normal + Utilizar viewport normal Visualizar la página de lejos al cargar Restaurar pestañas cerradas al iniciar + Navegadores compatibles + Navegador de sistema Navegador de sistema no detectado Detectado navegador de sistema soportado Ocultar barra de estado al navegar @@ -94,12 +96,12 @@ Contáctame twitter.com/RestainoAnthony Limpiar caché - La caché ha sido borrada - Se han importado los marcadores - El historial ha sido borrado - Las cookies han sido borradas + La caché se ha borrado + Los marcadores se han importado + El historial se ha borrado + Las cookies se han borrado Se ha alcanzado el máximo de pestañas - El texto ha sido copiado al portapapeles + El texto se ha copiado al portapapeles El enlace se ha copiado al portapapeles Dirección personalizada Se ha bloqueado la carga del archivo local @@ -116,6 +118,14 @@ Contraseña Sugerencias de búsqueda Proporcionadas por Google + Proporcionadas por DuckDuckGo + Sin sugerencias de búsqueda + + Ninguno + Orbot + I2P + Manual + Parece que tienes Orbot instalado. ¿Quieres usar Tor? Por favor, instala Orbot para usar Tor. @@ -134,6 +144,7 @@ Invertido Escala de grises Escala de grises invertida + Aumentar contraste Normal Sincronizar historial con Google Selector de archivos @@ -152,11 +163,12 @@ Detalles sobre la versión, autor y licencias. Cerrar pestaña Cerrar todas las pestañas + Cerrar las demás pestañas Bloquear cookies de terceras partes Habilitar modo de color Modo de lectura Cargando… - No se pudo cargar de la página. + No se pudo cargar la página. Snacktory jsoup: Java HTML Parser Licencia MIT @@ -172,33 +184,61 @@ Carpeta Renombrar Tema negro (AMOLED) - Vaciar almacenamiento web + Limpiar el almacenamiento web Vaciar almacenamiento web al salir ¿Qué quieres hacer con esta carpeta? - ¿Qué quieres hacer con este elemento del historial? + ¿Qué quieres hacer con esta entrada del historial? Nombre de la carpeta - Fichero hosts para filtrado de anuncios + Fuente del fichero hosts para bloqueo de anuncios Proxy HTTP - I2P no está corriendo. + I2P no está en funcionamiento. Los túneles I2P no están preparados aún. Tema claro Proxy manual la fecha del certificado no es válida - el dominio en el certificado no corresponde al dominio del sitio - el certificado expiró + el dominio del certificado no coincide con el dominio del sitio web + el certificado está caducado el certificado no es válido el certificado no es válido todavía - el certificado no es confiable - La conexión a este sitio no es segura:\n%1$s\n¿Continuar en cualquier caso? - El almacenamiento web ha sido borrado + el certificado no es de confianza + La conexión a este sitio no es segura:\n%1$s\n¿Continuar de todas formas? + Se limpió el almacenamiento web Puerto: - La dirección no es válida, no se pudo descargar - No se pudo descargar en la localización específica - Ajustes del bloqueo de anuncios - Mostrar pestañas en el menú lateral + No se pudo iniciar la descarga: la dirección no es válida + No se pudo descargar en la ubicación de destino + Preferencias del bloqueo de anuncios + Mostrar las pestañas en el menú lateral Codificación del texto Tema gráfico de la aplicación Renombrar carpeta Parece que tienes I2P instalado. ¿Quieres usar I2P? Servidor: + + Intercambiar los paneles de marcadores y de pestañas + Petición «No rastrear» («Do Not Track») + Eliminar cabeceras identificativas + Añadir a la pantalla de inicio + Se añadió el atajo a la pantalla de inicio + Borrar todos los marcadores + + PP. FF. + Preguntas frecuentes + + + Preferencias de depuración + LeakCanary + Por favor, reinicie la aplicación para que se apliquen los cambios. + + + Abrir en una pestaña nueva + Abrir en una pestaña en segundo plano + Abrir en una pestaña de incógnito + Eliminar marcador + Editar marcador + Eliminar del historial + Descargar imagen + Copiar enlace + Renombrar carpeta + Eliminar carpeta + Cerrar el navegador From 0128aa8ce0e28613ff130cf4af9c9de219942abe Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 16 Apr 2017 21:16:24 +0200 Subject: [PATCH 053/181] Fixed some old typos and re-worked some strings It would be cool to have these changes in the next update since the latest version has some outdated translations which may confuse users. --- app/src/main/res/values-it/strings.xml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index c64317001..9ba7e2625 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -47,14 +47,14 @@ Consigliato Motore di ricerca Cerca - Ottimizza le pagine allo schermo + Adatta le pagine allo schermo Visualizza le pagine alla massima larghezza Ripristina le schede precedentemente attive alla riapertura Browser supportati Browser di sistema Nessun browser di sistema rilevato Rilevato browser di sistema supportato - Nascondi la barra di stato mentre navighi + Nascondi la barra di stato durante la navigazione Cancella i cookie Cancella la cronologia Cosa vuoi fare con questa immagine? @@ -120,8 +120,8 @@ Cache cancellata Segnalibri importati Cronologia cancellata - Cookie cancellati - Raggiunto il numero massimo di schede + Cookies cancellati + Hai raggiunto il numero massimo di schede apribili Testo copiato negli appunti Link copiato negli appunti URL personalizzato @@ -244,18 +244,18 @@ Impostazioni di debug LeakCanary - Prego, riavvia la app per applicare le modifiche. + Riavvia l'applicazione per applicare le modifiche. - Apri in nuova scheda - Apri in secondo piano - Apri in scheda in incognito + Apri in una nuova scheda + Apri in background + Apri in incognito Elimina segnalibro Modifica segnalibro - Elimina dalla cronologia - Scarica immagine + Rimuovi dalla cronologia + Salva immagine Copia link Rinomina cartella Elimina cartella - Chiudi browser + Esci From 3d0568df63392532bcb8141d6444a7e82b461273 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 16 Apr 2017 21:26:55 +0200 Subject: [PATCH 054/181] I forgot the languages strings! Updated. --- app/src/main/res/values-it/strings.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 9ba7e2625..2806846b9 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -258,4 +258,25 @@ Rinomina cartella Elimina cartella Esci + + + Traduttori + Arabo + Tedesco + Spagnolo + Francese + Greco + Ungherese + Italiano + Ebraico + Giapponese + Coreano + Lituano + Polacco + Portoghese + Russo + Serbo + Turco + Cinese Semplificato + Cinese Tradizionale From b46129f83abfdf2b71ca14f4f0ce557aa59ec69b Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 17 Apr 2017 16:45:42 -0400 Subject: [PATCH 055/181] Use OkHttp to download images --- app/build.gradle | 2 + .../lightning/favicon/FaviconUtils.java | 3 +- .../lightning/favicon/ImageFetcher.java | 58 ++++++++++++------- .../acr/browser/lightning/utils/Utils.java | 1 + 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 161c19469..b67e13c95 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -94,6 +94,8 @@ dependencies { // proxy support compile 'net.i2p.android:client:0.8' + compile 'com.squareup.okhttp3:okhttp:3.7.0' + // tor proxy def netcipherVersion = '2.0.0-alpha1' compile "info.guardianproject.netcipher:netcipher:$netcipherVersion" diff --git a/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java b/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java index 9dbfea7c4..a25e69115 100644 --- a/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java +++ b/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java @@ -6,9 +6,8 @@ import android.text.TextUtils; /** - * Created by anthonycr on 4/13/17. + * Simple utils for favicon fetching. */ - class FaviconUtils { @Nullable static Uri safeUri(@NonNull String url) { diff --git a/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java b/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java index d9150262e..6dc37cebf 100644 --- a/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java +++ b/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java @@ -9,10 +9,11 @@ import java.io.File; import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; import acr.browser.lightning.utils.Utils; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; /** * An image fetcher that creates image @@ -23,9 +24,9 @@ class ImageFetcher { private static final String TAG = "ImageFetcher"; @NonNull private final BitmapFactory.Options mLoaderOptions = new BitmapFactory.Options(); + @NonNull private final OkHttpClient mHttpClient = new OkHttpClient(); - ImageFetcher() { - } + ImageFetcher() {} @Nullable Bitmap retrieveFaviconFromCache(@NonNull File cacheFile) { @@ -45,37 +46,50 @@ Bitmap retrieveBitmapFromDomain(@NonNull Uri uri) { Bitmap retrieveBitmapFromGoogle(@NonNull Uri uri) { FaviconUtils.assertUriSafe(uri); - String googleFaviconUrl = "https://www.google.com/s2/favicons?domain_url=" + uri.toString(); + String googleFaviconUrl = "https://www.google.com/s2/favicons?domain_url=" + uri.getHost(); return retrieveBitmapFromUrl(googleFaviconUrl); } - @Nullable private Bitmap retrieveBitmapFromUrl(@NonNull String url) { - InputStream in = null; Bitmap icon = null; + InputStream boundsStream = null; + InputStream iconStream = null; + try { - final URL urlDownload = new URL(url); - final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); - connection.setDoInput(true); - connection.setConnectTimeout(1000); - connection.setReadTimeout(1000); - connection.connect(); - in = connection.getInputStream(); - - if (in != null) { - icon = BitmapFactory.decodeStream(in, null, mLoaderOptions); - } - } catch (Exception ignored) { - Log.d(TAG, "Could not download icon from: " + url); + mLoaderOptions.inSampleSize = 1; + mLoaderOptions.inJustDecodeBounds = true; + + Request imageRequest = new Request.Builder().url(url).build(); + + Response boundsResponse = mHttpClient.newCall(imageRequest).execute(); + boundsStream = boundsResponse.body().byteStream(); + + BitmapFactory.decodeStream(boundsStream, null, mLoaderOptions); + + boundsResponse.body().close(); + + int size = Utils.dpToPx(24); + + mLoaderOptions.inJustDecodeBounds = false; + mLoaderOptions.inSampleSize = Utils.calculateInSampleSize(mLoaderOptions, size, size); + + Response imageResponse = mHttpClient.newCall(imageRequest).execute(); + iconStream = imageResponse.body().byteStream(); + + icon = BitmapFactory.decodeStream(iconStream, null, mLoaderOptions); + + imageResponse.body().close(); + } catch (Exception e) { + Log.d(TAG, "Unable to download icon: " + url); } finally { - Utils.close(in); + Utils.close(boundsStream); + Utils.close(iconStream); } return icon; } - } diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index 7ce25c886..fe604b5ea 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -256,6 +256,7 @@ private static boolean deleteDir(@Nullable File dir) { * @param bitmap is the bitmap to pad. * @return the padded bitmap. */ + @NonNull public static Bitmap padFavicon(@NonNull Bitmap bitmap) { int padding = Utils.dpToPx(4); From 79febae033116624b0386d7be55f3a0bfead6bed Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 17 Apr 2017 16:58:51 -0400 Subject: [PATCH 056/181] Using okhttpclient for suggestions downloads --- .../lightning/download/FetchUrlMimeType.java | 1 - .../lightning/search/BaseSuggestionsTask.java | 38 +++++++++++-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java index c07362c29..1be49f5a6 100644 --- a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java +++ b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java @@ -54,7 +54,6 @@ public FetchUrlMimeType(Activity context, DownloadManager.Request request, Strin public void run() { // User agent is likely to be null, though the AndroidHttpClient // seems ok with that. - final Bus eventBus = BrowserApp.getBus(mContext); String mimeType = null; String contentDisposition = null; HttpURLConnection connection = null; diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java index 67fad33ec..11f54e021 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java @@ -23,10 +23,12 @@ import java.util.concurrent.TimeUnit; import java.util.zip.GZIPInputStream; -import javax.net.ssl.HttpsURLConnection; - import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.utils.Utils; +import okhttp3.CacheControl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; abstract class BaseSuggestionsTask { @@ -38,6 +40,8 @@ abstract class BaseSuggestionsTask { @Nullable private static String sLanguage; @NonNull private final SuggestionsResult mResultCallback; @NonNull private final Application mApplication; + @NonNull private final OkHttpClient mHttpClient = new OkHttpClient(); + @NonNull private final CacheControl mCacheControl; @NonNull private String mQuery; protected abstract String getQueryUrl(@NonNull String query, @NonNull String language); @@ -52,6 +56,7 @@ abstract class BaseSuggestionsTask { mQuery = query; mResultCallback = callback; mApplication = application; + mCacheControl = new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build(); } @NonNull @@ -116,19 +121,22 @@ private File downloadSuggestionsForQuery(@NonNull String query, String language, FileOutputStream fos = null; try { URL url = new URL(queryUrl); - HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); - connection.setDoInput(true); - connection.setRequestProperty("Accept-Encoding", "gzip"); - connection.setRequestProperty("Accept-Charset", getEncoding()); - connection.connect(); - if (connection.getResponseCode() >= HttpURLConnection.HTTP_MULT_CHOICE || - connection.getResponseCode() < HttpURLConnection.HTTP_OK) { - Log.e(TAG, "Search API Responded with code: " + connection.getResponseCode()); - connection.disconnect(); + Request suggestionsRequest = new Request.Builder().url(url) + .addHeader("Accept-Encoding", "gzip") + .addHeader("Accept-Charset", getEncoding()) + .cacheControl(mCacheControl) + .build(); + + Response suggestionsResponse = mHttpClient.newCall(suggestionsRequest).execute(); + + if (suggestionsResponse.code() >= HttpURLConnection.HTTP_MULT_CHOICE || + suggestionsResponse.code() < HttpURLConnection.HTTP_OK) { + Log.e(TAG, "Search API Responded with code: " + suggestionsResponse.code()); + suggestionsResponse.body().close(); return cacheFile; } - in = connection.getInputStream(); + in = suggestionsResponse.body().byteStream(); if (in != null) { in = new GZIPInputStream(in); @@ -140,7 +148,7 @@ private File downloadSuggestionsForQuery(@NonNull String query, String language, } fos.flush(); } - connection.disconnect(); + suggestionsResponse.body().close(); cacheFile.setLastModified(System.currentTimeMillis()); } catch (Exception e) { Log.w(TAG, "Problem getting search suggestions", e); @@ -159,8 +167,8 @@ private static boolean isNetworkConnected(@NonNull Context context) { @Nullable private static NetworkInfo getActiveNetworkInfo(@NonNull Context context) { ConnectivityManager connectivity = (ConnectivityManager) context - .getApplicationContext() - .getSystemService(Context.CONNECTIVITY_SERVICE); + .getApplicationContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivity == null) { return null; } From f655a1f488ae1fbe8ba6d3256689a0ef7f84d486 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 18 Apr 2017 11:47:26 +0200 Subject: [PATCH 057/181] Fixed --- app/src/main/res/values-it/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 2806846b9..1f29a1939 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -244,7 +244,7 @@ Impostazioni di debug LeakCanary - Riavvia l'applicazione per applicare le modifiche. + Riavvia l\'applicazione per applicare le modifiche. Apri in una nuova scheda From 6ac7ef8443acf01540a1456881bb232f709b570e Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 18 Apr 2017 11:49:54 +0200 Subject: [PATCH 058/181] Fixed and removed the languages strings --- app/src/main/res/values-it/strings.xml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 1f29a1939..604dcd805 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -258,25 +258,4 @@ Rinomina cartella Elimina cartella Esci - - - Traduttori - Arabo - Tedesco - Spagnolo - Francese - Greco - Ungherese - Italiano - Ebraico - Giapponese - Coreano - Lituano - Polacco - Portoghese - Russo - Serbo - Turco - Cinese Semplificato - Cinese Tradizionale From efd5780c3149a7f80ded6791749022ee30ff1b3b Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 18 Apr 2017 22:32:40 -0400 Subject: [PATCH 059/181] Annotating suggestions methods with nullable annotations --- .../acr/browser/lightning/search/BaseSuggestionsTask.java | 4 +++- .../acr/browser/lightning/search/DuckSuggestionsTask.java | 4 +++- .../acr/browser/lightning/search/GoogleSuggestionsTask.java | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java index 11f54e021..76000bf47 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java @@ -44,10 +44,12 @@ abstract class BaseSuggestionsTask { @NonNull private final CacheControl mCacheControl; @NonNull private String mQuery; + @NonNull protected abstract String getQueryUrl(@NonNull String query, @NonNull String language); - protected abstract void parseResults(FileInputStream inputStream, List results) throws Exception; + protected abstract void parseResults(@NonNull FileInputStream inputStream, @NonNull List results) throws Exception; + @NonNull protected abstract String getEncoding(); BaseSuggestionsTask(@NonNull String query, diff --git a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java index cec467fca..7d4748dee 100644 --- a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java @@ -25,13 +25,14 @@ final class DuckSuggestionsTask extends BaseSuggestionsTask { mSearchSubtitle = application.getString(R.string.suggestion); } + @NonNull @Override protected String getQueryUrl(@NonNull String query, @NonNull String language) { return "https://duckduckgo.com/ac/?q=" + query; } @Override - protected void parseResults(FileInputStream inputStream, List results) throws Exception { + protected void parseResults(@NonNull FileInputStream inputStream, @NonNull List results) throws Exception { String content = FileUtils.readStringFromFile(inputStream, ENCODING); JSONArray jsonArray = new JSONArray(content); int counter = 0; @@ -47,6 +48,7 @@ protected void parseResults(FileInputStream inputStream, List resul } } + @NonNull @Override protected String getEncoding() { return ENCODING; diff --git a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java index d68da9a7f..f9db50e90 100644 --- a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java @@ -35,7 +35,7 @@ protected String getQueryUrl(@NonNull String query, @NonNull String language) { } @Override - protected void parseResults(FileInputStream inputStream, List results) throws Exception { + protected void parseResults(@NonNull FileInputStream inputStream, @NonNull List results) throws Exception { BufferedInputStream fileInput = new BufferedInputStream(inputStream); XmlPullParser parser = getParser(); parser.setInput(fileInput, ENCODING); @@ -55,6 +55,7 @@ protected void parseResults(FileInputStream inputStream, List resul } } + @NonNull @Override protected String getEncoding() { return ENCODING; From 460da386ec10cb82b97bd2def2724fe41f709a88 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 19 Apr 2017 22:01:45 -0400 Subject: [PATCH 060/181] Keeping connectivity manager around rather than getting it every time --- .../lightning/search/BaseSuggestionsTask.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java index 76000bf47..936b3fe78 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java @@ -42,6 +42,7 @@ abstract class BaseSuggestionsTask { @NonNull private final Application mApplication; @NonNull private final OkHttpClient mHttpClient = new OkHttpClient(); @NonNull private final CacheControl mCacheControl; + @NonNull private final ConnectivityManager mConnectivityManager; @NonNull private String mQuery; @NonNull @@ -59,6 +60,7 @@ abstract class BaseSuggestionsTask { mResultCallback = callback; mApplication = application; mCacheControl = new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build(); + mConnectivityManager = getConnectivityManager(mApplication); } @NonNull @@ -116,7 +118,7 @@ private File downloadSuggestionsForQuery(@NonNull String query, String language, if (System.currentTimeMillis() - INTERVAL_DAY < cacheFile.lastModified()) { return cacheFile; } - if (!isNetworkConnected(app)) { + if (!isNetworkConnected()) { return cacheFile; } InputStream in = null; @@ -161,20 +163,16 @@ private File downloadSuggestionsForQuery(@NonNull String query, String language, return cacheFile; } - private static boolean isNetworkConnected(@NonNull Context context) { - NetworkInfo networkInfo = getActiveNetworkInfo(context); + private boolean isNetworkConnected() { + NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); return networkInfo != null && networkInfo.isConnected(); } - @Nullable - private static NetworkInfo getActiveNetworkInfo(@NonNull Context context) { - ConnectivityManager connectivity = (ConnectivityManager) context + @NonNull + private static ConnectivityManager getConnectivityManager(@NonNull Context context) { + return (ConnectivityManager) context .getApplicationContext() .getSystemService(Context.CONNECTIVITY_SERVICE); - if (connectivity == null) { - return null; - } - return connectivity.getActiveNetworkInfo(); } } From 491d872008575bddff21fab165f3064167de4790 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 19 Apr 2017 22:10:25 -0400 Subject: [PATCH 061/181] Renaming task method --- .../lightning/search/BaseSuggestionsTask.java | 20 +++++++++---------- .../lightning/search/DuckSuggestionsTask.java | 4 ++-- .../search/GoogleSuggestionsTask.java | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java index 936b3fe78..6b73567a1 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java @@ -36,7 +36,7 @@ abstract class BaseSuggestionsTask { static final int MAX_RESULTS = 5; private static final long INTERVAL_DAY = TimeUnit.DAYS.toMillis(1); - private static final String DEFAULT_LANGUAGE = "en"; + @NonNull private static final String DEFAULT_LANGUAGE = "en"; @Nullable private static String sLanguage; @NonNull private final SuggestionsResult mResultCallback; @NonNull private final Application mApplication; @@ -46,7 +46,7 @@ abstract class BaseSuggestionsTask { @NonNull private String mQuery; @NonNull - protected abstract String getQueryUrl(@NonNull String query, @NonNull String language); + protected abstract String createQueryUrl(@NonNull String query, @NonNull String language); protected abstract void parseResults(@NonNull FileInputStream inputStream, @NonNull List results) throws Exception; @@ -113,7 +113,7 @@ private void post(@NonNull List result) { */ @NonNull private File downloadSuggestionsForQuery(@NonNull String query, String language, @NonNull Application app) { - String queryUrl = getQueryUrl(query, language); + String queryUrl = createQueryUrl(query, language); File cacheFile = new File(app.getCacheDir(), queryUrl.hashCode() + SuggestionsAdapter.CACHE_FILE_TYPE); if (System.currentTimeMillis() - INTERVAL_DAY < cacheFile.lastModified()) { return cacheFile; @@ -126,15 +126,15 @@ private File downloadSuggestionsForQuery(@NonNull String query, String language, try { URL url = new URL(queryUrl); Request suggestionsRequest = new Request.Builder().url(url) - .addHeader("Accept-Encoding", "gzip") - .addHeader("Accept-Charset", getEncoding()) - .cacheControl(mCacheControl) - .build(); + .addHeader("Accept-Encoding", "gzip") + .addHeader("Accept-Charset", getEncoding()) + .cacheControl(mCacheControl) + .build(); Response suggestionsResponse = mHttpClient.newCall(suggestionsRequest).execute(); if (suggestionsResponse.code() >= HttpURLConnection.HTTP_MULT_CHOICE || - suggestionsResponse.code() < HttpURLConnection.HTTP_OK) { + suggestionsResponse.code() < HttpURLConnection.HTTP_OK) { Log.e(TAG, "Search API Responded with code: " + suggestionsResponse.code()); suggestionsResponse.body().close(); return cacheFile; @@ -171,8 +171,8 @@ private boolean isNetworkConnected() { @NonNull private static ConnectivityManager getConnectivityManager(@NonNull Context context) { return (ConnectivityManager) context - .getApplicationContext() - .getSystemService(Context.CONNECTIVITY_SERVICE); + .getApplicationContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); } } diff --git a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java index 7d4748dee..475840486 100644 --- a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java @@ -15,7 +15,7 @@ final class DuckSuggestionsTask extends BaseSuggestionsTask { - private static final String ENCODING = "UTF-8"; + @NonNull private static final String ENCODING = "UTF-8"; @NonNull private final String mSearchSubtitle; DuckSuggestionsTask(@NonNull String query, @@ -27,7 +27,7 @@ final class DuckSuggestionsTask extends BaseSuggestionsTask { @NonNull @Override - protected String getQueryUrl(@NonNull String query, @NonNull String language) { + protected String createQueryUrl(@NonNull String query, @NonNull String language) { return "https://duckduckgo.com/ac/?q=" + query; } diff --git a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java index f9db50e90..2a4b91d39 100644 --- a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java @@ -17,7 +17,7 @@ class GoogleSuggestionsTask extends BaseSuggestionsTask { - private static final String ENCODING = "ISO-8859-1"; + @NonNull private static final String ENCODING = "ISO-8859-1"; @Nullable private static XmlPullParser sXpp; @NonNull private final String mSearchSubtitle; @@ -29,7 +29,7 @@ class GoogleSuggestionsTask extends BaseSuggestionsTask { } @NonNull - protected String getQueryUrl(@NonNull String query, @NonNull String language) { + protected String createQueryUrl(@NonNull String query, @NonNull String language) { return "https://suggestqueries.google.com/complete/search?output=toolbar&hl=" + language + "&q=" + query; } From 2723abcfd0ff3d54297bd2dcc9c023a8ad33cebf Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Thu, 20 Apr 2017 23:10:01 -0400 Subject: [PATCH 062/181] Switching from task thread to IO thread where appropriate --- .../browser/lightning/database/BookmarkManager.java | 12 ++++-------- .../java/acr/browser/lightning/utils/AdBlock.java | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java index 82ffad818..a5d5893b4 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java @@ -29,6 +29,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -36,6 +37,7 @@ import javax.inject.Singleton; import acr.browser.lightning.R; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.utils.Utils; @@ -54,12 +56,12 @@ public class BookmarkManager { private Map mBookmarksMap; @NonNull private String mCurrentFolder = ""; - @NonNull private final ExecutorService mExecutor; + @NonNull private final Executor mExecutor; private File mFilesDir; @Inject public BookmarkManager(@NonNull Context context) { - mExecutor = Executors.newSingleThreadExecutor(); + mExecutor = BrowserApp.getIOThread(); DEFAULT_BOOKMARK_TITLE = context.getString(R.string.untitled); mExecutor.execute(new BookmarkInitializer(context)); } @@ -177,12 +179,6 @@ public void run() { } } - @Override - protected void finalize() throws Throwable { - mExecutor.shutdownNow(); - super.finalize(); - } - public boolean isBookmark(String url) { return mBookmarksMap.containsKey(url); } diff --git a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java index 543b90abf..14cd76638 100644 --- a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java +++ b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java @@ -53,7 +53,7 @@ public void updatePreference() { } private void loadBlockedDomainsList(@NonNull final Context context) { - BrowserApp.getTaskThread().execute(new Runnable() { + BrowserApp.getIOThread().execute(new Runnable() { @Override public void run() { @@ -137,7 +137,7 @@ private static String getDomainName(@NonNull String url) throws URISyntaxExcepti * @param context the context needed to read the file */ private void loadHostsFile(@NonNull final Context context) { - BrowserApp.getTaskThread().execute(new Runnable() { + BrowserApp.getIOThread().execute(new Runnable() { @Override public void run() { From e7c5819a89200c87a2222f7850d26300744d18f0 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 22 Apr 2017 14:42:22 -0400 Subject: [PATCH 063/181] Cleaning up suggestions model code --- ...onsTask.java => BaseSuggestionsModel.java} | 33 ++++------ ...onsTask.java => DuckSuggestionsModel.java} | 8 +-- ...sTask.java => GoogleSuggestionsModel.java} | 8 +-- .../lightning/search/SuggestionsAdapter.java | 66 +++++++++---------- .../lightning/search/SuggestionsManager.java | 47 +++++++------ .../lightning/search/SuggestionsResult.java | 21 ------ 6 files changed, 73 insertions(+), 110 deletions(-) rename app/src/main/java/acr/browser/lightning/search/{BaseSuggestionsTask.java => BaseSuggestionsModel.java} (85%) rename app/src/main/java/acr/browser/lightning/search/{DuckSuggestionsTask.java => DuckSuggestionsModel.java} (85%) rename app/src/main/java/acr/browser/lightning/search/{GoogleSuggestionsTask.java => GoogleSuggestionsModel.java} (89%) delete mode 100644 app/src/main/java/acr/browser/lightning/search/SuggestionsResult.java diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java similarity index 85% rename from app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java rename to app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java index 6b73567a1..fc21cc97d 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java @@ -30,20 +30,18 @@ import okhttp3.Request; import okhttp3.Response; -abstract class BaseSuggestionsTask { +abstract class BaseSuggestionsModel { - private static final String TAG = BaseSuggestionsTask.class.getSimpleName(); + private static final String TAG = BaseSuggestionsModel.class.getSimpleName(); static final int MAX_RESULTS = 5; private static final long INTERVAL_DAY = TimeUnit.DAYS.toMillis(1); @NonNull private static final String DEFAULT_LANGUAGE = "en"; @Nullable private static String sLanguage; - @NonNull private final SuggestionsResult mResultCallback; @NonNull private final Application mApplication; @NonNull private final OkHttpClient mHttpClient = new OkHttpClient(); @NonNull private final CacheControl mCacheControl; @NonNull private final ConnectivityManager mConnectivityManager; - @NonNull private String mQuery; @NonNull protected abstract String createQueryUrl(@NonNull String query, @NonNull String language); @@ -53,11 +51,7 @@ abstract class BaseSuggestionsTask { @NonNull protected abstract String getEncoding(); - BaseSuggestionsTask(@NonNull String query, - @NonNull Application application, - @NonNull SuggestionsResult callback) { - mQuery = query; - mResultCallback = callback; + BaseSuggestionsModel(@NonNull Application application) { mApplication = application; mCacheControl = new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build(); mConnectivityManager = getConnectivityManager(mApplication); @@ -74,39 +68,36 @@ private static synchronized String getLanguage() { return sLanguage; } - void run() { + @NonNull + List getResults(@NonNull String query) { List filter = new ArrayList<>(5); try { - mQuery = URLEncoder.encode(mQuery, getEncoding()); + query = URLEncoder.encode(query, getEncoding()); } catch (UnsupportedEncodingException e) { Log.e(TAG, "Unable to encode the URL", e); } - File cache = downloadSuggestionsForQuery(mQuery, getLanguage(), mApplication); + File cache = downloadSuggestionsForQuery(query, getLanguage(), mApplication); if (!cache.exists()) { - post(filter); - return; + // There are no suggestions for this query, return an empty list. + return filter; } FileInputStream fileInput = null; try { fileInput = new FileInputStream(cache); parseResults(fileInput, filter); } catch (Exception e) { - post(filter); Log.e(TAG, "Unable to parse results", e); - return; + return filter; } finally { Utils.close(fileInput); } - post(filter); - } - private void post(@NonNull List result) { - mResultCallback.resultReceived(result); + return filter; } /** * This method downloads the search suggestions for the specific query. - * NOTE: This is a blocking operation, do not run on the UI thread. + * NOTE: This is a blocking operation, do not getResults on the UI thread. * * @param query the query to get suggestions for * @return the cache file containing the suggestions diff --git a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java similarity index 85% rename from app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java rename to app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java index 475840486..d8b9c23de 100644 --- a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java @@ -13,15 +13,13 @@ import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.utils.FileUtils; -final class DuckSuggestionsTask extends BaseSuggestionsTask { +final class DuckSuggestionsModel extends BaseSuggestionsModel { @NonNull private static final String ENCODING = "UTF-8"; @NonNull private final String mSearchSubtitle; - DuckSuggestionsTask(@NonNull String query, - @NonNull Application application, - @NonNull SuggestionsResult callback) { - super(query, application, callback); + DuckSuggestionsModel(@NonNull Application application) { + super(application); mSearchSubtitle = application.getString(R.string.suggestion); } diff --git a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java similarity index 89% rename from app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java rename to app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java index 2a4b91d39..579f79bca 100644 --- a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsTask.java +++ b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java @@ -15,16 +15,14 @@ import acr.browser.lightning.R; import acr.browser.lightning.database.HistoryItem; -class GoogleSuggestionsTask extends BaseSuggestionsTask { +class GoogleSuggestionsModel extends BaseSuggestionsModel { @NonNull private static final String ENCODING = "ISO-8859-1"; @Nullable private static XmlPullParser sXpp; @NonNull private final String mSearchSubtitle; - GoogleSuggestionsTask(@NonNull String query, - @NonNull Application application, - @NonNull SuggestionsResult callback) { - super(query, application, callback); + GoogleSuggestionsModel(@NonNull Application application) { + super(application); mSearchSubtitle = application.getString(R.string.suggestion); } diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index 02b67ad8c..7f8bcf53c 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -210,8 +210,8 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) { subscriber.onComplete(); } }).subscribeOn(FILTER_SCHEDULER) - .observeOn(Schedulers.main()) - .subscribe(); + .observeOn(Schedulers.main()) + .subscribe(); } private void combineResults(final @Nullable List bookmarkList, @@ -256,13 +256,13 @@ public void onSubscribe(@NonNull SingleSubscriber> subscriber) subscriber.onComplete(); } }).subscribeOn(FILTER_SCHEDULER) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe>() { - @Override - public void onItem(@Nullable List item) { - publishResults(item); - } - }); + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + publishResults(item); + } + }); } @NonNull @@ -277,7 +277,7 @@ public void onSubscribe(@NonNull SingleSubscriber> subscriber) break; } if (mAllBookmarks.get(n).getTitle().toLowerCase(Locale.getDefault()) - .startsWith(query)) { + .startsWith(query)) { bookmarks.add(mAllBookmarks.get(n)); counter++; } else if (mAllBookmarks.get(n).getUrl().contains(query)) { @@ -294,9 +294,9 @@ public void onSubscribe(@NonNull SingleSubscriber> subscriber) @NonNull private Single> getSuggestionsForQuery(@NonNull final String query) { if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_GOOGLE) { - return SuggestionsManager.getObservable(query, mContext, SuggestionsManager.Source.GOOGLE); + return SuggestionsManager.createGoogleQueryObservable(query, mContext); } else if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_DUCK) { - return SuggestionsManager.getObservable(query, mContext, SuggestionsManager.Source.DUCK); + return SuggestionsManager.createDuckQueryObservable(query, mContext); } else { return Single.empty(); } @@ -325,35 +325,35 @@ protected FilterResults performFiltering(CharSequence constraint) { if (mSuggestionsAdapter.shouldRequestNetwork() && !SuggestionsManager.isRequestInProgress()) { mSuggestionsAdapter.getSuggestionsForQuery(query) - .subscribeOn(Schedulers.worker()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe>() { - @Override - public void onItem(@Nullable List item) { - mSuggestionsAdapter.combineResults(null, null, item); - } - }); - } - - mSuggestionsAdapter.getBookmarksForQuery(query) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.worker()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable List item) { - mSuggestionsAdapter.combineResults(item, null, null); + mSuggestionsAdapter.combineResults(null, null, item); } }); + } + + mSuggestionsAdapter.getBookmarksForQuery(query) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + mSuggestionsAdapter.combineResults(item, null, null); + } + }); HistoryModel.findHistoryItemsContaining(query) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe>() { - @Override - public void onItem(@Nullable List item) { - mSuggestionsAdapter.combineResults(null, item, null); - } - }); + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + mSuggestionsAdapter.combineResults(null, item, null); + } + }); results.count = 1; return results; } diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java index 4eaccdea9..f453a6ad3 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java @@ -15,42 +15,39 @@ class SuggestionsManager { - public enum Source { - GOOGLE, - DUCK - } - private static volatile boolean sIsTaskExecuting; static boolean isRequestInProgress() { return sIsTaskExecuting; } - static Single> getObservable(@NonNull final String query, @NonNull final Context context, @NonNull final Source source) { + @NonNull + static Single> createGoogleQueryObservable(@NonNull final String query, + @NonNull final Context context) { + final Application application = BrowserApp.get(context); + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull final SingleSubscriber> subscriber) { + sIsTaskExecuting = true; + List results = new GoogleSuggestionsModel(application).getResults(query); + subscriber.onItem(results); + subscriber.onComplete(); + sIsTaskExecuting = false; + } + }); + } + + @NonNull + static Single> createDuckQueryObservable(@NonNull final String query, + @NonNull final Context context) { final Application application = BrowserApp.get(context); return Single.create(new SingleAction>() { @Override public void onSubscribe(@NonNull final SingleSubscriber> subscriber) { sIsTaskExecuting = true; - switch (source) { - case GOOGLE: - new GoogleSuggestionsTask(query, application, new SuggestionsResult() { - @Override - public void resultReceived(@NonNull List searchResults) { - subscriber.onItem(searchResults); - subscriber.onComplete(); - } - }).run(); - break; - case DUCK: - new DuckSuggestionsTask(query, application, new SuggestionsResult() { - @Override - public void resultReceived(@NonNull List searchResults) { - subscriber.onItem(searchResults); - subscriber.onComplete(); - } - }).run(); - } + List results = new DuckSuggestionsModel(application).getResults(query); + subscriber.onItem(results); + subscriber.onComplete(); sIsTaskExecuting = false; } }); diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsResult.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsResult.java deleted file mode 100644 index 63e420cdc..000000000 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsResult.java +++ /dev/null @@ -1,21 +0,0 @@ -package acr.browser.lightning.search; - -import android.support.annotation.NonNull; - -import java.util.List; - -import acr.browser.lightning.database.HistoryItem; - -interface SuggestionsResult { - - /** - * Called when the search suggestions have - * been retrieved from the server. - * - * @param searchResults the results, a valid - * list of results. May - * be empty. - */ - void resultReceived(@NonNull List searchResults); - -} From ba1bad6d9540a1bdd691a4393528d90cf7ac8387 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 22 Apr 2017 17:00:08 -0400 Subject: [PATCH 064/181] Use built in OkHttpCache instead of manual cache --- .../search/BaseSuggestionsModel.java | 101 ++++++------------ .../search/DuckSuggestionsModel.java | 5 +- .../search/GoogleSuggestionsModel.java | 7 +- .../lightning/search/SuggestionsAdapter.java | 6 +- .../browser/lightning/utils/FileUtils.java | 13 ++- 5 files changed, 54 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java index fc21cc97d..76abeedec 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java @@ -1,31 +1,28 @@ package acr.browser.lightning.search; import android.app.Application; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.concurrent.TimeUnit; -import java.util.zip.GZIPInputStream; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.utils.FileUtils; import acr.browser.lightning.utils.Utils; +import okhttp3.Cache; import okhttp3.CacheControl; +import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -35,26 +32,27 @@ abstract class BaseSuggestionsModel { private static final String TAG = BaseSuggestionsModel.class.getSimpleName(); static final int MAX_RESULTS = 5; - private static final long INTERVAL_DAY = TimeUnit.DAYS.toMillis(1); + private static final long INTERVAL_DAY = TimeUnit.DAYS.toSeconds(1); @NonNull private static final String DEFAULT_LANGUAGE = "en"; @Nullable private static String sLanguage; - @NonNull private final Application mApplication; - @NonNull private final OkHttpClient mHttpClient = new OkHttpClient(); + @NonNull private final OkHttpClient mHttpClient; @NonNull private final CacheControl mCacheControl; - @NonNull private final ConnectivityManager mConnectivityManager; @NonNull protected abstract String createQueryUrl(@NonNull String query, @NonNull String language); - protected abstract void parseResults(@NonNull FileInputStream inputStream, @NonNull List results) throws Exception; + protected abstract void parseResults(@NonNull InputStream inputStream, @NonNull List results) throws Exception; @NonNull protected abstract String getEncoding(); BaseSuggestionsModel(@NonNull Application application) { - mApplication = application; + File suggestionsCache = new File(application.getCacheDir(), "suggestion_responses"); + mHttpClient = new OkHttpClient.Builder() + .cache(new Cache(suggestionsCache, FileUtils.megabytesToBytes(1))) + .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR) + .build(); mCacheControl = new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build(); - mConnectivityManager = getConnectivityManager(mApplication); } @NonNull @@ -76,20 +74,18 @@ List getResults(@NonNull String query) { } catch (UnsupportedEncodingException e) { Log.e(TAG, "Unable to encode the URL", e); } - File cache = downloadSuggestionsForQuery(query, getLanguage(), mApplication); - if (!cache.exists()) { + InputStream inputStream = downloadSuggestionsForQuery(query, getLanguage()); + if (inputStream == null) { // There are no suggestions for this query, return an empty list. return filter; } - FileInputStream fileInput = null; try { - fileInput = new FileInputStream(cache); - parseResults(fileInput, filter); + parseResults(inputStream, filter); } catch (Exception e) { Log.e(TAG, "Unable to parse results", e); return filter; } finally { - Utils.close(fileInput); + Utils.close(inputStream); } return filter; @@ -102,68 +98,37 @@ List getResults(@NonNull String query) { * @param query the query to get suggestions for * @return the cache file containing the suggestions */ - @NonNull - private File downloadSuggestionsForQuery(@NonNull String query, String language, @NonNull Application app) { + @Nullable + private InputStream downloadSuggestionsForQuery(@NonNull String query, String language) { String queryUrl = createQueryUrl(query, language); - File cacheFile = new File(app.getCacheDir(), queryUrl.hashCode() + SuggestionsAdapter.CACHE_FILE_TYPE); - if (System.currentTimeMillis() - INTERVAL_DAY < cacheFile.lastModified()) { - return cacheFile; - } - if (!isNetworkConnected()) { - return cacheFile; - } - InputStream in = null; - FileOutputStream fos = null; + try { URL url = new URL(queryUrl); + + // OkHttp automatically gzips requests Request suggestionsRequest = new Request.Builder().url(url) - .addHeader("Accept-Encoding", "gzip") .addHeader("Accept-Charset", getEncoding()) .cacheControl(mCacheControl) .build(); Response suggestionsResponse = mHttpClient.newCall(suggestionsRequest).execute(); - if (suggestionsResponse.code() >= HttpURLConnection.HTTP_MULT_CHOICE || - suggestionsResponse.code() < HttpURLConnection.HTTP_OK) { - Log.e(TAG, "Search API Responded with code: " + suggestionsResponse.code()); - suggestionsResponse.body().close(); - return cacheFile; - } - - in = suggestionsResponse.body().byteStream(); - - if (in != null) { - in = new GZIPInputStream(in); - //noinspection IOResourceOpenedButNotSafelyClosed - fos = new FileOutputStream(cacheFile); - int buffer; - while ((buffer = in.read()) != -1) { - fos.write(buffer); - } - fos.flush(); - } - suggestionsResponse.body().close(); - cacheFile.setLastModified(System.currentTimeMillis()); + return suggestionsResponse.body().byteStream(); } catch (Exception e) { - Log.w(TAG, "Problem getting search suggestions", e); - } finally { - Utils.close(in); - Utils.close(fos); + Log.e(TAG, "Problem getting search suggestions", e); } - return cacheFile; - } - private boolean isNetworkConnected() { - NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); - return networkInfo != null && networkInfo.isConnected(); + return null; } - @NonNull - private static ConnectivityManager getConnectivityManager(@NonNull Context context) { - return (ConnectivityManager) context - .getApplicationContext() - .getSystemService(Context.CONNECTIVITY_SERVICE); - } + private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { + @Override + public Response intercept(Chain chain) throws IOException { + Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .header("cache-control", "max-age=" + INTERVAL_DAY + ", max-stale=" + INTERVAL_DAY) + .build(); + } + }; } diff --git a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java index d8b9c23de..d276d6577 100644 --- a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java @@ -7,6 +7,7 @@ import org.json.JSONObject; import java.io.FileInputStream; +import java.io.InputStream; import java.util.List; import acr.browser.lightning.R; @@ -30,8 +31,8 @@ protected String createQueryUrl(@NonNull String query, @NonNull String language) } @Override - protected void parseResults(@NonNull FileInputStream inputStream, @NonNull List results) throws Exception { - String content = FileUtils.readStringFromFile(inputStream, ENCODING); + protected void parseResults(@NonNull InputStream inputStream, @NonNull List results) throws Exception { + String content = FileUtils.readStringFromStream(inputStream, ENCODING); JSONArray jsonArray = new JSONArray(content); int counter = 0; for (int n = 0, size = jsonArray.length(); n < size; n++) { diff --git a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java index 579f79bca..0f90ab96b 100644 --- a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java @@ -10,6 +10,7 @@ import java.io.BufferedInputStream; import java.io.FileInputStream; +import java.io.InputStream; import java.util.List; import acr.browser.lightning.R; @@ -33,10 +34,10 @@ protected String createQueryUrl(@NonNull String query, @NonNull String language) } @Override - protected void parseResults(@NonNull FileInputStream inputStream, @NonNull List results) throws Exception { - BufferedInputStream fileInput = new BufferedInputStream(inputStream); + protected void parseResults(@NonNull InputStream inputStream, @NonNull List results) throws Exception { + BufferedInputStream bufferedInput = new BufferedInputStream(inputStream); XmlPullParser parser = getParser(); - parser.setInput(fileInput, ENCODING); + parser.setInput(bufferedInput, ENCODING); int eventType = parser.getEventType(); int counter = 0; while (eventType != XmlPullParser.END_DOCUMENT) { diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index 7f8bcf53c..f159e4c78 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -96,6 +96,7 @@ public void refreshPreferences() { } public void clearCache() { + // We don't need these cache files anymore Schedulers.io().execute(new ClearCacheRunnable(BrowserApp.get(mContext))); } @@ -382,12 +383,9 @@ private static class ClearCacheRunnable implements Runnable { public void run() { File dir = new File(app.getCacheDir().toString()); String[] fileList = dir.list(new NameFilter()); - long earliestTimeAllowed = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1); for (String fileName : fileList) { File file = new File(dir.getPath() + fileName); - if (earliestTimeAllowed > file.lastModified()) { - file.delete(); - } + file.delete(); } } diff --git a/app/src/main/java/acr/browser/lightning/utils/FileUtils.java b/app/src/main/java/acr/browser/lightning/utils/FileUtils.java index 2f572ad82..201c6462d 100644 --- a/app/src/main/java/acr/browser/lightning/utils/FileUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/FileUtils.java @@ -138,7 +138,8 @@ public static void writeCrashToStorage(@NonNull Throwable throwable) { } @NonNull - public static String readStringFromFile(@NonNull InputStream inputStream, @NonNull String encoding) throws IOException { + public static String readStringFromStream(@NonNull InputStream inputStream, + @NonNull String encoding) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, encoding)); StringBuilder result = new StringBuilder(); String line; @@ -148,4 +149,14 @@ public static String readStringFromFile(@NonNull InputStream inputStream, @NonNu return result.toString(); } + /** + * Converts megabytes to bytes. + * + * @param megaBytes the number of megabytes. + * @return the converted bytes. + */ + public static long megabytesToBytes(long megaBytes) { + return megaBytes * 1024 * 1024; + } + } From 103eea9fcb4463d162480c7d6d50abdf3589477c Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 22 Apr 2017 17:10:30 -0400 Subject: [PATCH 065/181] Making encoding a constructor parameter --- .../lightning/search/BaseSuggestionsModel.java | 11 +++++------ .../lightning/search/DuckSuggestionsModel.java | 8 +------- .../lightning/search/GoogleSuggestionsModel.java | 8 +------- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java index 76abeedec..f2be9ab0b 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java @@ -37,16 +37,15 @@ abstract class BaseSuggestionsModel { @Nullable private static String sLanguage; @NonNull private final OkHttpClient mHttpClient; @NonNull private final CacheControl mCacheControl; + @NonNull private final String mEncoding; @NonNull protected abstract String createQueryUrl(@NonNull String query, @NonNull String language); protected abstract void parseResults(@NonNull InputStream inputStream, @NonNull List results) throws Exception; - @NonNull - protected abstract String getEncoding(); - - BaseSuggestionsModel(@NonNull Application application) { + BaseSuggestionsModel(@NonNull Application application, @NonNull String encoding) { + mEncoding = encoding; File suggestionsCache = new File(application.getCacheDir(), "suggestion_responses"); mHttpClient = new OkHttpClient.Builder() .cache(new Cache(suggestionsCache, FileUtils.megabytesToBytes(1))) @@ -70,7 +69,7 @@ private static synchronized String getLanguage() { List getResults(@NonNull String query) { List filter = new ArrayList<>(5); try { - query = URLEncoder.encode(query, getEncoding()); + query = URLEncoder.encode(query, mEncoding); } catch (UnsupportedEncodingException e) { Log.e(TAG, "Unable to encode the URL", e); } @@ -107,7 +106,7 @@ private InputStream downloadSuggestionsForQuery(@NonNull String query, String la // OkHttp automatically gzips requests Request suggestionsRequest = new Request.Builder().url(url) - .addHeader("Accept-Charset", getEncoding()) + .addHeader("Accept-Charset", mEncoding) .cacheControl(mCacheControl) .build(); diff --git a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java index d276d6577..135156441 100644 --- a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java @@ -20,7 +20,7 @@ final class DuckSuggestionsModel extends BaseSuggestionsModel { @NonNull private final String mSearchSubtitle; DuckSuggestionsModel(@NonNull Application application) { - super(application); + super(application, ENCODING); mSearchSubtitle = application.getString(R.string.suggestion); } @@ -47,10 +47,4 @@ protected void parseResults(@NonNull InputStream inputStream, @NonNull List Date: Sat, 22 Apr 2017 18:32:55 -0400 Subject: [PATCH 066/181] Cleaning up potential NPEs and other lint warnings --- .../lightning/activity/TabsManager.java | 1 + .../browser/lightning/bus/BookmarkEvents.java | 7 +------ .../lightning/database/BookmarkManager.java | 2 -- .../lightning/dialog/BrowserDialog.java | 6 +++++- .../dialog/LightningDialogBuilder.java | 4 ++-- .../lightning/download/FetchUrlMimeType.java | 2 -- .../fragment/BookmarkSettingsFragment.java | 1 + .../lightning/search/BaseSuggestionsModel.java | 18 +++++++++--------- .../lightning/search/DuckSuggestionsModel.java | 1 - .../search/GoogleSuggestionsModel.java | 1 - .../lightning/search/SuggestionsAdapter.java | 1 - .../browser/lightning/utils/ProxyUtils.java | 3 ++- .../browser/lightning/utils/ThemeUtils.java | 15 +++++---------- .../browser/lightning/view/LightningView.java | 3 +++ 14 files changed, 29 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 1164bb38c..a69396e20 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -161,6 +161,7 @@ private void restoreLostTabs(@Nullable final String url, @NonNull final Activity @Override public void onNext(@Nullable Bundle item) { final LightningView tab = newTab(activity, "", false); + Preconditions.checkNonNull(item); String url = item.getString(URL_KEY); if (url != null && tab.getWebView() != null) { if (UrlUtils.isBookmarkUrl(url)) { diff --git a/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java b/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java index a2f8ca3d2..6b1900429 100644 --- a/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java @@ -24,12 +24,7 @@ public Deleted(final HistoryItem item) { */ public static class BookmarkChanged { - public final HistoryItem oldBookmark; - public final HistoryItem newBookmark; - - public BookmarkChanged(final HistoryItem oldItem, final HistoryItem newItem) { - oldBookmark = oldItem; - newBookmark = newItem; + public BookmarkChanged() { } } } diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java index a5d5893b4..cabbdf568 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java @@ -30,8 +30,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import javax.inject.Inject; import javax.inject.Singleton; diff --git a/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java b/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java index 15a240ce6..7fbf63235 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java +++ b/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java @@ -12,6 +12,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.Window; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; @@ -179,7 +180,10 @@ public static void setDialogSize(@NonNull Context context, @NonNull Dialog dialo if (maxWidth > screenSize - 2 * padding) { maxWidth = screenSize - 2 * padding; } - dialog.getWindow().setLayout(maxWidth, ViewGroup.LayoutParams.WRAP_CONTENT); + Window window = dialog.getWindow(); + if (window != null) { + window.setLayout(maxWidth, ViewGroup.LayoutParams.WRAP_CONTENT); + } } } diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 969b6a2db..bbad8e9d0 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -151,7 +151,7 @@ public void onClick(DialogInterface dialog, int which) { editedItem.setUrl(getUrl.getText().toString()); editedItem.setFolder(getFolder.getText().toString()); mBookmarkManager.editBookmark(item, editedItem); - mEventBus.post(new BookmarkEvents.BookmarkChanged(item, editedItem)); + mEventBus.post(new BookmarkEvents.BookmarkChanged()); } }); Dialog dialog = editBookmarkDialog.show(); @@ -190,7 +190,7 @@ public void onClick(String text) { editedItem.setFolder(item.getFolder()); editedItem.setIsFolder(true); mBookmarkManager.renameFolder(oldTitle, text); - mEventBus.post(new BookmarkEvents.BookmarkChanged(item, editedItem)); + mEventBus.post(new BookmarkEvents.BookmarkChanged()); } } }); diff --git a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java index 1be49f5a6..e89798abf 100644 --- a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java +++ b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java @@ -13,14 +13,12 @@ import android.webkit.URLUtil; import com.anthonycr.bonsai.Schedulers; -import com.squareup.otto.Bus; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import acr.browser.lightning.R; -import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.utils.Utils; /** diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index 088181e5b..1a81f91a5 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -299,6 +299,7 @@ private void showChooserDialog(final Activity activity, List list) { @Override public void onClick(DialogInterface dialog, int which) { String title = adapter.getItem(which); + Preconditions.checkNonNull(title); Source source = null; if (title.equals(getString(R.string.stock_browser))) { source = Source.STOCK; diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java index f2be9ab0b..ab36bc2b5 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java @@ -34,10 +34,11 @@ abstract class BaseSuggestionsModel { static final int MAX_RESULTS = 5; private static final long INTERVAL_DAY = TimeUnit.DAYS.toSeconds(1); @NonNull private static final String DEFAULT_LANGUAGE = "en"; - @Nullable private static String sLanguage; + @NonNull private final OkHttpClient mHttpClient; @NonNull private final CacheControl mCacheControl; @NonNull private final String mEncoding; + @NonNull private final String mLanguage; @NonNull protected abstract String createQueryUrl(@NonNull String query, @NonNull String language); @@ -46,6 +47,7 @@ abstract class BaseSuggestionsModel { BaseSuggestionsModel(@NonNull Application application, @NonNull String encoding) { mEncoding = encoding; + mLanguage = getLanguage(); File suggestionsCache = new File(application.getCacheDir(), "suggestion_responses"); mHttpClient = new OkHttpClient.Builder() .cache(new Cache(suggestionsCache, FileUtils.megabytesToBytes(1))) @@ -55,14 +57,12 @@ abstract class BaseSuggestionsModel { } @NonNull - private static synchronized String getLanguage() { - if (sLanguage == null) { - sLanguage = Locale.getDefault().getLanguage(); - } - if (TextUtils.isEmpty(sLanguage)) { - sLanguage = DEFAULT_LANGUAGE; + private static String getLanguage() { + String language = Locale.getDefault().getLanguage(); + if (TextUtils.isEmpty(language)) { + language = DEFAULT_LANGUAGE; } - return sLanguage; + return language; } @NonNull @@ -73,7 +73,7 @@ List getResults(@NonNull String query) { } catch (UnsupportedEncodingException e) { Log.e(TAG, "Unable to encode the URL", e); } - InputStream inputStream = downloadSuggestionsForQuery(query, getLanguage()); + InputStream inputStream = downloadSuggestionsForQuery(query, mLanguage); if (inputStream == null) { // There are no suggestions for this query, return an empty list. return filter; diff --git a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java index 135156441..b07b3039f 100644 --- a/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/DuckSuggestionsModel.java @@ -6,7 +6,6 @@ import org.json.JSONArray; import org.json.JSONObject; -import java.io.FileInputStream; import java.io.InputStream; import java.util.List; diff --git a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java index 2a4f1d636..e6cc6395f 100644 --- a/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/GoogleSuggestionsModel.java @@ -9,7 +9,6 @@ import org.xmlpull.v1.XmlPullParserFactory; import java.io.BufferedInputStream; -import java.io.FileInputStream; import java.io.InputStream; import java.util.List; diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index f159e4c78..f465d4551 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -33,7 +33,6 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; -import java.util.concurrent.TimeUnit; import javax.inject.Inject; diff --git a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java index f3ce53600..4bdc5f399 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java @@ -114,8 +114,9 @@ private void initializeProxy(@NonNull Activity activity) { // We shouldn't be here return; case Constants.PROXY_ORBOT: - if (!OrbotHelper.isOrbotRunning(activity)) + if (!OrbotHelper.isOrbotRunning(activity)) { OrbotHelper.requestStartTor(activity); + } host = "localhost"; port = 8118; break; diff --git a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java index 9bbb0a029..df2f58789 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java @@ -70,12 +70,7 @@ public static void themeImageView(@NonNull ImageView icon, @NonNull Context cont @NonNull private static Drawable getVectorDrawable(@NonNull Context context, int drawableId) { - Drawable drawable; - if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - drawable = context.getDrawable(drawableId); - } else { - drawable = context.getResources().getDrawable(drawableId); - } + Drawable drawable = ContextCompat.getDrawable(context, drawableId); Preconditions.checkNonNull(drawable); @@ -91,7 +86,7 @@ private static Bitmap getBitmapFromVectorDrawable(@NonNull Context context, int Drawable drawable = getVectorDrawable(context, drawableId); Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), - Bitmap.Config.ARGB_8888); + Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); @@ -104,7 +99,7 @@ public static Bitmap getThemedBitmap(@NonNull Context context, @DrawableRes int int color = dark ? getIconDarkThemeColor(context) : getIconLightThemeColor(context); Bitmap sourceBitmap = getBitmapFromVectorDrawable(context, res); Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight(), - Bitmap.Config.ARGB_8888); + Bitmap.Config.ARGB_8888); Paint p = new Paint(); ColorFilter filter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN); p.setColorFilter(filter); @@ -126,8 +121,8 @@ public static Drawable getThemedDrawable(@NonNull Context context, @DrawableRes @NonNull public static ColorDrawable getSelectedBackground(@NonNull Context context, boolean dark) { @ColorInt final int color = - (dark) ? ContextCompat.getColor(context, R.color.selected_dark) : ContextCompat.getColor( - context, R.color.selected_light); + (dark) ? ContextCompat.getColor(context, R.color.selected_dark) : ContextCompat.getColor( + context, R.color.selected_light); return new ColorDrawable(color); } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 34db90472..5937393c2 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -427,6 +427,7 @@ private void initializeSettings() { .subscribe(new SingleOnSubscribe() { @Override public void onItem(@Nullable File item) { + Preconditions.checkNonNull(item); settings.setAppCachePath(item.getPath()); } }); @@ -437,6 +438,7 @@ public void onItem(@Nullable File item) { .subscribe(new SingleOnSubscribe() { @Override public void onItem(@Nullable File item) { + Preconditions.checkNonNull(item); //noinspection deprecation settings.setGeolocationDatabasePath(item.getPath()); } @@ -449,6 +451,7 @@ public void onItem(@Nullable File item) { @Override public void onItem(@Nullable File item) { if (API < Build.VERSION_CODES.KITKAT) { + Preconditions.checkNonNull(item); //noinspection deprecation settings.setDatabasePath(item.getPath()); } From 89caf33f46214b5583596df54a1f8371c4855591 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 22 Apr 2017 18:33:02 -0400 Subject: [PATCH 067/181] Removing unused resources --- .../main/res/drawable/tab_vertical_background.xml | 6 ------ app/src/main/res/layout/animated_progress_bar.xml | 8 -------- app/src/main/res/values/arrays.xml | 12 ++---------- 3 files changed, 2 insertions(+), 24 deletions(-) delete mode 100644 app/src/main/res/drawable/tab_vertical_background.xml delete mode 100644 app/src/main/res/layout/animated_progress_bar.xml diff --git a/app/src/main/res/drawable/tab_vertical_background.xml b/app/src/main/res/drawable/tab_vertical_background.xml deleted file mode 100644 index 6286c4e79..000000000 --- a/app/src/main/res/drawable/tab_vertical_background.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/animated_progress_bar.xml b/app/src/main/res/layout/animated_progress_bar.xml deleted file mode 100644 index 7bb4ad110..000000000 --- a/app/src/main/res/layout/animated_progress_bar.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 2a550a6ee..d3d67168e 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -6,12 +6,12 @@ @string/agent_mobile @string/agent_custom - + @string/folder_default @string/folder_custom - + @string/action_homepage @string/action_blank @@ -24,14 +24,6 @@ @string/powered_by_duck @string/search_suggestions_off - - - @string/size_largest - @string/size_large - @string/size_normal - @string/size_small - @string/size_smallest - @string/light_theme From 5f8470c5778e8ae3c61d00b79da7e7eafc5b416d Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 22 Apr 2017 20:37:01 -0400 Subject: [PATCH 068/181] Using butterknife to bind views in fragments --- .../lightning/dialog/BrowserDialog.java | 8 +-- .../lightning/fragment/BookmarksFragment.java | 61 +++++++++++-------- .../lightning/fragment/TabsFragment.java | 23 ++++--- 3 files changed, 51 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java b/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java index 7fbf63235..9a3f180bd 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java +++ b/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java @@ -45,10 +45,6 @@ */ public class BrowserDialog { - public interface Listener { - void onClick(); - } - public interface EditorListener { void onClick(String text); } @@ -58,12 +54,12 @@ public static abstract class Item { private final int mTitle; private boolean mCondition = true; - public Item(@StringRes int title, boolean condition) { + Item(@StringRes int title, boolean condition) { this(title); mCondition = condition; } - public Item(@StringRes int title) { + protected Item(@StringRes int title) { mTitle = title; } diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 9de7337c3..9f963c341 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -56,6 +56,8 @@ import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.view.LightningView; +import butterknife.Bind; +import butterknife.ButterKnife; public class BookmarksFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener, BookmarksView { @@ -90,8 +92,9 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, private final List mBookmarks = new ArrayList<>(); // Views - private ListView mBookmarksListView; - private ImageView mBookmarkTitleImage, mBookmarkImage; + @Bind(R.id.right_drawer_list) ListView mBookmarksListView; + @Bind(R.id.starIcon) ImageView mBookmarkTitleImage; + @Bind(R.id.icon_star) ImageView mBookmarkImage; // Colors private int mIconColor, mScrollIndex; @@ -126,7 +129,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { mWebpageBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme); mFolderBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_folder, darkTheme); mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(context) : - ThemeUtils.getIconLightThemeColor(context); + ThemeUtils.getIconLightThemeColor(context); mFaviconModel = new FaviconModel(); } @@ -173,12 +176,10 @@ public void onResume() { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.bookmark_drawer, container, false); - mBookmarksListView = (ListView) view.findViewById(R.id.right_drawer_list); + ButterKnife.bind(this, view); mBookmarksListView.setOnItemClickListener(mItemClickListener); mBookmarksListView.setOnItemLongClickListener(mItemLongClickListener); - mBookmarkTitleImage = (ImageView) view.findViewById(R.id.starIcon); mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); - mBookmarkImage = (ImageView) view.findViewById(R.id.icon_star); final View backView = view.findViewById(R.id.bookmark_back_button); backView.setOnClickListener(new View.OnClickListener() { @Override @@ -195,16 +196,22 @@ public void onClick(View v) { setupNavigationButton(view, R.id.action_toggle_desktop, R.id.icon_desktop); initBookmarkManager().subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable BookmarkViewAdapter item) { - mBookmarksListView.setAdapter(mBookmarkAdapter); - } - }); + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable BookmarkViewAdapter item) { + mBookmarksListView.setAdapter(mBookmarkAdapter); + } + }); return view; } + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + } + @Override public void onStart() { super.onStart(); @@ -226,7 +233,7 @@ public void reinitializePreferences() { mWebpageBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_webpage, darkTheme); mFolderBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, darkTheme); mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(activity) : - ThemeUtils.getIconLightThemeColor(activity); + ThemeUtils.getIconLightThemeColor(activity); mFaviconModel = new FaviconModel(); } @@ -407,20 +414,20 @@ public View getView(int position, View convertView, @NonNull ViewGroup parent) { final WeakReference imageViewReference = new WeakReference<>(holder.favicon); mFaviconModel.faviconForUrl(url, mWebpageBitmap, true) - .subscribeOn(Schedulers.worker()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable Bitmap item) { - ImageView imageView = imageViewReference.get(); - Object tag = imageView != null ? imageView.getTag() : null; - if (tag != null && tag.equals(url.hashCode())) { - imageView.setImageBitmap(item); - } - - web.setBitmap(item); + .subscribeOn(Schedulers.worker()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Bitmap item) { + ImageView imageView = imageViewReference.get(); + Object tag = imageView != null ? imageView.getTag() : null; + if (tag != null && tag.equals(url.hashCode())) { + imageView.setImageBitmap(item); } - }); + + web.setBitmap(item); + } + }); } else { holder.favicon.setImageBitmap(web.getBitmap()); } diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index fdb9799dc..487711773 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -48,6 +48,8 @@ import acr.browser.lightning.utils.Utils; import acr.browser.lightning.view.BackgroundDrawable; import acr.browser.lightning.view.LightningView; +import butterknife.Bind; +import butterknife.ButterKnife; /** * A fragment that holds and manages the tabs and interaction with the tabs. @@ -74,7 +76,8 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Nullable private LightningViewAdapter mTabsAdapter; private UIController mUiController; - private RecyclerView mRecyclerView; + + @Bind(R.id.tabs_list) RecyclerView mRecyclerView; private TabsManager mTabsManager; @Inject Bus mBus; @@ -126,7 +129,9 @@ public void onClick(View v) { } }); } - mRecyclerView = (RecyclerView) view.findViewById(R.id.tabs_list); + + ButterKnife.bind(this, view); + SimpleItemAnimator animator; if (mShowInNavigationDrawer) { animator = new VerticalItemAnimator(); @@ -144,9 +149,17 @@ public void onClick(View v) { mTabsAdapter = new LightningViewAdapter(mShowInNavigationDrawer); mRecyclerView.setAdapter(mTabsAdapter); mRecyclerView.setHasFixedSize(true); + return view; } + @Override + public void onDestroyView() { + super.onDestroyView(); + ButterKnife.unbind(this); + mTabsAdapter = null; + } + private TabsManager getTabsManager() { if (mTabsManager == null) { mTabsManager = mUiController.getTabModel(); @@ -163,12 +176,6 @@ private void setupFrameLayoutButton(@NonNull final View root, @IdRes final int b buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); } - @Override - public void onDestroyView() { - super.onDestroyView(); - mTabsAdapter = null; - } - @Override public void onStart() { super.onStart(); From 2eea6fb60bfdf214111eadebf6635561a7c8be81 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 22 Apr 2017 20:46:41 -0400 Subject: [PATCH 069/181] Updating to butterknife v8 --- app/build.gradle | 6 +++--- .../lightning/activity/BrowserActivity.java | 20 +++++++++---------- .../lightning/activity/ReadingActivity.java | 9 +++------ .../lightning/fragment/BookmarksFragment.java | 17 ++++++++++------ .../lightning/fragment/TabsFragment.java | 13 ++++++++---- build.gradle | 1 - 6 files changed, 36 insertions(+), 30 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b67e13c95..0727128a4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,4 @@ apply plugin: 'com.android.application' -apply plugin: 'com.neenbedankt.android-apt' apply plugin: 'com.getkeepsafe.dexcount' android { @@ -82,11 +81,12 @@ dependencies { // dependency injection def daggerVersion = '2.0.2' compile "com.google.dagger:dagger:$daggerVersion" - apt "com.google.dagger:dagger-compiler:$daggerVersion" + annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion" provided 'javax.annotation:jsr250-api:1.0' // view binding - compile 'com.jakewharton:butterknife:7.0.1' + compile 'com.jakewharton:butterknife:8.5.1' + annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' // permissions compile 'com.anthonycr.grant:permissions:1.1.2' diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 8fdb36d2d..2a71a0a42 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -125,7 +125,7 @@ import acr.browser.lightning.view.Handlers; import acr.browser.lightning.view.LightningView; import acr.browser.lightning.view.SearchView; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; public abstract class BrowserActivity extends ThemableBrowserActivity implements BrowserView, UIController, OnClickListener, OnLongClickListener { @@ -138,18 +138,18 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private static final String TAG_TABS_FRAGMENT = "TAG_TABS_FRAGMENT"; // Static Layout - @Bind(R.id.drawer_layout) DrawerLayout mDrawerLayout; - @Bind(R.id.content_frame) FrameLayout mBrowserFrame; - @Bind(R.id.left_drawer) ViewGroup mDrawerLeft; - @Bind(R.id.right_drawer) ViewGroup mDrawerRight; - @Bind(R.id.ui_layout) ViewGroup mUiLayout; - @Bind(R.id.toolbar_layout) ViewGroup mToolbarLayout; - @Bind(R.id.progress_view) AnimatedProgressBar mProgressBar; - @Bind(R.id.search_bar) RelativeLayout mSearchBar; + @BindView(R.id.drawer_layout) DrawerLayout mDrawerLayout; + @BindView(R.id.content_frame) FrameLayout mBrowserFrame; + @BindView(R.id.left_drawer) ViewGroup mDrawerLeft; + @BindView(R.id.right_drawer) ViewGroup mDrawerRight; + @BindView(R.id.ui_layout) ViewGroup mUiLayout; + @BindView(R.id.toolbar_layout) ViewGroup mToolbarLayout; + @BindView(R.id.progress_view) AnimatedProgressBar mProgressBar; + @BindView(R.id.search_bar) RelativeLayout mSearchBar; // Toolbar Views - @Bind(R.id.toolbar) Toolbar mToolbar; + @BindView(R.id.toolbar) Toolbar mToolbar; private View mSearchBackground; private SearchView mSearch; private ImageView mArrowImage; diff --git a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java index e04abbe39..5b442dd9d 100644 --- a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java @@ -40,18 +40,15 @@ import acr.browser.lightning.reading.JResult; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.utils.Utils; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; public class ReadingActivity extends AppCompatActivity { private static final String TAG = ReadingActivity.class.getSimpleName(); - @Bind(R.id.textViewTitle) - TextView mTitle; - - @Bind(R.id.textViewBody) - TextView mBody; + @BindView(R.id.textViewTitle) TextView mTitle; + @BindView(R.id.textViewBody) TextView mBody; @Inject PreferenceManager mPreferences; diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 9f963c341..5e4efe555 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -56,8 +56,9 @@ import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.view.LightningView; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.Unbinder; public class BookmarksFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener, BookmarksView { @@ -92,9 +93,10 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, private final List mBookmarks = new ArrayList<>(); // Views - @Bind(R.id.right_drawer_list) ListView mBookmarksListView; - @Bind(R.id.starIcon) ImageView mBookmarkTitleImage; - @Bind(R.id.icon_star) ImageView mBookmarkImage; + @BindView(R.id.right_drawer_list) ListView mBookmarksListView; + @BindView(R.id.starIcon) ImageView mBookmarkTitleImage; + @BindView(R.id.icon_star) ImageView mBookmarkImage; + private Unbinder mUnbinder; // Colors private int mIconColor, mScrollIndex; @@ -176,7 +178,7 @@ public void onResume() { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.bookmark_drawer, container, false); - ButterKnife.bind(this, view); + mUnbinder = ButterKnife.bind(this, view); mBookmarksListView.setOnItemClickListener(mItemClickListener); mBookmarksListView.setOnItemLongClickListener(mItemLongClickListener); mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); @@ -209,7 +211,10 @@ public void onItem(@Nullable BookmarkViewAdapter item) { @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + if (mUnbinder != null) { + mUnbinder.unbind(); + mUnbinder = null; + } } @Override diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index 487711773..b9f5cb701 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -48,8 +48,9 @@ import acr.browser.lightning.utils.Utils; import acr.browser.lightning.view.BackgroundDrawable; import acr.browser.lightning.view.LightningView; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.Unbinder; /** * A fragment that holds and manages the tabs and interaction with the tabs. @@ -77,7 +78,8 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Nullable private LightningViewAdapter mTabsAdapter; private UIController mUiController; - @Bind(R.id.tabs_list) RecyclerView mRecyclerView; + @BindView(R.id.tabs_list) RecyclerView mRecyclerView; + private Unbinder mUnbinder; private TabsManager mTabsManager; @Inject Bus mBus; @@ -130,7 +132,7 @@ public void onClick(View v) { }); } - ButterKnife.bind(this, view); + mUnbinder = ButterKnife.bind(this, view); SimpleItemAnimator animator; if (mShowInNavigationDrawer) { @@ -156,7 +158,10 @@ public void onClick(View v) { @Override public void onDestroyView() { super.onDestroyView(); - ButterKnife.unbind(this); + if (mUnbinder != null) { + mUnbinder.unbind(); + mUnbinder = null; + } mTabsAdapter = null; } diff --git a/build.gradle b/build.gradle index b02baf915..ad168f3fd 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,6 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:2.3.1' - classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7' classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.3' } } From 413f76c00b81eca3bce77ea02e1e54443d9aa94b Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 22 Apr 2017 20:57:59 -0400 Subject: [PATCH 070/181] Updating dagger 2 --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 0727128a4..41f9972f7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,7 +79,7 @@ dependencies { compile 'com.squareup:otto:1.3.8' // dependency injection - def daggerVersion = '2.0.2' + def daggerVersion = '2.10' compile "com.google.dagger:dagger:$daggerVersion" annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion" provided 'javax.annotation:jsr250-api:1.0' From f90e89799581aa692c97f886c8dae41910454849 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 22 Apr 2017 23:07:08 -0400 Subject: [PATCH 071/181] Fixing fragment lifecycle for tab and bookmark drawers --- .../lightning/activity/BrowserActivity.java | 253 ++++++++++-------- .../lightning/fragment/BookmarksFragment.java | 36 ++- .../lightning/fragment/TabsFragment.java | 11 + 3 files changed, 188 insertions(+), 112 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 2a71a0a42..0400ecaf1 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -170,7 +170,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private ValueCallback mUploadMessage; private ValueCallback mFilePathCallback; - // Primatives + // Primitives private boolean mFullScreen; private boolean mDarkTheme; private boolean mIsFullScreen = false; @@ -215,9 +215,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private static final int API = android.os.Build.VERSION.SDK_INT; private static final String NETWORK_BROADCAST_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; private static final LayoutParams MATCH_PARENT = new LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT); + LayoutParams.MATCH_PARENT); private static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); protected abstract boolean isIncognito(); @@ -249,7 +249,7 @@ private synchronized void initialize(Bundle savedInstanceState) { mDarkTheme = mPreferences.getUseTheme() != 0 || isIncognito(); mIconColor = mDarkTheme ? ThemeUtils.getIconDarkThemeColor(this) : ThemeUtils.getIconLightThemeColor(this); mDisabledIconColor = mDarkTheme ? ContextCompat.getColor(this, R.color.icon_dark_theme_disabled) : - ContextCompat.getColor(this, R.color.icon_light_theme_disabled); + ContextCompat.getColor(this, R.color.icon_light_theme_disabled); mShowTabsInDrawer = mPreferences.getShowTabsInDrawer(!isTablet()); mSwapBookmarksAndTabs = mPreferences.getBookmarksAndTabsSwapped(); @@ -292,31 +292,37 @@ public void onDrawerStateChanged(int newState) { mWebpageBitmap = ThemeUtils.getThemedBitmap(this, R.drawable.ic_webpage, mDarkTheme); - final TabsFragment tabsFragment = new TabsFragment(); + final FragmentManager fragmentManager = getSupportFragmentManager(); + + TabsFragment tabsFragment = (TabsFragment) fragmentManager.findFragmentByTag(TAG_TABS_FRAGMENT); + BookmarksFragment bookmarksFragment = (BookmarksFragment) fragmentManager.findFragmentByTag(TAG_BOOKMARK_FRAGMENT); + + if (tabsFragment != null) { + fragmentManager.beginTransaction().remove(tabsFragment).commit(); + } + tabsFragment = TabsFragment.createTabsFragment(isIncognito(), mShowTabsInDrawer); + mTabsView = tabsFragment; - final Bundle tabsFragmentArguments = new Bundle(); - tabsFragmentArguments.putBoolean(TabsFragment.IS_INCOGNITO, isIncognito()); - tabsFragmentArguments.putBoolean(TabsFragment.VERTICAL_MODE, mShowTabsInDrawer); - tabsFragment.setArguments(tabsFragmentArguments); - final BookmarksFragment bookmarksFragment = new BookmarksFragment(); + if (bookmarksFragment != null) { + fragmentManager.beginTransaction().remove(bookmarksFragment).commit(); + } + bookmarksFragment = BookmarksFragment.createFragment(isIncognito()); + mBookmarksView = bookmarksFragment; - final Bundle bookmarksFragmentArguments = new Bundle(); - bookmarksFragmentArguments.putBoolean(BookmarksFragment.INCOGNITO_MODE, isIncognito()); - bookmarksFragment.setArguments(bookmarksFragmentArguments); - final FragmentManager fragmentManager = getSupportFragmentManager(); + fragmentManager.executePendingTransactions(); + fragmentManager - .beginTransaction() - .replace(getTabsFragmentViewId(), tabsFragment, TAG_TABS_FRAGMENT) - .replace(getBookmarksFragmentViewId(), bookmarksFragment, TAG_BOOKMARK_FRAGMENT) - .commit(); + .beginTransaction() + .replace(getTabsFragmentViewId(), tabsFragment, TAG_TABS_FRAGMENT) + .replace(getBookmarksFragmentViewId(), bookmarksFragment, TAG_BOOKMARK_FRAGMENT) + .commit(); if (mShowTabsInDrawer) { mToolbarLayout.removeView(findViewById(R.id.tabs_toolbar_container)); } - if (actionBar == null) - return; + Preconditions.checkNonNull(actionBar); // set display options of the ActionBar actionBar.setDisplayShowTitleEnabled(false); @@ -337,11 +343,35 @@ public void onDrawerStateChanged(int newState) { mArrowImage.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); } updateTabNumber(0); + + // Post drawer locking in case the activity is being recreated + Handlers.MAIN.post(new Runnable() { + @Override + public void run() { + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, getTabDrawer()); + } + }); } else { - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, getTabDrawer()); + + // Post drawer locking in case the activity is being recreated + Handlers.MAIN.post(new Runnable() { + @Override + public void run() { + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, getTabDrawer()); + } + }); mArrowImage.setImageResource(R.drawable.ic_action_home); mArrowImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); } + + // Post drawer locking in case the activity is being recreated + Handlers.MAIN.post(new Runnable() { + @Override + public void run() { + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, getBookmarkDrawer()); + } + }); + arrowButton.setOnClickListener(this); // create the search EditText in the ToolBar @@ -432,7 +462,7 @@ void panicClean() { } private class SearchListenerClass implements OnKeyListener, OnEditorActionListener, - OnFocusChangeListener, OnTouchListener, SearchView.PreFocusListener { + OnFocusChangeListener, OnTouchListener, SearchView.PreFocusListener { @Override public boolean onKey(View searchView, int keyCode, KeyEvent keyEvent) { @@ -458,10 +488,10 @@ public boolean onEditorAction(TextView arg0, int actionId, KeyEvent arg2) { // hide the keyboard and search the web when the enter key // button is pressed if (actionId == EditorInfo.IME_ACTION_GO || actionId == EditorInfo.IME_ACTION_DONE - || actionId == EditorInfo.IME_ACTION_NEXT - || actionId == EditorInfo.IME_ACTION_SEND - || actionId == EditorInfo.IME_ACTION_SEARCH - || (arg2.getAction() == KeyEvent.KEYCODE_ENTER)) { + || actionId == EditorInfo.IME_ACTION_NEXT + || actionId == EditorInfo.IME_ACTION_SEND + || actionId == EditorInfo.IME_ACTION_SEARCH + || (arg2.getAction() == KeyEvent.KEYCODE_ENTER)) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(mSearch.getWindowToken(), 0); searchTheWeb(mSearch.getText().toString()); @@ -498,7 +528,7 @@ public void onFocusChange(final View v, final boolean hasFocus) { public boolean onTouch(View v, MotionEvent event) { if (mSearch.getCompoundDrawables()[2] != null) { boolean tappedX = event.getX() > (mSearch.getWidth() - - mSearch.getPaddingRight() - mIcon.getIntrinsicWidth()); + - mSearch.getPaddingRight() - mIcon.getIntrinsicWidth()); if (tappedX) { if (event.getAction() == MotionEvent.ACTION_UP) { if (mSearch.hasFocus()) { @@ -532,19 +562,25 @@ private class DrawerLocker implements DrawerListener { @Override public void onDrawerClosed(View v) { - if (v == mDrawerRight && mShowTabsInDrawer) { - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, mDrawerLeft); - } else { - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, mDrawerRight); + View tabsDrawer = getTabDrawer(); + View bookmarksDrawer = getBookmarkDrawer(); + + if (v == tabsDrawer) { + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, bookmarksDrawer); + } else if (mShowTabsInDrawer) { + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, tabsDrawer); } } @Override public void onDrawerOpened(View v) { - if (v == mDrawerRight) { - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerLeft); + View tabsDrawer = getTabDrawer(); + View bookmarksDrawer = getBookmarkDrawer(); + + if (v == tabsDrawer) { + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, bookmarksDrawer); } else { - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerRight); + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, tabsDrawer); } } @@ -566,23 +602,23 @@ private void setNavigationDrawerWidth() { } if (width > maxWidth) { DrawerLayout.LayoutParams params = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerLeft - .getLayoutParams(); + .getLayoutParams(); params.width = maxWidth; mDrawerLeft.setLayoutParams(params); mDrawerLeft.requestLayout(); DrawerLayout.LayoutParams paramsRight = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerRight - .getLayoutParams(); + .getLayoutParams(); paramsRight.width = maxWidth; mDrawerRight.setLayoutParams(paramsRight); mDrawerRight.requestLayout(); } else { DrawerLayout.LayoutParams params = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerLeft - .getLayoutParams(); + .getLayoutParams(); params.width = width; mDrawerLeft.setLayoutParams(params); mDrawerLeft.requestLayout(); DrawerLayout.LayoutParams paramsRight = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerRight - .getLayoutParams(); + .getLayoutParams(); paramsRight.width = width; mDrawerRight.setLayoutParams(paramsRight); mDrawerRight.requestLayout(); @@ -612,7 +648,6 @@ private void initializePreferences() { ((BookmarksFragment) bookmarksFragment).reinitializePreferences(); } - // TODO layout transition causing memory leak // mBrowserFrame.setLayoutTransition(new LayoutTransition()); @@ -622,7 +657,7 @@ private void initializePreferences() { case 0: mSearchText = mPreferences.getSearchUrl(); if (!mSearchText.startsWith(Constants.HTTP) - && !mSearchText.startsWith(Constants.HTTPS)) { + && !mSearchText.startsWith(Constants.HTTPS)) { mSearchText = Constants.GOOGLE_SEARCH; } break; @@ -676,8 +711,8 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { searchTheWeb(mSearch.getText().toString()); } } else if ((keyCode == KeyEvent.KEYCODE_MENU) - && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) - && (Build.MANUFACTURER.compareTo("LGE") == 0)) { + && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) + && (Build.MANUFACTURER.compareTo("LGE") == 0)) { // Workaround for stupid LG devices that crash return true; } else if (keyCode == KeyEvent.KEYCODE_BACK) { @@ -698,8 +733,8 @@ public void run() { @Override public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_MENU) - && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) - && (Build.MANUFACTURER.compareTo("LGE") == 0)) { + && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) + && (Build.MANUFACTURER.compareTo("LGE") == 0)) { // Workaround for stupid LG devices that crash openOptionsMenu(); return true; @@ -796,8 +831,8 @@ public boolean onOptionsItemSelected(MenuItem item) { // By using a manager, adds a bookmark and notifies third parties about that private void addBookmark(final String title, final String url) { final HistoryItem item = !mBookmarkManager.isBookmark(url) - ? new HistoryItem(url, title) - : null; + ? new HistoryItem(url, title) + : null; if (item != null && mBookmarkManager.addBookmark(item)) { mSuggestionsAdapter.refreshBookmarks(); mBookmarksView.handleUpdatedUrl(url); @@ -806,8 +841,8 @@ private void addBookmark(final String title, final String url) { private void deleteBookmark(final String title, final String url) { final HistoryItem item = mBookmarkManager.isBookmark(url) - ? new HistoryItem(url, title) - : null; + ? new HistoryItem(url, title) + : null; if (item != null && mBookmarkManager.deleteBookmark(item)) { mSuggestionsAdapter.refreshBookmarks(); mBookmarksView.handleUpdatedUrl(url); @@ -852,17 +887,17 @@ private void setWebViewTranslation(float translation) { */ private void findInPage() { BrowserDialog.showEditText(this, - R.string.action_find, - R.string.search_hint, - R.string.search_hint, new BrowserDialog.EditorListener() { - @Override - public void onClick(String text) { - if (!TextUtils.isEmpty(text)) { - mPresenter.findInPage(text); - showFindInPageControls(text); - } + R.string.action_find, + R.string.search_hint, + R.string.search_hint, new BrowserDialog.EditorListener() { + @Override + public void onClick(String text) { + if (!TextUtils.isEmpty(text)) { + mPresenter.findInPage(text); + showFindInPageControls(text); } - }); + } + }); } private void showFindInPageControls(@NonNull String text) { @@ -892,24 +927,24 @@ public void showCloseDialog(final int position) { return; } BrowserDialog.show(this, R.string.dialog_title_close_browser, - new BrowserDialog.Item(R.string.close_tab) { - @Override - public void onClick() { - mPresenter.deleteTab(position); - } - }, - new BrowserDialog.Item(R.string.close_other_tabs) { - @Override - public void onClick() { - mPresenter.closeAllOtherTabs(); - } - }, - new BrowserDialog.Item(R.string.close_all_tabs) { - @Override - public void onClick() { - closeBrowser(); - } - }); + new BrowserDialog.Item(R.string.close_tab) { + @Override + public void onClick() { + mPresenter.deleteTab(position); + } + }, + new BrowserDialog.Item(R.string.close_other_tabs) { + @Override + public void onClick() { + mPresenter.closeAllOtherTabs(); + } + }, + new BrowserDialog.Item(R.string.close_all_tabs) { + @Override + public void onClick() { + closeBrowser(); + } + }); } @Override @@ -1016,11 +1051,11 @@ public void run() { public void showBlockedLocalFileDialog(DialogInterface.OnClickListener listener) { AlertDialog.Builder builder = new AlertDialog.Builder(this); Dialog dialog = builder.setCancelable(true) - .setTitle(R.string.title_warning) - .setMessage(R.string.message_blocked_local) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(R.string.action_open, listener) - .show(); + .setTitle(R.string.title_warning) + .setMessage(R.string.message_blocked_local) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(R.string.action_open, listener) + .show(); BrowserDialog.setDialogSize(this, dialog); } @@ -1397,7 +1432,7 @@ public void run() { mCurrentUiColor = color; mToolbarLayout.setBackgroundColor(color); mSearchBackground.getBackground().setColorFilter(DrawableUtils.mixColor(interpolatedTime, - startSearchColor, finalSearchColor), PorterDuff.Mode.SRC_IN); + startSearchColor, finalSearchColor), PorterDuff.Mode.SRC_IN); } }; animation.setDuration(300); @@ -1462,7 +1497,7 @@ public void updateUrl(@Nullable String url, boolean shortUrl) { public void updateTabNumber(int number) { if (mArrowImage != null && mShowTabsInDrawer) { mArrowImage.setImageBitmap(DrawableUtils.getRoundedNumberImage(number, Utils.dpToPx(24), - Utils.dpToPx(24), ThemeUtils.getIconThemeColor(this, mDarkTheme), Utils.dpToPx(2.5f))); + Utils.dpToPx(24), ThemeUtils.getIconThemeColor(this, mDarkTheme), Utils.dpToPx(2.5f))); } } @@ -1478,13 +1513,13 @@ void addItemToHistory(@Nullable final String title, @NonNull final String url) { } HistoryModel.visitHistoryItem(url, title) - .subscribeOn(Schedulers.io()) - .subscribe(new CompletableOnSubscribe() { - @Override - public void onError(@NonNull Throwable throwable) { - Log.e(TAG, "Exception while updating history", throwable); - } - }); + .subscribeOn(Schedulers.io()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onError(@NonNull Throwable throwable) { + Log.e(TAG, "Exception while updating history", throwable); + } + }); } /** @@ -1534,18 +1569,18 @@ public void onItemClick(AdapterView adapterView, View view, int pos, long l) */ private void openHistory() { new HistoryPage().getHistoryPage() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable String item) { - Preconditions.checkNonNull(item); - LightningView view = mTabsManager.getCurrentTab(); - if (view != null) { - view.loadUrl(item); - } + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + LightningView view = mTabsManager.getCurrentTab(); + if (view != null) { + view.loadUrl(item); } - }); + } + }); } private View getBookmarkDrawer() { @@ -1857,7 +1892,7 @@ public void onHideCustomView() { } private class VideoCompletionListener implements MediaPlayer.OnCompletionListener, - MediaPlayer.OnErrorListener { + MediaPlayer.OnErrorListener { @Override public boolean onError(MediaPlayer mp, int what, int extra) { @@ -1930,16 +1965,16 @@ private void setFullscreen(boolean enabled, boolean immersive) { if (enabled) { if (immersive) { decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } else { decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); } window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); + WindowManager.LayoutParams.FLAG_FULLSCREEN); } else { window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); @@ -2241,7 +2276,7 @@ public void bookmarkDeleted(final BookmarkEvents.Deleted event) { private void handleBookmarksChange() { final LightningView currentTab = mTabsManager.getCurrentTab(); if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) - && currentTab.getUrl().endsWith(BookmarkPage.FILENAME)) { + && currentTab.getUrl().endsWith(BookmarkPage.FILENAME)) { currentTab.loadBookmarkpage(); } if (currentTab != null) { diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 5e4efe555..3968405a5 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -32,6 +32,7 @@ import com.anthonycr.bonsai.SingleAction; import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.bonsai.SingleSubscriber; +import com.anthonycr.bonsai.Subscription; import com.squareup.otto.Bus; import com.squareup.otto.Subscribe; @@ -45,7 +46,6 @@ import acr.browser.lightning.activity.ReadingActivity; import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.favicon.FaviconModel; import acr.browser.lightning.browser.BookmarksView; import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.constant.Constants; @@ -53,6 +53,7 @@ import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.dialog.LightningDialogBuilder; +import acr.browser.lightning.favicon.FaviconModel; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.view.LightningView; @@ -62,6 +63,16 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener, BookmarksView { + @NonNull + public static BookmarksFragment createFragment(boolean isIncognito) { + BookmarksFragment bookmarksFragment = new BookmarksFragment(); + final Bundle bookmarksFragmentArguments = new Bundle(); + bookmarksFragmentArguments.putBoolean(BookmarksFragment.INCOGNITO_MODE, isIncognito); + bookmarksFragment.setArguments(bookmarksFragmentArguments); + + return bookmarksFragment; + } + private final static String TAG = BookmarksFragment.class.getSimpleName(); public final static String INCOGNITO_MODE = TAG + ".INCOGNITO_MODE"; @@ -96,6 +107,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @BindView(R.id.right_drawer_list) ListView mBookmarksListView; @BindView(R.id.starIcon) ImageView mBookmarkTitleImage; @BindView(R.id.icon_star) ImageView mBookmarkImage; + + @Nullable private Unbinder mUnbinder; // Colors @@ -103,6 +116,9 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, private boolean mIsIncognito; + @Nullable + private Subscription mBookmarksSubscription; + private Single initBookmarkManager() { return Single.create(new SingleAction() { @Override @@ -197,11 +213,12 @@ public void onClick(View v) { setupNavigationButton(view, R.id.action_reading, R.id.icon_reading); setupNavigationButton(view, R.id.action_toggle_desktop, R.id.icon_desktop); - initBookmarkManager().subscribeOn(Schedulers.io()) + mBookmarksSubscription = initBookmarkManager().subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe() { @Override public void onItem(@Nullable BookmarkViewAdapter item) { + mBookmarksSubscription = null; mBookmarksListView.setAdapter(mBookmarkAdapter); } }); @@ -211,12 +228,25 @@ public void onItem(@Nullable BookmarkViewAdapter item) { @Override public void onDestroyView() { super.onDestroyView(); + if (mBookmarksSubscription != null) { + mBookmarksSubscription.unsubscribe(); + mBookmarksSubscription = null; + } if (mUnbinder != null) { mUnbinder.unbind(); mUnbinder = null; } } + @Override + public void onDestroy() { + super.onDestroy(); + if (mBookmarksSubscription != null) { + mBookmarksSubscription.unsubscribe(); + mBookmarksSubscription = null; + } + } + @Override public void onStart() { super.onStart(); @@ -382,7 +412,7 @@ private class BookmarkViewAdapter extends ArrayAdapter { final Context context; - public BookmarkViewAdapter(Context context, @NonNull List data) { + BookmarkViewAdapter(Context context, @NonNull List data) { super(context, R.layout.bookmark_list_item, data); this.context = context; } diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index b9f5cb701..2617eb980 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -61,6 +61,17 @@ */ public class TabsFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener, TabsView { + @NonNull + public static TabsFragment createTabsFragment(boolean isIncognito, boolean showTabsInDrawer) { + TabsFragment tabsFragment = new TabsFragment(); + final Bundle tabsFragmentArguments = new Bundle(); + tabsFragmentArguments.putBoolean(TabsFragment.IS_INCOGNITO, isIncognito); + tabsFragmentArguments.putBoolean(TabsFragment.VERTICAL_MODE, showTabsInDrawer); + tabsFragment.setArguments(tabsFragmentArguments); + + return tabsFragment; + } + private static final String TAG = TabsFragment.class.getSimpleName(); /** From 80ab4aff3541f4fc26349393e658603fe97c36c5 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 23 Apr 2017 23:31:28 -0400 Subject: [PATCH 072/181] Improving performance of adblocking code by utilizing stringbuilder --- .../acr/browser/lightning/utils/AdBlock.java | 77 +++++++++++++++---- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java index 14cd76638..05ab4bffe 100644 --- a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java +++ b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java @@ -147,29 +147,41 @@ public void run() { //noinspection IOResourceOpenedButNotSafelyClosed reader = new BufferedReader(new InputStreamReader( asset.open(BLOCKED_DOMAINS_LIST_FILE_NAME))); + StringBuilder lineBuilder = new StringBuilder(); String line; + long time = System.currentTimeMillis(); + // TODO: 4/23/17 Improve performance by reading in on IO thread and then processing on worker thread while ((line = reader.readLine()) != null) { - if (!line.isEmpty() && !line.startsWith(COMMENT)) { - line = line.replace(LOCAL_IP_V4, EMPTY) - .replace(LOCAL_IP_V4_ALT, EMPTY) - .replace(LOCAL_IP_V6, EMPTY) - .replace(TAB, EMPTY); - int comment = line.indexOf(COMMENT); + lineBuilder.append(line); + + if (!isEmpty(lineBuilder) && !startsWith(lineBuilder, COMMENT)) { + replace(lineBuilder, LOCAL_IP_V4, EMPTY); + replace(lineBuilder, LOCAL_IP_V4_ALT, EMPTY); + replace(lineBuilder, LOCAL_IP_V6, EMPTY); + replace(lineBuilder, TAB, EMPTY); + + int comment = lineBuilder.indexOf(COMMENT); if (comment >= 0) { - line = line.substring(0, comment); + lineBuilder.replace(comment, lineBuilder.length(), EMPTY); } - line = line.trim(); - if (!line.isEmpty() && !line.equals(LOCALHOST)) { - while (line.contains(SPACE)) { - int space = line.indexOf(SPACE); - String host = line.substring(0, space); + + trim(lineBuilder); + + if (!isEmpty(lineBuilder) && !AdBlock.equals(lineBuilder, LOCALHOST)) { + while (contains(lineBuilder, SPACE)) { + int space = lineBuilder.indexOf(SPACE); + String host = lineBuilder.substring(0, space); + replace(lineBuilder, host, EMPTY); mBlockedDomainsList.add(host.trim()); - line = line.substring(space, line.length()).trim(); } - mBlockedDomainsList.add(line.trim()); + if (lineBuilder.length() > 0) { + mBlockedDomainsList.add(lineBuilder.toString()); + } } } + lineBuilder.setLength(0); } + Log.d(TAG, "Loaded ad list in: " + (System.currentTimeMillis() - time) + " ms"); } catch (IOException e) { Log.wtf(TAG, "Reading blocked domains list from file '" + BLOCKED_DOMAINS_LIST_FILE_NAME + "' failed.", e); @@ -179,4 +191,41 @@ public void run() { } }); } + + // TODO: 4/23/17 Move all these methods to a StringUtils class + private static void replace(@NonNull StringBuilder stringBuilder, + @NonNull String toReplace, + @NonNull String replacement) { + int index = stringBuilder.indexOf(toReplace); + if (index >= 0) { + stringBuilder.replace(index, index + toReplace.length(), replacement); + } + } + + private static void trim(@NonNull StringBuilder stringBuilder) { + while (stringBuilder.indexOf(SPACE) == 0) { + stringBuilder.replace(0, 1, EMPTY); + } + + while (stringBuilder.lastIndexOf(SPACE) == (stringBuilder.length() - 1)) { + stringBuilder.replace(stringBuilder.length() - 1, stringBuilder.length(), EMPTY); + } + } + + private static boolean isEmpty(@NonNull StringBuilder stringBuilder) { + return stringBuilder.length() == 0; + } + + private static boolean startsWith(@NonNull StringBuilder stringBuilder, @NonNull String start) { + return stringBuilder.indexOf(start) == 0; + } + + private static boolean contains(@NonNull StringBuilder stringBuilder, @NonNull String contains) { + return stringBuilder.indexOf(contains) >= 0; + } + + private static boolean equals(@NonNull StringBuilder stringBuilder, @NonNull String equal) { + int index = stringBuilder.indexOf(equal); + return index >= 0 && stringBuilder.length() == equal.length(); + } } From f235a56ed9f53e49df6048204a7f0e657ced9208 Mon Sep 17 00:00:00 2001 From: mtbu Date: Mon, 24 Apr 2017 20:35:12 +0100 Subject: [PATCH 073/181] Prevent URL-box resetting on cursor movement Stop the URL-box from resetting to the current URL (or blank) whenever the user clicks on it to move the cursor --- .../acr/browser/lightning/activity/BrowserActivity.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 0400ecaf1..12daa1ff1 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -550,10 +550,10 @@ public void onPreFocus() { return; } String url = currentView.getUrl(); - if (UrlUtils.isSpecialUrl(url)) { - mSearch.setText(""); - } else { - mSearch.setText(url); + if (!UrlUtils.isSpecialUrl(url)) { + if (!mSearch.hasFocus()) { + mSearch.setText(url); + } } } } From 431f5782ffa60d2784c924941557e24d76e4b0b9 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 24 Apr 2017 21:48:13 -0400 Subject: [PATCH 074/181] Moving string utils methods to a utils class --- .../acr/browser/lightning/utils/AdBlock.java | 56 +++-------- .../lightning/utils/StringBuilderUtils.java | 99 +++++++++++++++++++ 2 files changed, 110 insertions(+), 45 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java diff --git a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java index 05ab4bffe..4cc48d08b 100644 --- a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java +++ b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java @@ -154,24 +154,26 @@ public void run() { while ((line = reader.readLine()) != null) { lineBuilder.append(line); - if (!isEmpty(lineBuilder) && !startsWith(lineBuilder, COMMENT)) { - replace(lineBuilder, LOCAL_IP_V4, EMPTY); - replace(lineBuilder, LOCAL_IP_V4_ALT, EMPTY); - replace(lineBuilder, LOCAL_IP_V6, EMPTY); - replace(lineBuilder, TAB, EMPTY); + if (!StringBuilderUtils.isEmpty(lineBuilder) && + !StringBuilderUtils.startsWith(lineBuilder, COMMENT)) { + StringBuilderUtils.replace(lineBuilder, LOCAL_IP_V4, EMPTY); + StringBuilderUtils.replace(lineBuilder, LOCAL_IP_V4_ALT, EMPTY); + StringBuilderUtils.replace(lineBuilder, LOCAL_IP_V6, EMPTY); + StringBuilderUtils.replace(lineBuilder, TAB, EMPTY); int comment = lineBuilder.indexOf(COMMENT); if (comment >= 0) { lineBuilder.replace(comment, lineBuilder.length(), EMPTY); } - trim(lineBuilder); + StringBuilderUtils.trim(lineBuilder); - if (!isEmpty(lineBuilder) && !AdBlock.equals(lineBuilder, LOCALHOST)) { - while (contains(lineBuilder, SPACE)) { + if (!StringBuilderUtils.isEmpty(lineBuilder) && + !StringBuilderUtils.equals(lineBuilder, LOCALHOST)) { + while (StringBuilderUtils.contains(lineBuilder, SPACE)) { int space = lineBuilder.indexOf(SPACE); String host = lineBuilder.substring(0, space); - replace(lineBuilder, host, EMPTY); + StringBuilderUtils.replace(lineBuilder, host, EMPTY); mBlockedDomainsList.add(host.trim()); } if (lineBuilder.length() > 0) { @@ -192,40 +194,4 @@ public void run() { }); } - // TODO: 4/23/17 Move all these methods to a StringUtils class - private static void replace(@NonNull StringBuilder stringBuilder, - @NonNull String toReplace, - @NonNull String replacement) { - int index = stringBuilder.indexOf(toReplace); - if (index >= 0) { - stringBuilder.replace(index, index + toReplace.length(), replacement); - } - } - - private static void trim(@NonNull StringBuilder stringBuilder) { - while (stringBuilder.indexOf(SPACE) == 0) { - stringBuilder.replace(0, 1, EMPTY); - } - - while (stringBuilder.lastIndexOf(SPACE) == (stringBuilder.length() - 1)) { - stringBuilder.replace(stringBuilder.length() - 1, stringBuilder.length(), EMPTY); - } - } - - private static boolean isEmpty(@NonNull StringBuilder stringBuilder) { - return stringBuilder.length() == 0; - } - - private static boolean startsWith(@NonNull StringBuilder stringBuilder, @NonNull String start) { - return stringBuilder.indexOf(start) == 0; - } - - private static boolean contains(@NonNull StringBuilder stringBuilder, @NonNull String contains) { - return stringBuilder.indexOf(contains) >= 0; - } - - private static boolean equals(@NonNull StringBuilder stringBuilder, @NonNull String equal) { - int index = stringBuilder.indexOf(equal); - return index >= 0 && stringBuilder.length() == equal.length(); - } } diff --git a/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java b/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java new file mode 100644 index 000000000..da2b662b0 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java @@ -0,0 +1,99 @@ +package acr.browser.lightning.utils; + +import android.support.annotation.NonNull; + +/** + * A collection of utils methods for + * {@link StringBuilder} that provides + * API equality with the {@link String} + * API. + */ +public class StringBuilderUtils { + + private static final String SPACE = " "; + private static final String EMPTY = ""; + + /** + * Replace a string in a string + * builder with another string. + * + * @param stringBuilder the string builder. + * @param toReplace the string to replace. + * @param replacement the replacement string. + */ + public static void replace(@NonNull StringBuilder stringBuilder, + @NonNull String toReplace, + @NonNull String replacement) { + int index = stringBuilder.indexOf(toReplace); + if (index >= 0) { + stringBuilder.replace(index, index + toReplace.length(), replacement); + } + } + + /** + * Trims a string builder of + * any spaces at the beginning + * and end. + * + * @param stringBuilder the string builder. + */ + public static void trim(@NonNull StringBuilder stringBuilder) { + while (stringBuilder.indexOf(SPACE) == 0) { + stringBuilder.replace(0, 1, EMPTY); + } + + while (stringBuilder.lastIndexOf(SPACE) == (stringBuilder.length() - 1)) { + stringBuilder.replace(stringBuilder.length() - 1, stringBuilder.length(), EMPTY); + } + } + + /** + * Determines if the string builder is empty. + * + * @param stringBuilder the string builder. + * @return true if the string builder is empty, + * false otherwise. + */ + public static boolean isEmpty(@NonNull StringBuilder stringBuilder) { + return stringBuilder.length() == 0; + } + + /** + * Determines if a string builder starts with + * a specific string. + * + * @param stringBuilder the string builder. + * @param start the starting string. + * @return true if the string builder starts + * with the string, false otherwise. + */ + public static boolean startsWith(@NonNull StringBuilder stringBuilder, @NonNull String start) { + return stringBuilder.indexOf(start) == 0; + } + + /** + * Determines if a string builder contains a string. + * + * @param stringBuilder the string builder. + * @param contains the string that it might contain. + * @return true if the string builder contains the + * string, false otherwise. + */ + public static boolean contains(@NonNull StringBuilder stringBuilder, @NonNull String contains) { + return stringBuilder.indexOf(contains) >= 0; + } + + /** + * Determines equality between a string + * builder and a string. + * + * @param stringBuilder the string builder. + * @param equal the string. + * @return true if the string represented by + * the string builder is equal to the string. + */ + public static boolean equals(@NonNull StringBuilder stringBuilder, @NonNull String equal) { + int index = stringBuilder.indexOf(equal); + return index >= 0 && stringBuilder.length() == equal.length(); + } +} From 638220efc6e9c479e98b1db8bb962839794c19e9 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 25 Apr 2017 22:42:10 -0400 Subject: [PATCH 075/181] Improving memory performance in case with multiple hosts per line --- .../acr/browser/lightning/utils/AdBlock.java | 65 +++++++------------ .../lightning/utils/StringBuilderUtils.java | 19 ++++++ 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java index 4cc48d08b..b529eaa2b 100644 --- a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java +++ b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java @@ -1,11 +1,15 @@ package acr.browser.lightning.utils; -import android.content.Context; import android.content.res.AssetManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; +import com.anthonycr.bonsai.Schedulers; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -40,10 +44,10 @@ public class AdBlock { @Inject PreferenceManager mPreferenceManager; @Inject - public AdBlock(@NonNull Context context) { + public AdBlock() { BrowserApp.getAppComponent().inject(this); if (mBlockedDomainsList.isEmpty() && Constants.FULL_VERSION) { - loadHostsFile(context); + loadHostsFile().subscribeOn(Schedulers.io()).subscribe(); } mBlockAds = mPreferenceManager.getAdBlockEnabled(); } @@ -52,31 +56,6 @@ public void updatePreference() { mBlockAds = mPreferenceManager.getAdBlockEnabled(); } - private void loadBlockedDomainsList(@NonNull final Context context) { - BrowserApp.getIOThread().execute(new Runnable() { - - @Override - public void run() { - AssetManager asset = context.getAssets(); - BufferedReader reader = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - reader = new BufferedReader(new InputStreamReader( - asset.open(BLOCKED_DOMAINS_LIST_FILE_NAME))); - String line; - while ((line = reader.readLine()) != null) { - mBlockedDomainsList.add(line.trim()); - } - } catch (IOException e) { - Log.wtf(TAG, "Reading blocked domains list from file '" - + BLOCKED_DOMAINS_LIST_FILE_NAME + "' failed.", e); - } finally { - Utils.close(reader); - } - } - }); - } - /** * a method that determines if the given URL is an ad or not. It performs * a search of the URL's domain on the blocked domain hash set. @@ -128,20 +107,20 @@ private static String getDomainName(@NonNull String url) throws URISyntaxExcepti } /** - * This method reads through a hosts file and extracts the domains that should + * This Completable reads through a hosts file and extracts the domains that should * be redirected to localhost (a.k.a. IP address 127.0.0.1). It can handle files that - * simply have a list of hostnames to block, or it can handle a full blown hosts file. + * simply have a list of host names to block, or it can handle a full blown hosts file. * It will strip out comments, references to the base IP address and just extract the - * domains to be used + * domains to be used. * - * @param context the context needed to read the file + * @return a Completable that will load the hosts file into memory. */ - private void loadHostsFile(@NonNull final Context context) { - BrowserApp.getIOThread().execute(new Runnable() { - + @NonNull + private Completable loadHostsFile() { + return Completable.create(new CompletableAction() { @Override - public void run() { - AssetManager asset = context.getAssets(); + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + AssetManager asset = BrowserApp.getApplication().getAssets(); BufferedReader reader = null; try { //noinspection IOResourceOpenedButNotSafelyClosed @@ -150,7 +129,7 @@ public void run() { StringBuilder lineBuilder = new StringBuilder(); String line; long time = System.currentTimeMillis(); - // TODO: 4/23/17 Improve performance by reading in on IO thread and then processing on worker thread + while ((line = reader.readLine()) != null) { lineBuilder.append(line); @@ -172,9 +151,13 @@ public void run() { !StringBuilderUtils.equals(lineBuilder, LOCALHOST)) { while (StringBuilderUtils.contains(lineBuilder, SPACE)) { int space = lineBuilder.indexOf(SPACE); - String host = lineBuilder.substring(0, space); - StringBuilderUtils.replace(lineBuilder, host, EMPTY); - mBlockedDomainsList.add(host.trim()); + StringBuilder partial = StringBuilderUtils.substring(lineBuilder, 0, space); + StringBuilderUtils.trim(partial); + + String partialLine = partial.toString(); + mBlockedDomainsList.add(partialLine); + StringBuilderUtils.replace(lineBuilder, partialLine, EMPTY); + StringBuilderUtils.trim(lineBuilder); } if (lineBuilder.length() > 0) { mBlockedDomainsList.add(lineBuilder.toString()); diff --git a/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java b/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java index da2b662b0..378175169 100644 --- a/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java @@ -96,4 +96,23 @@ public static boolean equals(@NonNull StringBuilder stringBuilder, @NonNull Stri int index = stringBuilder.indexOf(equal); return index >= 0 && stringBuilder.length() == equal.length(); } + + /** + * Creates a sub-string builder from the + * current string builder. + * + * @param stringBuilder the string builder. + * @param start the starting index. + * @param end the ending index. + * @return a string builder that contains the + * characters between the indices. + */ + @NonNull + public static StringBuilder substring(@NonNull StringBuilder stringBuilder, int start, int end) { + StringBuilder newStringBuilder = new StringBuilder(stringBuilder); + newStringBuilder.replace(end, stringBuilder.length(), EMPTY); + newStringBuilder.replace(0, start, EMPTY); + + return newStringBuilder; + } } From ba976cd4b0548c462b33fcf838fa5e61a4345618 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 26 Apr 2017 19:33:05 -0400 Subject: [PATCH 076/181] Constructor injection > field injection --- .../browser/lightning/app/AppComponent.java | 2 -- .../acr/browser/lightning/utils/AdBlock.java | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index c807078ba..de92ee974 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -56,8 +56,6 @@ public interface AppComponent { void inject(ThemableSettingsActivity activity); - void inject(AdBlock adBlock); - void inject(LightningDownloadListener listener); void inject(PrivacySettingsFragment fragment); diff --git a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java index b529eaa2b..5c504a25e 100644 --- a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java +++ b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java @@ -1,5 +1,6 @@ package acr.browser.lightning.utils; +import android.app.Application; import android.content.res.AssetManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -21,7 +22,6 @@ import javax.inject.Inject; import javax.inject.Singleton; -import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.preference.PreferenceManager; @@ -38,14 +38,16 @@ public class AdBlock { private static final String TAB = "\t"; private static final String SPACE = " "; private static final String EMPTY = ""; - private final Set mBlockedDomainsList = new HashSet<>(); - private boolean mBlockAds; - @Inject PreferenceManager mPreferenceManager; + @NonNull private final Set mBlockedDomainsList = new HashSet<>(); + @NonNull private final PreferenceManager mPreferenceManager; + @NonNull private final Application mApplication; + private boolean mBlockAds; @Inject - public AdBlock() { - BrowserApp.getAppComponent().inject(this); + AdBlock(@NonNull Application application, @NonNull PreferenceManager preferenceManager) { + mApplication = application; + mPreferenceManager = preferenceManager; if (mBlockedDomainsList.isEmpty() && Constants.FULL_VERSION) { loadHostsFile().subscribeOn(Schedulers.io()).subscribe(); } @@ -120,10 +122,10 @@ private Completable loadHostsFile() { return Completable.create(new CompletableAction() { @Override public void onSubscribe(@NonNull CompletableSubscriber subscriber) { - AssetManager asset = BrowserApp.getApplication().getAssets(); + AssetManager asset = mApplication.getAssets(); BufferedReader reader = null; + //noinspection TryFinallyCanBeTryWithResources try { - //noinspection IOResourceOpenedButNotSafelyClosed reader = new BufferedReader(new InputStreamReader( asset.open(BLOCKED_DOMAINS_LIST_FILE_NAME))); StringBuilder lineBuilder = new StringBuilder(); From e7280be103d4687301e3e954aea0265456b8d73e Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 26 Apr 2017 21:24:45 -0400 Subject: [PATCH 077/181] Constructor injection for HistoryDatabase --- .../browser/lightning/app/AppComponent.java | 5 +++ .../lightning/database/HistoryDatabase.java | 33 ++++++++----------- .../lightning/database/HistoryModel.java | 23 ++++++++++--- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index de92ee974..b265c9d12 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -1,5 +1,7 @@ package acr.browser.lightning.app; +import android.support.annotation.NonNull; + import javax.inject.Singleton; import acr.browser.lightning.activity.BrowserActivity; @@ -11,6 +13,7 @@ import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.constant.StartPage; +import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.download.LightningDownloadListener; import acr.browser.lightning.fragment.BookmarkSettingsFragment; @@ -74,4 +77,6 @@ public interface AppComponent { void inject(SuggestionsAdapter suggestionsAdapter); + @NonNull HistoryDatabase historyDatabase(); + } diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java index 4d4c3c927..0b570f525 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java @@ -3,6 +3,7 @@ */ package acr.browser.lightning.database; +import android.app.Application; import android.content.ContentValues; import android.database.Cursor; import android.database.DatabaseUtils; @@ -15,11 +16,15 @@ import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; +import javax.inject.Singleton; + import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; +@Singleton @WorkerThread -class HistoryDatabase extends SQLiteOpenHelper { +public class HistoryDatabase extends SQLiteOpenHelper { // All Static variables // Database Version @@ -39,28 +44,18 @@ class HistoryDatabase extends SQLiteOpenHelper { @Nullable private SQLiteDatabase mDatabase; - @Nullable private static HistoryDatabase sInstance; - - private HistoryDatabase() { - super(BrowserApp.getApplication(), DATABASE_NAME, null, DATABASE_VERSION); + @Inject + HistoryDatabase(@NonNull Application application) { + super(application, DATABASE_NAME, null, DATABASE_VERSION); mDatabase = HistoryDatabase.this.getWritableDatabase(); } - @NonNull - public synchronized static HistoryDatabase getInstance() { - if (sInstance == null) { - sInstance = new HistoryDatabase(); - } - - return sInstance; - } - // Creating Tables @Override public void onCreate(@NonNull SQLiteDatabase db) { String CREATE_HISTORY_TABLE = "CREATE TABLE " + TABLE_HISTORY + '(' + KEY_ID - + " INTEGER PRIMARY KEY," + KEY_URL + " TEXT," + KEY_TITLE + " TEXT," - + KEY_TIME_VISITED + " INTEGER" + ')'; + + " INTEGER PRIMARY KEY," + KEY_URL + " TEXT," + KEY_TITLE + " TEXT," + + KEY_TIME_VISITED + " INTEGER" + ')'; db.execSQL(CREATE_HISTORY_TABLE); } @@ -123,7 +118,7 @@ synchronized void visitHistoryItem(@NonNull String url, @Nullable String title) values.put(KEY_TIME_VISITED, System.currentTimeMillis()); Cursor cursor = mDatabase.query(false, TABLE_HISTORY, new String[]{KEY_URL}, - KEY_URL + " = ?", new String[]{url}, null, null, null, "1"); + KEY_URL + " = ?", new String[]{url}, null, null, null, "1"); if (cursor.getCount() > 0) { mDatabase.update(TABLE_HISTORY, values, KEY_URL + " = ?", new String[]{url}); @@ -149,7 +144,7 @@ private synchronized void addHistoryItem(@NonNull HistoryItem item) { synchronized String getHistoryItem(@NonNull String url) { mDatabase = openIfNecessary(); Cursor cursor = mDatabase.query(TABLE_HISTORY, new String[]{KEY_ID, KEY_URL, KEY_TITLE}, - KEY_URL + " = ?", new String[]{url}, null, null, null, "1"); + KEY_URL + " = ?", new String[]{url}, null, null, null, "1"); String m = null; if (cursor != null) { cursor.moveToFirst(); @@ -172,7 +167,7 @@ synchronized List findItemsContaining(@Nullable String search) { search = '%' + search + '%'; Cursor cursor = mDatabase.query(TABLE_HISTORY, null, KEY_TITLE + " LIKE ? OR " + KEY_URL + " LIKE ?", - new String[]{search, search}, null, null, KEY_TIME_VISITED + " DESC", "5"); + new String[]{search, search}, null, null, KEY_TIME_VISITED + " DESC", "5"); while (cursor.moveToNext()) { itemList.add(fromCursor(cursor)); diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryModel.java b/app/src/main/java/acr/browser/lightning/database/HistoryModel.java index c04a341e9..a58d5b6b9 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryModel.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryModel.java @@ -12,6 +12,8 @@ import java.util.List; +import acr.browser.lightning.app.BrowserApp; + /** * A model class providing reactive bindings * with the underlying history database. @@ -25,7 +27,9 @@ public static Completable deleteHistory() { return Completable.create(new CompletableAction() { @Override public void onSubscribe(@NonNull CompletableSubscriber subscriber) { - HistoryDatabase.getInstance().deleteHistory(); + BrowserApp.getAppComponent() + .historyDatabase() + .deleteHistory(); subscriber.onComplete(); } @@ -37,7 +41,9 @@ public static Completable deleteHistoryItem(@NonNull final String url) { return Completable.create(new CompletableAction() { @Override public void onSubscribe(@NonNull CompletableSubscriber subscriber) { - HistoryDatabase.getInstance().deleteHistoryItem(url); + BrowserApp.getAppComponent() + .historyDatabase() + .deleteHistoryItem(url); subscriber.onComplete(); } @@ -49,7 +55,12 @@ public static Completable visitHistoryItem(@NonNull final String url, @Nullable return Completable.create(new CompletableAction() { @Override public void onSubscribe(@NonNull CompletableSubscriber subscriber) { - HistoryDatabase.getInstance().visitHistoryItem(url, title); + BrowserApp.getAppComponent() + .historyDatabase() + .visitHistoryItem(url, title); + + System.out.println("SHIT: " + BrowserApp.getAppComponent().historyDatabase().toString()); + System.out.println("SHIT: " + BrowserApp.getAppComponent().historyDatabase().toString()); subscriber.onComplete(); } @@ -61,7 +72,8 @@ public static Single> findHistoryItemsContaining(@NonNull fina return Single.create(new SingleAction>() { @Override public void onSubscribe(@NonNull SingleSubscriber> subscriber) { - List result = HistoryDatabase.getInstance().findItemsContaining(query); + List result = BrowserApp.getAppComponent() + .historyDatabase().findItemsContaining(query); subscriber.onItem(result); subscriber.onComplete(); @@ -74,7 +86,8 @@ public static Single> lastHundredVisitedHistoryItems() { return Single.create(new SingleAction>() { @Override public void onSubscribe(@NonNull SingleSubscriber> subscriber) { - List result = HistoryDatabase.getInstance().getLastHundredItems(); + List result = BrowserApp.getAppComponent() + .historyDatabase().getLastHundredItems(); subscriber.onItem(result); subscriber.onComplete(); From 0cc8777e319a846c9199cc1f442e10ba039b6a0f Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 26 Apr 2017 21:41:47 -0400 Subject: [PATCH 078/181] More injection --- .../browser/lightning/app/AppComponent.java | 5 ++++- .../acr/browser/lightning/app/BrowserApp.java | 18 ++++++------------ .../lightning/favicon/FaviconModel.java | 19 +++++++++++-------- .../lightning/fragment/BookmarksFragment.java | 6 +----- .../lightning/view/LightningChromeClient.java | 9 ++++++--- 5 files changed, 28 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index b265c9d12..12547398a 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -25,6 +25,7 @@ import acr.browser.lightning.search.SuggestionsAdapter; import acr.browser.lightning.utils.AdBlock; import acr.browser.lightning.utils.ProxyUtils; +import acr.browser.lightning.view.LightningChromeClient; import acr.browser.lightning.view.LightningView; import acr.browser.lightning.view.LightningWebClient; import dagger.Component; @@ -77,6 +78,8 @@ public interface AppComponent { void inject(SuggestionsAdapter suggestionsAdapter); - @NonNull HistoryDatabase historyDatabase(); + void inject(LightningChromeClient chromeClient); + + HistoryDatabase historyDatabase(); } diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index cf30a595a..8866e5f18 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -49,13 +49,13 @@ public void onCreate() { super.onCreate(); if (BuildConfig.DEBUG) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); + .detectAll() + .penaltyLog() + .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); + .detectAll() + .penaltyLog() + .build()); } final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); @@ -95,12 +95,6 @@ public void onActivityDestroyed(Activity activity) { }); } - @NonNull - public static Application getApplication() { - Preconditions.checkNonNull(sApplication); - return sApplication; - } - @NonNull public static BrowserApp get(@NonNull Context context) { return (BrowserApp) context.getApplicationContext(); diff --git a/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java index 3b5110465..350e6b9a9 100644 --- a/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java +++ b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java @@ -17,6 +17,9 @@ import java.io.FileOutputStream; import java.io.IOException; +import javax.inject.Inject; +import javax.inject.Singleton; + import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.utils.Utils; @@ -24,14 +27,18 @@ * Reactive model that can fetch favicons * from URLs and also cache them. */ +@Singleton public class FaviconModel { private static final String TAG = "FaviconModel"; - private final ImageFetcher mImageFetcher; + @NonNull private final ImageFetcher mImageFetcher; + @NonNull private final Application mApplication; - public FaviconModel() { + @Inject + public FaviconModel(@NonNull Application application) { mImageFetcher = new ImageFetcher(); + mApplication = application; } @NonNull @@ -63,9 +70,7 @@ public void onSubscribe(@NonNull SingleSubscriber subscriber) { return; } - Application app = BrowserApp.getApplication(); - - File faviconCacheFile = createFaviconCacheFile(app, uri); + File faviconCacheFile = createFaviconCacheFile(mApplication, uri); Bitmap favicon = null; @@ -117,13 +122,11 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) { return; } - Application app = BrowserApp.getApplication(); - Log.d(TAG, "Caching icon for " + uri.getHost()); FileOutputStream fos = null; try { - File image = createFaviconCacheFile(app, uri); + File image = createFaviconCacheFile(mApplication, uri); fos = new FileOutputStream(image); favicon.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 3968405a5..fbb75f4cb 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -88,7 +88,7 @@ public static BookmarksFragment createFragment(boolean isIncognito) { @Inject PreferenceManager mPreferenceManager; - private FaviconModel mFaviconModel; + @Inject FaviconModel mFaviconModel; private TabsManager mTabsManager; @@ -148,8 +148,6 @@ public void onCreate(@Nullable Bundle savedInstanceState) { mFolderBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_folder, darkTheme); mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(context) : ThemeUtils.getIconLightThemeColor(context); - - mFaviconModel = new FaviconModel(); } private TabsManager getTabsManager() { @@ -269,8 +267,6 @@ public void reinitializePreferences() { mFolderBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, darkTheme); mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(activity) : ThemeUtils.getIconLightThemeColor(activity); - - mFaviconModel = new FaviconModel(); } private void updateBookmarkIndicator(final String url) { diff --git a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java index 1ab5694b7..2aab716df 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java @@ -22,13 +22,16 @@ import com.anthonycr.grant.PermissionsManager; import com.anthonycr.grant.PermissionsResultAction; +import javax.inject.Inject; + import acr.browser.lightning.R; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.controller.UIController; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.favicon.FaviconModel; import acr.browser.lightning.utils.Preconditions; -class LightningChromeClient extends WebChromeClient { +public class LightningChromeClient extends WebChromeClient { private static final String TAG = LightningChromeClient.class.getSimpleName(); @@ -37,15 +40,15 @@ class LightningChromeClient extends WebChromeClient { @NonNull private final Activity mActivity; @NonNull private final LightningView mLightningView; @NonNull private final UIController mUIController; - @NonNull private final FaviconModel mFaviconModel; + @Inject FaviconModel mFaviconModel; LightningChromeClient(@NonNull Activity activity, @NonNull LightningView lightningView) { Preconditions.checkNonNull(activity); Preconditions.checkNonNull(lightningView); + BrowserApp.getAppComponent().inject(this); mActivity = activity; mUIController = (UIController) activity; mLightningView = lightningView; - mFaviconModel = new FaviconModel(); } @Override From 61bb99c3be40cc0dc2b5f445ba867353674114d3 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 26 Apr 2017 22:03:49 -0400 Subject: [PATCH 079/181] Injecting application where possible --- .../main/java/acr/browser/lightning/app/BrowserApp.java | 7 ------- .../acr/browser/lightning/download/DownloadHandler.java | 6 +----- .../acr/browser/lightning/search/SuggestionsAdapter.java | 7 ++++--- .../acr/browser/lightning/search/SuggestionsManager.java | 6 ++---- .../java/acr/browser/lightning/view/LightningView.java | 3 ++- 5 files changed, 9 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index 8866e5f18..c09f6881c 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -30,7 +30,6 @@ public class BrowserApp extends Application { private static final String TAG = BrowserApp.class.getSimpleName(); - @Nullable private static Application sApplication; @Nullable private static AppComponent sAppComponent; private static final Executor mIOThread = Executors.newSingleThreadExecutor(); private static final Executor mTaskThread = Executors.newCachedThreadPool(); @@ -41,7 +40,6 @@ public class BrowserApp extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); - sApplication = this; } @Override @@ -116,11 +114,6 @@ public static Executor getTaskThread() { return mTaskThread; } - @NonNull - public static Bus getBus(@NonNull Context context) { - return get(context).mBus; - } - /** * Determines whether this is a release build. * diff --git a/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java index ede6725e0..1f55e1776 100644 --- a/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java +++ b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java @@ -23,15 +23,12 @@ import android.webkit.MimeTypeMap; import android.webkit.URLUtil; -import com.squareup.otto.Bus; - import java.io.File; import java.io.IOException; import acr.browser.lightning.BuildConfig; import acr.browser.lightning.R; import acr.browser.lightning.activity.MainActivity; -import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.preference.PreferenceManager; @@ -50,7 +47,7 @@ public class DownloadHandler { .getPath(); @Nullable - public static String guessFileExtension(@NonNull String filename) { + static String guessFileExtension(@NonNull String filename) { int lastIndex = filename.lastIndexOf('.') + 1; if (lastIndex > 0 && filename.length() > lastIndex) { return filename.substring(lastIndex, filename.length()); @@ -157,7 +154,6 @@ private static String encodePath(@NonNull String path) { private static void onDownloadStartNoStream(@NonNull final Activity context, @NonNull PreferenceManager preferences, String url, String userAgent, String contentDisposition, @Nullable String mimetype) { - final Bus eventBus = BrowserApp.getBus(context); final String filename = URLUtil.guessFileName(url, contentDisposition, mimetype); // Check to see if we have an SDCard diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index f465d4551..d49af228c 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -66,6 +66,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable { @Inject BookmarkManager mBookmarkManager; @Inject PreferenceManager mPreferenceManager; + @Inject Application mApplication; private final List mAllBookmarks = new ArrayList<>(5); @@ -96,7 +97,7 @@ public void refreshPreferences() { public void clearCache() { // We don't need these cache files anymore - Schedulers.io().execute(new ClearCacheRunnable(BrowserApp.get(mContext))); + Schedulers.io().execute(new ClearCacheRunnable(mApplication)); } public void refreshBookmarks() { @@ -294,9 +295,9 @@ public void onSubscribe(@NonNull SingleSubscriber> subscriber) @NonNull private Single> getSuggestionsForQuery(@NonNull final String query) { if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_GOOGLE) { - return SuggestionsManager.createGoogleQueryObservable(query, mContext); + return SuggestionsManager.createGoogleQueryObservable(query, mApplication); } else if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_DUCK) { - return SuggestionsManager.createDuckQueryObservable(query, mContext); + return SuggestionsManager.createDuckQueryObservable(query, mApplication); } else { return Single.empty(); } diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java index f453a6ad3..0ee0aa023 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java @@ -23,8 +23,7 @@ static boolean isRequestInProgress() { @NonNull static Single> createGoogleQueryObservable(@NonNull final String query, - @NonNull final Context context) { - final Application application = BrowserApp.get(context); + @NonNull final Application application) { return Single.create(new SingleAction>() { @Override public void onSubscribe(@NonNull final SingleSubscriber> subscriber) { @@ -39,8 +38,7 @@ public void onSubscribe(@NonNull final SingleSubscriber> subsc @NonNull static Single> createDuckQueryObservable(@NonNull final String query, - @NonNull final Context context) { - final Application application = BrowserApp.get(context); + @NonNull final Application application) { return Single.create(new SingleAction>() { @Override public void onSubscribe(@NonNull final SingleSubscriber> subscriber) { diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 5937393c2..3508f7917 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -464,11 +464,12 @@ public void onComplete() { } + @NonNull private Single getPathObservable(final String subFolder) { return Single.create(new SingleAction() { @Override public void onSubscribe(@NonNull SingleSubscriber subscriber) { - File file = BrowserApp.get(mActivity).getDir(subFolder, 0); + File file = mActivity.getDir(subFolder, 0); subscriber.onItem(file); subscriber.onComplete(); } From 5af0f5f0c1cee793818b82a1dd36ac921b854f92 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 26 Apr 2017 22:12:21 -0400 Subject: [PATCH 080/181] Getting rid of BrowserApp.get method --- .../java/acr/browser/lightning/activity/BrowserActivity.java | 4 ++-- app/src/main/java/acr/browser/lightning/app/BrowserApp.java | 5 ----- .../main/java/acr/browser/lightning/utils/ProxyUtils.java | 3 +-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 0400ecaf1..66a32cc91 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -1284,7 +1284,7 @@ protected void onPause() { Log.d(TAG, "onPause"); mTabsManager.pauseAll(); try { - BrowserApp.get(this).unregisterReceiver(mNetworkReceiver); + getApplication().unregisterReceiver(mNetworkReceiver); } catch (IllegalArgumentException e) { Log.e(TAG, "Receiver was not registered", e); } @@ -1349,7 +1349,7 @@ protected void onResume() { IntentFilter filter = new IntentFilter(); filter.addAction(NETWORK_BROADCAST_ACTION); - BrowserApp.get(this).registerReceiver(mNetworkReceiver, filter); + getApplication().registerReceiver(mNetworkReceiver, filter); mEventBus.register(mBusEventListener); diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index c09f6881c..8b66e7562 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -93,11 +93,6 @@ public void onActivityDestroyed(Activity activity) { }); } - @NonNull - public static BrowserApp get(@NonNull Context context) { - return (BrowserApp) context.getApplicationContext(); - } - @NonNull public static AppComponent getAppComponent() { Preconditions.checkNonNull(sAppComponent); diff --git a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java index 4bdc5f399..85acd54e0 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java @@ -202,9 +202,8 @@ public static int setProxyChoice(int choice, @NonNull Activity activity) { Utils.showSnackbar(activity, R.string.install_orbot); } break; - case Constants.PROXY_I2P: - I2PAndroidHelper ih = new I2PAndroidHelper(BrowserApp.get(activity)); + I2PAndroidHelper ih = new I2PAndroidHelper(activity.getApplication()); if (!ih.isI2PAndroidInstalled()) { choice = Constants.NO_PROXY; ih.promptToInstall(activity); From 7fa33156621013414198a8d51d9f27d97b92eb9d Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 26 Apr 2017 22:50:15 -0400 Subject: [PATCH 081/181] Localizing log tags --- .../lightning/activity/BrowserActivity.java | 12 +- .../lightning/activity/TabsManager.java | 164 +++++++++--------- .../browser/lightning/constant/Constants.java | 5 +- .../download/LightningDownloadListener.java | 4 +- .../fragment/BookmarkSettingsFragment.java | 61 +++---- .../fragment/GeneralSettingsFragment.java | 2 +- .../preference/PreferenceManager.java | 6 +- .../browser/lightning/reading/Converter.java | 20 ++- .../browser/lightning/utils/FileUtils.java | 8 +- .../browser/lightning/utils/ProxyUtils.java | 7 +- .../acr/browser/lightning/utils/Utils.java | 4 +- .../lightning/view/LightningWebClient.java | 6 +- 12 files changed, 154 insertions(+), 145 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 66a32cc91..096f606ed 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -187,8 +187,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private String mUntitledTitle; private String mCameraPhotoPath; - private final Handler mDrawerHandler = new Handler(); - // The singleton BookmarkManager @Inject BookmarkManager mBookmarkManager; @@ -991,7 +989,7 @@ public void removeTabView() { // Use a delayed handler to make the transition smooth // otherwise it will get caught up with the showTab code // and cause a janky motion - mDrawerHandler.postDelayed(new Runnable() { + Handlers.MAIN.postDelayed(new Runnable() { @Override public void run() { mDrawerLayout.closeDrawers(); @@ -1030,14 +1028,14 @@ public void setTabView(@NonNull final View view) { // Use a delayed handler to make the transition smooth // otherwise it will get caught up with the showTab code // and cause a janky motion - mDrawerHandler.postDelayed(new Runnable() { + Handlers.MAIN.postDelayed(new Runnable() { @Override public void run() { mDrawerLayout.closeDrawers(); } }, 200); - // mDrawerHandler.postDelayed(new Runnable() { + // Handlers.MAIN.postDelayed(new Runnable() { // @Override // public void run() { // Remove browser frame background to reduce overdraw @@ -1114,7 +1112,7 @@ public void bookmarkItemClicked(@NonNull HistoryItem item) { mPresenter.loadUrlInCurrentView(item.getUrl()); // keep any jank from happening when the drawer is closed after the // URL starts to load - mDrawerHandler.postDelayed(new Runnable() { + Handlers.MAIN.postDelayed(new Runnable() { @Override public void run() { closeDrawers(null); @@ -1311,7 +1309,7 @@ protected void onStop() { protected void onDestroy() { Log.d(TAG, "onDestroy"); - mDrawerHandler.removeCallbacksAndMessages(null); + Handlers.MAIN.removeCallbacksAndMessages(null); mPresenter.shutdown(); diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index a69396e20..464449bab 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -155,97 +155,97 @@ private void restoreLostTabs(@Nullable final String url, @NonNull final Activity @NonNull final CompletableSubscriber subscriber) { restoreState() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new StreamOnSubscribe() { - @Override - public void onNext(@Nullable Bundle item) { - final LightningView tab = newTab(activity, "", false); - Preconditions.checkNonNull(item); - String url = item.getString(URL_KEY); - if (url != null && tab.getWebView() != null) { - if (UrlUtils.isBookmarkUrl(url)) { - new BookmarkPage(activity).getBookmarkPage() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable String item) { - Preconditions.checkNonNull(item); - tab.loadUrl(item); - } - }); - } else if (UrlUtils.isStartPageUrl(url)) { - new StartPage().getHomepage() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable String item) { - Preconditions.checkNonNull(item); - tab.loadUrl(item); - } - }); - } else if (UrlUtils.isHistoryUrl(url)) { - new HistoryPage().getHistoryPage() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable String item) { - Preconditions.checkNonNull(item); - tab.loadUrl(item); - } - }); - } - } else if (tab.getWebView() != null) { - tab.getWebView().restoreState(item); + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new StreamOnSubscribe() { + @Override + public void onNext(@Nullable Bundle item) { + final LightningView tab = newTab(activity, "", false); + Preconditions.checkNonNull(item); + String url = item.getString(URL_KEY); + if (url != null && tab.getWebView() != null) { + if (UrlUtils.isBookmarkUrl(url)) { + new BookmarkPage(activity).getBookmarkPage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + tab.loadUrl(item); + } + }); + } else if (UrlUtils.isStartPageUrl(url)) { + new StartPage().getHomepage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + tab.loadUrl(item); + } + }); + } else if (UrlUtils.isHistoryUrl(url)) { + new HistoryPage().getHistoryPage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + tab.loadUrl(item); + } + }); } + } else if (tab.getWebView() != null) { + tab.getWebView().restoreState(item); } + } - @Override - public void onComplete() { - if (url != null) { - if (url.startsWith(Constants.FILE)) { - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - Dialog dialog = builder.setCancelable(true) - .setTitle(R.string.title_warning) - .setMessage(R.string.message_blocked_local) - .setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - if (mTabList.isEmpty()) { - newTab(activity, null, false); - } - finishInitialization(); - subscriber.onComplete(); - } - }) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(R.string.action_open, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - newTab(activity, url, false); - } - }).show(); - BrowserDialog.setDialogSize(activity, dialog); - } else { - newTab(activity, url, false); - if (mTabList.isEmpty()) { - newTab(activity, null, false); - } - finishInitialization(); - subscriber.onComplete(); - } + @Override + public void onComplete() { + if (url != null) { + if (url.startsWith(Constants.FILE)) { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + Dialog dialog = builder.setCancelable(true) + .setTitle(R.string.title_warning) + .setMessage(R.string.message_blocked_local) + .setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + if (mTabList.isEmpty()) { + newTab(activity, null, false); + } + finishInitialization(); + subscriber.onComplete(); + } + }) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(R.string.action_open, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + newTab(activity, url, false); + } + }).show(); + BrowserDialog.setDialogSize(activity, dialog); } else { + newTab(activity, url, false); if (mTabList.isEmpty()) { newTab(activity, null, false); } finishInitialization(); subscriber.onComplete(); } + } else { + if (mTabList.isEmpty()) { + newTab(activity, null, false); + } + finishInitialization(); + subscriber.onComplete(); } - }); + } + }); } /** @@ -475,7 +475,7 @@ public synchronized int positionOf(final LightningView tab) { */ public void saveState() { Bundle outState = new Bundle(ClassLoader.getSystemClassLoader()); - Log.d(Constants.TAG, "Saving tab state"); + Log.d(TAG, "Saving tab state"); for (int n = 0; n < mTabList.size(); n++) { LightningView tab = mTabList.get(n); if (TextUtils.isEmpty(tab.getUrl())) { @@ -515,7 +515,7 @@ private Stream restoreState() { public void onSubscribe(@NonNull StreamSubscriber subscriber) { Bundle savedState = FileUtils.readBundleFromStorage(mApp, BUNDLE_STORAGE); if (savedState != null) { - Log.d(Constants.TAG, "Restoring previous WebView state now"); + Log.d(TAG, "Restoring previous WebView state now"); for (String key : savedState.keySet()) { if (key.startsWith(BUNDLE_KEY)) { subscriber.onNext(savedState.getBundle(key)); diff --git a/app/src/main/java/acr/browser/lightning/constant/Constants.java b/app/src/main/java/acr/browser/lightning/constant/Constants.java index a6b47bd0a..00c928700 100644 --- a/app/src/main/java/acr/browser/lightning/constant/Constants.java +++ b/app/src/main/java/acr/browser/lightning/constant/Constants.java @@ -67,13 +67,10 @@ private Constants() { public static final String ABOUT = "about:"; public static final String FOLDER = "folder://"; - // Application log tag - public static final String TAG = "Lightning"; - // These should match the order of @array/proxy_choices_array @IntDef({NO_PROXY, PROXY_ORBOT, PROXY_I2P, PROXY_MANUAL}) @Retention(RetentionPolicy.SOURCE) - public @interface PROXY {} + public @interface Proxy {} public static final int NO_PROXY = 0; public static final int PROXY_ORBOT = 1; diff --git a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java index 47768e0e5..c5a3aeb8e 100644 --- a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java +++ b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java @@ -25,6 +25,8 @@ public class LightningDownloadListener implements DownloadListener { + private static final String TAG = "LightningDownloader"; + private final Activity mActivity; @Inject PreferenceManager mPreferenceManager; @@ -65,7 +67,7 @@ public void onClick(DialogInterface dialog, int which) { .setNegativeButton(mActivity.getResources().getString(R.string.action_cancel), dialogClickListener).show(); BrowserDialog.setDialogSize(mActivity, dialog); - Log.i(Constants.TAG, "Downloading: " + fileName); + Log.i(TAG, "Downloading: " + fileName); } @Override diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index 1a81f91a5..f8e90816f 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -41,6 +41,7 @@ import acr.browser.lightning.database.BookmarkLocalSync.Source; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; + import com.anthonycr.bonsai.Schedulers; import acr.browser.lightning.dialog.BrowserDialog; @@ -49,6 +50,8 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener { + private static final String TAG = "BookmarkSettingsFrag"; + private static final String SETTINGS_EXPORT = "export_bookmark"; private static final String SETTINGS_IMPORT = "import_bookmark"; private static final String SETTINGS_IMPORT_BROWSER = "import_browser"; @@ -62,8 +65,8 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @Nullable private BookmarkLocalSync mSync; private static final String[] REQUIRED_PERMISSIONS = new String[]{ - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.WRITE_EXTERNAL_STORAGE + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE }; private static final File mPath = new File(Environment.getExternalStorageDirectory().toString()); @@ -80,7 +83,7 @@ public ImportBookmarksTask(Activity activity, Source source) { @Override protected Integer doInBackground(Void... params) { List list; - Log.d(Constants.TAG, "Loading bookmarks from: " + mSource.name()); + Log.d(TAG, "Loading bookmarks from: " + mSource.name()); switch (mSource) { case STOCK: list = getSync().getBookmarksFromStockBrowser(); @@ -184,36 +187,36 @@ public boolean onPreferenceClick(@NonNull Preference preference) { switch (preference.getKey()) { case SETTINGS_EXPORT: PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS, - new PermissionsResultAction() { - @Override - public void onGranted() { - mBookmarkManager.exportBookmarks(getActivity()); - } - - @Override - public void onDenied(String permission) { - //TODO Show message - } - }); + new PermissionsResultAction() { + @Override + public void onGranted() { + mBookmarkManager.exportBookmarks(getActivity()); + } + + @Override + public void onDenied(String permission) { + //TODO Show message + } + }); return true; case SETTINGS_IMPORT: PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS, - new PermissionsResultAction() { - @Override - public void onGranted() { - loadFileList(null); - createDialog(); - } - - @Override - public void onDenied(String permission) { - //TODO Show message - } - }); + new PermissionsResultAction() { + @Override + public void onGranted() { + loadFileList(null); + createDialog(); + } + + @Override + public void onDenied(String permission) { + //TODO Show message + } + }); return true; case SETTINGS_IMPORT_BROWSER: getSync().getSupportedBrowsers().subscribeOn(Schedulers.worker()) - .observeOn(Schedulers.main()).subscribe(new SingleOnSubscribe>() { + .observeOn(Schedulers.main()).subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable List item) { Activity activity = getActivity(); @@ -289,7 +292,7 @@ private List buildTitleList(@NonNull Activity activity, @NonNull List list) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); final ArrayAdapter adapter = new ArrayAdapter<>(activity, - android.R.layout.simple_list_item_1); + android.R.layout.simple_list_item_1); for (String title : list) { adapter.add(title); } @@ -385,7 +388,7 @@ public int compare(@NonNull File a, @NonNull File b) { } private void createDialog() { - if(mActivity == null){ + if (mActivity == null) { return; } final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); diff --git a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java index 1ae471b84..7365b485a 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java @@ -230,7 +230,7 @@ public void onClick(DialogInterface dialog, int which) { BrowserDialog.setDialogSize(mActivity, dialog); } - private void setProxyChoice(@Constants.PROXY int choice) { + private void setProxyChoice(@Constants.Proxy int choice) { switch (choice) { case Constants.PROXY_ORBOT: choice = ProxyUtils.setProxyChoice(choice, mActivity); diff --git a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java index a1855e99c..b62b1d84b 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -251,9 +251,9 @@ public boolean getUseProxy() { return mPrefs.getBoolean(Name.USE_PROXY, false); } - @Constants.PROXY + @Constants.Proxy public int getProxyChoice() { - @Constants.PROXY int proxy = mPrefs.getInt(Name.PROXY_CHOICE, Constants.NO_PROXY); + @Constants.Proxy int proxy = mPrefs.getInt(Name.PROXY_CHOICE, Constants.NO_PROXY); switch (proxy) { case Constants.NO_PROXY: case Constants.PROXY_ORBOT: @@ -473,7 +473,7 @@ public boolean getUseLeakCanary() { * * @param choice the proxy to use. */ - public void setProxyChoice(@Constants.PROXY int choice) { + public void setProxyChoice(@Constants.Proxy int choice) { putBoolean(Name.USE_PROXY, choice != Constants.NO_PROXY); putInt(Name.PROXY_CHOICE, choice); } diff --git a/app/src/main/java/acr/browser/lightning/reading/Converter.java b/app/src/main/java/acr/browser/lightning/reading/Converter.java index 6e3ba338c..5513342a6 100644 --- a/app/src/main/java/acr/browser/lightning/reading/Converter.java +++ b/app/src/main/java/acr/browser/lightning/reading/Converter.java @@ -30,11 +30,13 @@ /** * This class is not thread safe. Use one new instance every time due to * encoding variable. - * + * * @author Peter Karich */ public class Converter { + private static final String TAG = "Converter"; + private final static String UTF8 = "UTF-8"; private final static String ISO = "ISO-8859-1"; private final static int K2 = 2048; @@ -93,7 +95,7 @@ public String streamToString(InputStream is, String enc) { /** * reads bytes off the string and returns a string - * + * * @param is input stream to read * @param maxBytes * The max bytes that we want to read from the input stream @@ -118,20 +120,20 @@ private String streamToString(InputStream is, int maxBytes, String enc) { if (tmpEnc != null) encoding = tmpEnc; else { - Log.d(Constants.TAG, "no charset found in first stage"); + Log.d(TAG, "no charset found in first stage"); // detect with the help of xml beginning ala // encoding="charset" tmpEnc = detectCharset("encoding=", output, in, encoding); if (tmpEnc != null) encoding = tmpEnc; else - Log.d(Constants.TAG, "no charset found in second stage"); + Log.d(TAG, "no charset found in second stage"); } if (!Charset.isSupported(encoding)) throw new UnsupportedEncodingException(encoding); } catch (UnsupportedEncodingException e) { - Log.d(Constants.TAG, + Log.d(TAG, "Using default encoding:" + UTF8 + " problem:" + e.getMessage() + " encoding:" + encoding + ' ' + url); encoding = UTF8; @@ -146,7 +148,7 @@ private String streamToString(InputStream is, int maxBytes, String enc) { byte[] arr = new byte[K2]; while (true) { if (bytesRead >= maxBytes) { - Log.d(Constants.TAG, "Maxbyte of " + maxBytes + Log.d(TAG, "Maxbyte of " + maxBytes + " exceeded! Maybe html is now broken but try it nevertheless. Url: " + url); break; @@ -161,7 +163,7 @@ private String streamToString(InputStream is, int maxBytes, String enc) { return output.toString(encoding); } catch (IOException e) { - Log.e(Constants.TAG, e.toString() + " url:" + url); + Log.e(TAG, e.toString() + " url:" + url); } finally { if (in != null) { try { @@ -178,7 +180,7 @@ private String streamToString(InputStream is, int maxBytes, String enc) { * This method detects the charset even if the first call only returns some * bytes. It will read until 4K bytes are reached and then try to determine * the encoding - * + * * @throws IOException */ private static String detectCharset(String key, ByteArrayOutputStream bos, BufferedInputStream in, @@ -236,7 +238,7 @@ else if (startChar == '\"') bos.reset(); return tmpEnc; } catch (IOException ex) { - Log.e(Constants.TAG, "Couldn't reset stream to re-read with new encoding " + Log.e(TAG, "Couldn't reset stream to re-read with new encoding " + tmpEnc + ' ' + ex.toString()); } } diff --git a/app/src/main/java/acr/browser/lightning/utils/FileUtils.java b/app/src/main/java/acr/browser/lightning/utils/FileUtils.java index 201c6462d..e7b7c8503 100644 --- a/app/src/main/java/acr/browser/lightning/utils/FileUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/FileUtils.java @@ -27,6 +27,8 @@ */ public class FileUtils { + private static final String TAG = "FileUtils"; + /** * Writes a bundle to persistent storage in the files directory * using the specified file name. This method is a blocking @@ -51,7 +53,7 @@ public void run() { outputStream.flush(); parcel.recycle(); } catch (IOException e) { - Log.e(Constants.TAG, "Unable to write bundle to storage"); + Log.e(TAG, "Unable to write bundle to storage"); } finally { Utils.close(outputStream); } @@ -103,7 +105,7 @@ public static Bundle readBundleFromStorage(@NonNull Application app, @NonNull St parcel.recycle(); return out; } catch (FileNotFoundException e) { - Log.e(Constants.TAG, "Unable to read bundle from storage"); + Log.e(TAG, "Unable to read bundle from storage"); } catch (IOException e) { e.printStackTrace(); } finally { @@ -131,7 +133,7 @@ public static void writeCrashToStorage(@NonNull Throwable throwable) { throwable.printStackTrace(new PrintStream(outputStream)); outputStream.flush(); } catch (IOException e) { - Log.e(Constants.TAG, "Unable to write bundle to storage"); + Log.e(TAG, "Unable to write bundle to storage"); } finally { Utils.close(outputStream); } diff --git a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java index 85acd54e0..149cd489d 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java @@ -24,6 +24,9 @@ @Singleton public class ProxyUtils { + + private static final String TAG = "ProxyUtils"; + // Helper private static boolean mI2PHelperBound; private static boolean mI2PProxyInitialized; @@ -141,7 +144,7 @@ private void initializeProxy(@NonNull Activity activity) { try { WebkitProxy.setProxy(BrowserApp.class.getName(), activity.getApplicationContext(), null, host, port); } catch (Exception e) { - Log.d(Constants.TAG, "error enabling web proxying", e); + Log.d(TAG, "error enabling web proxying", e); } } @@ -193,7 +196,7 @@ public void onI2PAndroidBound() { } } - @Constants.PROXY + @Constants.Proxy public static int setProxyChoice(int choice, @NonNull Activity activity) { switch (choice) { case Constants.PROXY_ORBOT: diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index fe604b5ea..c13a3eb9e 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -80,7 +80,7 @@ public static void downloadFile(final Activity activity, final PreferenceManager public void onGranted() { String fileName = URLUtil.guessFileName(url, null, null); DownloadHandler.onDownloadStart(activity, manager, url, userAgent, contentDisposition, null); - Log.i(Constants.TAG, "Downloading: " + fileName); + Log.i(TAG, "Downloading: " + fileName); } @Override @@ -418,7 +418,7 @@ public static void createShortcut(@NonNull Activity activity, @NonNull HistoryIt if (TextUtils.isEmpty(item.getUrl())) { return; } - Log.d(Constants.TAG, "Creating shortcut: " + item.getTitle() + ' ' + item.getUrl()); + Log.d(TAG, "Creating shortcut: " + item.getTitle() + ' ' + item.getUrl()); Intent shortcutIntent = new Intent(activity, MainActivity.class); shortcutIntent.setData(Uri.parse(item.getUrl())); diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index e5f24f88f..b6ace1c0d 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -48,6 +48,8 @@ public class LightningWebClient extends WebViewClient { + private static final String TAG = "LightningWebClient"; + @NonNull private final Activity mActivity; @NonNull private final LightningView mLightningView; @NonNull private final UIController mUIController; @@ -149,7 +151,7 @@ public void onClick(DialogInterface dialog, int id) { String user = name.getText().toString(); String pass = password.getText().toString(); handler.proceed(user.trim(), pass.trim()); - Log.d(Constants.TAG, "Request Login"); + Log.d(TAG, "Request Login"); } }) @@ -364,7 +366,7 @@ private boolean isMailOrIntent(@NonNull String url, @NonNull WebView view) { try { mActivity.startActivity(intent); } catch (ActivityNotFoundException e) { - Log.e(Constants.TAG, "ActivityNotFoundException"); + Log.e(TAG, "ActivityNotFoundException"); } return true; } From fa7673b3d1a4e148702aa550632a87d351072f0d Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Thu, 27 Apr 2017 21:37:57 -0400 Subject: [PATCH 082/181] Better stringbuilder comparison --- .../acr/browser/lightning/app/AppComponent.java | 3 --- .../lightning/utils/StringBuilderUtils.java | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index 12547398a..12ed5ef25 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -1,7 +1,5 @@ package acr.browser.lightning.app; -import android.support.annotation.NonNull; - import javax.inject.Singleton; import acr.browser.lightning.activity.BrowserActivity; @@ -23,7 +21,6 @@ import acr.browser.lightning.fragment.PrivacySettingsFragment; import acr.browser.lightning.fragment.TabsFragment; import acr.browser.lightning.search.SuggestionsAdapter; -import acr.browser.lightning.utils.AdBlock; import acr.browser.lightning.utils.ProxyUtils; import acr.browser.lightning.view.LightningChromeClient; import acr.browser.lightning.view.LightningView; diff --git a/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java b/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java index 378175169..3b2e56530 100644 --- a/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/StringBuilderUtils.java @@ -93,8 +93,19 @@ public static boolean contains(@NonNull StringBuilder stringBuilder, @NonNull St * the string builder is equal to the string. */ public static boolean equals(@NonNull StringBuilder stringBuilder, @NonNull String equal) { - int index = stringBuilder.indexOf(equal); - return index >= 0 && stringBuilder.length() == equal.length(); + + int builderLength = stringBuilder.length(); + if (builderLength != equal.length()) { + return false; + } + + for (int n = 0; n < builderLength; n++) { + if (stringBuilder.charAt(n) != equal.charAt(n)) { + return false; + } + } + + return true; } /** From 54026bf6ccf8ffb7f3d14ff11738936f5576c373 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Fri, 28 Apr 2017 22:24:21 -0400 Subject: [PATCH 083/181] Cleaning up unused code --- .../lightning/activity/BrowserActivity.java | 1 - .../lightning/activity/TabsManager.java | 11 --- .../lightning/database/HistoryDatabase.java | 1 - .../lightning/dialog/BrowserDialog.java | 22 ++--- .../download/LightningDownloadListener.java | 1 - .../lightning/favicon/FaviconModel.java | 1 - .../fragment/BookmarkSettingsFragment.java | 1 - .../browser/lightning/reading/Converter.java | 2 - .../lightning/search/SuggestionsManager.java | 2 - .../lightning/utils/DrawableUtils.java | 10 -- .../browser/lightning/utils/FileUtils.java | 1 - .../browser/lightning/utils/ThemeUtils.java | 2 - .../acr/browser/lightning/utils/UrlUtils.java | 94 +++---------------- 13 files changed, 17 insertions(+), 132 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 096f606ed..d55dfa23f 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -22,7 +22,6 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Handler; import android.os.Message; import android.provider.MediaStore; import android.support.annotation.ColorInt; diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 464449bab..f72462afe 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -528,17 +528,6 @@ public void onSubscribe(@NonNull StreamSubscriber subscriber) { }); } - /** - * Return the {@link WebView} associated to the current tab, - * or null if there is no current tab. - * - * @return a {@link WebView} or null if there is no current tab. - */ - @Nullable - public synchronized WebView getCurrentWebView() { - return mCurrentTab != null ? mCurrentTab.getWebView() : null; - } - /** * Returns the index of the current tab. * diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java index 0b570f525..07ae7ccc0 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java @@ -20,7 +20,6 @@ import javax.inject.Singleton; import acr.browser.lightning.R; -import acr.browser.lightning.app.BrowserApp; @Singleton @WorkerThread diff --git a/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java b/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java index 9a3f180bd..3d5da1935 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java +++ b/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java @@ -75,16 +75,11 @@ private boolean isConditionMet() { public abstract void onClick(); } - - public static void show(@NonNull Activity activity, @NonNull Item item, @Nullable Item... items) { - show(activity, null, item, items); - } - - public static void show(@NonNull Activity activity, @StringRes int title, @NonNull Item item, @Nullable Item... items) { - show(activity, activity.getString(title), item, items); + public static void show(@NonNull Activity activity, @StringRes int title, @NonNull Item... items) { + show(activity, activity.getString(title), items); } - public static void show(@NonNull Activity activity, @Nullable String title, @NonNull Item item, @Nullable Item... items) { + public static void show(@NonNull Activity activity, @Nullable String title, @NonNull Item... items) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); View layout = LayoutInflater.from(activity).inflate(R.layout.list_dialog, null); @@ -96,14 +91,9 @@ public static void show(@NonNull Activity activity, @Nullable String title, @Non android.R.layout.simple_list_item_1); final List itemList = new ArrayList<>(1); - if (item.isConditionMet()) { - itemList.add(item); - } - if (items != null) { - for (Item it : items) { - if (it.isConditionMet()) { - itemList.add(it); - } + for (Item it : items) { + if (it.isConditionMet()) { + itemList.add(it); } } diff --git a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java index c5a3aeb8e..28264b2b6 100644 --- a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java +++ b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java @@ -14,7 +14,6 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.constant.Constants; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.preference.PreferenceManager; diff --git a/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java index 350e6b9a9..8900b18a5 100644 --- a/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java +++ b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java @@ -20,7 +20,6 @@ import javax.inject.Inject; import javax.inject.Singleton; -import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.utils.Utils; /** diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index f8e90816f..e8c8da5ce 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -36,7 +36,6 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.constant.Constants; import acr.browser.lightning.database.BookmarkLocalSync; import acr.browser.lightning.database.BookmarkLocalSync.Source; import acr.browser.lightning.database.BookmarkManager; diff --git a/app/src/main/java/acr/browser/lightning/reading/Converter.java b/app/src/main/java/acr/browser/lightning/reading/Converter.java index 5513342a6..6f35f8c03 100644 --- a/app/src/main/java/acr/browser/lightning/reading/Converter.java +++ b/app/src/main/java/acr/browser/lightning/reading/Converter.java @@ -25,8 +25,6 @@ import java.nio.charset.Charset; import java.util.Locale; -import acr.browser.lightning.constant.Constants; - /** * This class is not thread safe. Use one new instance every time due to * encoding variable. diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java index 0ee0aa023..2855f40f1 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java @@ -1,7 +1,6 @@ package acr.browser.lightning.search; import android.app.Application; -import android.content.Context; import android.support.annotation.NonNull; import com.anthonycr.bonsai.Single; @@ -10,7 +9,6 @@ import java.util.List; -import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.HistoryItem; class SuggestionsManager { diff --git a/app/src/main/java/acr/browser/lightning/utils/DrawableUtils.java b/app/src/main/java/acr/browser/lightning/utils/DrawableUtils.java index 91d76a400..3bc3c12bc 100644 --- a/app/src/main/java/acr/browser/lightning/utils/DrawableUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/DrawableUtils.java @@ -78,16 +78,6 @@ public static int mixColor(float fraction, int startValue, int endValue) { (startB + (int) (fraction * (endB - startB))); } - public static Drawable resolveDrawableAttribute(@NonNull Context context, @AttrRes int res) { - int[] attribute = new int[]{res}; - int indexOfAttrTextSize = 0; - TypedValue typedValue = new TypedValue(); - TypedArray a = context.obtainStyledAttributes(typedValue.data, attribute); - Drawable drawable = a.getDrawable(indexOfAttrTextSize); - a.recycle(); - return drawable; - } - public static void setBackground(@NonNull View view, @Nullable Drawable drawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { view.setBackground(drawable); diff --git a/app/src/main/java/acr/browser/lightning/utils/FileUtils.java b/app/src/main/java/acr/browser/lightning/utils/FileUtils.java index e7b7c8503..d099a036d 100644 --- a/app/src/main/java/acr/browser/lightning/utils/FileUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/FileUtils.java @@ -19,7 +19,6 @@ import java.io.PrintStream; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.constant.Constants; /** * A utility class containing helpful methods diff --git a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java index df2f58789..77bb8ca56 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java @@ -12,8 +12,6 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; import android.support.annotation.AttrRes; import android.support.annotation.ColorInt; import android.support.annotation.DrawableRes; diff --git a/app/src/main/java/acr/browser/lightning/utils/UrlUtils.java b/app/src/main/java/acr/browser/lightning/utils/UrlUtils.java index 2baa6bd97..63ba7980a 100644 --- a/app/src/main/java/acr/browser/lightning/utils/UrlUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/UrlUtils.java @@ -33,44 +33,18 @@ */ public class UrlUtils { private static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile( - "(?i)" + // switch on case insensitive matching - '(' + // begin group for schema - "(?:http|https|file)://" + - "|(?:inline|data|about|javascript):" + - "|(?:.*:.*@)" + - ')' + - "(.*)"); + "(?i)" + // switch on case insensitive matching + '(' + // begin group for schema + "(?:http|https|file)://" + + "|(?:inline|data|about|javascript):" + + "|(?:.*:.*@)" + + ')' + + "(.*)"); // Google search public final static String QUERY_PLACE_HOLDER = "%s"; - // Regular expression to strip http:// and optionally - // the trailing slash - private static final Pattern STRIP_URL_PATTERN = - Pattern.compile("^http://(.*?)/?$"); private UrlUtils() { /* cannot be instantiated */ } - /** - * Strips the provided url of preceding "http://" and any trailing "/". Does not - * strip "https://". If the provided string cannot be stripped, the original string - * is returned. - *

- * TODO: Put this in TextUtils to be used by other packages doing something similar. - * - * @param url a url to strip, like "http://www.google.com/" - * @return a stripped url like "www.google.com", or the original string if it could - * not be stripped - */ - @Nullable - public static String stripUrl(@Nullable String url) { - if (url == null) return null; - Matcher m = STRIP_URL_PATTERN.matcher(url); - if (m.matches()) { - return m.group(1); - } else { - return url; - } - } - /** * Attempts to determine whether user input is a URL or search * terms. Anything with a space is passed to search if canBeSearch is true. @@ -106,65 +80,19 @@ public static String smartUrlFilter(@NonNull String url, boolean canBeSearch, St } if (canBeSearch) { return URLUtil.composeSearchUrl(inUrl, - searchUrl, QUERY_PLACE_HOLDER); + searchUrl, QUERY_PLACE_HOLDER); } return ""; } - /* package */ - @NonNull - static String fixUrl(@NonNull String inUrl) { - // FIXME: Converting the url to lower case - // duplicates functionality in smartUrlFilter(). - // However, changing all current callers of fixUrl to - // call smartUrlFilter in addition may have unwanted - // consequences, and is deferred for now. - int colon = inUrl.indexOf(':'); - boolean allLower = true; - for (int index = 0; index < colon; index++) { - char ch = inUrl.charAt(index); - if (!Character.isLetter(ch)) { - break; - } - allLower &= Character.isLowerCase(ch); - if (index == colon - 1 && !allLower) { - inUrl = inUrl.substring(0, colon).toLowerCase() - + inUrl.substring(colon); - } - } - if (inUrl.startsWith("http://") || inUrl.startsWith("https://")) - return inUrl; - if (inUrl.startsWith("http:") || - inUrl.startsWith("https:")) { - if (inUrl.startsWith("http:/") || inUrl.startsWith("https:/")) { - inUrl = inUrl.replaceFirst("/", "//"); - } else inUrl = inUrl.replaceFirst(":", "://"); - } - return inUrl; - } - - // Returns the filtered URL. Cannot return null, but can return an empty string - /* package */ - @Nullable - static String filteredUrl(@Nullable String inUrl) { - if (inUrl == null) { - return ""; - } - if (inUrl.startsWith("content:") - || inUrl.startsWith("browser:")) { - return ""; - } - return inUrl; - } - /** * Returns whether the given url is the bookmarks/history page or a normal website */ public static boolean isSpecialUrl(@Nullable String url) { return url != null && url.startsWith(Constants.FILE) && - (url.endsWith(BookmarkPage.FILENAME) || - url.endsWith(HistoryPage.FILENAME) || - url.endsWith(StartPage.FILENAME)); + (url.endsWith(BookmarkPage.FILENAME) || + url.endsWith(HistoryPage.FILENAME) || + url.endsWith(StartPage.FILENAME)); } /** From 72e5b0fa914806b98ffbd7b470b141cd069043b8 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 29 Apr 2017 17:18:43 -0400 Subject: [PATCH 084/181] Inferring nullity --- .../lightning/receiver/NetworkReceiver.java | 2 +- .../search/BaseSuggestionsModel.java | 4 ++-- .../lightning/search/SuggestionsAdapter.java | 19 ++++++++++++------- .../lightning/utils/MemoryLeakUtils.java | 3 ++- .../lightning/utils/Preconditions.java | 4 +++- .../acr/browser/lightning/utils/Utils.java | 2 +- .../lightning/view/BackgroundDrawable.java | 3 ++- .../lightning/view/LightningWebClient.java | 4 ++-- .../browser/lightning/view/SearchView.java | 9 +++++---- 9 files changed, 30 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/receiver/NetworkReceiver.java b/app/src/main/java/acr/browser/lightning/receiver/NetworkReceiver.java index a5a382510..29d3bc6b5 100644 --- a/app/src/main/java/acr/browser/lightning/receiver/NetworkReceiver.java +++ b/app/src/main/java/acr/browser/lightning/receiver/NetworkReceiver.java @@ -12,7 +12,7 @@ public abstract class NetworkReceiver extends BroadcastReceiver { public abstract void onConnectivityChange(boolean isConnected); @Override - public void onReceive(Context context, Intent intent) { + public void onReceive(@NonNull Context context, Intent intent) { onConnectivityChange(isConnected(context)); } diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java index ab36bc2b5..6e279c4df 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java @@ -98,7 +98,7 @@ List getResults(@NonNull String query) { * @return the cache file containing the suggestions */ @Nullable - private InputStream downloadSuggestionsForQuery(@NonNull String query, String language) { + private InputStream downloadSuggestionsForQuery(@NonNull String query, @NonNull String language) { String queryUrl = createQueryUrl(query, language); try { @@ -122,7 +122,7 @@ private InputStream downloadSuggestionsForQuery(@NonNull String query, String la private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override - public Response intercept(Chain chain) throws IOException { + public Response intercept(@NonNull Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder() .header("cache-control", "max-age=" + INTERVAL_DAY + ", max-stale=" + INTERVAL_DAY) diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index d49af228c..cebd9fecd 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -117,6 +117,7 @@ public int getCount() { return mFilteredList.size(); } + @Nullable @Override public Object getItem(int position) { if (position > mFilteredList.size() || position < 0) { @@ -138,14 +139,15 @@ private static class SuggestionHolder { mImage = (ImageView) view.findViewById(R.id.suggestionIcon); } - final ImageView mImage; - final TextView mTitle; - final TextView mUrl; + @NonNull final ImageView mImage; + @NonNull final TextView mTitle; + @NonNull final TextView mUrl; } + @Nullable @Override - public View getView(int position, View convertView, ViewGroup parent) { + public View getView(int position, @Nullable View convertView, ViewGroup parent) { SuggestionHolder holder; if (convertView == null) { @@ -190,12 +192,13 @@ public View getView(int position, View convertView, ViewGroup parent) { return convertView; } + @NonNull @Override public Filter getFilter() { return new SearchFilter(this); } - private synchronized void publishResults(List list) { + private synchronized void publishResults(@NonNull List list) { mFilteredList.clear(); mFilteredList.addAll(list); notifyDataSetChanged(); @@ -315,8 +318,9 @@ private static class SearchFilter extends Filter { mSuggestionsAdapter = suggestionsAdapter; } + @NonNull @Override - protected FilterResults performFiltering(CharSequence constraint) { + protected FilterResults performFiltering(@Nullable CharSequence constraint) { FilterResults results = new FilterResults(); if (constraint == null || constraint.length() == 0) { mSuggestionsAdapter.clearSuggestions(); @@ -359,8 +363,9 @@ public void onItem(@Nullable List item) { return results; } + @NonNull @Override - public CharSequence convertResultToString(Object resultValue) { + public CharSequence convertResultToString(@NonNull Object resultValue) { return ((HistoryItem) resultValue).getUrl(); } diff --git a/app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java b/app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java index 0dac3e3c0..814e1ebde 100644 --- a/app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java @@ -6,6 +6,7 @@ import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodManager; @@ -17,7 +18,7 @@ public class MemoryLeakUtils { private static final String TAG = MemoryLeakUtils.class.getSimpleName(); - private static Method sFinishInputLocked = null; + @Nullable private static Method sFinishInputLocked = null; /** * Clears the mNextServedView and mServedView in diff --git a/app/src/main/java/acr/browser/lightning/utils/Preconditions.java b/app/src/main/java/acr/browser/lightning/utils/Preconditions.java index e9ffd8416..df91d7519 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Preconditions.java +++ b/app/src/main/java/acr/browser/lightning/utils/Preconditions.java @@ -1,5 +1,7 @@ package acr.browser.lightning.utils; +import android.support.annotation.Nullable; + public class Preconditions { /** * Ensure that an object is not null @@ -8,7 +10,7 @@ public class Preconditions { * * @param object check nullness on this object. */ - public static void checkNonNull(Object object) { + public static void checkNonNull(@Nullable Object object) { if (object == null) { throw new RuntimeException("Object must not be null"); } diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index c13a3eb9e..9b838b790 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -72,7 +72,7 @@ public static boolean doesSupportHeaders() { * @param userAgent the user agent of the browser. * @param contentDisposition the content description of the file. */ - public static void downloadFile(final Activity activity, final PreferenceManager manager, final String url, + public static void downloadFile(@NonNull final Activity activity, @NonNull final PreferenceManager manager, final String url, final String userAgent, final String contentDisposition) { PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsResultAction() { diff --git a/app/src/main/java/acr/browser/lightning/view/BackgroundDrawable.java b/app/src/main/java/acr/browser/lightning/view/BackgroundDrawable.java index 94da56bd9..ec1ad8523 100644 --- a/app/src/main/java/acr/browser/lightning/view/BackgroundDrawable.java +++ b/app/src/main/java/acr/browser/lightning/view/BackgroundDrawable.java @@ -4,6 +4,7 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; +import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import acr.browser.lightning.R; @@ -17,7 +18,7 @@ public class BackgroundDrawable extends TransitionDrawable { * Create a new transition drawable with the specified list of layers. At least * 2 layers are required for this drawable to work properly. */ - public BackgroundDrawable(Context context) { + public BackgroundDrawable(@NonNull Context context) { super(new Drawable[]{new ColorDrawable(ContextCompat.getColor(context, R.color.transparent)), new ColorDrawable(ThemeUtils.getColor(context, R.attr.selectedBackground))}); } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index b6ace1c0d..d7d506584 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -282,7 +282,7 @@ public void onClick(DialogInterface dialog, int id) { @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull WebResourceRequest request) { return shouldOverrideLoading(view, request.getUrl().toString()) || super.shouldOverrideUrlLoading(view, request); } @@ -292,7 +292,7 @@ public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull String u return shouldOverrideLoading(view, url) || super.shouldOverrideUrlLoading(view, url); } - private boolean shouldOverrideLoading(WebView view, String url) { + private boolean shouldOverrideLoading(@NonNull WebView view, @NonNull String url) { // Check if configured proxy is available if (!mProxyUtils.isProxyReady(mActivity)) { // User has been notified diff --git a/app/src/main/java/acr/browser/lightning/view/SearchView.java b/app/src/main/java/acr/browser/lightning/view/SearchView.java index 025fa0db9..80b6c9aec 100644 --- a/app/src/main/java/acr/browser/lightning/view/SearchView.java +++ b/app/src/main/java/acr/browser/lightning/view/SearchView.java @@ -1,6 +1,7 @@ package acr.browser.lightning.view; import android.content.Context; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatAutoCompleteTextView; import android.util.AttributeSet; @@ -17,15 +18,15 @@ public interface PreFocusListener { private boolean mIsBeingClicked; private long mTimePressed; - public SearchView(Context context) { + public SearchView(@NonNull Context context) { super(context); } - public SearchView(Context context, AttributeSet attrs) { + public SearchView(@NonNull Context context, AttributeSet attrs) { super(context, attrs); } - public SearchView(Context context, AttributeSet attrs, int defStyleAttr) { + public SearchView(@NonNull Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @@ -34,7 +35,7 @@ public void setOnPreFocusListener(@Nullable PreFocusListener listener) { } @Override - public boolean onTouchEvent(MotionEvent event) { + public boolean onTouchEvent(@NonNull MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mTimePressed = System.currentTimeMillis(); From 4649d4b0b45c2338c523a32826a987e58f6aa93f Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 29 Apr 2017 17:19:55 -0400 Subject: [PATCH 085/181] Inferring nullity --- .../acr/browser/lightning/activity/IncognitoActivity.java | 3 ++- .../java/acr/browser/lightning/activity/MainActivity.java | 1 + .../main/java/acr/browser/lightning/activity/TabsManager.java | 1 + app/src/main/java/acr/browser/lightning/app/BrowserApp.java | 2 +- .../java/acr/browser/lightning/constant/BookmarkPage.java | 2 +- .../acr/browser/lightning/database/BookmarkLocalSync.java | 1 + .../acr/browser/lightning/dialog/LightningDialogBuilder.java | 4 ++-- 7 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java b/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java index a6ab3a8cd..9f085b507 100644 --- a/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java @@ -17,6 +17,7 @@ @SuppressWarnings("deprecation") public class IncognitoActivity extends BrowserActivity { + @NonNull @Override public Completable updateCookiePreference() { return Completable.create(new CompletableAction() { @@ -33,7 +34,7 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) { } @Override - public boolean onCreateOptionsMenu(Menu menu) { + public boolean onCreateOptionsMenu(@NonNull Menu menu) { getMenuInflater().inflate(R.menu.incognito, menu); return super.onCreateOptionsMenu(menu); } diff --git a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java index a4f6c3528..3220d6508 100644 --- a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java @@ -17,6 +17,7 @@ @SuppressWarnings("deprecation") public class MainActivity extends BrowserActivity { + @NonNull @Override public Completable updateCookiePreference() { return Completable.create(new CompletableAction() { diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index f72462afe..1cc56233a 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -111,6 +111,7 @@ private synchronized void finishInitialization() { * @param intent the intent that started the browser activity. * @param incognito whether or not we are in incognito mode. */ + @NonNull public synchronized Completable initializeTabs(@NonNull final Activity activity, @Nullable final Intent intent, final boolean incognito) { diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index 8b66e7562..28f4350e9 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -60,7 +60,7 @@ public void onCreate() { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override - public void uncaughtException(Thread thread, Throwable ex) { + public void uncaughtException(Thread thread, @NonNull Throwable ex) { if (BuildConfig.DEBUG) { FileUtils.writeCrashToStorage(ex); diff --git a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java index b44d561ca..bdf878d3f 100644 --- a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java @@ -73,7 +73,7 @@ public final class BookmarkPage { @Inject Application mApp; @Inject BookmarkManager mManager; - private final Bitmap mFolderIcon; + @NonNull private final Bitmap mFolderIcon; @NonNull private final String mTitle; public BookmarkPage(@NonNull Activity activity) { diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java index f2be1709f..7511b6108 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java @@ -43,6 +43,7 @@ public BookmarkLocalSync(@NonNull Context context) { mContext = context; } + @NonNull private List getBookmarksFromContentUri(String contentUri) { List list = new ArrayList<>(); Cursor cursor = getBrowserCursor(contentUri); diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index bbad8e9d0..6d4edcebd 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -181,7 +181,7 @@ private void showRenameFolderDialog(@NonNull final Activity activity, @NonNull f R.string.hint_title, item.getTitle(), R.string.action_ok, new BrowserDialog.EditorListener() { @Override - public void onClick(String text) { + public void onClick(@NonNull String text) { if (!TextUtils.isEmpty(text)) { final String oldTitle = item.getTitle(); final HistoryItem editedItem = new HistoryItem(); @@ -274,7 +274,7 @@ public void onClick() { }); } - public void showLongPressLinkDialog(@NonNull final Activity activity, final String url) { + public void showLongPressLinkDialog(@NonNull final Activity activity, @NonNull final String url) { BrowserDialog.show(activity, url, new BrowserDialog.Item(R.string.dialog_open_new_tab) { @Override From 923e71d51f6b2f1824fcccdb4c0a1edceb486eaf Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 29 Apr 2017 17:22:49 -0400 Subject: [PATCH 086/181] Ensure that published items aren't null --- .../java/acr/browser/lightning/search/SuggestionsAdapter.java | 2 ++ .../main/java/acr/browser/lightning/utils/DrawableUtils.java | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index cebd9fecd..a29f83ecf 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -42,6 +42,7 @@ import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.database.HistoryModel; import acr.browser.lightning.preference.PreferenceManager; +import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.ThemeUtils; public class SuggestionsAdapter extends BaseAdapter implements Filterable { @@ -264,6 +265,7 @@ public void onSubscribe(@NonNull SingleSubscriber> subscriber) .subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable List item) { + Preconditions.checkNonNull(item); publishResults(item); } }); diff --git a/app/src/main/java/acr/browser/lightning/utils/DrawableUtils.java b/app/src/main/java/acr/browser/lightning/utils/DrawableUtils.java index 3bc3c12bc..19e426cf4 100644 --- a/app/src/main/java/acr/browser/lightning/utils/DrawableUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/DrawableUtils.java @@ -1,7 +1,5 @@ package acr.browser.lightning.utils; -import android.content.Context; -import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; @@ -11,10 +9,8 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.AttrRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.util.TypedValue; import android.view.View; public class DrawableUtils { From 0fcf7451cb2c9a68ada8569ea5b6e2875c178023 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 30 Apr 2017 21:00:45 -0400 Subject: [PATCH 087/181] Removing event buss --- app/build.gradle | 3 - .../lightning/activity/BrowserActivity.java | 115 ++--- .../lightning/activity/TabsManager.java | 6 +- .../acr/browser/lightning/app/AppModule.java | 10 - .../acr/browser/lightning/app/BrowserApp.java | 2 - .../lightning/browser/BookmarksView.java | 4 + .../lightning/browser/BrowserPresenter.java | 2 - .../browser/lightning/bus/BookmarkEvents.java | 30 -- .../browser/lightning/bus/BrowserEvents.java | 37 -- .../lightning/controller/UIController.java | 9 + .../dialog/LightningDialogBuilder.java | 393 +++++++++--------- .../lightning/fragment/BookmarksFragment.java | 20 +- .../lightning/fragment/TabsFragment.java | 15 - .../browser/lightning/utils/ProxyUtils.java | 3 - .../browser/lightning/view/LightningView.java | 20 +- 15 files changed, 277 insertions(+), 392 deletions(-) delete mode 100644 app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java delete mode 100644 app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java diff --git a/app/build.gradle b/app/build.gradle index 41f9972f7..41e36b725 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -75,9 +75,6 @@ dependencies { // html parsing for reading mode compile 'org.jsoup:jsoup:1.10.2' - // event bus - compile 'com.squareup:otto:1.3.8' - // dependency injection def daggerVersion = '2.10' compile "com.google.dagger:dagger:$daggerVersion" diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index d55dfa23f..d50ec6bc9 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -84,8 +84,6 @@ import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.grant.PermissionsManager; import com.anthonycr.progress.AnimatedProgressBar; -import com.squareup.otto.Bus; -import com.squareup.otto.Subscribe; import java.io.File; import java.io.IOException; @@ -98,8 +96,6 @@ import acr.browser.lightning.browser.BrowserPresenter; import acr.browser.lightning.browser.BrowserView; import acr.browser.lightning.browser.TabsView; -import acr.browser.lightning.bus.BookmarkEvents; -import acr.browser.lightning.bus.BrowserEvents; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.HistoryPage; @@ -189,9 +185,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements // The singleton BookmarkManager @Inject BookmarkManager mBookmarkManager; - // Event bus - @Inject Bus mEventBus; - @Inject LightningDialogBuilder mBookmarksDialogBuilder; private TabsManager mTabsManager; @@ -1119,6 +1112,11 @@ public void run() { }, 150); } + @Override + public void handleHistoryChange() { + openHistory(); + } + /** * displays the WebView contained in the LightningView Also handles the * removal of previous views @@ -1288,8 +1286,6 @@ protected void onPause() { if (isIncognito() && isFinishing()) { overridePendingTransition(R.anim.fade_in_scale, R.anim.slide_down_out); } - - mEventBus.unregister(mBusEventListener); } void saveOpenTabs() { @@ -1348,8 +1344,6 @@ protected void onResume() { filter.addAction(NETWORK_BROADCAST_ACTION); getApplication().registerReceiver(mNetworkReceiver, filter); - mEventBus.register(mBusEventListener); - if (mFullScreen) { overlayToolbarOnWebView(); } else { @@ -2080,6 +2074,43 @@ protected void applyTransformation(float interpolatedTime, Transformation t) { } } + @Override + public void handleBookmarksChange() { + final LightningView currentTab = mTabsManager.getCurrentTab(); + if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) + && currentTab.getUrl().endsWith(BookmarkPage.FILENAME)) { + currentTab.loadBookmarkpage(); + } + if (currentTab != null) { + mBookmarksView.handleUpdatedUrl(currentTab.getUrl()); + } + } + + @Override + public void handleBookmarkDeleted(@NonNull HistoryItem item) { + mBookmarksView.handleBookmarkDeleted(item); + handleBookmarksChange(); + } + + @Override + public void handleNewTab(@NonNull LightningDialogBuilder.NewTab newTabType, @NonNull String url) { + mDrawerLayout.closeDrawers(); + switch (newTabType) { + case FOREGROUND: + newTab(url, true); + break; + case BACKGROUND: + newTab(url, false); + break; + case INCOGNITO: + Intent intent = new Intent(BrowserActivity.this, IncognitoActivity.class); + intent.setData(Uri.parse(url)); + startActivity(intent); + overridePendingTransition(R.anim.slide_up_in, R.anim.fade_out_scale); + break; + } + } + /** * Performs an action when the provided view is laid out. * @@ -2220,66 +2251,4 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis super.onRequestPermissionsResult(requestCode, permissions, grantResults); } - private final Object mBusEventListener = new Object() { - - @Subscribe - public void loadHistory(final BrowserEvents.OpenHistoryInCurrentTab event) { - openHistory(); - } - - /** - * Load the given url in a new tab, used by the the - * {@link acr.browser.lightning.fragment.BookmarksFragment} and by the - * {@link LightningDialogBuilder} - * - * @param event Bus event indicating that the user wishes - * to open a bookmark in a new tab - */ - @Subscribe - public void loadUrlInNewTab(final BrowserEvents.OpenUrlInNewTab event) { - mDrawerLayout.closeDrawers(); - if (event.location == BrowserEvents.OpenUrlInNewTab.Location.NEW_TAB) { - newTab(event.url, true); - } else if (event.location == BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND) { - newTab(event.url, false); - } else if (event.location == BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO) { - Intent intent = new Intent(BrowserActivity.this, IncognitoActivity.class); - intent.setData(Uri.parse(event.url)); - startActivity(intent); - overridePendingTransition(R.anim.slide_up_in, R.anim.fade_out_scale); - } - } - - /** - * This method is called when the user edits a bookmark. - * - * @param event the event that the bookmark has changed. - */ - @Subscribe - public void bookmarkChanged(final BookmarkEvents.BookmarkChanged event) { - handleBookmarksChange(); - } - - /** - * Notify the browser that a bookmark was deleted. - * - * @param event the event that the bookmark has been deleted - */ - @Subscribe - public void bookmarkDeleted(final BookmarkEvents.Deleted event) { - handleBookmarksChange(); - } - - private void handleBookmarksChange() { - final LightningView currentTab = mTabsManager.getCurrentTab(); - if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) - && currentTab.getUrl().endsWith(BookmarkPage.FILENAME)) { - currentTab.loadBookmarkpage(); - } - if (currentTab != null) { - mBookmarksView.handleUpdatedUrl(currentTab.getUrl()); - } - } - - }; } diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 1cc56233a..98098d6c5 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -17,12 +17,12 @@ import com.anthonycr.bonsai.Completable; import com.anthonycr.bonsai.CompletableAction; import com.anthonycr.bonsai.CompletableSubscriber; +import com.anthonycr.bonsai.Schedulers; import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.bonsai.Stream; import com.anthonycr.bonsai.StreamAction; import com.anthonycr.bonsai.StreamOnSubscribe; import com.anthonycr.bonsai.StreamSubscriber; -import com.squareup.otto.Bus; import java.util.ArrayList; import java.util.List; @@ -38,9 +38,6 @@ import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.preference.PreferenceManager; - -import com.anthonycr.bonsai.Schedulers; - import acr.browser.lightning.utils.FileUtils; import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.UrlUtils; @@ -67,7 +64,6 @@ public class TabsManager { @Inject PreferenceManager mPreferenceManager; @Inject BookmarkManager mBookmarkManager; - @Inject Bus mEventBus; @Inject Application mApp; public TabsManager() { diff --git a/app/src/main/java/acr/browser/lightning/app/AppModule.java b/app/src/main/java/acr/browser/lightning/app/AppModule.java index 9a4811eef..605baf277 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppModule.java +++ b/app/src/main/java/acr/browser/lightning/app/AppModule.java @@ -4,8 +4,6 @@ import android.content.Context; import android.support.annotation.NonNull; -import com.squareup.otto.Bus; - import net.i2p.android.ui.I2PAndroidHelper; import javax.inject.Singleton; @@ -16,11 +14,9 @@ @Module public class AppModule { private final BrowserApp mApp; - @NonNull private final Bus mBus; public AppModule(BrowserApp app) { this.mApp = app; - this.mBus = new Bus(); } @Provides @@ -33,12 +29,6 @@ public Context provideContext() { return mApp.getApplicationContext(); } - @NonNull - @Provides - public Bus provideBus() { - return mBus; - } - @NonNull @Provides @Singleton diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index 28f4350e9..b87a12a7b 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -13,7 +13,6 @@ import android.webkit.WebView; import com.squareup.leakcanary.LeakCanary; -import com.squareup.otto.Bus; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -34,7 +33,6 @@ public class BrowserApp extends Application { private static final Executor mIOThread = Executors.newSingleThreadExecutor(); private static final Executor mTaskThread = Executors.newCachedThreadPool(); - @Inject Bus mBus; @Inject PreferenceManager mPreferenceManager; @Override diff --git a/app/src/main/java/acr/browser/lightning/browser/BookmarksView.java b/app/src/main/java/acr/browser/lightning/browser/BookmarksView.java index de578ca57..c09b4c789 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BookmarksView.java +++ b/app/src/main/java/acr/browser/lightning/browser/BookmarksView.java @@ -2,10 +2,14 @@ import android.support.annotation.NonNull; +import acr.browser.lightning.database.HistoryItem; + public interface BookmarksView { void navigateBack(); void handleUpdatedUrl(@NonNull String url); + void handleBookmarkDeleted(@NonNull HistoryItem item); + } diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java index e6a2c9350..0163d6162 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java @@ -9,7 +9,6 @@ import com.anthonycr.bonsai.CompletableOnSubscribe; import com.anthonycr.bonsai.Schedulers; -import com.squareup.otto.Bus; import javax.inject.Inject; @@ -34,7 +33,6 @@ public class BrowserPresenter { @NonNull private final TabsManager mTabsModel; @Inject PreferenceManager mPreferences; - @Inject Bus mEventBus; @NonNull private final BrowserView mView; @Nullable private LightningView mCurrentTab; diff --git a/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java b/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java deleted file mode 100644 index 6b1900429..000000000 --- a/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java +++ /dev/null @@ -1,30 +0,0 @@ -package acr.browser.lightning.bus; - -import acr.browser.lightning.database.HistoryItem; - -public final class BookmarkEvents { - - private BookmarkEvents() { - // No instances - } - - /** - * The user ask to delete the selected bookmark - */ - public static class Deleted { - public final HistoryItem item; - - public Deleted(final HistoryItem item) { - this.item = item; - } - } - - /** - * Sended when a bookmark is edited - */ - public static class BookmarkChanged { - - public BookmarkChanged() { - } - } -} diff --git a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java deleted file mode 100644 index e0a281f58..000000000 --- a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java +++ /dev/null @@ -1,37 +0,0 @@ -package acr.browser.lightning.bus; - -public final class BrowserEvents { - - private BrowserEvents() { - // No instances - } - - public final static class OpenHistoryInCurrentTab { - } - - /** - * The user ask to open the given url as new tab - */ - public final static class OpenUrlInNewTab { - - public enum Location { - NEW_TAB, - BACKGROUND, - INCOGNITO - } - - public final String url; - - public final Location location; - - public OpenUrlInNewTab(final String url) { - this.url = url; - this.location = Location.NEW_TAB; - } - - public OpenUrlInNewTab(final String url, Location location) { - this.url = url; - this.location = location; - } - } -} diff --git a/app/src/main/java/acr/browser/lightning/controller/UIController.java b/app/src/main/java/acr/browser/lightning/controller/UIController.java index 7f2bb2bb3..a39a1bd23 100644 --- a/app/src/main/java/acr/browser/lightning/controller/UIController.java +++ b/app/src/main/java/acr/browser/lightning/controller/UIController.java @@ -16,6 +16,7 @@ import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.view.LightningView; public interface UIController { @@ -83,4 +84,12 @@ public interface UIController { void onHomeButtonPressed(); + void handleBookmarksChange(); + + void handleBookmarkDeleted(@NonNull HistoryItem item); + + void handleNewTab(@NonNull LightningDialogBuilder.NewTab newTabType, @NonNull String url); + + void handleHistoryChange(); + } diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 6d4edcebd..b07cb8831 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -14,7 +14,6 @@ import com.anthonycr.bonsai.CompletableOnSubscribe; import com.anthonycr.bonsai.Schedulers; -import com.squareup.otto.Bus; import java.util.List; @@ -23,10 +22,9 @@ import acr.browser.lightning.R; import acr.browser.lightning.activity.MainActivity; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.bus.BookmarkEvents; -import acr.browser.lightning.bus.BrowserEvents; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; +import acr.browser.lightning.controller.UIController; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.database.HistoryModel; @@ -40,9 +38,14 @@ */ public class LightningDialogBuilder { + public enum NewTab { + FOREGROUND, + BACKGROUND, + INCOGNITO + } + @Inject BookmarkManager mBookmarkManager; @Inject PreferenceManager mPreferenceManager; - @Inject Bus mEventBus; @Inject public LightningDialogBuilder() { @@ -53,10 +56,12 @@ public LightningDialogBuilder() { * Show the appropriated dialog for the long pressed link. It means that we try to understand * if the link is relative to a bookmark or is just a folder. * - * @param context used to show the dialog - * @param url the long pressed url + * @param activity used to show the dialog + * @param url the long pressed url */ - public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity context, @NonNull final String url) { + public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity activity, + @NonNull UIController uiController, + @NonNull final String url) { final HistoryItem item; if (url.startsWith(Constants.FILE) && url.endsWith(BookmarkPage.FILENAME)) { // TODO hacky, make a better bookmark mechanism in the future @@ -73,56 +78,60 @@ public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity context, } if (item != null) { if (item.isFolder()) { - showBookmarkFolderLongPressedDialog(context, item); + showBookmarkFolderLongPressedDialog(activity, uiController, item); } else { - showLongPressedDialogForBookmarkUrl(context, item); + showLongPressedDialogForBookmarkUrl(activity, uiController, item); } } } - public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity activity, @NonNull final HistoryItem item) { + public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity activity, + @NonNull final UIController uiController, + @NonNull final HistoryItem item) { BrowserDialog.show(activity, R.string.action_bookmarks, - new BrowserDialog.Item(R.string.dialog_open_new_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl(), BrowserEvents.OpenUrlInNewTab.Location.NEW_TAB)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_background_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl(), BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl(), BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); - } - }, - new BrowserDialog.Item(R.string.dialog_copy_link) { - @Override - public void onClick() { - BrowserApp.copyToClipboard(activity, item.getUrl()); - } - }, - new BrowserDialog.Item(R.string.dialog_remove_bookmark) { - @Override - public void onClick() { - if (mBookmarkManager.deleteBookmark(item)) { - mEventBus.post(new BookmarkEvents.Deleted(item)); - } + new BrowserDialog.Item(R.string.dialog_open_new_tab) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.FOREGROUND, item.getUrl()); + } + }, + new BrowserDialog.Item(R.string.dialog_open_background_tab) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.BACKGROUND, item.getUrl()); + } + }, + new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.INCOGNITO, item.getUrl()); + } + }, + new BrowserDialog.Item(R.string.dialog_copy_link) { + @Override + public void onClick() { + BrowserApp.copyToClipboard(activity, item.getUrl()); + } + }, + new BrowserDialog.Item(R.string.dialog_remove_bookmark) { + @Override + public void onClick() { + if (mBookmarkManager.deleteBookmark(item)) { + uiController.handleBookmarkDeleted(item); } - }, - new BrowserDialog.Item(R.string.dialog_edit_bookmark) { - @Override - public void onClick() { - showEditBookmarkDialog(activity, item); - } - }); + } + }, + new BrowserDialog.Item(R.string.dialog_edit_bookmark) { + @Override + public void onClick() { + showEditBookmarkDialog(activity, uiController, item); + } + }); } - private void showEditBookmarkDialog(@NonNull final Activity activity, @NonNull final HistoryItem item) { + private void showEditBookmarkDialog(@NonNull final Activity activity, + @NonNull final UIController uiController, + @NonNull final HistoryItem item) { final AlertDialog.Builder editBookmarkDialog = new AlertDialog.Builder(activity); editBookmarkDialog.setTitle(R.string.title_edit_bookmark); final View dialogLayout = View.inflate(activity, R.layout.dialog_edit_bookmark, null); @@ -131,175 +140,185 @@ private void showEditBookmarkDialog(@NonNull final Activity activity, @NonNull f final EditText getUrl = (EditText) dialogLayout.findViewById(R.id.bookmark_url); getUrl.setText(item.getUrl()); final AutoCompleteTextView getFolder = - (AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder); + (AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder); getFolder.setHint(R.string.folder); getFolder.setText(item.getFolder()); final List folders = mBookmarkManager.getFolderTitles(); final ArrayAdapter suggestionsAdapter = new ArrayAdapter<>(activity, - android.R.layout.simple_dropdown_item_1line, folders); + android.R.layout.simple_dropdown_item_1line, folders); getFolder.setThreshold(1); getFolder.setAdapter(suggestionsAdapter); editBookmarkDialog.setView(dialogLayout); editBookmarkDialog.setPositiveButton(activity.getString(R.string.action_ok), - new DialogInterface.OnClickListener() { + new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - HistoryItem editedItem = new HistoryItem(); - editedItem.setTitle(getTitle.getText().toString()); - editedItem.setUrl(getUrl.getText().toString()); - editedItem.setUrl(getUrl.getText().toString()); - editedItem.setFolder(getFolder.getText().toString()); - mBookmarkManager.editBookmark(item, editedItem); - mEventBus.post(new BookmarkEvents.BookmarkChanged()); - } - }); + @Override + public void onClick(DialogInterface dialog, int which) { + HistoryItem editedItem = new HistoryItem(); + editedItem.setTitle(getTitle.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setFolder(getFolder.getText().toString()); + mBookmarkManager.editBookmark(item, editedItem); + uiController.handleBookmarksChange(); + } + }); Dialog dialog = editBookmarkDialog.show(); BrowserDialog.setDialogSize(activity, dialog); } - public void showBookmarkFolderLongPressedDialog(@NonNull final Activity activity, @NonNull final HistoryItem item) { + public void showBookmarkFolderLongPressedDialog(@NonNull final Activity activity, + @NonNull final UIController uiController, + @NonNull final HistoryItem item) { BrowserDialog.show(activity, R.string.action_folder, - new BrowserDialog.Item(R.string.dialog_rename_folder) { - @Override - public void onClick() { - showRenameFolderDialog(activity, item); - } - }, - new BrowserDialog.Item(R.string.dialog_remove_folder) { - @Override - public void onClick() { - mBookmarkManager.deleteFolder(item.getTitle()); - mEventBus.post(new BookmarkEvents.Deleted(item)); - } - }); + new BrowserDialog.Item(R.string.dialog_rename_folder) { + @Override + public void onClick() { + showRenameFolderDialog(activity, uiController, item); + } + }, + new BrowserDialog.Item(R.string.dialog_remove_folder) { + @Override + public void onClick() { + mBookmarkManager.deleteFolder(item.getTitle()); + uiController.handleBookmarkDeleted(item); + } + }); } - private void showRenameFolderDialog(@NonNull final Activity activity, @NonNull final HistoryItem item) { + private void showRenameFolderDialog(@NonNull final Activity activity, + @NonNull final UIController uiController, + @NonNull final HistoryItem item) { BrowserDialog.showEditText(activity, R.string.title_rename_folder, - R.string.hint_title, item.getTitle(), - R.string.action_ok, new BrowserDialog.EditorListener() { - @Override - public void onClick(@NonNull String text) { - if (!TextUtils.isEmpty(text)) { - final String oldTitle = item.getTitle(); - final HistoryItem editedItem = new HistoryItem(); - editedItem.setTitle(text); - editedItem.setUrl(Constants.FOLDER + text); - editedItem.setFolder(item.getFolder()); - editedItem.setIsFolder(true); - mBookmarkManager.renameFolder(oldTitle, text); - mEventBus.post(new BookmarkEvents.BookmarkChanged()); - } + R.string.hint_title, item.getTitle(), + R.string.action_ok, new BrowserDialog.EditorListener() { + @Override + public void onClick(@NonNull String text) { + if (!TextUtils.isEmpty(text)) { + final String oldTitle = item.getTitle(); + final HistoryItem editedItem = new HistoryItem(); + editedItem.setTitle(text); + editedItem.setUrl(Constants.FOLDER + text); + editedItem.setFolder(item.getFolder()); + editedItem.setIsFolder(true); + mBookmarkManager.renameFolder(oldTitle, text); + uiController.handleBookmarksChange(); } - }); + } + }); } - public void showLongPressedHistoryLinkDialog(@NonNull final Activity activity, @NonNull final String url) { + public void showLongPressedHistoryLinkDialog(@NonNull final Activity activity, + @NonNull final UIController uiController, + @NonNull final String url) { BrowserDialog.show(activity, R.string.action_history, - new BrowserDialog.Item(R.string.dialog_open_new_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_background_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); - } - }, - new BrowserDialog.Item(R.string.dialog_copy_link) { - @Override - public void onClick() { - BrowserApp.copyToClipboard(activity, url); - } - }, - new BrowserDialog.Item(R.string.dialog_remove_from_history) { - @Override - public void onClick() { - HistoryModel.deleteHistoryItem(url) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new CompletableOnSubscribe() { - @Override - public void onComplete() { - mEventBus.post(new BrowserEvents.OpenHistoryInCurrentTab()); - } - }); - } - }); + new BrowserDialog.Item(R.string.dialog_open_new_tab) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.FOREGROUND, url); + } + }, + new BrowserDialog.Item(R.string.dialog_open_background_tab) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.BACKGROUND, url); + } + }, + new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.INCOGNITO, url); + } + }, + new BrowserDialog.Item(R.string.dialog_copy_link) { + @Override + public void onClick() { + BrowserApp.copyToClipboard(activity, url); + } + }, + new BrowserDialog.Item(R.string.dialog_remove_from_history) { + @Override + public void onClick() { + HistoryModel.deleteHistoryItem(url) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + uiController.handleHistoryChange(); + } + }); + } + }); } // TODO There should be a way in which we do not need an activity reference to dowload a file - public void showLongPressImageDialog(@NonNull final Activity activity, @NonNull final String url, + public void showLongPressImageDialog(@NonNull final Activity activity, + @NonNull final UIController uiController, + @NonNull final String url, @NonNull final String userAgent) { BrowserDialog.show(activity, url.replace(Constants.HTTP, ""), - new BrowserDialog.Item(R.string.dialog_open_new_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_background_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); - } - }, - new BrowserDialog.Item(R.string.dialog_copy_link) { - @Override - public void onClick() { - BrowserApp.copyToClipboard(activity, url); - } - }, - new BrowserDialog.Item(R.string.dialog_download_image) { - @Override - public void onClick() { - Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment"); - } - }); + new BrowserDialog.Item(R.string.dialog_open_new_tab) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.FOREGROUND, url); + } + }, + new BrowserDialog.Item(R.string.dialog_open_background_tab) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.BACKGROUND, url); + } + }, + new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.INCOGNITO, url); + } + }, + new BrowserDialog.Item(R.string.dialog_copy_link) { + @Override + public void onClick() { + BrowserApp.copyToClipboard(activity, url); + } + }, + new BrowserDialog.Item(R.string.dialog_download_image) { + @Override + public void onClick() { + Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment"); + } + }); } - public void showLongPressLinkDialog(@NonNull final Activity activity, @NonNull final String url) { + public void showLongPressLinkDialog(@NonNull final Activity activity, + @NonNull final UIController uiController, + @NonNull final String url) { BrowserDialog.show(activity, url, - new BrowserDialog.Item(R.string.dialog_open_new_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_background_tab) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.BACKGROUND)); - } - }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { - @Override - public void onClick() { - mEventBus.post(new BrowserEvents.OpenUrlInNewTab(url, BrowserEvents.OpenUrlInNewTab.Location.INCOGNITO)); - } - }, - new BrowserDialog.Item(R.string.dialog_copy_link) { - @Override - public void onClick() { - BrowserApp.copyToClipboard(activity, url); - } - }); + new BrowserDialog.Item(R.string.dialog_open_new_tab) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.FOREGROUND, url); + } + }, + new BrowserDialog.Item(R.string.dialog_open_background_tab) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.BACKGROUND, url); + } + }, + new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { + @Override + public void onClick() { + uiController.handleNewTab(NewTab.INCOGNITO, url); + } + }, + new BrowserDialog.Item(R.string.dialog_copy_link) { + @Override + public void onClick() { + BrowserApp.copyToClipboard(activity, url); + } + }); } } diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index fbb75f4cb..92f5db253 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -33,8 +33,6 @@ import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.bonsai.SingleSubscriber; import com.anthonycr.bonsai.Subscription; -import com.squareup.otto.Bus; -import com.squareup.otto.Subscribe; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -47,7 +45,6 @@ import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.browser.BookmarksView; -import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.controller.UIController; import acr.browser.lightning.database.BookmarkManager; @@ -80,9 +77,6 @@ public static BookmarksFragment createFragment(boolean isIncognito) { // Managers @Inject BookmarkManager mBookmarkManager; - // Event bus - @Inject Bus mEventBus; - // Dialog builder @Inject LightningDialogBuilder mBookmarksDialogBuilder; @@ -248,13 +242,11 @@ public void onDestroy() { @Override public void onStart() { super.onStart(); - mEventBus.register(this); } @Override public void onStop() { super.onStop(); - mEventBus.unregister(this); } public void reinitializePreferences() { @@ -279,10 +271,10 @@ private void updateBookmarkIndicator(final String url) { } } - @Subscribe - public void bookmarkDeleted(@NonNull final BookmarkEvents.Deleted event) { - mBookmarks.remove(event.item); - if (event.item.isFolder()) { + @Override + public void handleBookmarkDeleted(@NonNull HistoryItem item) { + mBookmarks.remove(item); + if (item.isFolder()) { setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); } else { mBookmarkAdapter.notifyDataSetChanged(); @@ -349,9 +341,9 @@ private void setupNavigationButton(@NonNull View view, @IdRes int buttonId, @IdR private void handleLongPress(@NonNull final HistoryItem item) { if (item.isFolder()) { - mBookmarksDialogBuilder.showBookmarkFolderLongPressedDialog(getActivity(), item); + mBookmarksDialogBuilder.showBookmarkFolderLongPressedDialog(getActivity(), mUiController, item); } else { - mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(getActivity(), item); + mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(getActivity(), mUiController, item); } } diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index 2617eb980..9723e7ae6 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -31,8 +31,6 @@ import android.widget.LinearLayout; import android.widget.TextView; -import com.squareup.otto.Bus; - import javax.inject.Inject; import acr.browser.lightning.R; @@ -93,7 +91,6 @@ public static TabsFragment createTabsFragment(boolean isIncognito, boolean showT private Unbinder mUnbinder; private TabsManager mTabsManager; - @Inject Bus mBus; @Inject PreferenceManager mPreferences; public TabsFragment() { @@ -192,12 +189,6 @@ private void setupFrameLayoutButton(@NonNull final View root, @IdRes final int b buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); } - @Override - public void onStart() { - super.onStart(); - mBus.register(this); - } - @Override public void onResume() { super.onResume(); @@ -207,12 +198,6 @@ public void onResume() { } } - @Override - public void onStop() { - super.onStop(); - mBus.unregister(this); - } - @Override public void tabsInitialized() { if (mTabsAdapter != null) { diff --git a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java index 149cd489d..9c7e8daf0 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ProxyUtils.java @@ -7,8 +7,6 @@ import android.support.v7.app.AlertDialog; import android.util.Log; -import com.squareup.otto.Bus; - import net.i2p.android.ui.I2PAndroidHelper; import javax.inject.Inject; @@ -33,7 +31,6 @@ public class ProxyUtils { @Inject PreferenceManager mPreferences; @Inject I2PAndroidHelper mI2PHelper; - @Inject Bus mBus; @Inject public ProxyUtils() { diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 3508f7917..d1205cb7f 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -36,7 +36,6 @@ import com.anthonycr.bonsai.SingleAction; import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.bonsai.SingleSubscriber; -import com.squareup.otto.Bus; import java.io.File; import java.lang.ref.WeakReference; @@ -108,7 +107,6 @@ public class LightningView { @NonNull private final WebViewHandler mWebViewHandler = new WebViewHandler(this); @NonNull private final Map mRequestHeaders = new ArrayMap<>(); - @Inject Bus mEventBus; @Inject PreferenceManager mPreferences; @Inject LightningDialogBuilder mBookmarksDialogBuilder; @Inject ProxyUtils mProxyUtils; @@ -974,36 +972,36 @@ private void longClickPage(@Nullable final String url) { if (currentUrl != null && UrlUtils.isSpecialUrl(currentUrl)) { if (currentUrl.endsWith(HistoryPage.FILENAME)) { if (url != null) { - mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, url); + mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity,mUIController, url); } else if (result != null && result.getExtra() != null) { final String newUrl = result.getExtra(); - mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, newUrl); + mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, mUIController, newUrl); } } else if (currentUrl.endsWith(BookmarkPage.FILENAME)) { if (url != null) { - mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, url); + mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, mUIController, url); } else if (result != null && result.getExtra() != null) { final String newUrl = result.getExtra(); - mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, newUrl); + mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, mUIController, newUrl); } } } else { if (url != null) { if (result != null) { if (result.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE || result.getType() == WebView.HitTestResult.IMAGE_TYPE) { - mBookmarksDialogBuilder.showLongPressImageDialog(mActivity, url, getUserAgent()); + mBookmarksDialogBuilder.showLongPressImageDialog(mActivity, mUIController, url, getUserAgent()); } else { - mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url); + mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, mUIController, url); } } else { - mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url); + mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, mUIController, url); } } else if (result != null && result.getExtra() != null) { final String newUrl = result.getExtra(); if (result.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE || result.getType() == WebView.HitTestResult.IMAGE_TYPE) { - mBookmarksDialogBuilder.showLongPressImageDialog(mActivity, newUrl, getUserAgent()); + mBookmarksDialogBuilder.showLongPressImageDialog(mActivity, mUIController, newUrl, getUserAgent()); } else { - mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl); + mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, mUIController, newUrl); } } } From e8b8ddaa0222f20e166607cfa604debb4355c42d Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 30 Apr 2017 21:12:49 -0400 Subject: [PATCH 088/181] Removing unnecessary long click listener --- .../lightning/activity/BrowserActivity.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index d50ec6bc9..2f5283b01 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -123,7 +123,7 @@ import butterknife.BindView; import butterknife.ButterKnife; -public abstract class BrowserActivity extends ThemableBrowserActivity implements BrowserView, UIController, OnClickListener, OnLongClickListener { +public abstract class BrowserActivity extends ThemableBrowserActivity implements BrowserView, UIController, OnClickListener { private static final String TAG = BrowserActivity.class.getSimpleName(); @@ -2207,21 +2207,6 @@ public void onClick(View v) { } } - /** - * Handle long presses on views that use this class - * as their OnLongClickListener. This method should - * distinguish between the IDs of the views that are - * getting clicked. - * - * @param view the view that has been long pressed - * @return returns true since the method handles the long press - * event - */ - @Override - public boolean onLongClick(View view) { - return true; - } - /** * This NetworkReceiver notifies each of the WebViews in the browser whether * the network is currently connected or not. This is important because some From ee078c1495320b425b79dee075b7844007eea731 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 2 May 2017 22:04:31 -0400 Subject: [PATCH 089/181] Fix bug with background tabs opening urls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a background tab opened a URL that triggered the intent chooser, and the user chose to open the URL in the browser, the current tab would open the URL instead of the originating URL. Using the tab’s hashcode, the original tab now will open the URL. --- .../lightning/activity/TabsManager.java | 20 +++ .../lightning/browser/BrowserPresenter.java | 31 ++--- .../browser/lightning/utils/IntentUtils.java | 6 +- .../browser/lightning/view/LightningView.java | 118 +++++++++--------- 4 files changed, 100 insertions(+), 75 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 98098d6c5..ee189a39b 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -556,6 +556,26 @@ public synchronized LightningView getCurrentTab() { return mCurrentTab; } + /** + * Returns the {@link LightningView} with + * the provided hash, or null if there is + * no tab with the hash. + * + * @param hashCode the hashcode. + * @return the tab with an identical hash, or null. + */ + @Nullable + public synchronized LightningView getTabForHashCode(int hashCode) { + for (LightningView tab : mTabList) { + if (tab.getWebView() != null) { + if (tab.getWebView().hashCode() == hashCode) { + return tab; + } + } + } + return null; + } + /** * Switch the current tab to the one at the given position. * It returns the selected tab that has been switced to. diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java index 0163d6162..3d616939a 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java @@ -61,16 +61,16 @@ public void tabNumberChanged(int newNumber) { */ public void setupTabs(@Nullable Intent intent) { mTabsModel.initializeTabs((Activity) mView, intent, mIsIncognito) - .subscribeOn(Schedulers.main()) - .subscribe(new CompletableOnSubscribe() { - @Override - public void onComplete() { - // At this point we always have at least a tab in the tab manager - mView.notifyTabViewInitialized(); - mView.updateTabNumber(mTabsModel.size()); - tabChanged(mTabsModel.last()); - } - }); + .subscribeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + // At this point we always have at least a tab in the tab manager + mView.notifyTabViewInitialized(); + mView.updateTabNumber(mTabsModel.size()); + tabChanged(mTabsModel.last()); + } + }); } /** @@ -220,13 +220,16 @@ public void run() { } else { url = null; } - int num = 0; + int tabHashCode = 0; if (intent != null && intent.getExtras() != null) { - num = intent.getExtras().getInt(Constants.INTENT_ORIGIN); + tabHashCode = intent.getExtras().getInt(Constants.INTENT_ORIGIN); } - if (num == 1) { - loadUrlInCurrentView(url); + if (tabHashCode != 0) { + LightningView tab = mTabsModel.getTabForHashCode(tabHashCode); + if (tab != null) { + tab.loadUrl(url); + } } else if (url != null) { if (url.startsWith(Constants.FILE)) { mView.showBlockedLocalFileDialog(new DialogInterface.OnClickListener() { diff --git a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java index 11cb21a6f..d7727a8fd 100644 --- a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java @@ -31,7 +31,7 @@ public class IntentUtils { "(?:http|https|file)://" + "|(?:inline|data|about|javascript):" + "|(?:.*:.*@)" + ')' + "(.*)"); - public IntentUtils(Activity activity) { + public IntentUtils(@NonNull Activity activity) { mActivity = activity; } @@ -63,7 +63,7 @@ public boolean startActivityForUrl(@Nullable WebView tab, @NonNull String url) { } } if (tab != null) { - intent.putExtra(Constants.INTENT_ORIGIN, 1); + intent.putExtra(Constants.INTENT_ORIGIN, tab.hashCode()); } Matcher m = ACCEPTED_URI_SCHEMA.matcher(url); @@ -84,7 +84,7 @@ public boolean startActivityForUrl(@Nullable WebView tab, @NonNull String url) { * Search for intent handlers that are specific to this URL aka, specialized * apps like google maps or youtube */ - private boolean isSpecializedHandlerAvailable(Intent intent) { + private boolean isSpecializedHandlerAvailable(@NonNull Intent intent) { PackageManager pm = mActivity.getPackageManager(); List handlers = pm.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER); diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index d1205cb7f..8798e17d7 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -77,20 +77,20 @@ public class LightningView { private static final int API = android.os.Build.VERSION.SDK_INT; private static final int SCROLL_UP_THRESHOLD = Utils.dpToPx(10); - private static String sHomepage; - private static String sDefaultUserAgent; + @Nullable private static String sHomepage; + @Nullable private static String sDefaultUserAgent; private static float sMaxFling; private static final float[] sNegativeColorArray = { - -1.0f, 0, 0, 0, 255, // red - 0, -1.0f, 0, 0, 255, // green - 0, 0, -1.0f, 0, 255, // blue - 0, 0, 0, 1.0f, 0 // alpha + -1.0f, 0, 0, 0, 255, // red + 0, -1.0f, 0, 0, 255, // green + 0, 0, -1.0f, 0, 255, // blue + 0, 0, 0, 1.0f, 0 // alpha }; private static final float[] sIncreaseContrastColorArray = { - 2.0f, 0, 0, 0, -160.f, // red - 0, 2.0f, 0, 0, -160.f, // green - 0, 0, 2.0f, 0, -160.f, // blue - 0, 0, 0, 1.0f, 0 // alpha + 2.0f, 0, 0, 0, -160.f, // red + 0, 2.0f, 0, 0, -160.f, // green + 0, 0, 2.0f, 0, -160.f, // blue + 0, 0, 0, 1.0f, 0 // alpha }; @NonNull private final LightningViewTitle mTitle; @@ -193,6 +193,8 @@ public void loadHomepage() { if (mWebView == null) { return; } + + Preconditions.checkNonNull(sHomepage); switch (sHomepage) { case Constants.SCHEME_HOMEPAGE: loadStartpage(); @@ -213,15 +215,15 @@ public void loadHomepage() { */ private void loadStartpage() { new StartPage().getHomepage() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable String item) { - Preconditions.checkNonNull(item); - loadUrl(item); - } - }); + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + loadUrl(item); + } + }); } /** @@ -231,15 +233,15 @@ public void onItem(@Nullable String item) { */ public void loadBookmarkpage() { new BookmarkPage(mActivity).getBookmarkPage() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable String item) { - Preconditions.checkNonNull(item); - loadUrl(item); - } - }); + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + loadUrl(item); + } + }); } /** @@ -368,7 +370,7 @@ public synchronized void initializePreferences(@NonNull Context context) { } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { CookieManager.getInstance().setAcceptThirdPartyCookies(mWebView, - !mPreferences.getBlockThirdPartyCookiesEnabled()); + !mPreferences.getBlockThirdPartyCookiesEnabled()); } } @@ -421,44 +423,44 @@ private void initializeSettings() { } getPathObservable("appcache").subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable File item) { + Preconditions.checkNonNull(item); + settings.setAppCachePath(item.getPath()); + } + }); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + getPathObservable("geolocation").subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe() { @Override public void onItem(@Nullable File item) { Preconditions.checkNonNull(item); - settings.setAppCachePath(item.getPath()); + //noinspection deprecation + settings.setGeolocationDatabasePath(item.getPath()); } }); - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - getPathObservable("geolocation").subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable File item) { - Preconditions.checkNonNull(item); - //noinspection deprecation - settings.setGeolocationDatabasePath(item.getPath()); - } - }); } getPathObservable("databases").subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable File item) { - if (API < Build.VERSION_CODES.KITKAT) { - Preconditions.checkNonNull(item); - //noinspection deprecation - settings.setDatabasePath(item.getPath()); - } + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable File item) { + if (API < Build.VERSION_CODES.KITKAT) { + Preconditions.checkNonNull(item); + //noinspection deprecation + settings.setDatabasePath(item.getPath()); } + } - @Override - public void onComplete() { - } - }); + @Override + public void onComplete() { + } + }); } @@ -714,7 +716,7 @@ private void setColorMode(int mode) { break; case 1: ColorMatrixColorFilter filterInvert = new ColorMatrixColorFilter( - sNegativeColorArray); + sNegativeColorArray); mPaint.setColorFilter(filterInvert); setHardwareRendering(); @@ -743,7 +745,7 @@ private void setColorMode(int mode) { case 4: ColorMatrixColorFilter IncreaseHighContrast = new ColorMatrixColorFilter( - sIncreaseContrastColorArray); + sIncreaseContrastColorArray); mPaint.setColorFilter(IncreaseHighContrast); setHardwareRendering(); break; @@ -972,7 +974,7 @@ private void longClickPage(@Nullable final String url) { if (currentUrl != null && UrlUtils.isSpecialUrl(currentUrl)) { if (currentUrl.endsWith(HistoryPage.FILENAME)) { if (url != null) { - mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity,mUIController, url); + mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, mUIController, url); } else if (result != null && result.getExtra() != null) { final String newUrl = result.getExtra(); mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, mUIController, newUrl); From b8bbd8f6e03b411cb69f1fda30c7cecbf960f424 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 2 May 2017 22:22:29 -0400 Subject: [PATCH 090/181] Using observables instead of executors --- .../acr/browser/lightning/app/BrowserApp.java | 5 - .../lightning/database/BookmarkLocalSync.java | 29 +++-- .../fragment/BookmarkSettingsFragment.java | 26 ++-- .../fragment/PrivacySettingsFragment.java | 120 ++++++++++-------- 4 files changed, 94 insertions(+), 86 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index b87a12a7b..ebbae02b0 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -102,11 +102,6 @@ public static Executor getIOThread() { return mIOThread; } - @NonNull - public static Executor getTaskThread() { - return mTaskThread; - } - /** * Determines whether this is a release build. * diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java index 7511b6108..945c59c12 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java @@ -83,7 +83,7 @@ private Cursor getBrowserCursor(String contentUri) { Uri uri = Uri.parse(contentUri); try { cursor = mContext.getContentResolver().query(uri, - new String[]{COLUMN_URL, COLUMN_TITLE, COLUMN_BOOKMARK}, null, null, null); + new String[]{COLUMN_URL, COLUMN_TITLE, COLUMN_BOOKMARK}, null, null, null); } catch (IllegalArgumentException e) { return null; } @@ -145,16 +145,23 @@ public List getBookmarksFromChromeDev() { return getBookmarksFromContentUri(CHROME_DEV_BOOKMARKS_CONTENT); } - @WorkerThread - public boolean isBrowserImportSupported() { - Cursor chrome = getChromeCursor(); - Utils.close(chrome); - Cursor dev = getChromeDevCursor(); - Utils.close(dev); - Cursor beta = getChromeBetaCursor(); - Cursor stock = getStockCursor(); - Utils.close(stock); - return chrome != null || dev != null || beta != null || stock != null; + @NonNull + public Single isBrowserImportSupported() { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + Cursor chrome = getChromeCursor(); + Utils.close(chrome); + Cursor dev = getChromeDevCursor(); + Utils.close(dev); + Cursor beta = getChromeBetaCursor(); + Cursor stock = getStockCursor(); + Utils.close(stock); + + subscriber.onItem(chrome != null || dev != null || beta != null || stock != null); + subscriber.onComplete(); + } + }); } @Nullable diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index e8c8da5ce..3bf259009 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -164,20 +164,18 @@ private void initPrefs() { importPref.setOnPreferenceClickListener(this); deletePref.setOnPreferenceClickListener(this); - BrowserApp.getTaskThread().execute(new Runnable() { - @Override - public void run() { - final boolean isBrowserImportSupported = getSync().isBrowserImportSupported(); - Schedulers.main().execute(new Runnable() { - @Override - public void run() { - Preference importStock = findPreference(SETTINGS_IMPORT_BROWSER); - importStock.setEnabled(isBrowserImportSupported); - importStock.setOnPreferenceClickListener(BookmarkSettingsFragment.this); - } - }); - } - }); + getSync().isBrowserImportSupported() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean supported) { + Preconditions.checkNonNull(supported); + Preference importStock = findPreference(SETTINGS_IMPORT_BROWSER); + importStock.setEnabled(supported); + importStock.setOnPreferenceClickListener(BookmarkSettingsFragment.this); + } + }); } diff --git a/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java index 425556bcc..fac64afb1 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java @@ -16,6 +16,12 @@ import android.support.v7.app.AlertDialog; import android.webkit.WebView; +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableOnSubscribe; +import com.anthonycr.bonsai.CompletableSubscriber; +import com.anthonycr.bonsai.Schedulers; + import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.dialog.BrowserDialog; @@ -40,7 +46,6 @@ public class PrivacySettingsFragment extends LightningPreferenceFragment impleme private static final String SETTINGS_IDENTIFYINGHEADERS = "remove_identifying_headers"; private Activity mActivity; - private Handler mMessageHandler; @Override public void onCreate(Bundle savedInstanceState) { @@ -103,29 +108,6 @@ private void initPrefs() { cb3cookies.setEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP); - mMessageHandler = new MessageHandler(mActivity); - } - - private static class MessageHandler extends Handler { - - final Activity mHandlerContext; - - public MessageHandler(Activity context) { - this.mHandlerContext = context; - } - - @Override - public void handleMessage(@NonNull Message msg) { - switch (msg.what) { - case 1: - Utils.showSnackbar(mHandlerContext, R.string.message_clear_history); - break; - case 2: - Utils.showSnackbar(mHandlerContext, R.string.message_cookies_cleared); - break; - } - super.handleMessage(msg); - } } @Override @@ -152,19 +134,22 @@ private void clearHistoryDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); builder.setTitle(getResources().getString(R.string.title_clear_history)); Dialog dialog = builder.setMessage(getResources().getString(R.string.dialog_history)) - .setPositiveButton(getResources().getString(R.string.action_yes), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface arg0, int arg1) { - BrowserApp.getIOThread().execute(new Runnable() { - @Override - public void run() { - clearHistory(); - } - }); - } - }) - .setNegativeButton(getResources().getString(R.string.action_no), null).show(); + .setPositiveButton(getResources().getString(R.string.action_yes), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface arg0, int arg1) { + clearHistory() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + Utils.showSnackbar(getActivity(), R.string.message_clear_history); + } + }); + } + }) + .setNegativeButton(getResources().getString(R.string.action_no), null).show(); BrowserDialog.setDialogSize(mActivity, dialog); } @@ -172,19 +157,22 @@ private void clearCookiesDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); builder.setTitle(getResources().getString(R.string.title_clear_cookies)); builder.setMessage(getResources().getString(R.string.dialog_cookies)) - .setPositiveButton(getResources().getString(R.string.action_yes), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface arg0, int arg1) { - BrowserApp.getTaskThread().execute(new Runnable() { - @Override - public void run() { - clearCookies(); - } - }); - } - }) - .setNegativeButton(getResources().getString(R.string.action_no), null).show(); + .setPositiveButton(getResources().getString(R.string.action_yes), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface arg0, int arg1) { + clearCookies() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + Utils.showSnackbar(getActivity(), R.string.message_cookies_cleared); + } + }); + } + }) + .setNegativeButton(getResources().getString(R.string.action_no), null).show(); } private void clearCache() { @@ -194,14 +182,34 @@ private void clearCache() { Utils.showSnackbar(mActivity, R.string.message_cache_cleared); } - private void clearHistory() { - WebUtils.clearHistory(getActivity()); - mMessageHandler.sendEmptyMessage(1); + @NonNull + private Completable clearHistory() { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + Activity activity = getActivity(); + if (activity != null) { + WebUtils.clearHistory(activity); + subscriber.onComplete(); + } + subscriber.onError(new RuntimeException("Activity was null in clearHistory")); + } + }); } - private void clearCookies() { - WebUtils.clearCookies(getActivity()); - mMessageHandler.sendEmptyMessage(2); + @NonNull + private Completable clearCookies() { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + Activity activity = getActivity(); + if (activity != null) { + WebUtils.clearCookies(activity); + subscriber.onComplete(); + } + subscriber.onError(new RuntimeException("Activity was null in clearCookies")); + } + }); } private void clearWebStorage() { From f89829735d501248e39cfb7d1c43bc88d9cbabd7 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 3 May 2017 21:49:32 -0400 Subject: [PATCH 091/181] Simplifying shouldOverrideUrlLoading --- .../lightning/view/LightningWebClient.java | 62 ++++++++----------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index d7d506584..768faace2 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -301,45 +301,35 @@ private boolean shouldOverrideLoading(@NonNull WebView view, @NonNull String url Map headers = mLightningView.getRequestHeaders(); - // If the headers are empty, the user has not expressed the desire - // to use them and therefore we can revert back to the old way of loading - if (headers.isEmpty()) { - if (mLightningView.isIncognito()) { - // If we are in incognito, immediately load, we don't want the url to leave the app - return false; - } - if (url.startsWith(Constants.ABOUT)) { - // If this is an about page, immediately load, we don't need to leave the app - return false; - } + if (mLightningView.isIncognito()) { + // If we are in incognito, immediately load, we don't want the url to leave the app + return continueLoadingUrl(view, url, headers); + } + if (url.startsWith(Constants.ABOUT)) { + // If this is an about page, immediately load, we don't need to leave the app + return continueLoadingUrl(view, url, headers); + } - if (isMailOrIntent(url, view) || mIntentUtils.startActivityForUrl(view, url)) { - // If it was a mailto: link, or an intent, or could be launched elsewhere, do that - return true; - } - } else { - if (mLightningView.isIncognito() && Utils.doesSupportHeaders()) { - // If we are in incognito, immediately load, we don't want the url to leave the app - view.loadUrl(url, headers); - return true; - } - if (url.startsWith(Constants.ABOUT) && Utils.doesSupportHeaders()) { - // If this is an about page, immediately load, we don't need to leave the app - view.loadUrl(url, headers); - return true; - } + if (isMailOrIntent(url, view) || mIntentUtils.startActivityForUrl(view, url)) { + // If it was a mailto: link, or an intent, or could be launched elsewhere, do that + return true; + } - if (isMailOrIntent(url, view) || mIntentUtils.startActivityForUrl(view, url)) { - // If it was a mailto: link, or an intent, or could be launched elsewhere, do that - return true; - } else if (Utils.doesSupportHeaders()) { - // Otherwise, load the headers. - view.loadUrl(url, headers); - return true; - } + // If none of the special conditions was met, continue with loading the url + return continueLoadingUrl(view, url, headers); + } + + private boolean continueLoadingUrl(@NonNull WebView webView, + @NonNull String url, + @NonNull Map headers) { + if (headers.isEmpty()) { + return false; + } else if (Utils.doesSupportHeaders()) { + webView.loadUrl(url, headers); + return true; + } else { + return false; } - // If none of those instances was true, revert back to the old way of loading - return false; } private boolean isMailOrIntent(@NonNull String url, @NonNull WebView view) { From d7e5a5fbe2e420737ab9136c1e6d03df98e469d9 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 3 May 2017 22:01:42 -0400 Subject: [PATCH 092/181] Removing unused class --- .../lightning/utils/KeyboardHelper.java | 67 ------------------- 1 file changed, 67 deletions(-) delete mode 100644 app/src/main/java/acr/browser/lightning/utils/KeyboardHelper.java diff --git a/app/src/main/java/acr/browser/lightning/utils/KeyboardHelper.java b/app/src/main/java/acr/browser/lightning/utils/KeyboardHelper.java deleted file mode 100644 index d6ed3ec76..000000000 --- a/app/src/main/java/acr/browser/lightning/utils/KeyboardHelper.java +++ /dev/null @@ -1,67 +0,0 @@ -package acr.browser.lightning.utils; - -import android.graphics.Rect; -import android.support.annotation.NonNull; -import android.view.View; -import android.view.ViewTreeObserver; - -class KeyboardHelper { - - interface KeyboardListener { - /** - * Called when the visibility of the keyboard changes. - * Parameter tells whether the keyboard has been shown - * or hidden. - * - * @param visible true if the keyboard has been shown, - * false otherwise. - */ - void keyboardVisibilityChanged(boolean visible); - } - - @NonNull private final View mView; - private int mLastRight = -1; - private int mLastBottom = -1; - - /** - * Constructor - * - * @param view the view to listen on, should be - * the {@link android.R.id#content} view. - */ - public KeyboardHelper(@NonNull View view) { - mView = view; - } - - /** - * Registers a {@link KeyboardListener} to receive - * callbacks when the keyboard is shown for the specific - * view. The view used should be the content view as it - * will receive resize events from the system. - * - * @param listener the listener to register to receive events. - */ - public void registerKeyboardListener(@NonNull final KeyboardListener listener) { - mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - Rect rect = new Rect(); - if (mLastBottom == -1) { - mLastBottom = rect.bottom; - } - if (mLastRight == -1) { - mLastRight = rect.right; - } - mView.getWindowVisibleDisplayFrame(rect); - if (mLastRight == rect.right && rect.bottom < mLastBottom) { - listener.keyboardVisibilityChanged(true); - } else if (mLastRight == rect.right && rect.bottom > mLastBottom) { - listener.keyboardVisibilityChanged(false); - } - mLastBottom = rect.bottom; - mLastRight = rect.right; - } - }); - } - -} From 368d71df7da878078d5874dd7853a2ef2a397d78 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Fri, 5 May 2017 20:26:01 -0400 Subject: [PATCH 093/181] Deleting unused code --- .../browser/lightning/activity/BrowserActivity.java | 1 - .../java/acr/browser/lightning/app/BrowserApp.java | 1 - .../acr/browser/lightning/database/HistoryItem.java | 8 -------- .../lightning/fragment/PrivacySettingsFragment.java | 2 -- .../acr/browser/lightning/utils/ThemeUtils.java | 13 ------------- .../lightning/view/LightningChromeClient.java | 2 -- 6 files changed, 27 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 2f5283b01..3813360e8 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -49,7 +49,6 @@ import android.view.View.OnClickListener; import android.view.View.OnFocusChangeListener; import android.view.View.OnKeyListener; -import android.view.View.OnLongClickListener; import android.view.View.OnTouchListener; import android.view.ViewConfiguration; import android.view.ViewGroup; diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index ebbae02b0..d7679c535 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -31,7 +31,6 @@ public class BrowserApp extends Application { @Nullable private static AppComponent sAppComponent; private static final Executor mIOThread = Executors.newSingleThreadExecutor(); - private static final Executor mTaskThread = Executors.newCachedThreadPool(); @Inject PreferenceManager mPreferenceManager; diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryItem.java b/app/src/main/java/acr/browser/lightning/database/HistoryItem.java index 137f29518..b439b1bce 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryItem.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryItem.java @@ -30,14 +30,6 @@ public class HistoryItem implements Comparable { public HistoryItem() {} - public HistoryItem(@NonNull HistoryItem item) { - this.mUrl = item.mUrl; - this.mTitle = item.mTitle; - this.mFolder = item.mFolder; - this.mOrder = item.mOrder; - this.mIsFolder = item.mIsFolder; - } - public HistoryItem(@NonNull String url, @NonNull String title) { Preconditions.checkNonNull(url); Preconditions.checkNonNull(title); diff --git a/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java index fac64afb1..f3d6ecc40 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java @@ -8,8 +8,6 @@ import android.content.DialogInterface; import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.support.annotation.NonNull; diff --git a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java index 77bb8ca56..165f8d85e 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java @@ -61,11 +61,6 @@ public static int getIconThemeColor(@NonNull Context context, boolean dark) { return (dark) ? getIconDarkThemeColor(context) : getIconLightThemeColor(context); } - public static void themeImageView(@NonNull ImageView icon, @NonNull Context context, boolean dark) { - int color = dark ? getIconDarkThemeColor(context) : getIconLightThemeColor(context); - icon.setColorFilter(color, PorterDuff.Mode.SRC_IN); - } - @NonNull private static Drawable getVectorDrawable(@NonNull Context context, int drawableId) { Drawable drawable = ContextCompat.getDrawable(context, drawableId); @@ -116,14 +111,6 @@ public static Drawable getThemedDrawable(@NonNull Context context, @DrawableRes return drawable; } - @NonNull - public static ColorDrawable getSelectedBackground(@NonNull Context context, boolean dark) { - @ColorInt final int color = - (dark) ? ContextCompat.getColor(context, R.color.selected_dark) : ContextCompat.getColor( - context, R.color.selected_light); - return new ColorDrawable(color); - } - public static int getThemedTextHintColor(boolean dark) { return 0x80ffffff & (dark ? Color.WHITE : Color.BLACK); } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java index 2aab716df..80f40bc06 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java @@ -33,8 +33,6 @@ public class LightningChromeClient extends WebChromeClient { - private static final String TAG = LightningChromeClient.class.getSimpleName(); - private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION}; @NonNull private final Activity mActivity; From 66b4ea16f4baecf2bbf0f7c50c728289bafa51d1 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Fri, 5 May 2017 20:37:15 -0400 Subject: [PATCH 094/181] Making the tab object tag more specific for its use case --- .../lightning/browser/BrowserPresenter.java | 10 +++--- .../browser/lightning/view/LightningView.java | 36 ++++++++++--------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java index 3d616939a..cb3d4a575 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java @@ -105,12 +105,12 @@ private void onTabChanged(@Nullable LightningView newTab) { // TODO: Restore this when Google fixes the bug where the WebView is // blank after calling onPause followed by onResume. // mCurrentTab.onPause(); - mCurrentTab.setForegroundTab(false); + mCurrentTab.setIsForegroundTab(false); } newTab.resumeTimers(); newTab.onResume(); - newTab.setForegroundTab(true); + newTab.setIsForegroundTab(true); mView.updateProgress(newTab.getProgress()); mView.setBackButtonEnabled(newTab.canGoBack()); @@ -161,7 +161,7 @@ public void deleteTab(int position) { } final boolean isShown = tabToDelete.isShown(); - boolean shouldClose = mShouldClose && isShown && Boolean.TRUE.equals(tabToDelete.getTag()); + boolean shouldClose = mShouldClose && isShown && tabToDelete.isNewTab(); final LightningView currentTab = mTabsModel.getCurrentTab(); if (mTabsModel.size() == 1 && currentTab != null && (UrlUtils.isSpecialUrl(currentTab.getUrl()) || @@ -239,7 +239,7 @@ public void onClick(DialogInterface dialog, int which) { mShouldClose = true; LightningView tab = mTabsModel.lastTab(); if (tab != null) { - tab.setTag(true); + tab.setIsNewTab(true); } } }); @@ -248,7 +248,7 @@ public void onClick(DialogInterface dialog, int which) { mShouldClose = true; LightningView tab = mTabsModel.lastTab(); if (tab != null) { - tab.setTag(true); + tab.setIsNewTab(true); } } } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 8798e17d7..ad267c458 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -99,9 +99,9 @@ public class LightningView { @NonNull private final GestureDetector mGestureDetector; @NonNull private final Activity mActivity; @NonNull private final Paint mPaint = new Paint(); - @Nullable private Object mTag; + private boolean mIsNewTab; private final boolean mIsIncognitoTab; - private boolean isForegroundTab; + private boolean mIsForegroundTab; private boolean mInvertPage = false; private boolean mToggleDesktop = false; @NonNull private final WebViewHandler mWebViewHandler = new WebViewHandler(this); @@ -162,25 +162,27 @@ public LightningView(@NonNull Activity activity, @Nullable String url, boolean i } /** - * Sets the tag on the object, - * a reference to this object is held - * indefinitely. + * Sets whether this tab was the + * result of a new intent sent + * to the browser. * - * @param tag the tag to set, may be null. + * @param isNewTab true if it's from + * a new intent, + * false otherwise. */ - public void setTag(@Nullable Object tag) { - mTag = tag; + public void setIsNewTab(boolean isNewTab) { + mIsNewTab = isNewTab; } /** - * The tag set on the object. + * Returns whether this tab was created + * as a result of a new intent. * - * @return the tag set on the object, - * may be null. + * @return true if it was a new intent, + * false otherwise. */ - @Nullable - public Object getTag() { - return mTag; + public boolean isNewTab() { + return mIsNewTab; } /** @@ -617,8 +619,8 @@ public synchronized void freeMemory() { * @param isForeground true if the tab should be set as * foreground, false otherwise. */ - public void setForegroundTab(boolean isForeground) { - isForegroundTab = isForeground; + public void setIsForegroundTab(boolean isForeground) { + mIsForegroundTab = isForeground; mUIController.tabChanged(this); } @@ -629,7 +631,7 @@ public void setForegroundTab(boolean isForeground) { * false otherwise. */ public boolean isForegroundTab() { - return isForegroundTab; + return mIsForegroundTab; } /** From 510e7fd7a0ca7f591b70c90b546e239f89ea4318 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Fri, 5 May 2017 21:31:05 -0400 Subject: [PATCH 095/181] Switching to recycler view --- .../lightning/fragment/BookmarksFragment.java | 158 ++++++++++++------ app/src/main/res/layout/bookmark_drawer.xml | 2 +- 2 files changed, 107 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 92f5db253..8862ee88c 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -11,6 +11,8 @@ import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.view.ViewCompat; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -18,13 +20,8 @@ import android.view.animation.Animation; import android.view.animation.DecelerateInterpolator; import android.view.animation.Transformation; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.ArrayAdapter; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.ListView; import android.widget.TextView; import com.anthonycr.bonsai.Schedulers; @@ -52,6 +49,7 @@ import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.favicon.FaviconModel; import acr.browser.lightning.preference.PreferenceManager; +import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.view.LightningView; import butterknife.BindView; @@ -89,7 +87,7 @@ public static BookmarksFragment createFragment(boolean isIncognito) { private UIController mUiController; // Adapter - private BookmarkViewAdapter mBookmarkAdapter; + private BookmarkListAdapter mBookmarkAdapter; // Preloaded images private Bitmap mWebpageBitmap, mFolderBitmap; @@ -98,7 +96,7 @@ public static BookmarksFragment createFragment(boolean isIncognito) { private final List mBookmarks = new ArrayList<>(); // Views - @BindView(R.id.right_drawer_list) ListView mBookmarksListView; + @BindView(R.id.right_drawer_list) RecyclerView mBookmarksListView; @BindView(R.id.starIcon) ImageView mBookmarkTitleImage; @BindView(R.id.icon_star) ImageView mBookmarkImage; @@ -113,17 +111,13 @@ public static BookmarksFragment createFragment(boolean isIncognito) { @Nullable private Subscription mBookmarksSubscription; - private Single initBookmarkManager() { - return Single.create(new SingleAction() { + private static Single> initBookmarks(@NonNull final BookmarkManager bookmarkManager) { + return Single.create(new SingleAction>() { @Override - public void onSubscribe(@NonNull SingleSubscriber subscriber) { - Context context = getContext(); - if (context != null) { - mBookmarkAdapter = new BookmarkViewAdapter(context, mBookmarks); - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); - subscriber.onItem(mBookmarkAdapter); - } + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { + subscriber.onItem(bookmarkManager.getBookmarksFromFolder(null, true)); subscriber.onComplete(); + } }); } @@ -154,10 +148,10 @@ private TabsManager getTabsManager() { // Handle bookmark click private final OnItemClickListener mItemClickListener = new OnItemClickListener() { @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { + public void onItemClick(int position) { final HistoryItem item = mBookmarks.get(position); if (item.isFolder()) { - mScrollIndex = mBookmarksListView.getFirstVisiblePosition(); + mScrollIndex = ((LinearLayoutManager) mBookmarksListView.getLayoutManager()).findFirstVisibleItemPosition(); setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(item.getTitle(), true), true); } else { mUiController.bookmarkItemClicked(item); @@ -167,7 +161,7 @@ public void onItemClick(AdapterView parent, View view, int position, long id) private final OnItemLongClickListener mItemLongClickListener = new OnItemLongClickListener() { @Override - public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + public boolean onItemLongClick(int position) { final HistoryItem item = mBookmarks.get(position); handleLongPress(item); return true; @@ -187,8 +181,6 @@ public void onResume() { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.bookmark_drawer, container, false); mUnbinder = ButterKnife.bind(this, view); - mBookmarksListView.setOnItemClickListener(mItemClickListener); - mBookmarksListView.setOnItemLongClickListener(mItemLongClickListener); mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); final View backView = view.findViewById(R.id.bookmark_back_button); backView.setOnClickListener(new View.OnClickListener() { @@ -197,7 +189,7 @@ public void onClick(View v) { if (mBookmarkManager == null) return; if (!mBookmarkManager.isRootFolder()) { setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); - mBookmarksListView.setSelection(mScrollIndex); + mBookmarksListView.getLayoutManager().scrollToPosition(mScrollIndex); } } }); @@ -205,15 +197,24 @@ public void onClick(View v) { setupNavigationButton(view, R.id.action_reading, R.id.icon_reading); setupNavigationButton(view, R.id.action_toggle_desktop, R.id.icon_desktop); - mBookmarksSubscription = initBookmarkManager().subscribeOn(Schedulers.io()) + mBookmarkAdapter = new BookmarkListAdapter(mBookmarks, mFaviconModel, mFolderBitmap, mWebpageBitmap); + mBookmarkAdapter.setOnItemClickListener(mItemClickListener); + mBookmarkAdapter.setOnItemLongClickListener(mItemLongClickListener); + mBookmarksListView.setLayoutManager(new LinearLayoutManager(getContext())); + mBookmarksListView.setAdapter(mBookmarkAdapter); + + mBookmarksSubscription = initBookmarks(mBookmarkManager) + .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { + .subscribe(new SingleOnSubscribe>() { @Override - public void onItem(@Nullable BookmarkViewAdapter item) { + public void onItem(@Nullable List item) { mBookmarksSubscription = null; - mBookmarksListView.setAdapter(mBookmarkAdapter); + Preconditions.checkNonNull(item); + setBookmarkDataSet(item, true); } }); + return view; } @@ -385,7 +386,7 @@ public void navigateBack() { mUiController.closeBookmarksDrawer(); } else { setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); - mBookmarksListView.setSelection(mScrollIndex); + mBookmarksListView.getLayoutManager().scrollToPosition(mScrollIndex); } } @@ -396,34 +397,87 @@ public void handleUpdatedUrl(@NonNull String url) { setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(folder, true), false); } - private class BookmarkViewAdapter extends ArrayAdapter { + static class BookmarkViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { + @BindView(R.id.textBookmark) TextView txtTitle; + @BindView(R.id.faviconBookmark) ImageView favicon; - final Context context; + @Nullable private final OnItemLongClickListener onItemLongClickListener; + @Nullable private final OnItemClickListener onItemClickListener; - BookmarkViewAdapter(Context context, @NonNull List data) { - super(context, R.layout.bookmark_list_item, data); - this.context = context; + BookmarkViewHolder(@NonNull View itemView, + @Nullable OnItemLongClickListener onItemLongClickListener, + @Nullable OnItemClickListener onItemClickListener) { + super(itemView); + ButterKnife.bind(this, itemView); + + this.onItemClickListener = onItemClickListener; + this.onItemLongClickListener = onItemLongClickListener; + + itemView.setOnLongClickListener(this); + itemView.setOnClickListener(this); } - @NonNull @Override - public View getView(int position, View convertView, @NonNull ViewGroup parent) { - View row = convertView; - BookmarkViewHolder holder; - - if (row == null) { - LayoutInflater inflater = LayoutInflater.from(context); - row = inflater.inflate(R.layout.bookmark_list_item, parent, false); - - holder = new BookmarkViewHolder(); - holder.txtTitle = (TextView) row.findViewById(R.id.textBookmark); - holder.favicon = (ImageView) row.findViewById(R.id.faviconBookmark); - row.setTag(holder); - } else { - holder = (BookmarkViewHolder) row.getTag(); + public void onClick(View v) { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(getAdapterPosition()); } + } + + @Override + public boolean onLongClick(View v) { + return onItemLongClickListener != null && + onItemLongClickListener.onItemLongClick(getAdapterPosition()); + } + } + + interface OnItemLongClickListener { + boolean onItemLongClick(int position); + } + + interface OnItemClickListener { + void onItemClick(int position); + } - ViewCompat.jumpDrawablesToCurrentState(row); + private static class BookmarkListAdapter extends RecyclerView.Adapter { + + @NonNull private final List mBookmarks; + @NonNull private final FaviconModel mFaviconModel; + @NonNull private final Bitmap mFolderBitmap; + @NonNull private final Bitmap mWebpageBitmap; + + @Nullable private OnItemLongClickListener mOnItemLongCLickListener; + @Nullable private OnItemClickListener mOnItemClickListener; + + BookmarkListAdapter(@NonNull List bookmarks, + @NonNull FaviconModel faviconModel, + @NonNull Bitmap folderBitmap, + @NonNull Bitmap webpageBitmap) { + mBookmarks = bookmarks; + mFaviconModel = faviconModel; + mFolderBitmap = folderBitmap; + mWebpageBitmap = webpageBitmap; + } + + void setOnItemLongClickListener(@Nullable OnItemLongClickListener listener) { + mOnItemLongCLickListener = listener; + } + + void setOnItemClickListener(@Nullable OnItemClickListener listener) { + mOnItemClickListener = listener; + } + + @Override + public BookmarkViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View itemView = inflater.inflate(R.layout.bookmark_list_item, parent, false); + + return new BookmarkViewHolder(itemView, mOnItemLongCLickListener, mOnItemClickListener); + } + + @Override + public void onBindViewHolder(BookmarkViewHolder holder, int position) { + ViewCompat.jumpDrawablesToCurrentState(holder.itemView); final HistoryItem web = mBookmarks.get(position); holder.txtTitle.setText(web.getTitle()); @@ -454,12 +508,12 @@ public void onItem(@Nullable Bitmap item) { } else { holder.favicon.setImageBitmap(web.getBitmap()); } - return row; + } - private class BookmarkViewHolder { - TextView txtTitle; - ImageView favicon; + @Override + public int getItemCount() { + return mBookmarks.size(); } } diff --git a/app/src/main/res/layout/bookmark_drawer.xml b/app/src/main/res/layout/bookmark_drawer.xml index 2345bcd6d..35cdc5064 100644 --- a/app/src/main/res/layout/bookmark_drawer.xml +++ b/app/src/main/res/layout/bookmark_drawer.xml @@ -43,7 +43,7 @@ android:textAppearance="?android:attr/textAppearanceLarge"/> - Date: Fri, 5 May 2017 21:45:24 -0400 Subject: [PATCH 096/181] Setting the background of the item --- app/src/main/res/layout/bookmark_drawer.xml | 3 +-- app/src/main/res/layout/bookmark_list_item.xml | 10 ++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/bookmark_drawer.xml b/app/src/main/res/layout/bookmark_drawer.xml index 35cdc5064..265a23d7e 100644 --- a/app/src/main/res/layout/bookmark_drawer.xml +++ b/app/src/main/res/layout/bookmark_drawer.xml @@ -49,8 +49,7 @@ android:layout_height="0dp" android:layout_weight="1" android:divider="@null" - android:dividerHeight="0dp" - android:listSelector="?attr/listBackground"/> + android:dividerHeight="0dp"/> - + android:orientation="horizontal"> + android:gravity="center_vertical"> + android:textAppearance="?android:attr/textAppearanceListItemSmall"/> \ No newline at end of file From 086f915e203ba3b40017dfe16c7e89f3f4bc51a9 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 6 May 2017 14:34:44 -0400 Subject: [PATCH 097/181] Switching from getSimpleName to hardcoded tag --- .../java/acr/browser/lightning/activity/BrowserActivity.java | 2 +- .../java/acr/browser/lightning/activity/ReadingActivity.java | 2 +- .../main/java/acr/browser/lightning/activity/TabsManager.java | 3 ++- app/src/main/java/acr/browser/lightning/app/BrowserApp.java | 2 +- .../java/acr/browser/lightning/browser/BrowserPresenter.java | 2 +- .../main/java/acr/browser/lightning/constant/HistoryPage.java | 2 +- .../java/acr/browser/lightning/database/BookmarkLocalSync.java | 2 +- .../java/acr/browser/lightning/database/BookmarkManager.java | 2 +- .../java/acr/browser/lightning/download/DownloadHandler.java | 3 ++- .../java/acr/browser/lightning/download/FetchUrlMimeType.java | 2 +- .../java/acr/browser/lightning/fragment/BookmarksFragment.java | 2 +- .../main/java/acr/browser/lightning/fragment/TabsFragment.java | 2 +- .../acr/browser/lightning/search/BaseSuggestionsModel.java | 2 +- .../main/java/acr/browser/lightning/utils/MemoryLeakUtils.java | 2 +- app/src/main/java/acr/browser/lightning/utils/Utils.java | 2 +- .../main/java/acr/browser/lightning/view/LightningView.java | 2 +- 16 files changed, 18 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 3813360e8..176c140e9 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -124,7 +124,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements BrowserView, UIController, OnClickListener { - private static final String TAG = BrowserActivity.class.getSimpleName(); + private static final String TAG = "BrowserActivity"; private static final String INTENT_PANIC_TRIGGER = "info.guardianproject.panic.action.TRIGGER"; diff --git a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java index 5b442dd9d..bf2e0dfa0 100644 --- a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java @@ -45,7 +45,7 @@ public class ReadingActivity extends AppCompatActivity { - private static final String TAG = ReadingActivity.class.getSimpleName(); + private static final String TAG = "ReadingActivity"; @BindView(R.id.textViewTitle) TextView mTitle; @BindView(R.id.textViewBody) TextView mBody; diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index ee189a39b..02f825dfb 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -50,7 +50,8 @@ */ public class TabsManager { - private static final String TAG = TabsManager.class.getSimpleName(); + private static final String TAG = "TabsManager"; + private static final String BUNDLE_KEY = "WEBVIEW_"; private static final String URL_KEY = "URL_KEY"; private static final String BUNDLE_STORAGE = "SAVED_TABS.parcel"; diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index d7679c535..1fd4962ac 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -27,7 +27,7 @@ public class BrowserApp extends Application { - private static final String TAG = BrowserApp.class.getSimpleName(); + private static final String TAG = "BrowserApp"; @Nullable private static AppComponent sAppComponent; private static final Executor mIOThread = Executors.newSingleThreadExecutor(); diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java index cb3d4a575..291ec1c5f 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java @@ -29,7 +29,7 @@ */ public class BrowserPresenter { - private static final String TAG = BrowserPresenter.class.getSimpleName(); + private static final String TAG = "BrowserPresenter"; @NonNull private final TabsManager mTabsModel; @Inject PreferenceManager mPreferences; diff --git a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java index 265366484..6c179c67e 100644 --- a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java @@ -33,7 +33,7 @@ public class HistoryPage { - private static final String TAG = HistoryPage.class.getSimpleName(); + private static final String TAG = "HistoryPage"; public static final String FILENAME = "history.html"; diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java index 945c59c12..ce329a956 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java @@ -19,7 +19,7 @@ public class BookmarkLocalSync { - private static final String TAG = BookmarkLocalSync.class.getSimpleName(); + private static final String TAG = "BookmarkLocalSync"; private static final String STOCK_BOOKMARKS_CONTENT = "content://browser/bookmarks"; private static final String CHROME_BOOKMARKS_CONTENT = "content://com.android.chrome.browser/bookmarks"; diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java index cabbdf568..045ae1ead 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java @@ -42,7 +42,7 @@ @Singleton public class BookmarkManager { - private static final String TAG = BookmarkManager.class.getSimpleName(); + private static final String TAG = "BookmarkManager"; private static final String TITLE = "title"; private static final String URL = "url"; diff --git a/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java index 1f55e1776..7fdab9b4f 100644 --- a/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java +++ b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java @@ -39,7 +39,8 @@ */ public class DownloadHandler { - private static final String TAG = DownloadHandler.class.getSimpleName(); + private static final String TAG = "DownloadHandler"; + private static final String COOKIE_REQUEST_HEADER = "Cookie"; public static final String DEFAULT_DOWNLOAD_PATH = diff --git a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java index e89798abf..fcef5ce71 100644 --- a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java +++ b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java @@ -31,7 +31,7 @@ */ class FetchUrlMimeType extends Thread { - private static final String TAG = FetchUrlMimeType.class.getSimpleName(); + private static final String TAG = "FetchUrlMimeType"; private final Activity mContext; private final DownloadManager.Request mRequest; diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 8862ee88c..aaf4a4783 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -68,7 +68,7 @@ public static BookmarksFragment createFragment(boolean isIncognito) { return bookmarksFragment; } - private final static String TAG = BookmarksFragment.class.getSimpleName(); + private static final String TAG = "BookmarksFragment"; public final static String INCOGNITO_MODE = TAG + ".INCOGNITO_MODE"; diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index 9723e7ae6..7d077dae0 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -70,7 +70,7 @@ public static TabsFragment createTabsFragment(boolean isIncognito, boolean showT return tabsFragment; } - private static final String TAG = TabsFragment.class.getSimpleName(); + private static final String TAG = "TabsFragment"; /** * Arguments boolean to tell the fragment it is displayed in the drawner or on the tab strip diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java index 6e279c4df..05e1b93b5 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java @@ -29,7 +29,7 @@ abstract class BaseSuggestionsModel { - private static final String TAG = BaseSuggestionsModel.class.getSimpleName(); + private static final String TAG = "BaseSuggestionsModel"; static final int MAX_RESULTS = 5; private static final long INTERVAL_DAY = TimeUnit.DAYS.toSeconds(1); diff --git a/app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java b/app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java index 814e1ebde..17d08e7ad 100644 --- a/app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/MemoryLeakUtils.java @@ -16,7 +16,7 @@ public class MemoryLeakUtils { - private static final String TAG = MemoryLeakUtils.class.getSimpleName(); + private static final String TAG = "MemoryLeakUtils"; @Nullable private static Method sFinishInputLocked = null; diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index 9b838b790..62a266992 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -56,7 +56,7 @@ public final class Utils { - private static final String TAG = Utils.class.getSimpleName(); + private static final String TAG = "Utils"; public static boolean doesSupportHeaders() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index ad267c458..4bf514e1e 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -69,7 +69,7 @@ */ public class LightningView { - private static final String TAG = LightningView.class.getSimpleName(); + private static final String TAG = "LightningView"; public static final String HEADER_REQUESTED_WITH = "X-Requested-With"; public static final String HEADER_WAP_PROFILE = "X-Wap-Profile"; From 6f4e4115d84bae2a893459ecf43e1519e77a039b Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 6 May 2017 19:58:12 -0400 Subject: [PATCH 098/181] Break out rotation animation into animation utils --- .../lightning/animation/AnimationUtils.java | 52 +++++++++++++++++++ .../lightning/fragment/BookmarksFragment.java | 49 ++--------------- 2 files changed, 55 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/animation/AnimationUtils.java diff --git a/app/src/main/java/acr/browser/lightning/animation/AnimationUtils.java b/app/src/main/java/acr/browser/lightning/animation/AnimationUtils.java new file mode 100644 index 000000000..825144847 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/animation/AnimationUtils.java @@ -0,0 +1,52 @@ +package acr.browser.lightning.animation; + +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Animation; +import android.view.animation.Transformation; +import android.widget.ImageView; + +/** + * Animation specific helper code. + */ +public class AnimationUtils { + + /** + * Creates an animation that rotates an {@link ImageView} + * around the Y axis by 180 degrees and changes the image + * resource shown when the view is rotated 90 degrees to the user. + * + * @param imageView the view to rotate. + * @param drawableRes the drawable to set when the view + * is rotated by 90 degrees. + * @return an animation that will change the image shown by the view. + */ + @NonNull + public static Animation createRotationTransitionAnimation(@NonNull final ImageView imageView, + @DrawableRes final int drawableRes) { + Animation animation = new Animation() { + + private boolean mSetFinalDrawable; + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + if (interpolatedTime < 0.5f) { + imageView.setRotationY(90 * interpolatedTime * 2f); + } else { + if (!mSetFinalDrawable) { + mSetFinalDrawable = true; + imageView.setImageResource(drawableRes); + } + imageView.setRotationY((-90) + (90 * (interpolatedTime - 0.5f) * 2f)); + } + } + }; + + animation.setDuration(300); + animation.setInterpolator(new AccelerateDecelerateInterpolator()); + + return animation; + } + +} diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index aaf4a4783..c48cffe42 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -16,10 +16,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Transformation; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -40,6 +37,7 @@ import acr.browser.lightning.R; import acr.browser.lightning.activity.ReadingActivity; import acr.browser.lightning.activity.TabsManager; +import acr.browser.lightning.animation.AnimationUtils; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.browser.BookmarksView; import acr.browser.lightning.constant.Constants; @@ -240,16 +238,6 @@ public void onDestroy() { } } - @Override - public void onStart() { - super.onStart(); - } - - @Override - public void onStop() { - super.onStop(); - } - public void reinitializePreferences() { Activity activity = getActivity(); if (activity == null) { @@ -293,40 +281,9 @@ private void setBookmarkDataSet(@NonNull List items, boolean animat resource = R.drawable.ic_action_back; } - final Animation startRotation = new Animation() { - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - mBookmarkTitleImage.setRotationY(90 * interpolatedTime); - } - }; - final Animation finishRotation = new Animation() { - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - mBookmarkTitleImage.setRotationY((-90) + (90 * interpolatedTime)); - } - }; - startRotation.setAnimationListener(new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - mBookmarkTitleImage.setImageResource(resource); - mBookmarkTitleImage.startAnimation(finishRotation); - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - }); - startRotation.setInterpolator(new AccelerateInterpolator()); - finishRotation.setInterpolator(new DecelerateInterpolator()); - startRotation.setDuration(250); - finishRotation.setDuration(250); - if (animate) { - mBookmarkTitleImage.startAnimation(startRotation); + Animation transition = AnimationUtils.createRotationTransitionAnimation(mBookmarkTitleImage, resource); + mBookmarkTitleImage.startAnimation(transition); } else { mBookmarkTitleImage.setImageResource(resource); } From efe33753897a2b5e81b2b350acedb64e92a1c2ca Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 6 May 2017 21:59:29 -0400 Subject: [PATCH 099/181] Making history page method static --- .../lightning/activity/BrowserActivity.java | 12 +++- .../lightning/activity/MainActivity.java | 2 +- .../lightning/constant/HistoryPage.java | 72 +++++++++---------- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 176c140e9..97ab0b36a 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -141,7 +141,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @BindView(R.id.progress_view) AnimatedProgressBar mProgressBar; @BindView(R.id.search_bar) RelativeLayout mSearchBar; - // Toolbar Views @BindView(R.id.toolbar) Toolbar mToolbar; private View mSearchBackground; @@ -214,6 +213,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements public abstract void updateHistory(@Nullable final String title, @NonNull final String url); + @NonNull abstract Completable updateCookiePreference(); @Override @@ -433,6 +433,14 @@ private int getTabsFragmentViewId() { } } + /** + * Determines if an intent is originating + * from a panic trigger. + * + * @param intent the intent to check. + * @return true if the panic trigger sent + * the intent, false otherwise. + */ static boolean isPanicTrigger(@Nullable Intent intent) { return intent != null && INTENT_PANIC_TRIGGER.equals(intent.getAction()); } @@ -442,7 +450,7 @@ void panicClean() { mTabsManager.newTab(this, "", false); mTabsManager.switchToTab(0); mTabsManager.clearSavedState(); - new HistoryPage().deleteHistoryPage().subscribe(); + HistoryPage.deleteHistoryPage(getApplication()).subscribe(); closeBrowser(); // System exit needed in the case of receiving // the panic intent since finish() isn't completely diff --git a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java index 3220d6508..058085937 100644 --- a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java @@ -34,7 +34,7 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) { } @Override - public boolean onCreateOptionsMenu(Menu menu) { + public boolean onCreateOptionsMenu(@NonNull Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } diff --git a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java index 6c179c67e..323c19072 100644 --- a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java @@ -68,41 +68,41 @@ public void onSubscribe(@NonNull final SingleSubscriber subscriber) { final StringBuilder historyBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2); HistoryModel.lastHundredVisitedHistoryItems() - .subscribe(new SingleOnSubscribe>() { - @Override - public void onItem(@Nullable List item) { - - Preconditions.checkNonNull(item); - Iterator it = item.iterator(); - HistoryItem helper; - while (it.hasNext()) { - helper = it.next(); - historyBuilder.append(PART1); - historyBuilder.append(helper.getUrl()); - historyBuilder.append(PART2); - historyBuilder.append(helper.getTitle()); - historyBuilder.append(PART3); - historyBuilder.append(helper.getUrl()); - historyBuilder.append(PART4); - } - - historyBuilder.append(END); - File historyWebPage = new File(mApp.getFilesDir(), FILENAME); - FileWriter historyWriter = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - historyWriter = new FileWriter(historyWebPage, false); - historyWriter.write(historyBuilder.toString()); - } catch (IOException e) { - Log.e(TAG, "Unable to write history page to disk", e); - } finally { - Utils.close(historyWriter); - } - - subscriber.onItem(Constants.FILE + historyWebPage); - subscriber.onComplete(); + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + + Preconditions.checkNonNull(item); + Iterator it = item.iterator(); + HistoryItem helper; + while (it.hasNext()) { + helper = it.next(); + historyBuilder.append(PART1); + historyBuilder.append(helper.getUrl()); + historyBuilder.append(PART2); + historyBuilder.append(helper.getTitle()); + historyBuilder.append(PART3); + historyBuilder.append(helper.getUrl()); + historyBuilder.append(PART4); } - }); + + historyBuilder.append(END); + File historyWebPage = new File(mApp.getFilesDir(), FILENAME); + FileWriter historyWriter = null; + try { + //noinspection IOResourceOpenedButNotSafelyClosed + historyWriter = new FileWriter(historyWebPage, false); + historyWriter.write(historyBuilder.toString()); + } catch (IOException e) { + Log.e(TAG, "Unable to write history page to disk", e); + } finally { + Utils.close(historyWriter); + } + + subscriber.onItem(Constants.FILE + historyWebPage); + subscriber.onComplete(); + } + }); } }); } @@ -116,11 +116,11 @@ public void onItem(@Nullable List item) { * when subscribed. */ @NonNull - public Completable deleteHistoryPage() { + public static Completable deleteHistoryPage(@NonNull final Application application) { return Completable.create(new CompletableAction() { @Override public void onSubscribe(@NonNull CompletableSubscriber subscriber) { - File historyWebPage = new File(mApp.getFilesDir(), FILENAME); + File historyWebPage = new File(application.getFilesDir(), FILENAME); if (historyWebPage.exists()) { historyWebPage.delete(); } From cf9dec3dcbf51985885aa31f4e5d06a413e9a597 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 6 May 2017 22:16:21 -0400 Subject: [PATCH 100/181] Removing unnecessary comments --- .../lightning/database/BookmarkManager.java | 22 +++++++++---------- .../lightning/database/HistoryModel.java | 3 --- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java index 045ae1ead..cf6fac45d 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java @@ -64,17 +64,6 @@ public BookmarkManager(@NonNull Context context) { mExecutor.execute(new BookmarkInitializer(context)); } - /** - * Look for bookmark using the url - * - * @param url the lookup url - * @return the bookmark as an {@link HistoryItem} or null - */ - @Nullable - public HistoryItem findBookmarkForUrl(final String url) { - return mBookmarksMap.get(url); - } - /** * Initialize the BookmarkManager, it's a one-time operation and will be executed asynchronously. * When done, mReady flag will been set to true. @@ -177,6 +166,17 @@ public void run() { } } + /** + * Look for bookmark using the url + * + * @param url the lookup url + * @return the bookmark as an {@link HistoryItem} or null + */ + @Nullable + public HistoryItem findBookmarkForUrl(final String url) { + return mBookmarksMap.get(url); + } + public boolean isBookmark(String url) { return mBookmarksMap.containsKey(url); } diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryModel.java b/app/src/main/java/acr/browser/lightning/database/HistoryModel.java index a58d5b6b9..a577c092b 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryModel.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryModel.java @@ -59,9 +59,6 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) { .historyDatabase() .visitHistoryItem(url, title); - System.out.println("SHIT: " + BrowserApp.getAppComponent().historyDatabase().toString()); - System.out.println("SHIT: " + BrowserApp.getAppComponent().historyDatabase().toString()); - subscriber.onComplete(); } }); From f148283053048f577c8a3a51b0d8e26774be2b70 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 7 May 2017 19:25:50 -0400 Subject: [PATCH 101/181] Moving bookmarks storage from flat file to database --- .../lightning/activity/BookmarkUiModel.java | 30 ++ .../lightning/activity/BrowserActivity.java | 66 ++- .../lightning/activity/TabsManager.java | 4 +- .../browser/lightning/app/AppComponent.java | 2 +- .../acr/browser/lightning/app/AppModule.java | 9 + .../acr/browser/lightning/app/BrowserApp.java | 21 + .../lightning/constant/BookmarkPage.java | 117 +++--- .../lightning/constant/HistoryPage.java | 2 +- .../lightning/database/HistoryItem.java | 14 +- .../database/bookmark/BookmarkDatabase.java | 375 ++++++++++++++++++ .../database/bookmark/BookmarkExporter.java | 166 ++++++++ .../{ => bookmark}/BookmarkLocalSync.java | 3 +- .../{ => bookmark}/BookmarkManager.java | 12 +- .../database/bookmark/BookmarkModel.java | 60 +++ .../{ => history}/HistoryDatabase.java | 3 +- .../database/{ => history}/HistoryModel.java | 3 +- .../dialog/LightningDialogBuilder.java | 120 ++++-- .../fragment/BookmarkSettingsFragment.java | 62 ++- .../lightning/fragment/BookmarksFragment.java | 103 +++-- .../lightning/search/SuggestionsAdapter.java | 25 +- .../acr/browser/lightning/utils/WebUtils.java | 2 +- .../browser/lightning/view/LightningView.java | 6 +- 22 files changed, 1006 insertions(+), 199 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/activity/BookmarkUiModel.java create mode 100644 app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java create mode 100644 app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkExporter.java rename app/src/main/java/acr/browser/lightning/database/{ => bookmark}/BookmarkLocalSync.java (98%) rename app/src/main/java/acr/browser/lightning/database/{ => bookmark}/BookmarkManager.java (98%) create mode 100644 app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java rename app/src/main/java/acr/browser/lightning/database/{ => history}/HistoryDatabase.java (98%) rename app/src/main/java/acr/browser/lightning/database/{ => history}/HistoryModel.java (96%) diff --git a/app/src/main/java/acr/browser/lightning/activity/BookmarkUiModel.java b/app/src/main/java/acr/browser/lightning/activity/BookmarkUiModel.java new file mode 100644 index 000000000..5895dee4c --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/activity/BookmarkUiModel.java @@ -0,0 +1,30 @@ +package acr.browser.lightning.activity; + +import android.support.annotation.Nullable; + +import acr.browser.lightning.browser.BookmarksView; + +/** + * The UI model representing the current folder shown + * by the {@link BookmarksView}. + *

+ * Created by anthonycr on 5/7/17. + */ +public class BookmarkUiModel { + + @Nullable private String mCurrentFolder; + + public void setCurrentFolder(@Nullable String folder) { + mCurrentFolder = folder; + } + + public boolean isRootFolder() { + return mCurrentFolder == null; + } + + @Nullable + public String getCurrentFolder() { + return mCurrentFolder; + } + +} diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 97ab0b36a..71f44fab8 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -99,9 +99,9 @@ import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.controller.UIController; -import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; -import acr.browser.lightning.database.HistoryModel; +import acr.browser.lightning.database.bookmark.BookmarkModel; +import acr.browser.lightning.database.history.HistoryModel; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.fragment.BookmarksFragment; @@ -181,7 +181,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private String mCameraPhotoPath; // The singleton BookmarkManager - @Inject BookmarkManager mBookmarkManager; + @Inject BookmarkModel mBookmarkManager; @Inject LightningDialogBuilder mBookmarksDialogBuilder; @@ -827,23 +827,37 @@ public boolean onOptionsItemSelected(MenuItem item) { // By using a manager, adds a bookmark and notifies third parties about that private void addBookmark(final String title, final String url) { - final HistoryItem item = !mBookmarkManager.isBookmark(url) - ? new HistoryItem(url, title) - : null; - if (item != null && mBookmarkManager.addBookmark(item)) { - mSuggestionsAdapter.refreshBookmarks(); - mBookmarksView.handleUpdatedUrl(url); - } + + final HistoryItem item = new HistoryItem(url, title); + mBookmarkManager.addBookmarkIfNotExists(item) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean item) { + if (Boolean.TRUE.equals(item)) { + mSuggestionsAdapter.refreshBookmarks(); + mBookmarksView.handleUpdatedUrl(url); + } + } + }); } private void deleteBookmark(final String title, final String url) { - final HistoryItem item = mBookmarkManager.isBookmark(url) - ? new HistoryItem(url, title) - : null; - if (item != null && mBookmarkManager.deleteBookmark(item)) { - mSuggestionsAdapter.refreshBookmarks(); - mBookmarksView.handleUpdatedUrl(url); - } + final HistoryItem item = new HistoryItem(url, title); + + mBookmarkManager.deleteBookmark(item) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean item) { + if (Boolean.TRUE.equals(item)) { + mSuggestionsAdapter.refreshBookmarks(); + mBookmarksView.handleUpdatedUrl(url); + } + } + }); } private void putToolbarInRoot() { @@ -1098,11 +1112,19 @@ public void bookmarkButtonClicked() { } if (!UrlUtils.isSpecialUrl(url)) { - if (!mBookmarkManager.isBookmark(url)) { - addBookmark(title, url); - } else { - deleteBookmark(title, url); - } + mBookmarkManager.isBookmark(url) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean item) { + if (Boolean.TRUE.equals(item)) { + addBookmark(title, url); + } else { + deleteBookmark(title, url); + } + } + }); } } diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 02f825dfb..e2bf71355 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -35,7 +35,6 @@ import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.constant.StartPage; -import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.FileUtils; @@ -51,7 +50,7 @@ public class TabsManager { private static final String TAG = "TabsManager"; - + private static final String BUNDLE_KEY = "WEBVIEW_"; private static final String URL_KEY = "URL_KEY"; private static final String BUNDLE_STORAGE = "SAVED_TABS.parcel"; @@ -64,7 +63,6 @@ public class TabsManager { private final List mPostInitializationWorkList = new ArrayList<>(); @Inject PreferenceManager mPreferenceManager; - @Inject BookmarkManager mBookmarkManager; @Inject Application mApp; public TabsManager() { diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index 12ed5ef25..6605da1f1 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -11,7 +11,7 @@ import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.constant.StartPage; -import acr.browser.lightning.database.HistoryDatabase; +import acr.browser.lightning.database.history.HistoryDatabase; import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.download.LightningDownloadListener; import acr.browser.lightning.fragment.BookmarkSettingsFragment; diff --git a/app/src/main/java/acr/browser/lightning/app/AppModule.java b/app/src/main/java/acr/browser/lightning/app/AppModule.java index 605baf277..d4c68f8c9 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppModule.java +++ b/app/src/main/java/acr/browser/lightning/app/AppModule.java @@ -8,6 +8,8 @@ import javax.inject.Singleton; +import acr.browser.lightning.database.bookmark.BookmarkDatabase; +import acr.browser.lightning.database.bookmark.BookmarkModel; import dagger.Module; import dagger.Provides; @@ -29,6 +31,13 @@ public Context provideContext() { return mApp.getApplicationContext(); } + @NonNull + @Provides + @Singleton + public BookmarkModel provideBookmarkMode() { + return new BookmarkDatabase(mApp); + } + @NonNull @Provides @Singleton diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index 1fd4962ac..916a31f82 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -12,14 +12,19 @@ import android.util.Log; import android.webkit.WebView; +import com.anthonycr.bonsai.Schedulers; import com.squareup.leakcanary.LeakCanary; +import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import javax.inject.Inject; import acr.browser.lightning.BuildConfig; +import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.database.bookmark.BookmarkManager; +import acr.browser.lightning.database.bookmark.BookmarkModel; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.FileUtils; import acr.browser.lightning.utils.MemoryLeakUtils; @@ -33,6 +38,8 @@ public class BrowserApp extends Application { private static final Executor mIOThread = Executors.newSingleThreadExecutor(); @Inject PreferenceManager mPreferenceManager; + @Inject BookmarkManager mOldBookmarkManager; + @Inject BookmarkModel mBookmarkModel; @Override protected void attachBaseContext(Context base) { @@ -74,6 +81,20 @@ public void uncaughtException(Thread thread, @NonNull Throwable ex) { sAppComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); sAppComponent.inject(this); + Schedulers.worker().execute(new Runnable() { + @Override + public void run() { + List oldBookmarks = mOldBookmarkManager.getAllBookmarks(true); + mOldBookmarkManager.deleteAllBookmarks(); + + if (!oldBookmarks.isEmpty()) { + mBookmarkModel.addBookmarkList(oldBookmarks).subscribeOn(Schedulers.io()).subscribe(); + } else { + // TODO: 5/7/17 Import bookmarks from assets if not empty + } + } + }); + if (mPreferenceManager.getUseLeakCanary() && !isRelease()) { LeakCanary.install(this); } diff --git a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java index bdf878d3f..208dc811a 100644 --- a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java @@ -11,6 +11,7 @@ import com.anthonycr.bonsai.Single; import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.bonsai.SingleSubscriber; import java.io.File; @@ -24,8 +25,9 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.database.bookmark.BookmarkModel; +import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.utils.Utils; @@ -37,25 +39,25 @@ public final class BookmarkPage { public static final String FILENAME = "bookmarks.html"; private static final String HEADING_1 = "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - ""; + "<head>\n" + + "<meta content=en-us http-equiv=Content-Language />\n" + + "<meta content='text/html; charset=utf-8' http-equiv=Content-Type />\n" + + "<meta name=viewport content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>\n" + + "<title>"; private static final String HEADING_2 = "\n" + - "\n" + - "\n" + - "

"; + "\n" + + "\n" + + "
"; private static final String PART1 = "
\n" + - "
\n" + - "
\n" + - "

\n" + - " list = mManager.getBookmarksCopyFromFolder(folder, true); - final File bookmarkWebPage; - if (folder == null || folder.isEmpty()) { - bookmarkWebPage = new File(mFilesDir, FILENAME); - } else { - bookmarkWebPage = new File(mFilesDir, folder + '-' + FILENAME); - } - final StringBuilder bookmarkBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2); - - final String folderIconPath = Constants.FILE + mCacheDir + '/' + FOLDER_ICON; - for (int n = 0, size = list.size(); n < size; n++) { - final HistoryItem item = list.get(n); - bookmarkBuilder.append(PART1); - if (item.isFolder()) { - final File folderPage = new File(mFilesDir, item.getTitle() + '-' + FILENAME); - bookmarkBuilder.append(Constants.FILE).append(folderPage); - bookmarkBuilder.append(PART2); - bookmarkBuilder.append(folderIconPath); - buildBookmarkPage(item.getTitle()); - } else { - bookmarkBuilder.append(item.getUrl()); - bookmarkBuilder.append(PART2).append(PART3); - bookmarkBuilder.append(item.getUrl()); - } - bookmarkBuilder.append(PART4); - bookmarkBuilder.append(item.getTitle()); - bookmarkBuilder.append(PART5); - } - bookmarkBuilder.append(END); - FileWriter bookWriter = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - bookWriter = new FileWriter(bookmarkWebPage, false); - bookWriter.write(bookmarkBuilder.toString()); - } catch (IOException e) { - e.printStackTrace(); - } finally { - Utils.close(bookWriter); - } + mManager.getBookmarksFromFolder(folder) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List list) { + Preconditions.checkNonNull(list); + + final File bookmarkWebPage; + if (folder == null || folder.isEmpty()) { + bookmarkWebPage = new File(mFilesDir, FILENAME); + } else { + bookmarkWebPage = new File(mFilesDir, folder + '-' + FILENAME); + } + final StringBuilder bookmarkBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2); + + final String folderIconPath = Constants.FILE + mCacheDir + '/' + FOLDER_ICON; + for (int n = 0, size = list.size(); n < size; n++) { + final HistoryItem item = list.get(n); + bookmarkBuilder.append(PART1); + if (item.isFolder()) { + final File folderPage = new File(mFilesDir, item.getTitle() + '-' + FILENAME); + bookmarkBuilder.append(Constants.FILE).append(folderPage); + bookmarkBuilder.append(PART2); + bookmarkBuilder.append(folderIconPath); + buildBookmarkPage(item.getTitle()); + } else { + bookmarkBuilder.append(item.getUrl()); + bookmarkBuilder.append(PART2).append(PART3); + bookmarkBuilder.append(item.getUrl()); + } + bookmarkBuilder.append(PART4); + bookmarkBuilder.append(item.getTitle()); + bookmarkBuilder.append(PART5); + } + bookmarkBuilder.append(END); + FileWriter bookWriter = null; + try { + //noinspection IOResourceOpenedButNotSafelyClosed + bookWriter = new FileWriter(bookmarkWebPage, false); + bookWriter.write(bookmarkBuilder.toString()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + Utils.close(bookWriter); + } + } + }); } } diff --git a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java index 323c19072..b175082aa 100644 --- a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java @@ -27,7 +27,7 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.HistoryItem; -import acr.browser.lightning.database.HistoryModel; +import acr.browser.lightning.database.history.HistoryModel; import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.Utils; diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryItem.java b/app/src/main/java/acr/browser/lightning/database/HistoryItem.java index b439b1bce..9021e7380 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryItem.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryItem.java @@ -25,7 +25,7 @@ public class HistoryItem implements Comparable { private Bitmap mBitmap = null; private int mImageId = 0; - private int mOrder = 0; + private int mPosition = 0; private boolean mIsFolder = false; public HistoryItem() {} @@ -63,12 +63,12 @@ public void setFolder(@Nullable String folder) { mFolder = (folder == null) ? "" : folder; } - public void setOrder(int order) { - mOrder = order; + public void setPosition(int order) { + mPosition = order; } - public int getOrder() { - return mOrder; + public int getPosition() { + return mPosition; } @NonNull @@ -132,8 +132,8 @@ public boolean equals(@Nullable Object object) { HistoryItem that = (HistoryItem) object; return mImageId == that.mImageId && - this.mTitle.equals(that.mTitle) && this.mUrl.equals(that.mUrl) && - this.mFolder.equals(that.mFolder); + this.mTitle.equals(that.mTitle) && this.mUrl.equals(that.mUrl) && + this.mFolder.equals(that.mFolder); } @Override diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java new file mode 100644 index 000000000..3bfcf1fce --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java @@ -0,0 +1,375 @@ +package acr.browser.lightning.database.bookmark; + +import android.app.Application; +import android.content.ContentValues; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import acr.browser.lightning.R; +import acr.browser.lightning.constant.Constants; +import acr.browser.lightning.database.HistoryItem; + +/** + * The disk backed bookmark database. + *

+ * Created by anthonycr on 5/6/17. + */ +@Singleton +public class BookmarkDatabase extends SQLiteOpenHelper implements BookmarkModel { + + private static final String TAG = "BookmarkDatabase"; + + // Database Version + private static final int DATABASE_VERSION = 1; + + // Database Name + private static final String DATABASE_NAME = "bookmarkManager"; + + // HistoryItems table name + private static final String TABLE_BOOKMARK = "bookmark"; + + // HistoryItems Table Columns names + private static final String KEY_ID = "id"; + private static final String KEY_URL = "url"; + private static final String KEY_TITLE = "title"; + private static final String KEY_FOLDER = "folder"; + private static final String KEY_POSITION = "position"; + + + @NonNull private final String DEFAULT_BOOKMARK_TITLE; + + @Nullable private SQLiteDatabase mDatabase; + + @Inject + public BookmarkDatabase(@NonNull Application application) { + super(application, DATABASE_NAME, null, DATABASE_VERSION); + DEFAULT_BOOKMARK_TITLE = application.getString(R.string.untitled); + } + + @NonNull + private SQLiteDatabase lazyDatabase() { + if (mDatabase == null) { + mDatabase = getWritableDatabase(); + } + + return mDatabase; + } + + // Creating Tables + @Override + public void onCreate(@NonNull SQLiteDatabase db) { + String CREATE_BOOKMARK_TABLE = "CREATE TABLE " + + DatabaseUtils.sqlEscapeString(TABLE_BOOKMARK) + '(' + + DatabaseUtils.sqlEscapeString(KEY_ID) + " INTEGER PRIMARY KEY," + + DatabaseUtils.sqlEscapeString(KEY_URL) + " TEXT," + + DatabaseUtils.sqlEscapeString(KEY_TITLE) + " TEXT," + + DatabaseUtils.sqlEscapeString(KEY_FOLDER) + " TEXT," + + DatabaseUtils.sqlEscapeString(KEY_POSITION) + " INTEGER" + ')'; + db.execSQL(CREATE_BOOKMARK_TABLE); + } + + // Upgrading database + @Override + public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { + // Drop older table if it exists + db.execSQL("DROP TABLE IF EXISTS " + DatabaseUtils.sqlEscapeString(TABLE_BOOKMARK)); + // Create tables again + onCreate(db); + } + + @NonNull + private static ContentValues bindBookmarkToContentValues(@NonNull HistoryItem historyItem) { + ContentValues contentValues = new ContentValues(4); + contentValues.put(KEY_TITLE, historyItem.getTitle()); + contentValues.put(KEY_URL, historyItem.getUrl()); + contentValues.put(KEY_FOLDER, historyItem.getFolder()); + contentValues.put(KEY_POSITION, historyItem.getPosition()); + + return contentValues; + } + + @NonNull + private static HistoryItem bindCursorToHistoryItem(@NonNull Cursor cursor) { + HistoryItem bookmark = new HistoryItem(); + + bookmark.setImageId(R.drawable.ic_bookmark); + bookmark.setUrl(cursor.getString(cursor.getColumnIndex(KEY_URL))); + bookmark.setTitle(cursor.getString(cursor.getColumnIndex(KEY_TITLE))); + bookmark.setFolder(cursor.getString(cursor.getColumnIndex(KEY_FOLDER))); + bookmark.setPosition(cursor.getInt(cursor.getColumnIndex(KEY_POSITION))); + + return bookmark; + } + + @NonNull + private static List bindCursorToHistoryItemList(@NonNull Cursor cursor) { + List bookmarks = new ArrayList<>(); + + while (cursor.moveToNext()) { + bookmarks.add(bindCursorToHistoryItem(cursor)); + } + + cursor.close(); + + return bookmarks; + } + + @NonNull + @Override + public Single findBookmarkForUrl(@NonNull final String url) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + Cursor cursor = lazyDatabase().query(TABLE_BOOKMARK, null, KEY_URL + "=?", new String[]{url}, null, null, null, "1"); + + if (cursor.moveToFirst()) { + subscriber.onItem(bindCursorToHistoryItem(cursor)); + } + + cursor.close(); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single isBookmark(@NonNull final String url) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + Cursor cursor = lazyDatabase().query(TABLE_BOOKMARK, null, KEY_URL + "=?", new String[]{url}, null, null, null, "1"); + + subscriber.onItem(cursor.moveToFirst()); + + cursor.close(); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single addBookmarkIfNotExists(@NonNull final HistoryItem item) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + Cursor cursor = lazyDatabase().query(TABLE_BOOKMARK, null, KEY_URL + "=?", new String[]{item.getUrl()}, null, null, null, "1"); + + if (cursor.moveToFirst()) { + cursor.close(); + subscriber.onItem(false); + subscriber.onComplete(); + return; + } + + cursor.close(); + + long id = lazyDatabase().insert(TABLE_BOOKMARK, null, bindBookmarkToContentValues(item)); + + subscriber.onItem(id != -1); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Completable addBookmarkList(@NonNull final List bookmarkItems) { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + lazyDatabase().beginTransaction(); + + for (HistoryItem item : bookmarkItems) { + addBookmarkIfNotExists(item).subscribe(); + } + + lazyDatabase().setTransactionSuccessful(); + lazyDatabase().endTransaction(); + + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single deleteBookmark(@NonNull final HistoryItem bookmark) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + int rows = lazyDatabase().delete(TABLE_BOOKMARK, KEY_URL + "=?", new String[]{bookmark.getUrl()}); + + subscriber.onItem(rows > 0); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Completable renameFolder(@NonNull final String oldName, @NonNull final String newName) { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + ContentValues contentValues = new ContentValues(1); + contentValues.put(KEY_FOLDER, newName); + + lazyDatabase().update(TABLE_BOOKMARK, contentValues, KEY_FOLDER + "=?", new String[]{oldName}); + + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Completable deleteFolder(@NonNull final String folderToDelete) { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + renameFolder(folderToDelete, "").subscribe(); + + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Completable deleteAllBookmarks() { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + lazyDatabase().delete(TABLE_BOOKMARK, null, null); + + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Completable editBookmark(@NonNull final HistoryItem oldBookmark, @NonNull final HistoryItem newBookmark) { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + if (newBookmark.getTitle().isEmpty()) { + newBookmark.setTitle(DEFAULT_BOOKMARK_TITLE); + } + ContentValues contentValues = bindBookmarkToContentValues(newBookmark); + + lazyDatabase().update(TABLE_BOOKMARK, contentValues, KEY_URL + "=?", new String[]{oldBookmark.getUrl()}); + + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single> getAllBookmarks() { + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { + Cursor cursor = lazyDatabase().query(TABLE_BOOKMARK, null, null, null, null, null, null); + + subscriber.onItem(bindCursorToHistoryItemList(cursor)); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single> getBookmarksFromFolder(@Nullable final String folder) { + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { + String finalFolder = folder != null ? folder : ""; + Cursor cursor = lazyDatabase().query(TABLE_BOOKMARK, null, KEY_FOLDER + "=?", new String[]{finalFolder}, null, null, null); + + subscriber.onItem(bindCursorToHistoryItemList(cursor)); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single> getFolders() { + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { + Cursor cursor = lazyDatabase().query(true, TABLE_BOOKMARK, new String[]{KEY_FOLDER}, null, null, null, null, null, null); + + List folders = new ArrayList<>(); + while (cursor.moveToNext()) { + String folderName = cursor.getString(cursor.getColumnIndex(KEY_FOLDER)); + if (TextUtils.isEmpty(folderName)) { + continue; + } + + final HistoryItem folder = new HistoryItem(); + folder.setIsFolder(true); + folder.setTitle(folderName); + folder.setImageId(R.drawable.ic_folder); + folder.setUrl(Constants.FOLDER + folderName); + + folders.add(folder); + } + + cursor.close(); + + subscriber.onItem(folders); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single> getFolderNames() { + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { + Cursor cursor = lazyDatabase().query(true, TABLE_BOOKMARK, new String[]{KEY_FOLDER}, null, null, null, null, null, null); + + List folders = new ArrayList<>(); + while (cursor.moveToNext()) { + String folderName = cursor.getString(cursor.getColumnIndex(KEY_FOLDER)); + if (TextUtils.isEmpty(folderName)) { + continue; + } + + folders.add(folderName); + } + + cursor.close(); + + subscriber.onItem(folders); + subscriber.onComplete(); + } + }); + } + +} diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkExporter.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkExporter.java new file mode 100644 index 000000000..05557f824 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkExporter.java @@ -0,0 +1,166 @@ +package acr.browser.lightning.database.bookmark; + +import android.content.Context; +import android.os.Environment; +import android.support.annotation.NonNull; +import android.support.annotation.WorkerThread; +import android.util.Log; + +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +import acr.browser.lightning.R; +import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.utils.Preconditions; +import acr.browser.lightning.utils.Utils; + +/** + * The class responsible for importing and exporting + * bookmarks in the JSON format. + *

+ * Created by anthonycr on 5/7/17. + */ +public class BookmarkExporter { + + private static final String TAG = "BookmarkExporter"; + + private static final String KEY_URL = "url"; + private static final String KEY_TITLE = "title"; + private static final String KEY_FOLDER = "folder"; + private static final String KEY_ORDER = "order"; + + @NonNull + public static List importBookmarksFromAssets(@NonNull Context context) { + List bookmarks = new ArrayList<>(); + BufferedReader bookmarksReader = null; + InputStream inputStream = null; + try { + inputStream = context.getResources().openRawResource(R.raw.default_bookmarks); + //noinspection IOResourceOpenedButNotSafelyClosed + bookmarksReader = new BufferedReader(new InputStreamReader(inputStream)); + String line; + while ((line = bookmarksReader.readLine()) != null) { + try { + JSONObject object = new JSONObject(line); + HistoryItem item = new HistoryItem(); + item.setTitle(object.getString(KEY_TITLE)); + final String url = object.getString(KEY_URL); + item.setUrl(url); + item.setFolder(object.getString(KEY_FOLDER)); + item.setPosition(object.getInt(KEY_ORDER)); + item.setImageId(R.drawable.ic_bookmark); + bookmarks.add(item); + } catch (JSONException e) { + Log.e(TAG, "Can't parse line " + line, e); + } + } + } catch (IOException e) { + Log.e(TAG, "Error reading the bookmarks file", e); + } finally { + Utils.close(bookmarksReader); + Utils.close(inputStream); + } + + return bookmarks; + } + + @NonNull + public static Completable exportBookmarksToFile(@NonNull final List bookmarkList, + @NonNull final File file) { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull final CompletableSubscriber subscriber) { + Preconditions.checkNonNull(bookmarkList); + BufferedWriter bookmarkWriter = null; + try { + //noinspection IOResourceOpenedButNotSafelyClosed + bookmarkWriter = new BufferedWriter(new FileWriter(file, false)); + + JSONObject object = new JSONObject(); + for (HistoryItem item : bookmarkList) { + object.put(KEY_TITLE, item.getTitle()); + object.put(KEY_URL, item.getUrl()); + object.put(KEY_FOLDER, item.getFolder()); + object.put(KEY_ORDER, item.getPosition()); + bookmarkWriter.write(object.toString()); + bookmarkWriter.newLine(); + } + subscriber.onComplete(); + } catch (@NonNull IOException | JSONException e) { + subscriber.onError(e); + } finally { + Utils.close(bookmarkWriter); + } + } + }); + } + + @NonNull + public static Single> importBookmarksFromFile(@NonNull final File file) { + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { + BufferedReader bookmarksReader = null; + try { + //noinspection IOResourceOpenedButNotSafelyClosed + bookmarksReader = new BufferedReader(new FileReader(file)); + String line; + + List bookmarks = new ArrayList<>(); + while ((line = bookmarksReader.readLine()) != null) { + JSONObject object = new JSONObject(line); + HistoryItem item = new HistoryItem(); + item.setTitle(object.getString(KEY_TITLE)); + item.setUrl(object.getString(KEY_URL)); + item.setFolder(object.getString(KEY_FOLDER)); + item.setPosition(object.getInt(KEY_ORDER)); + bookmarks.add(item); + } + + subscriber.onItem(bookmarks); + subscriber.onComplete(); + } catch (IOException | JSONException e) { + subscriber.onError(e); + } finally { + Utils.close(bookmarksReader); + } + } + }); + } + + @WorkerThread + @NonNull + public static File createNewExportFile() { + File bookmarksExport = new File( + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), + "BookmarksExport.txt"); + int counter = 0; + while (bookmarksExport.exists()) { + counter++; + bookmarksExport = new File( + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), + "BookmarksExport-" + counter + ".txt"); + } + + return bookmarksExport; + } + +} diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkLocalSync.java similarity index 98% rename from app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java rename to app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkLocalSync.java index ce329a956..d7bd6d7d6 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkLocalSync.java @@ -1,4 +1,4 @@ -package acr.browser.lightning.database; +package acr.browser.lightning.database.bookmark; import android.content.Context; import android.database.Cursor; @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.List; +import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.utils.Utils; public class BookmarkLocalSync { diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkManager.java similarity index 98% rename from app/src/main/java/acr/browser/lightning/database/BookmarkManager.java rename to app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkManager.java index cf6fac45d..8eb1132ec 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkManager.java @@ -1,4 +1,4 @@ -package acr.browser.lightning.database; +package acr.browser.lightning.database.bookmark; import android.app.Activity; import android.content.Context; @@ -37,8 +37,10 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; +import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.utils.Utils; +@Deprecated @Singleton public class BookmarkManager { @@ -102,7 +104,7 @@ public void run() { final String url = object.getString(URL); item.setUrl(url); item.setFolder(object.getString(FOLDER)); - item.setOrder(object.getInt(ORDER)); + item.setPosition(object.getInt(ORDER)); item.setImageId(R.drawable.ic_bookmark); bookmarks.put(url, item); } catch (JSONException e) { @@ -147,7 +149,7 @@ public void run() { object.put(TITLE, item.getTitle()); object.put(URL, item.getUrl()); object.put(FOLDER, item.getFolder()); - object.put(ORDER, item.getOrder()); + object.put(ORDER, item.getPosition()); bookmarkWriter.write(object.toString()); bookmarkWriter.newLine(); } @@ -339,7 +341,7 @@ public synchronized void exportBookmarks(@NonNull Activity activity) { object.put(TITLE, item.getTitle()); object.put(URL, item.getUrl()); object.put(FOLDER, item.getFolder()); - object.put(ORDER, item.getOrder()); + object.put(ORDER, item.getPosition()); bookmarkWriter.write(object.toString()); bookmarkWriter.newLine(); } @@ -515,7 +517,7 @@ public synchronized void importBookmarksFromFile(@Nullable File file, @NonNull A item.setTitle(object.getString(TITLE)); item.setUrl(object.getString(URL)); item.setFolder(object.getString(FOLDER)); - item.setOrder(object.getInt(ORDER)); + item.setPosition(object.getInt(ORDER)); list.add(item); number++; } diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java new file mode 100644 index 000000000..9d27d2c36 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java @@ -0,0 +1,60 @@ +package acr.browser.lightning.database.bookmark; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.Single; + +import java.io.File; +import java.util.List; + +import acr.browser.lightning.database.HistoryItem; + +/** + * The interface that should be used to + * communicate with the bookmark database. + *

+ * Created by anthonycr on 5/6/17. + */ +public interface BookmarkModel { + + @NonNull + Single findBookmarkForUrl(@NonNull String url); + + @NonNull + Single isBookmark(@NonNull String url); + + @NonNull + Single addBookmarkIfNotExists(@NonNull HistoryItem item); + + @NonNull + Completable addBookmarkList(@NonNull List bookmarkItems); + + @NonNull + Single deleteBookmark(@NonNull HistoryItem bookmark); + + @NonNull + Completable renameFolder(@NonNull String oldName, @NonNull String newName); + + @NonNull + Completable deleteFolder(@NonNull String folderToDelete); + + @NonNull + Completable deleteAllBookmarks(); + + @NonNull + Completable editBookmark(@NonNull HistoryItem oldBookmark, @NonNull HistoryItem newBookmark); + + @NonNull + Single> getAllBookmarks(); + + @NonNull + Single> getBookmarksFromFolder(@Nullable String folder); + + @NonNull + Single> getFolders(); + + @NonNull + Single> getFolderNames(); +} diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java b/app/src/main/java/acr/browser/lightning/database/history/HistoryDatabase.java similarity index 98% rename from app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java rename to app/src/main/java/acr/browser/lightning/database/history/HistoryDatabase.java index 07ae7ccc0..7bbc07e32 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/history/HistoryDatabase.java @@ -1,7 +1,7 @@ /* * Copyright 2014 A.C.R. Development */ -package acr.browser.lightning.database; +package acr.browser.lightning.database.history; import android.app.Application; import android.content.ContentValues; @@ -20,6 +20,7 @@ import javax.inject.Singleton; import acr.browser.lightning.R; +import acr.browser.lightning.database.HistoryItem; @Singleton @WorkerThread diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryModel.java b/app/src/main/java/acr/browser/lightning/database/history/HistoryModel.java similarity index 96% rename from app/src/main/java/acr/browser/lightning/database/HistoryModel.java rename to app/src/main/java/acr/browser/lightning/database/history/HistoryModel.java index a577c092b..36605846e 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryModel.java +++ b/app/src/main/java/acr/browser/lightning/database/history/HistoryModel.java @@ -1,4 +1,4 @@ -package acr.browser.lightning.database; +package acr.browser.lightning.database.history; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -13,6 +13,7 @@ import java.util.List; import acr.browser.lightning.app.BrowserApp; +import acr.browser.lightning.database.HistoryItem; /** * A model class providing reactive bindings diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index b07cb8831..12022996c 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -5,6 +5,7 @@ import android.content.DialogInterface; import android.net.Uri; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v7.app.AlertDialog; import android.text.TextUtils; import android.view.View; @@ -14,6 +15,7 @@ import com.anthonycr.bonsai.CompletableOnSubscribe; import com.anthonycr.bonsai.Schedulers; +import com.anthonycr.bonsai.SingleOnSubscribe; import java.util.List; @@ -25,10 +27,11 @@ import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.controller.UIController; -import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; -import acr.browser.lightning.database.HistoryModel; +import acr.browser.lightning.database.bookmark.BookmarkModel; +import acr.browser.lightning.database.history.HistoryModel; import acr.browser.lightning.preference.PreferenceManager; +import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.Utils; /** @@ -44,7 +47,7 @@ public enum NewTab { INCOGNITO } - @Inject BookmarkManager mBookmarkManager; + @Inject BookmarkModel mBookmarkManager; @Inject PreferenceManager mPreferenceManager; @Inject @@ -60,7 +63,7 @@ public LightningDialogBuilder() { * @param url the long pressed url */ public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity activity, - @NonNull UIController uiController, + @NonNull final UIController uiController, @NonNull final String url) { final HistoryItem item; if (url.startsWith(Constants.FILE) && url.endsWith(BookmarkPage.FILENAME)) { @@ -73,15 +76,19 @@ public void showLongPressedDialogForBookmarkUrl(@NonNull final Activity activity item.setTitle(folderTitle); item.setImageId(R.drawable.ic_folder); item.setUrl(Constants.FOLDER + folderTitle); + showBookmarkFolderLongPressedDialog(activity, uiController, item); } else { - item = mBookmarkManager.findBookmarkForUrl(url); - } - if (item != null) { - if (item.isFolder()) { - showBookmarkFolderLongPressedDialog(activity, uiController, item); - } else { - showLongPressedDialogForBookmarkUrl(activity, uiController, item); - } + mBookmarkManager.findBookmarkForUrl(url) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable HistoryItem historyItem) { + if (historyItem != null) { + showLongPressedDialogForBookmarkUrl(activity, uiController, historyItem); + } + } + }); } } @@ -116,9 +123,18 @@ public void onClick() { new BrowserDialog.Item(R.string.dialog_remove_bookmark) { @Override public void onClick() { - if (mBookmarkManager.deleteBookmark(item)) { - uiController.handleBookmarkDeleted(item); - } + mBookmarkManager.deleteBookmark(item) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean success) { + Preconditions.checkNonNull(success); + if (success) { + uiController.handleBookmarkDeleted(item); + } + } + }); } }, new BrowserDialog.Item(R.string.dialog_edit_bookmark) { @@ -143,28 +159,44 @@ private void showEditBookmarkDialog(@NonNull final Activity activity, (AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder); getFolder.setHint(R.string.folder); getFolder.setText(item.getFolder()); - final List folders = mBookmarkManager.getFolderTitles(); - final ArrayAdapter suggestionsAdapter = new ArrayAdapter<>(activity, - android.R.layout.simple_dropdown_item_1line, folders); - getFolder.setThreshold(1); - getFolder.setAdapter(suggestionsAdapter); - editBookmarkDialog.setView(dialogLayout); - editBookmarkDialog.setPositiveButton(activity.getString(R.string.action_ok), - new DialogInterface.OnClickListener() { + mBookmarkManager.getFolderNames() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe>() { @Override - public void onClick(DialogInterface dialog, int which) { - HistoryItem editedItem = new HistoryItem(); - editedItem.setTitle(getTitle.getText().toString()); - editedItem.setUrl(getUrl.getText().toString()); - editedItem.setUrl(getUrl.getText().toString()); - editedItem.setFolder(getFolder.getText().toString()); - mBookmarkManager.editBookmark(item, editedItem); - uiController.handleBookmarksChange(); + public void onItem(@Nullable List folders) { + Preconditions.checkNonNull(folders); + final ArrayAdapter suggestionsAdapter = new ArrayAdapter<>(activity, + android.R.layout.simple_dropdown_item_1line, folders); + getFolder.setThreshold(1); + getFolder.setAdapter(suggestionsAdapter); + editBookmarkDialog.setView(dialogLayout); + editBookmarkDialog.setPositiveButton(activity.getString(R.string.action_ok), + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + HistoryItem editedItem = new HistoryItem(); + editedItem.setTitle(getTitle.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setFolder(getFolder.getText().toString()); + mBookmarkManager.editBookmark(item, editedItem) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + uiController.handleBookmarksChange(); + } + }); + } + }); + Dialog dialog = editBookmarkDialog.show(); + BrowserDialog.setDialogSize(activity, dialog); } }); - Dialog dialog = editBookmarkDialog.show(); - BrowserDialog.setDialogSize(activity, dialog); } public void showBookmarkFolderLongPressedDialog(@NonNull final Activity activity, @@ -181,8 +213,15 @@ public void onClick() { new BrowserDialog.Item(R.string.dialog_remove_folder) { @Override public void onClick() { - mBookmarkManager.deleteFolder(item.getTitle()); - uiController.handleBookmarkDeleted(item); + mBookmarkManager.deleteFolder(item.getTitle()) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + uiController.handleBookmarkDeleted(item); + } + }); } }); } @@ -202,8 +241,15 @@ public void onClick(@NonNull String text) { editedItem.setUrl(Constants.FOLDER + text); editedItem.setFolder(item.getFolder()); editedItem.setIsFolder(true); - mBookmarkManager.renameFolder(oldTitle, text); - uiController.handleBookmarksChange(); + mBookmarkManager.renameFolder(oldTitle, text) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + uiController.handleBookmarksChange(); + } + }); } } }); diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index 3bf259009..5a7e1aff4 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -21,6 +21,7 @@ import android.util.Log; import android.widget.ArrayAdapter; +import com.anthonycr.bonsai.CompletableOnSubscribe; import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.grant.PermissionsManager; import com.anthonycr.grant.PermissionsResultAction; @@ -36,13 +37,14 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.database.BookmarkLocalSync; -import acr.browser.lightning.database.BookmarkLocalSync.Source; -import acr.browser.lightning.database.BookmarkManager; +import acr.browser.lightning.database.bookmark.BookmarkExporter; +import acr.browser.lightning.database.bookmark.BookmarkLocalSync; +import acr.browser.lightning.database.bookmark.BookmarkLocalSync.Source; import acr.browser.lightning.database.HistoryItem; import com.anthonycr.bonsai.Schedulers; +import acr.browser.lightning.database.bookmark.BookmarkModel; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.Utils; @@ -58,7 +60,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @Nullable private Activity mActivity; - @Inject BookmarkManager mBookmarkManager; + @Inject BookmarkModel mBookmarkManager; private File[] mFileList; private String[] mFileNameList; @Nullable private BookmarkLocalSync mSync; @@ -187,7 +189,28 @@ public boolean onPreferenceClick(@NonNull Preference preference) { new PermissionsResultAction() { @Override public void onGranted() { - mBookmarkManager.exportBookmarks(getActivity()); + mBookmarkManager.getAllBookmarks() + .subscribeOn(Schedulers.io()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + Preconditions.checkNonNull(item); + final File exportFile = BookmarkExporter.createNewExportFile(); + BookmarkExporter.exportBookmarksToFile(item, exportFile) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + Activity activity = getActivity(); + if (activity != null) { + Utils.showSnackbar(activity, activity.getString(R.string.bookmark_export_path) + + ' ' + exportFile.getPath()); + } + } + }); + } + }); } @Override @@ -245,7 +268,7 @@ private void showDeleteBookmarksDialog() { builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mBookmarkManager.deleteAllBookmarks(); + mBookmarkManager.deleteAllBookmarks().subscribeOn(Schedulers.io()).subscribe(); } }); Dialog dialog = builder.show(); @@ -408,7 +431,32 @@ public void onClick(DialogInterface dialog, int which) { Dialog dialog1 = builder.show(); BrowserDialog.setDialogSize(mActivity, dialog1); } else { - mBookmarkManager.importBookmarksFromFile(mFileList[which], getActivity()); + BookmarkExporter.importBookmarksFromFile(mFileList[which]) + .subscribeOn(Schedulers.io()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable final List importList) { + Preconditions.checkNonNull(importList); + mBookmarkManager.addBookmarkList(importList) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + Activity activity = getActivity(); + if (activity != null) { + String message = activity.getResources().getString(R.string.message_import); + Utils.showSnackbar(activity, importList.size() + " " + message); + } + } + }); + } + + @Override + public void onError(@NonNull Throwable throwable) { + Log.e(TAG, "onError: importing bookmarks", throwable); + Utils.createInformativeDialog(getActivity(), R.string.title_error, R.string.import_bookmark_error); + } + }); } } diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index c48cffe42..be9724e4f 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -35,6 +35,7 @@ import javax.inject.Inject; import acr.browser.lightning.R; +import acr.browser.lightning.activity.BookmarkUiModel; import acr.browser.lightning.activity.ReadingActivity; import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.animation.AnimationUtils; @@ -42,8 +43,8 @@ import acr.browser.lightning.browser.BookmarksView; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.controller.UIController; -import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.database.bookmark.BookmarkModel; import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.favicon.FaviconModel; import acr.browser.lightning.preference.PreferenceManager; @@ -71,7 +72,7 @@ public static BookmarksFragment createFragment(boolean isIncognito) { public final static String INCOGNITO_MODE = TAG + ".INCOGNITO_MODE"; // Managers - @Inject BookmarkManager mBookmarkManager; + @Inject BookmarkModel mBookmarkManager; // Dialog builder @Inject LightningDialogBuilder mBookmarksDialogBuilder; @@ -109,16 +110,8 @@ public static BookmarksFragment createFragment(boolean isIncognito) { @Nullable private Subscription mBookmarksSubscription; - private static Single> initBookmarks(@NonNull final BookmarkManager bookmarkManager) { - return Single.create(new SingleAction>() { - @Override - public void onSubscribe(@NonNull SingleSubscriber> subscriber) { - subscriber.onItem(bookmarkManager.getBookmarksFromFolder(null, true)); - subscriber.onComplete(); - - } - }); - } + @NonNull + private final BookmarkUiModel mUiModel = new BookmarkUiModel(); @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -150,7 +143,7 @@ public void onItemClick(int position) { final HistoryItem item = mBookmarks.get(position); if (item.isFolder()) { mScrollIndex = ((LinearLayoutManager) mBookmarksListView.getLayoutManager()).findFirstVisibleItemPosition(); - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(item.getTitle(), true), true); + setBookmarksShown(item.getTitle(), true); } else { mUiController.bookmarkItemClicked(item); } @@ -170,7 +163,7 @@ public boolean onItemLongClick(int position) { public void onResume() { super.onResume(); if (mBookmarkAdapter != null) { - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); + setBookmarksShown(null, false); } } @@ -184,9 +177,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, backView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (mBookmarkManager == null) return; - if (!mBookmarkManager.isRootFolder()) { - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); + if (!mUiModel.isRootFolder()) { + setBookmarksShown(null, true); mBookmarksListView.getLayoutManager().scrollToPosition(mScrollIndex); } } @@ -201,17 +193,7 @@ public void onClick(View v) { mBookmarksListView.setLayoutManager(new LinearLayoutManager(getContext())); mBookmarksListView.setAdapter(mBookmarkAdapter); - mBookmarksSubscription = initBookmarks(mBookmarkManager) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe>() { - @Override - public void onItem(@Nullable List item) { - mBookmarksSubscription = null; - Preconditions.checkNonNull(item); - setBookmarkDataSet(item, true); - } - }); + setBookmarksShown(null, true); return view; } @@ -251,31 +233,70 @@ public void reinitializePreferences() { } private void updateBookmarkIndicator(final String url) { - if (!mBookmarkManager.isBookmark(url)) { - mBookmarkImage.setImageResource(R.drawable.ic_action_star); - mBookmarkImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); - } else { - mBookmarkImage.setImageResource(R.drawable.ic_bookmark); - mBookmarkImage.setColorFilter(ThemeUtils.getAccentColor(getContext()), PorterDuff.Mode.SRC_IN); - } + mBookmarkManager.isBookmark(url) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean item) { + Preconditions.checkNonNull(item); + if (!item) { + mBookmarkImage.setImageResource(R.drawable.ic_action_star); + mBookmarkImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); + } else { + mBookmarkImage.setImageResource(R.drawable.ic_bookmark); + mBookmarkImage.setColorFilter(ThemeUtils.getAccentColor(getContext()), PorterDuff.Mode.SRC_IN); + } + } + }); } @Override public void handleBookmarkDeleted(@NonNull HistoryItem item) { mBookmarks.remove(item); if (item.isFolder()) { - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); + setBookmarksShown(null, false); } else { mBookmarkAdapter.notifyDataSetChanged(); } } + private void setBookmarksShown(@Nullable final String folder, final boolean animate) { + mBookmarksSubscription = mBookmarkManager.getBookmarksFromFolder(folder) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable final List item) { + mBookmarksSubscription = null; + Preconditions.checkNonNull(item); + + mUiModel.setCurrentFolder(folder); + if (folder == null) { + mBookmarkManager.getFolders() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List folders) { + Preconditions.checkNonNull(folders); + item.addAll(folders); + setBookmarkDataSet(item, animate); + } + }); + } else { + setBookmarkDataSet(item, animate); + } + } + }); + } + private void setBookmarkDataSet(@NonNull List items, boolean animate) { mBookmarks.clear(); mBookmarks.addAll(items); mBookmarkAdapter.notifyDataSetChanged(); final int resource; - if (mBookmarkManager.isRootFolder()) { + if (mUiModel.isRootFolder()) { resource = R.drawable.ic_action_star; } else { resource = R.drawable.ic_action_back; @@ -339,10 +360,10 @@ public boolean onLongClick(View v) { @Override public void navigateBack() { - if (mBookmarkManager.isRootFolder()) { + if (mUiModel.isRootFolder()) { mUiController.closeBookmarksDrawer(); } else { - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); + setBookmarksShown(null, true); mBookmarksListView.getLayoutManager().scrollToPosition(mScrollIndex); } } @@ -350,8 +371,8 @@ public void navigateBack() { @Override public void handleUpdatedUrl(@NonNull String url) { updateBookmarkIndicator(url); - String folder = mBookmarkManager.getCurrentFolder(); - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(folder, true), false); + String folder = mUiModel.getCurrentFolder(); + setBookmarksShown(folder, false); } static class BookmarkViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index a29f83ecf..2937f7035 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -38,9 +38,9 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; -import acr.browser.lightning.database.HistoryModel; +import acr.browser.lightning.database.bookmark.BookmarkModel; +import acr.browser.lightning.database.history.HistoryModel; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.ThemeUtils; @@ -65,7 +65,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable { private final Comparator mFilterComparator = new SuggestionsComparator(); - @Inject BookmarkManager mBookmarkManager; + @Inject BookmarkModel mBookmarkManager; @Inject PreferenceManager mPreferenceManager; @Inject Application mApplication; @@ -102,15 +102,16 @@ public void clearCache() { } public void refreshBookmarks() { - Completable.create(new CompletableAction() { - @Override - public void onSubscribe(@NonNull CompletableSubscriber subscriber) { - mAllBookmarks.clear(); - mAllBookmarks.addAll(mBookmarkManager.getAllBookmarks(true)); - - subscriber.onComplete(); - } - }).subscribeOn(Schedulers.io()).subscribe(); + mBookmarkManager.getAllBookmarks() + .subscribeOn(Schedulers.io()) + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List item) { + Preconditions.checkNonNull(item); + mAllBookmarks.clear(); + mAllBookmarks.addAll(item); + } + }); } @Override diff --git a/app/src/main/java/acr/browser/lightning/utils/WebUtils.java b/app/src/main/java/acr/browser/lightning/utils/WebUtils.java index 790566472..2ae62c605 100644 --- a/app/src/main/java/acr/browser/lightning/utils/WebUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/WebUtils.java @@ -13,7 +13,7 @@ import com.anthonycr.bonsai.Schedulers; -import acr.browser.lightning.database.HistoryModel; +import acr.browser.lightning.database.history.HistoryModel; /** * Copyright 8/4/2015 Anthony Restaino diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 4bf514e1e..4148fe5e5 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -32,6 +32,7 @@ import android.webkit.WebSettings.PluginState; import android.webkit.WebView; +import com.anthonycr.bonsai.Schedulers; import com.anthonycr.bonsai.Single; import com.anthonycr.bonsai.SingleAction; import com.anthonycr.bonsai.SingleOnSubscribe; @@ -49,13 +50,9 @@ import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.constant.StartPage; import acr.browser.lightning.controller.UIController; -import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.download.LightningDownloadListener; import acr.browser.lightning.preference.PreferenceManager; - -import com.anthonycr.bonsai.Schedulers; - import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.ProxyUtils; import acr.browser.lightning.utils.UrlUtils; @@ -110,7 +107,6 @@ public class LightningView { @Inject PreferenceManager mPreferences; @Inject LightningDialogBuilder mBookmarksDialogBuilder; @Inject ProxyUtils mProxyUtils; - @Inject BookmarkManager mBookmarkManager; public LightningView(@NonNull Activity activity, @Nullable String url, boolean isIncognito) { BrowserApp.getAppComponent().inject(this); From 18216543d4704393ee8fc86d5411b72aa272ff38 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 7 May 2017 20:13:29 -0400 Subject: [PATCH 102/181] Documentation for the bookmark model --- .../database/bookmark/BookmarkDatabase.java | 2 + .../database/bookmark/BookmarkModel.java | 94 +++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java index 3bfcf1fce..cfe717489 100644 --- a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java @@ -142,6 +142,8 @@ public void onSubscribe(@NonNull SingleSubscriber subscriber) { if (cursor.moveToFirst()) { subscriber.onItem(bindCursorToHistoryItem(cursor)); + } else { + subscriber.onItem(null); } cursor.close(); diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java index 9d27d2c36..d4cb905d7 100644 --- a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java @@ -19,42 +19,136 @@ */ public interface BookmarkModel { + /** + * Gets the bookmark associated with the URL. + * + * @param url the URL to look for. + * @return an observable that will emit either + * the bookmark associated with the URL or null. + */ @NonNull Single findBookmarkForUrl(@NonNull String url); + /** + * Determines if a URL is associated with a bookmark. + * + * @param url the URL to check. + * @return an observable that will emit true if + * the URL is a bookmark, false otherwise. + */ @NonNull Single isBookmark(@NonNull String url); + /** + * Adds a bookmark if one does not already exist with + * the same URL. + * + * @param item the bookmark to add. + * @return an observable that emits true if the bookmark + * was added, false otherwise. + */ @NonNull Single addBookmarkIfNotExists(@NonNull HistoryItem item); + /** + * Adds a list of bookmarks to the database. + * + * @param bookmarkItems the bookmarks to add. + * @return an observable that emits a complete event + * when all the bookmarks have been added. + */ @NonNull Completable addBookmarkList(@NonNull List bookmarkItems); + /** + * Deletes a bookmark from the database. + * + * @param bookmark the bookmark to delete. + * @return an observable that emits true when + * the bookmark is deleted, false otherwise. + */ @NonNull Single deleteBookmark(@NonNull HistoryItem bookmark); + /** + * Moves all bookmarks in the old folder to the new folder. + * + * @param oldName the name of the old folder. + * @param newName the name of the new folder. + * @return an observable that emits a completion + * event when the folder is renamed. + */ @NonNull Completable renameFolder(@NonNull String oldName, @NonNull String newName); + /** + * Deletes a folder from the database, all bookmarks + * in that folder will be moved to the root level. + * + * @param folderToDelete the folder to delete. + * @return an observable that emits a completion + * event when the folder has been deleted. + */ @NonNull Completable deleteFolder(@NonNull String folderToDelete); + /** + * Deletes all bookmarks in the database. + * + * @return an observable that emits a completion + * event when all bookmarks have been deleted. + */ @NonNull Completable deleteAllBookmarks(); + /** + * Changes the bookmark with the original URL + * with all the data from the new bookmark. + * + * @param oldBookmark the old bookmark to replace. + * @param newBookmark the new bookmark. + * @return an observable that emits a completion event + * when the bookmark edit is done. + */ @NonNull Completable editBookmark(@NonNull HistoryItem oldBookmark, @NonNull HistoryItem newBookmark); + /** + * Emits a list of all bookmarks + * + * @return an observable that emits a list + * of all bookmarks. + */ @NonNull Single> getAllBookmarks(); + /** + * Emits all bookmarks in a certain folder. + * If the folder chosen is null, then all bookmarks + * without a specified folder will be returned. + * + * @param folder gets the bookmarks from this folder, may be null. + * @return an observable that emits a list of bookmarks + * in the given folder. + */ @NonNull Single> getBookmarksFromFolder(@Nullable String folder); + /** + * Returns all folders as {@link HistoryItem}. + * The root folder is omitted. + * + * @return an observable that emits a list of folders. + */ @NonNull Single> getFolders(); + /** + * Returns the names of all folders. + * The root folder is omitted. + * + * @return an observable that emits a list of folder names. + */ @NonNull Single> getFolderNames(); } From ae30951e41a8030ed671eab2584095c62c5976c0 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 7 May 2017 20:41:31 -0400 Subject: [PATCH 103/181] Moving old bookmark manager to LegacyBookmarkManager LegacyBookmarkManager has read only functionality --- .../acr/browser/lightning/app/BrowserApp.java | 6 +- .../database/bookmark/BookmarkManager.java | 554 ------------------ .../legacy/LegacyBookmarkManager.java | 112 ++++ 3 files changed, 114 insertions(+), 558 deletions(-) delete mode 100644 app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkManager.java create mode 100644 app/src/main/java/acr/browser/lightning/database/bookmark/legacy/LegacyBookmarkManager.java diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index 916a31f82..5056f3112 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -23,7 +23,7 @@ import acr.browser.lightning.BuildConfig; import acr.browser.lightning.database.HistoryItem; -import acr.browser.lightning.database.bookmark.BookmarkManager; +import acr.browser.lightning.database.bookmark.legacy.LegacyBookmarkManager; import acr.browser.lightning.database.bookmark.BookmarkModel; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.FileUtils; @@ -38,7 +38,6 @@ public class BrowserApp extends Application { private static final Executor mIOThread = Executors.newSingleThreadExecutor(); @Inject PreferenceManager mPreferenceManager; - @Inject BookmarkManager mOldBookmarkManager; @Inject BookmarkModel mBookmarkModel; @Override @@ -84,8 +83,7 @@ public void uncaughtException(Thread thread, @NonNull Throwable ex) { Schedulers.worker().execute(new Runnable() { @Override public void run() { - List oldBookmarks = mOldBookmarkManager.getAllBookmarks(true); - mOldBookmarkManager.deleteAllBookmarks(); + List oldBookmarks = LegacyBookmarkManager.destructiveGetBookmarks(BrowserApp.this); if (!oldBookmarks.isEmpty()) { mBookmarkModel.addBookmarkList(oldBookmarks).subscribeOn(Schedulers.io()).subscribe(); diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkManager.java deleted file mode 100644 index 8eb1132ec..000000000 --- a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkManager.java +++ /dev/null @@ -1,554 +0,0 @@ -package acr.browser.lightning.database.bookmark; - -import android.app.Activity; -import android.content.Context; -import android.os.Environment; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Executor; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import acr.browser.lightning.R; -import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.constant.Constants; -import acr.browser.lightning.database.HistoryItem; -import acr.browser.lightning.utils.Utils; - -@Deprecated -@Singleton -public class BookmarkManager { - - private static final String TAG = "BookmarkManager"; - - private static final String TITLE = "title"; - private static final String URL = "url"; - private static final String FOLDER = "folder"; - private static final String ORDER = "order"; - private static final String FILE_BOOKMARKS = "bookmarks.dat"; - - @NonNull private final String DEFAULT_BOOKMARK_TITLE; - - private Map mBookmarksMap; - @NonNull private String mCurrentFolder = ""; - @NonNull private final Executor mExecutor; - private File mFilesDir; - - @Inject - public BookmarkManager(@NonNull Context context) { - mExecutor = BrowserApp.getIOThread(); - DEFAULT_BOOKMARK_TITLE = context.getString(R.string.untitled); - mExecutor.execute(new BookmarkInitializer(context)); - } - - /** - * Initialize the BookmarkManager, it's a one-time operation and will be executed asynchronously. - * When done, mReady flag will been set to true. - */ - private class BookmarkInitializer implements Runnable { - private final Context mContext; - - BookmarkInitializer(Context context) { - mContext = context; - } - - @Override - public void run() { - synchronized (BookmarkManager.this) { - mFilesDir = mContext.getFilesDir(); - final Map bookmarks = new HashMap<>(); - final File bookmarksFile = new File(mFilesDir, FILE_BOOKMARKS); - - BufferedReader bookmarksReader = null; - InputStream inputStream = null; - try { - if (bookmarksFile.exists() && bookmarksFile.isFile()) { - //noinspection IOResourceOpenedButNotSafelyClosed - inputStream = new FileInputStream(bookmarksFile); - } else { - inputStream = mContext.getResources().openRawResource(R.raw.default_bookmarks); - } - //noinspection IOResourceOpenedButNotSafelyClosed - bookmarksReader = new BufferedReader(new InputStreamReader(inputStream)); - String line; - while ((line = bookmarksReader.readLine()) != null) { - try { - JSONObject object = new JSONObject(line); - HistoryItem item = new HistoryItem(); - item.setTitle(object.getString(TITLE)); - final String url = object.getString(URL); - item.setUrl(url); - item.setFolder(object.getString(FOLDER)); - item.setPosition(object.getInt(ORDER)); - item.setImageId(R.drawable.ic_bookmark); - bookmarks.put(url, item); - } catch (JSONException e) { - Log.e(TAG, "Can't parse line " + line, e); - } - } - } catch (IOException e) { - Log.e(TAG, "Error reading the bookmarks file", e); - } finally { - Utils.close(bookmarksReader); - Utils.close(inputStream); - } - mBookmarksMap = bookmarks; - } - } - - } - - /** - * Dump all the given bookmarks to the bookmark file using a temporary file - */ - private class BookmarksWriter implements Runnable { - - private final List mBookmarks; - - BookmarksWriter(List bookmarks) { - mBookmarks = bookmarks; - } - - @Override - public void run() { - final File tempFile = new File(mFilesDir, - String.format(Locale.US, "bm_%d.dat", System.currentTimeMillis())); - final File bookmarksFile = new File(mFilesDir, FILE_BOOKMARKS); - boolean success = false; - BufferedWriter bookmarkWriter = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - bookmarkWriter = new BufferedWriter(new FileWriter(tempFile, false)); - JSONObject object = new JSONObject(); - for (HistoryItem item : mBookmarks) { - object.put(TITLE, item.getTitle()); - object.put(URL, item.getUrl()); - object.put(FOLDER, item.getFolder()); - object.put(ORDER, item.getPosition()); - bookmarkWriter.write(object.toString()); - bookmarkWriter.newLine(); - } - success = true; - } catch (@NonNull IOException | JSONException e) { - e.printStackTrace(); - } finally { - Utils.close(bookmarkWriter); - } - - if (success) { - // Overwrite the bookmarks file by renaming the temp file - //noinspection ResultOfMethodCallIgnored - tempFile.renameTo(bookmarksFile); - } - } - } - - /** - * Look for bookmark using the url - * - * @param url the lookup url - * @return the bookmark as an {@link HistoryItem} or null - */ - @Nullable - public HistoryItem findBookmarkForUrl(final String url) { - return mBookmarksMap.get(url); - } - - public boolean isBookmark(String url) { - return mBookmarksMap.containsKey(url); - } - - /** - * This method adds the the HistoryItem item to permanent bookmark storage.
- * This operation is blocking if the manager is still not ready. - * - * @param item the item to add - * @return It returns true if the operation was successful. - */ - public synchronized boolean addBookmark(@NonNull HistoryItem item) { - final String url = item.getUrl(); - if (mBookmarksMap.containsKey(url)) { - return false; - } - mBookmarksMap.put(url, item); - mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); - return true; - } - - /** - * This method adds the list of HistoryItems to permanent bookmark storage - * - * @param list the list of HistoryItems to add to bookmarks - */ - public synchronized void addBookmarkList(@Nullable List list) { - if (list == null || list.isEmpty()) { - return; - } - for (HistoryItem item : list) { - final String url = item.getUrl(); - if (!mBookmarksMap.containsKey(url)) { - mBookmarksMap.put(url, item); - } - } - mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); - } - - /** - * This method deletes the bookmark with the given url. It returns - * true if the deletion was successful. - * - * @param deleteItem the bookmark item to delete - */ - public synchronized boolean deleteBookmark(@Nullable HistoryItem deleteItem) { - if (deleteItem == null || deleteItem.isFolder()) { - return false; - } - mBookmarksMap.remove(deleteItem.getUrl()); - mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); - return true; - } - - /** - * renames a folder and moves all it's contents to that folder - * - * @param oldName the folder to be renamed - * @param newName the new name of the folder - */ - public synchronized void renameFolder(@NonNull String oldName, @NonNull String newName) { - if (newName.isEmpty()) { - return; - } - for (HistoryItem item : mBookmarksMap.values()) { - if (item.getFolder().equals(oldName)) { - item.setFolder(newName); - } else if (item.isFolder() && item.getTitle().equals(oldName)) { - item.setTitle(newName); - item.setUrl(Constants.FOLDER + newName); - } - } - mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); - } - - /** - * Delete the folder and move all bookmarks to the top level - * - * @param name the name of the folder to be deleted - */ - public synchronized void deleteFolder(@NonNull String name) { - final Map bookmarks = new HashMap<>(); - for (HistoryItem item : mBookmarksMap.values()) { - final String url = item.getUrl(); - if (item.isFolder()) { - if (!item.getTitle().equals(name)) { - bookmarks.put(url, item); - } - } else { - if (item.getFolder().equals(name)) { - item.setFolder(""); - } - bookmarks.put(url, item); - } - } - mBookmarksMap = bookmarks; - mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); - } - - /** - * This method deletes ALL bookmarks created - * by the user. Use this method carefully and - * do not use it without explicit user consent. - */ - public synchronized void deleteAllBookmarks() { - mBookmarksMap = new HashMap<>(); - mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); - } - - /** - * This method edits a particular bookmark in the bookmark database - * - * @param oldItem This is the old item that you wish to edit - * @param newItem This is the new item that will overwrite the old item - */ - public synchronized void editBookmark(@Nullable HistoryItem oldItem, @Nullable HistoryItem newItem) { - if (oldItem == null || newItem == null || oldItem.isFolder()) { - return; - } - if (newItem.getUrl().isEmpty()) { - deleteBookmark(oldItem); - return; - } - if (newItem.getTitle().isEmpty()) { - newItem.setTitle(DEFAULT_BOOKMARK_TITLE); - } - final String oldUrl = oldItem.getUrl(); - final String newUrl = newItem.getUrl(); - if (!oldUrl.equals(newUrl)) { - // The url has been changed, remove the old one - mBookmarksMap.remove(oldUrl); - } - mBookmarksMap.put(newUrl, newItem); - mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); - } - - /** - * This method exports the stored bookmarks to a text file in the device's - * external download directory - */ - public synchronized void exportBookmarks(@NonNull Activity activity) { - List bookmarkList = getAllBookmarks(true); - File bookmarksExport = new File( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), - "BookmarksExport.txt"); - int counter = 0; - while (bookmarksExport.exists()) { - counter++; - bookmarksExport = new File( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), - "BookmarksExport-" + counter + ".txt"); - } - BufferedWriter bookmarkWriter = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksExport, - false)); - JSONObject object = new JSONObject(); - for (HistoryItem item : bookmarkList) { - object.put(TITLE, item.getTitle()); - object.put(URL, item.getUrl()); - object.put(FOLDER, item.getFolder()); - object.put(ORDER, item.getPosition()); - bookmarkWriter.write(object.toString()); - bookmarkWriter.newLine(); - } - Utils.showSnackbar(activity, activity.getString(R.string.bookmark_export_path) - + ' ' + bookmarksExport.getPath()); - } catch (@NonNull IOException | JSONException e) { - e.printStackTrace(); - } finally { - Utils.close(bookmarkWriter); - } - - } - - /** - * This method returns a list of ALL stored bookmarks. - * This is a disk-bound operation and should not be - * done very frequently. - * - * @param sort force to sort the returned bookmarkList - * @return returns a list of bookmarks that can be sorted - */ - @NonNull - public synchronized List getAllBookmarks(boolean sort) { - final List bookmarks = new ArrayList<>(mBookmarksMap.values()); - if (sort) { - Collections.sort(bookmarks, new SortIgnoreCase()); - } - return bookmarks; - } - - /** - * This method returns a list of bookmarks and folders located in the specified folder. - * This method should generally be used by the UI when it needs a list to display to the - * user as it returns a subset of all bookmarks and includes folders as well which are - * really 'fake' bookmarks. - * - * @param folder the name of the folder to retrieve bookmarks from - * @return a list of bookmarks found in that folder - */ - @NonNull - public synchronized List getBookmarksFromFolder(@Nullable String folder, boolean sort) { - List bookmarks = new ArrayList<>(1); - if (folder == null || folder.isEmpty()) { - bookmarks.addAll(getFolders(sort)); - folder = ""; - } - mCurrentFolder = folder; - for (HistoryItem item : mBookmarksMap.values()) { - if (item.getFolder().equals(folder)) - bookmarks.add(item); - } - if (sort) { - Collections.sort(bookmarks, new SortIgnoreCase()); - } - return bookmarks; - } - - /** - * Different from {@link #getBookmarksFromFolder(String, boolean)} only in - * that it doesn't affect the internal state of the bookmark manager which - * tracks the current folder used by the bookmark drawer. - *

- * This method returns a list of bookmarks and folders located in the specified folder. - * This method should generally be used by the UI when it needs a list to display to the - * user as it returns a subset of all bookmarks and includes folders as well which are - * really 'fake' bookmarks. - * - * @param folder the name of the folder to retrieve bookmarks from - * @return a list of bookmarks found in that folder - */ - @NonNull - public synchronized List getBookmarksCopyFromFolder(@Nullable String folder, boolean sort) { - List bookmarks = new ArrayList<>(1); - if (folder == null || folder.isEmpty()) { - bookmarks.addAll(getFolders(sort)); - folder = ""; - } - for (HistoryItem item : mBookmarksMap.values()) { - if (item.getFolder().equals(folder)) - bookmarks.add(item); - } - if (sort) { - Collections.sort(bookmarks, new SortIgnoreCase()); - } - return bookmarks; - } - - /** - * Tells you if you are at the root folder or in a subfolder - * - * @return returns true if you are in the root folder - */ - public boolean isRootFolder() { - return mCurrentFolder.isEmpty(); - } - - /** - * Returns the current folder - * - * @return the current folder - */ - @NonNull - public String getCurrentFolder() { - return mCurrentFolder; - } - - /** - * This method returns a list of all folders. - * Folders cannot be empty as they are generated from - * the list of bookmarks that have non-empty folder fields. - * - * @return a list of all folders - */ - @NonNull - private synchronized List getFolders(boolean sort) { - final HashMap folders = new HashMap<>(); - for (HistoryItem item : mBookmarksMap.values()) { - final String folderName = item.getFolder(); - if (!folderName.isEmpty() && !folders.containsKey(folderName)) { - final HistoryItem folder = new HistoryItem(); - folder.setIsFolder(true); - folder.setTitle(folderName); - folder.setImageId(R.drawable.ic_folder); - folder.setUrl(Constants.FOLDER + folderName); - folders.put(folderName, folder); - } - } - final List result = new ArrayList<>(folders.values()); - if (sort) { - Collections.sort(result, new SortIgnoreCase()); - } - return result; - } - - /** - * returns a list of folder titles that can be used for suggestions in a - * simple list adapter - * - * @return a list of folder title strings - */ - @NonNull - public synchronized List getFolderTitles() { - final Set folders = new HashSet<>(); - for (HistoryItem item : mBookmarksMap.values()) { - final String folderName = item.getFolder(); - if (!folderName.isEmpty()) { - folders.add(folderName); - } - } - return new ArrayList<>(folders); - } - - /** - * This method imports the bookmarks from a backup file that is located on - * external storage - * - * @param file the file to attempt to import bookmarks from - */ - public synchronized void importBookmarksFromFile(@Nullable File file, @NonNull Activity activity) { - if (file == null) { - return; - } - List list = new ArrayList<>(); - BufferedReader bookmarksReader = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - bookmarksReader = new BufferedReader(new FileReader(file)); - String line; - int number = 0; - while ((line = bookmarksReader.readLine()) != null) { - JSONObject object = new JSONObject(line); - HistoryItem item = new HistoryItem(); - item.setTitle(object.getString(TITLE)); - item.setUrl(object.getString(URL)); - item.setFolder(object.getString(FOLDER)); - item.setPosition(object.getInt(ORDER)); - list.add(item); - number++; - } - addBookmarkList(list); - String message = activity.getResources().getString(R.string.message_import); - Utils.showSnackbar(activity, number + " " + message); - } catch (@NonNull IOException | JSONException e) { - e.printStackTrace(); - Utils.createInformativeDialog(activity, R.string.title_error, R.string.import_bookmark_error); - } finally { - Utils.close(bookmarksReader); - } - } - - /** - * This class sorts bookmarks alphabetically, with folders coming after bookmarks - */ - private static class SortIgnoreCase implements Comparator { - - public int compare(@Nullable HistoryItem o1, @Nullable HistoryItem o2) { - if (o1 == null || o2 == null) { - return 0; - } - if (o1.isFolder() == o2.isFolder()) { - return o1.getTitle().toLowerCase(Locale.getDefault()) - .compareTo(o2.getTitle().toLowerCase(Locale.getDefault())); - - } else { - return o1.isFolder() ? 1 : -1; - } - } - - } -} diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/legacy/LegacyBookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/bookmark/legacy/LegacyBookmarkManager.java new file mode 100644 index 000000000..75280e8f3 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/legacy/LegacyBookmarkManager.java @@ -0,0 +1,112 @@ +package acr.browser.lightning.database.bookmark.legacy; + +import android.app.Application; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.WorkerThread; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + +import acr.browser.lightning.R; +import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.utils.Utils; + +@Deprecated +public class LegacyBookmarkManager { + + private static final String TAG = "BookmarkManager"; + + private static final String TITLE = "title"; + private static final String URL = "url"; + private static final String FOLDER = "folder"; + private static final String ORDER = "order"; + private static final String FILE_BOOKMARKS = "bookmarks.dat"; + + /** + * Gets all bookmarks from the old bookmark file + * and then deletes the file. + * + * @param application the context needed to open the file. + * @return a list of bookmarks from the old bookmark file. + */ + @WorkerThread + @NonNull + public static List destructiveGetBookmarks(@NonNull Application application) { + File filesDir = application.getFilesDir(); + List bookmarks = new ArrayList<>(); + final File bookmarksFile = new File(filesDir, FILE_BOOKMARKS); + + BufferedReader bookmarksReader = null; + InputStream inputStream = null; + try { + if (bookmarksFile.exists() && bookmarksFile.isFile()) { + //noinspection IOResourceOpenedButNotSafelyClosed + inputStream = new FileInputStream(bookmarksFile); + } else { + return bookmarks; + } + //noinspection IOResourceOpenedButNotSafelyClosed + bookmarksReader = new BufferedReader(new InputStreamReader(inputStream)); + String line; + while ((line = bookmarksReader.readLine()) != null) { + try { + JSONObject object = new JSONObject(line); + + HistoryItem item = new HistoryItem(); + + item.setTitle(object.getString(TITLE)); + item.setUrl(object.getString(URL)); + item.setFolder(object.getString(FOLDER)); + item.setPosition(object.getInt(ORDER)); + item.setImageId(R.drawable.ic_bookmark); + + bookmarks.add(item); + } catch (JSONException e) { + Log.e(TAG, "Can't parse line " + line, e); + } + } + } catch (IOException e) { + Log.e(TAG, "Error reading the bookmarks file", e); + } finally { + Utils.close(bookmarksReader); + Utils.close(inputStream); + } + + bookmarksFile.delete(); + + return bookmarks; + } + + /** + * This class sorts bookmarks alphabetically, with folders coming after bookmarks + */ + private static class SortIgnoreCase implements Comparator { + + public int compare(@Nullable HistoryItem o1, @Nullable HistoryItem o2) { + if (o1 == null || o2 == null) { + return 0; + } + if (o1.isFolder() == o2.isFolder()) { + return o1.getTitle().toLowerCase(Locale.getDefault()) + .compareTo(o2.getTitle().toLowerCase(Locale.getDefault())); + + } else { + return o1.isFolder() ? 1 : -1; + } + } + + } +} From c71ffda636251518f4a0b4a58e367046e05d995c Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 7 May 2017 20:58:07 -0400 Subject: [PATCH 104/181] Import bookmarks from assets if the database is empty --- .../java/acr/browser/lightning/app/BrowserApp.java | 6 +++++- .../lightning/database/bookmark/BookmarkDatabase.java | 5 +++++ .../lightning/database/bookmark/BookmarkModel.java | 11 +++++++++++ .../bookmark/legacy/LegacyBookmarkManager.java | 2 +- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index 5056f3112..cc16cc3d9 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -23,6 +23,7 @@ import acr.browser.lightning.BuildConfig; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.database.bookmark.BookmarkExporter; import acr.browser.lightning.database.bookmark.legacy.LegacyBookmarkManager; import acr.browser.lightning.database.bookmark.BookmarkModel; import acr.browser.lightning.preference.PreferenceManager; @@ -88,7 +89,10 @@ public void run() { if (!oldBookmarks.isEmpty()) { mBookmarkModel.addBookmarkList(oldBookmarks).subscribeOn(Schedulers.io()).subscribe(); } else { - // TODO: 5/7/17 Import bookmarks from assets if not empty + if (mBookmarkModel.count() == 0) { + List assetsBookmarks = BookmarkExporter.importBookmarksFromAssets(BrowserApp.this); + mBookmarkModel.addBookmarkList(assetsBookmarks).subscribeOn(Schedulers.io()).subscribe(); + } } } }); diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java index cfe717489..67e5eaef9 100644 --- a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java @@ -374,4 +374,9 @@ public void onSubscribe(@NonNull SingleSubscriber> subscriber) { }); } + @Override + public long count() { + return DatabaseUtils.queryNumEntries(lazyDatabase(), TABLE_BOOKMARK); + } + } diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java index d4cb905d7..0326f216c 100644 --- a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java @@ -2,6 +2,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.WorkerThread; import com.anthonycr.bonsai.Completable; import com.anthonycr.bonsai.Single; @@ -151,4 +152,14 @@ public interface BookmarkModel { */ @NonNull Single> getFolderNames(); + + /** + * A synchronous call to the model + * that returns the number of bookmarks. + * Should be called from a background thread. + * + * @return the number of bookmarks in the database. + */ + @WorkerThread + long count(); } diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/legacy/LegacyBookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/bookmark/legacy/LegacyBookmarkManager.java index 75280e8f3..50de3e683 100644 --- a/app/src/main/java/acr/browser/lightning/database/bookmark/legacy/LegacyBookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/legacy/LegacyBookmarkManager.java @@ -27,7 +27,7 @@ @Deprecated public class LegacyBookmarkManager { - private static final String TAG = "BookmarkManager"; + private static final String TAG = "LegacyBookmarkManager"; private static final String TITLE = "title"; private static final String URL = "url"; From 6765ec96e50355d589d5f7ede42fe88aa74e3940 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 7 May 2017 21:05:50 -0400 Subject: [PATCH 105/181] Cleaning up bookmark initialization logic --- .../java/acr/browser/lightning/app/BrowserApp.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index cc16cc3d9..e51ee5f44 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -87,12 +87,12 @@ public void run() { List oldBookmarks = LegacyBookmarkManager.destructiveGetBookmarks(BrowserApp.this); if (!oldBookmarks.isEmpty()) { + // If there are old bookmarks, import them mBookmarkModel.addBookmarkList(oldBookmarks).subscribeOn(Schedulers.io()).subscribe(); - } else { - if (mBookmarkModel.count() == 0) { - List assetsBookmarks = BookmarkExporter.importBookmarksFromAssets(BrowserApp.this); - mBookmarkModel.addBookmarkList(assetsBookmarks).subscribeOn(Schedulers.io()).subscribe(); - } + } else if (mBookmarkModel.count() == 0) { + // If the database is empty, fill it from the assets list + List assetsBookmarks = BookmarkExporter.importBookmarksFromAssets(BrowserApp.this); + mBookmarkModel.addBookmarkList(assetsBookmarks).subscribeOn(Schedulers.io()).subscribe(); } } }); From a3de701cf42fb23373b3099f34e814a65dcaf696 Mon Sep 17 00:00:00 2001 From: t61p Date: Mon, 8 May 2017 10:14:17 +0900 Subject: [PATCH 106/181] Japanese translation update (#565) --- app/src/main/res/values-ja/strings.xml | 252 ++++++++++++++++--------- 1 file changed, 164 insertions(+), 88 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index ebb59f53f..a19ef8d93 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -20,47 +20,50 @@ 履歴 ブックマーク ブックマークに追加 - リンクをコピー + ページの URL をコピー 進む 設定 - 位置情報 + 位置情報の使用を許可する パスワードを記憶する ユーザーエージェント - Adobe Flash - スタートページ + Adobe Flash を有効にする + ホームページ 全画面モード - JavaScript - ダウンロード先のフォルダ - 高度な設定 + JavaScript を有効にする + ダウンロードフォルダ + 詳細 Apache License 2.0 - アプリケーションのバージョン + アプリのバージョン 終了時にキャッシュを消去する - 文字を右端で折り返す + テキストを右端で折り返す 画像を読み込まない - 新しいタブでページを開くことを許可する - Cookiesを有効にする - 他のブラウザからブックマークを読み込む + サイトが新しいタブを開くことを許可する + Cookie を有効にする + 他のブラウザからブックマークをインポートする 文字サイズ 推奨 検索エンジン 検索 - ワイドビューモードを使用する - オーバービューモードでページを読み込む - 開始時に前のタブを修復する - 読み込み可能なブラウザはありません - 読み込み可能なブラウザがあります - ブラウズ中ステータスバーを非表示にする - Cookiesを消去する - Clear Browser History + Wide view port を使用する + Overview mode でページを読み込む + 前回終了時のタブをアプリ起動時に復元する + サポートしているブラウザ + 標準ブラウザ + 標準ブラウザが見つかりません + サポートしている標準ブラウザが見つかりました + ステータスバーを非表示にする + Cookie を消去する + 履歴を消去する この画像をどうしますか? ダウンロード 開く このリンクをどうしますか? - このページを共有 + このページを共有します + この履歴項目をどうしますか? このブックマークをどうしますか? - 消去 - 空のページ - 標準 + 削除 + 空白ページ + デフォルト デスクトップ モバイル カスタム @@ -69,15 +72,15 @@ このファイルをダウンロードしますか? キャンセル 警告 - Adobe Flash Playerをインストールしてください + Adobe Flash Player が見つかりません\nFlash Player をインストールしてください ユーザーエージェント - ダウンロード先 - カスタムスタートページ - Webpage + ダウンロードフォルダ + カスタムホームページ + ウェブページ 履歴を消去する - Cookiesを消去する + Cookie を消去する すべての履歴を消去しますか? - すべてのCookiesを消去しますか? + すべての Cookie を消去しますか? はい いいえ 文字サイズ @@ -87,96 +90,169 @@ 最小 エラー - どのブラウザからもブックマークが読み込めませんでした - 名前 + ブックマークをインポートするブラウザが見つかりません + タイトル URL ブックマークを編集する 編集 新しいシークレットタブ - 標準 + デフォルト 戻る - ページ内検索 - Starting download\u2026 - \"http\" や \"https\" から始まるURLのみダウンロードできます - SDカードがありません - ファイルをダウンロードするにはUSBストレージが必要です - USBストレージが利用不可です - ストレージがビジー状態です。ダウンロードするには、ステータスバーからUSB接続を変更してください。 - シークレットタブでCookiesを有効にする + ページ内を検索 + ダウンロードを開始します\u2026 + \"http\" または \"https\" で始まる URL のみダウンロードできます + 無効な URL です。ダウンロードできません + 指定したフォルダにダウンロードできません + SD カードがありません + ファイルをダウンロードするには USB ストレージが必要です + USB ストレージが使用できません + ストレージがビジー状態です。ダウンロードするには、ステータスバーの \"USB ストレージをオフにする\" をタップしてください + シークレットタブで Cookie を有効にする Adobe Flash - マニュアル + 手動 自動 - Contact Me - twitter.com/ACRDevelopment + 問い合わせ先 + twitter.com/RestainoAnthony キャッシュを消去する キャッシュを消去しました - ブックマークを読み込みました + ブックマークをインポートしました 履歴を消去しました - Cookiesを消去しました + Cookie を消去しました これ以上タブは開けません - クリップボードにテキストをコピーしました - クリップボードにリンクをコピーしました - カスタムURL - Local file has been blocked from loading - オープンソースライセンス - Search for - 広告ブロック - フォームの再送 - データを再送しますか? - \n位置情報の提供を許可しますか? + テキストをクリップボードにコピーしました + リンクをクリップボードにコピーしました + カスタム URL + ファイルを読み込めませんでした + オープンソース ライセンス + 検索 : + 広告をブロックする + このサイトへの接続は安全ではありません:\n%1$s\nそれでも続行しますか? + 証明書の日付が無効です + 証明書の期限が切れました + 証明書のドメインとサイトのドメインが一致しません + 証明書は無効です + 証明書はまだ有効ではありません + 証明書が信頼できません + フォームの再送信 + データを再送信しますか? + \n位置情報の使用を要求しています 許可する 許可しない サインイン ユーザー名 パスワード - 検索候補を表示する - Powered by Google - Orbotがインストールされています。Torを使用しますか? - Torでプロキシを有効にするにはOrbotをインストールしてください + 検索候補表示 + Google を使用する + DuckDuckGo を使用する + 検索候補を表示しない + HTTP プロキシ + + 使用しない + Orbot + I2P + 手動 + + 手動プロキシ + ホスト: + ポート: + Orbot はインストール済みです。Tor を使用しますか? + I2P はインストール済みです。I2P を使用しますか? + プロキシとして Tor を使用にするには Orbot をインストールしてください + I2P が動作していません + I2P トンネルの使用準備が整っていません はい いいえ - 終了時にCookiesを消去する + 終了時に Cookie を消去する 終了時に履歴を消去する - 規定 + デフォルト カスタム - Untitled + タイトルなし Mozilla Public License v. 2.0 Freeware Android Open Source Project hpHosts Ad Server List - 古いタブをもう1度開く + 閉じたタブを元に戻す レンダリングモード - 反転 + 色の反転 グレースケール - 反転・グレースケール + 反転グレースケール + 高コントラスト 通常 - Googleと履歴を同期する - File Chooser + Google と履歴を同期する + ファイルの選択 NetCipher GNU Lesser General Public License - バックアップにブックマークを書き出す - バックアップからブックマークを読み込む - ブックマークの書き出し先 - ブックマーク設定 - ファイルからブックマークを読み込めませんでした + ブックマークをエクスポートする + ブックマークをインポートする + ブックマークをエクスポートしました + ブックマーク + ブックマークのインポートに失敗しました ファイルを選択してください - 一般設定 - 表示設定 - 個人設定 - About - バージョン・開発者・ライセンスについての詳細 + 全般 + 表示 + プライバシー + このアプリについて + バージョン, 開発者, ライセンスなどの詳細 + 現在のタブを閉じる 全てのタブを閉じる - タブを閉じる + 他のタブを閉じる + サードパーティ Cookie を拒否する カラーモードを有効にする - フォルダ - リネーム - Webストレージをクリア - 終了時にWebストレージをクリア - フォルダ名 - 色を反転する リーダーモード + 読み込み中… + このページから何も読み出せませんでした + Snacktory + jsoup: Java HTML Parser + MIT License + URL 欄の表示内容 + テキストエンコーディング + + ドメイン名 (デフォルト) + URL + タイトル + + 色を反転する + ダーク タブ - サードパーティCookieを無効にする - ナビゲーションドロワでタブを表示する - URL-Boxコンテンツ + アプリのテーマ + ライト + ブラック (AMOLED) + フォルダ名 + フォルダ + 名前の変更 + フォルダ名の変更 + このフォルダをどうしますか? + Web storage を消去する + 終了時に Web storage を消去する + Web storage を消去しました + 広告ブロック用の Hosts ファイルの取得元 + 広告ブロック + タブをドロワーで表示する + ブックマークとタブのドロワーを入れ替える + \'Do Not Track\' を有効にする + Identifying Header を削除する + ホーム画面に追加 + ホーム画面にショートカットを追加しました + すべてのブックマークを削除する + + FAQ + よくある質問と回答 + + + デバッグ + LeakCanary + 変更を反映するにはアプリを再起動してください + + + 新しいタブで開く + バックグラウンドのタブで開く + シークレットタブで開く + ブックマークから削除する + ブックマークを編集する + 履歴から削除する + 画像をダウンロードする + リンクをコピーする + フォルダ名を変更する + フォルダを削除する + タブの消去 From 64cdd016e635c1857c059d2d98f1772d88f564f1 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 7 May 2017 23:16:59 -0400 Subject: [PATCH 107/181] Documentation for BookmarkExporter --- .../database/bookmark/BookmarkDatabase.java | 18 +++++++--- .../database/bookmark/BookmarkExporter.java | 35 +++++++++++++++++++ .../database/bookmark/BookmarkModel.java | 1 - .../lightning/fragment/BookmarksFragment.java | 3 -- .../browser/lightning/utils/ThemeUtils.java | 2 -- 5 files changed, 48 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java index 67e5eaef9..e82904b93 100644 --- a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkDatabase.java @@ -29,6 +29,8 @@ /** * The disk backed bookmark database. + * See {@link BookmarkModel} for method + * documentation. *

* Created by anthonycr on 5/6/17. */ @@ -64,6 +66,12 @@ public BookmarkDatabase(@NonNull Application application) { DEFAULT_BOOKMARK_TITLE = application.getString(R.string.untitled); } + /** + * Lazily initializes the database + * field when called. + * + * @return a non null writable database. + */ @NonNull private SQLiteDatabase lazyDatabase() { if (mDatabase == null) { @@ -96,12 +104,12 @@ public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion } @NonNull - private static ContentValues bindBookmarkToContentValues(@NonNull HistoryItem historyItem) { + private static ContentValues bindBookmarkToContentValues(@NonNull HistoryItem bookmarkItem) { ContentValues contentValues = new ContentValues(4); - contentValues.put(KEY_TITLE, historyItem.getTitle()); - contentValues.put(KEY_URL, historyItem.getUrl()); - contentValues.put(KEY_FOLDER, historyItem.getFolder()); - contentValues.put(KEY_POSITION, historyItem.getPosition()); + contentValues.put(KEY_TITLE, bookmarkItem.getTitle()); + contentValues.put(KEY_URL, bookmarkItem.getUrl()); + contentValues.put(KEY_FOLDER, bookmarkItem.getFolder()); + contentValues.put(KEY_POSITION, bookmarkItem.getPosition()); return contentValues; } diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkExporter.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkExporter.java index 05557f824..005f395b3 100644 --- a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkExporter.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkExporter.java @@ -47,6 +47,13 @@ public class BookmarkExporter { private static final String KEY_FOLDER = "folder"; private static final String KEY_ORDER = "order"; + /** + * Retrieves all the default bookmarks stored + * in the raw file within assets. + * + * @param context the context necessary to open assets. + * @return a non null list of the bookmarks stored in assets. + */ @NonNull public static List importBookmarksFromAssets(@NonNull Context context) { List bookmarks = new ArrayList<>(); @@ -82,6 +89,15 @@ public static List importBookmarksFromAssets(@NonNull Context conte return bookmarks; } + /** + * Exports the list of bookmarks to a file. + * + * @param bookmarkList the bookmarks to export. + * @param file the file to export to. + * @return an observable that emits a completion + * event when the export is complete, or an error + * event if there is a problem. + */ @NonNull public static Completable exportBookmarksToFile(@NonNull final List bookmarkList, @NonNull final File file) { @@ -113,6 +129,16 @@ public void onSubscribe(@NonNull final CompletableSubscriber subscriber) { }); } + /** + * Attempts to import bookmarks from the + * given file. If the file is not in a + * supported format, it will fail. + * + * @param file the file to import from. + * @return an observable that emits the + * imported bookmarks, or an error if the + * file cannot be imported. + */ @NonNull public static Single> importBookmarksFromFile(@NonNull final File file) { return Single.create(new SingleAction>() { @@ -146,6 +172,15 @@ public void onSubscribe(@NonNull SingleSubscriber> subscriber) }); } + /** + * A blocking call that creates a new export file with + * the name "BookmarkExport.txt" and an appropriate + * numerical appendage if a file already exists with + * that name. + * + * @return a non null empty file that can be used + * to export bookmarks to. + */ @WorkerThread @NonNull public static File createNewExportFile() { diff --git a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java index 0326f216c..04d8f0069 100644 --- a/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java +++ b/app/src/main/java/acr/browser/lightning/database/bookmark/BookmarkModel.java @@ -7,7 +7,6 @@ import com.anthonycr.bonsai.Completable; import com.anthonycr.bonsai.Single; -import java.io.File; import java.util.List; import acr.browser.lightning.database.HistoryItem; diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index be9724e4f..8c4964f0e 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -22,10 +22,7 @@ import android.widget.TextView; import com.anthonycr.bonsai.Schedulers; -import com.anthonycr.bonsai.Single; -import com.anthonycr.bonsai.SingleAction; import com.anthonycr.bonsai.SingleOnSubscribe; -import com.anthonycr.bonsai.SingleSubscriber; import com.anthonycr.bonsai.Subscription; import java.lang.ref.WeakReference; diff --git a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java index 165f8d85e..0660f39a2 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java @@ -9,7 +9,6 @@ import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.support.annotation.AttrRes; @@ -19,7 +18,6 @@ import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; import android.util.TypedValue; -import android.widget.ImageView; import acr.browser.lightning.R; From 6ca31c61cf02f1c56fcbe9d501a7f147d8bfcc5f Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 7 May 2017 23:32:41 -0400 Subject: [PATCH 108/181] Add documentation for BookmarkUiModel --- .../lightning/activity/BookmarkUiModel.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/src/main/java/acr/browser/lightning/activity/BookmarkUiModel.java b/app/src/main/java/acr/browser/lightning/activity/BookmarkUiModel.java index 5895dee4c..457a98417 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BookmarkUiModel.java +++ b/app/src/main/java/acr/browser/lightning/activity/BookmarkUiModel.java @@ -14,14 +14,32 @@ public class BookmarkUiModel { @Nullable private String mCurrentFolder; + /** + * Sets the current folder that is being shown. + * Use null as the root folder. + * + * @param folder the current folder, null for root. + */ public void setCurrentFolder(@Nullable String folder) { mCurrentFolder = folder; } + /** + * Determines if the current folder is + * the root folder. + * + * @return true if the current folder is + * the root, false otherwise. + */ public boolean isRootFolder() { return mCurrentFolder == null; } + /** + * Gets the current folder that is being shown. + * + * @return the current folder, null for root. + */ @Nullable public String getCurrentFolder() { return mCurrentFolder; From 5ff3d6140e64d8b6f9632748312ce6f448f21391 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Mon, 8 May 2017 00:00:39 -0400 Subject: [PATCH 109/181] Removing unnecessary iml file --- Lightning-Browser.iml | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 Lightning-Browser.iml diff --git a/Lightning-Browser.iml b/Lightning-Browser.iml deleted file mode 100644 index 8a90bdfb3..000000000 --- a/Lightning-Browser.iml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file From 4c516ce211d8cddee2dd11af930a51b378e84465 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Mon, 8 May 2017 00:01:04 -0400 Subject: [PATCH 110/181] Removing no longer necessary gitmodules file --- .gitmodules | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb..000000000 From 81937a498d6e8ee77e1b94e0ee1e8bd966fffc5a Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Mon, 8 May 2017 00:03:00 -0400 Subject: [PATCH 111/181] Removing incomplete license file --- LICENSE | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 66f4f57ab..000000000 --- a/LICENSE +++ /dev/null @@ -1,10 +0,0 @@ -Copyright 2014 Anthony Restaino - -Lightning Browser - - This Source Code Form is subject to the terms of the - Mozilla Public License, v. 2.0. If a copy of the MPL - was not distributed with this file, You can obtain one at - - http://mozilla.org/MPL/2.0/ - From 7fd2060bb00de16dea8ceb686a76579ca82d39c6 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Mon, 8 May 2017 00:03:15 -0400 Subject: [PATCH 112/181] Update and rename Mozilla Public License v. 2.0 to LICENSE --- LICENSE | 373 ++++++++++++++++++++++++++++++++++ Mozilla Public License v. 2.0 | 362 --------------------------------- 2 files changed, 373 insertions(+), 362 deletions(-) create mode 100644 LICENSE delete mode 100644 Mozilla Public License v. 2.0 diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/Mozilla Public License v. 2.0 b/Mozilla Public License v. 2.0 deleted file mode 100644 index be2cc4dfb..000000000 --- a/Mozilla Public License v. 2.0 +++ /dev/null @@ -1,362 +0,0 @@ -Mozilla Public License, version 2.0 - -1. Definitions - -1.1. "Contributor" - - means each individual or legal entity that creates, contributes to the - creation of, or owns Covered Software. - -1.2. "Contributor Version" - - means the combination of the Contributions of others (if any) used by a - Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - - means Source Code Form to which the initial Contributor has attached the - notice in Exhibit A, the Executable Form of such Source Code Form, and - Modifications of such Source Code Form, in each case including portions - thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - a. that the initial Contributor has attached the notice described in - Exhibit B to the Covered Software; or - - b. that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the terms of - a Secondary License. - -1.6. "Executable Form" - - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - - means a work that combines Covered Software with other material, in a - separate file or files, that is not Covered Software. - -1.8. "License" - - means this document. - -1.9. "Licensable" - - means having the right to grant, to the maximum extent possible, whether - at the time of the initial grant or subsequently, any and all of the - rights conveyed by this License. - -1.10. "Modifications" - - means any of the following: - - a. any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered Software; or - - b. any new file in Source Code Form that contains any Covered Software. - -1.11. "Patent Claims" of a Contributor - - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the License, - by the making, using, selling, offering for sale, having made, import, - or transfer of either its Contributions or its Contributor Version. - -1.12. "Secondary License" - - means either the GNU General Public License, Version 2.0, the GNU Lesser - General Public License, Version 2.1, the GNU Affero General Public - License, Version 3.0, or any later versions of those licenses. - -1.13. "Source Code Form" - - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that controls, is - controlled by, or is under common control with You. For purposes of this - definition, "control" means (a) the power, direct or indirect, to cause - the direction or management of such entity, whether by contract or - otherwise, or (b) ownership of more than fifty percent (50%) of the - outstanding shares or beneficial ownership of such entity. - - -2. License Grants and Conditions - -2.1. Grants - - Each Contributor hereby grants You a world-wide, royalty-free, - non-exclusive license: - - a. under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - - b. under Patent Claims of such Contributor to make, use, sell, offer for - sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - - The licenses granted in Section 2.1 with respect to any Contribution - become effective for each Contribution on the date the Contributor first - distributes such Contribution. - -2.3. Limitations on Grant Scope - - The licenses granted in this Section 2 are the only rights granted under - this License. No additional rights or licenses will be implied from the - distribution or licensing of Covered Software under this License. - Notwithstanding Section 2.1(b) above, no patent license is granted by a - Contributor: - - a. for any code that a Contributor has removed from Covered Software; or - - b. for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - - c. under Patent Claims infringed by Covered Software in the absence of - its Contributions. - - This License does not grant any rights in the trademarks, service marks, - or logos of any Contributor (except as may be necessary to comply with - the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - - No Contributor makes additional grants as a result of Your choice to - distribute the Covered Software under a subsequent version of this - License (see Section 10.2) or under the terms of a Secondary License (if - permitted under the terms of Section 3.3). - -2.5. Representation - - Each Contributor represents that the Contributor believes its - Contributions are its original creation(s) or it has sufficient rights to - grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - - This License is not intended to limit any rights You have under - applicable copyright doctrines of fair use, fair dealing, or other - equivalents. - -2.7. Conditions - - Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in - Section 2.1. - - -3. Responsibilities - -3.1. Distribution of Source Form - - All distribution of Covered Software in Source Code Form, including any - Modifications that You create or to which You contribute, must be under - the terms of this License. You must inform recipients that the Source - Code Form of the Covered Software is governed by the terms of this - License, and how they can obtain a copy of this License. You may not - attempt to alter or restrict the recipients' rights in the Source Code - Form. - -3.2. Distribution of Executable Form - - If You distribute Covered Software in Executable Form then: - - a. such Covered Software must also be made available in Source Code Form, - as described in Section 3.1, and You must inform recipients of the - Executable Form how they can obtain a copy of such Source Code Form by - reasonable means in a timely manner, at a charge no more than the cost - of distribution to the recipient; and - - b. You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter the - recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - - You may create and distribute a Larger Work under terms of Your choice, - provided that You also comply with the requirements of this License for - the Covered Software. If the Larger Work is a combination of Covered - Software with a work governed by one or more Secondary Licenses, and the - Covered Software is not Incompatible With Secondary Licenses, this - License permits You to additionally distribute such Covered Software - under the terms of such Secondary License(s), so that the recipient of - the Larger Work may, at their option, further distribute the Covered - Software under the terms of either this License or such Secondary - License(s). - -3.4. Notices - - You may not remove or alter the substance of any license notices - (including copyright notices, patent notices, disclaimers of warranty, or - limitations of liability) contained within the Source Code Form of the - Covered Software, except that You may alter any license notices to the - extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - - You may choose to offer, and to charge a fee for, warranty, support, - indemnity or liability obligations to one or more recipients of Covered - Software. However, You may do so only on Your own behalf, and not on - behalf of any Contributor. You must make it absolutely clear that any - such warranty, support, indemnity, or liability obligation is offered by - You alone, and You hereby agree to indemnify every Contributor for any - liability incurred by such Contributor as a result of warranty, support, - indemnity or liability terms You offer. You may include additional - disclaimers of warranty and limitations of liability specific to any - jurisdiction. - -4. Inability to Comply Due to Statute or Regulation - - If it is impossible for You to comply with any of the terms of this License - with respect to some or all of the Covered Software due to statute, - judicial order, or regulation then You must: (a) comply with the terms of - this License to the maximum extent possible; and (b) describe the - limitations and the code they affect. Such description must be placed in a - text file included with all distributions of the Covered Software under - this License. Except to the extent prohibited by statute or regulation, - such description must be sufficiently detailed for a recipient of ordinary - skill to be able to understand it. - -5. Termination - -5.1. The rights granted under this License will terminate automatically if You - fail to comply with any of its terms. However, if You become compliant, - then the rights granted under this License from a particular Contributor - are reinstated (a) provisionally, unless and until such Contributor - explicitly and finally terminates Your grants, and (b) on an ongoing - basis, if such Contributor fails to notify You of the non-compliance by - some reasonable means prior to 60 days after You have come back into - compliance. Moreover, Your grants from a particular Contributor are - reinstated on an ongoing basis if such Contributor notifies You of the - non-compliance by some reasonable means, this is the first time You have - received notice of non-compliance with this License from such - Contributor, and You become compliant prior to 30 days after Your receipt - of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent - infringement claim (excluding declaratory judgment actions, - counter-claims, and cross-claims) alleging that a Contributor Version - directly or indirectly infringes any patent, then the rights granted to - You by any and all Contributors for the Covered Software under Section - 2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user - license agreements (excluding distributors and resellers) which have been - validly granted by You or Your distributors under this License prior to - termination shall survive termination. - -6. Disclaimer of Warranty - - Covered Software is provided under this License on an "as is" basis, - without warranty of any kind, either expressed, implied, or statutory, - including, without limitation, warranties that the Covered Software is free - of defects, merchantable, fit for a particular purpose or non-infringing. - The entire risk as to the quality and performance of the Covered Software - is with You. Should any Covered Software prove defective in any respect, - You (not any Contributor) assume the cost of any necessary servicing, - repair, or correction. This disclaimer of warranty constitutes an essential - part of this License. No use of any Covered Software is authorized under - this License except under this disclaimer. - -7. Limitation of Liability - - Under no circumstances and under no legal theory, whether tort (including - negligence), contract, or otherwise, shall any Contributor, or anyone who - distributes Covered Software as permitted above, be liable to You for any - direct, indirect, special, incidental, or consequential damages of any - character including, without limitation, damages for lost profits, loss of - goodwill, work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses, even if such party shall have been - informed of the possibility of such damages. This limitation of liability - shall not apply to liability for death or personal injury resulting from - such party's negligence to the extent applicable law prohibits such - limitation. Some jurisdictions do not allow the exclusion or limitation of - incidental or consequential damages, so this exclusion and limitation may - not apply to You. - -8. Litigation - - Any litigation relating to this License may be brought only in the courts - of a jurisdiction where the defendant maintains its principal place of - business and such litigation shall be governed by laws of that - jurisdiction, without reference to its conflict-of-law provisions. Nothing - in this Section shall prevent a party's ability to bring cross-claims or - counter-claims. - -9. Miscellaneous - - This License represents the complete agreement concerning the subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. Any law or regulation which provides that - the language of a contract shall be construed against the drafter shall not - be used to construe this License against a Contributor. - - -10. Versions of the License - -10.1. New Versions - - Mozilla Foundation is the license steward. Except as provided in Section - 10.3, no one other than the license steward has the right to modify or - publish new versions of this License. Each version will be given a - distinguishing version number. - -10.2. Effect of New Versions - - You may distribute the Covered Software under the terms of the version - of the License under which You originally received the Covered Software, - or under the terms of any subsequent version published by the license - steward. - -10.3. Modified Versions - - If you create software not governed by this License, and you want to - create a new license for such software, you may create and use a - modified version of this License if you rename the license and remove - any references to the name of the license steward (except to note that - such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary - Licenses If You choose to distribute Source Code Form that is - Incompatible With Secondary Licenses under the terms of this version of - the License, the notice described in Exhibit B of this License must be - attached. - -Exhibit A - Source Code Form License Notice - - This Source Code Form is subject to the - terms of the Mozilla Public License, v. - 2.0. If a copy of the MPL was not - distributed with this file, You can - obtain one at - http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular file, -then You may include the notice in a location (such as a LICENSE file in a -relevant directory) where a recipient would be likely to look for such a -notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice - - This Source Code Form is "Incompatible - With Secondary Licenses", as defined by - the Mozilla Public License, v. 2.0. From 79b322f115ea9b4b22120cb22817d51647c224b8 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Mon, 8 May 2017 00:05:44 -0400 Subject: [PATCH 113/181] Updating leakcanary --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 41e36b725..b7b3c7722 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -103,7 +103,7 @@ dependencies { compile 'com.anthonycr.progress:animated-progress:1.0' // memory leak analysis - def leakCanaryVersion = '1.5' + def leakCanaryVersion = '1.5.1' debugCompile "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion" releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanaryVersion" -} \ No newline at end of file +} From 50b0ad2512d83a225adb6a64abd14912416c3b92 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 9 May 2017 23:40:22 -0400 Subject: [PATCH 114/181] Avoid constant condition by changing full_version declaration --- app/build.gradle | 4 ++-- .../java/acr/browser/lightning/browser/BrowserPresenter.java | 3 ++- .../main/java/acr/browser/lightning/constant/Constants.java | 2 -- .../browser/lightning/fragment/GeneralSettingsFragment.java | 5 +++-- app/src/main/java/acr/browser/lightning/utils/AdBlock.java | 3 ++- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b7b3c7722..83e6432dd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,13 +33,13 @@ android { productFlavors { lightningPlus { - buildConfigField "boolean", "FULL_VERSION", "true" + buildConfigField "boolean", "FULL_VERSION", "Boolean.parseBoolean(\"true\")" applicationId "acr.browser.lightning" versionCode 91 } lightningLite { - buildConfigField "boolean", "FULL_VERSION", "false" + buildConfigField "boolean", "FULL_VERSION", "Boolean.parseBoolean(\"false\")" applicationId "acr.browser.barebones" versionCode 93 } diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java index 291ec1c5f..8aa1e5bb9 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java @@ -12,6 +12,7 @@ import javax.inject.Inject; +import acr.browser.lightning.BuildConfig; import acr.browser.lightning.R; import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.app.BrowserApp; @@ -317,7 +318,7 @@ public synchronized void tabChanged(int position) { */ public synchronized boolean newTab(@Nullable String url, boolean show) { // Limit number of tabs for limited version of app - if (!Constants.FULL_VERSION && mTabsModel.size() >= 10) { + if (!BuildConfig.FULL_VERSION && mTabsModel.size() >= 10) { mView.showSnackbar(R.string.max_tabs); return false; } diff --git a/app/src/main/java/acr/browser/lightning/constant/Constants.java b/app/src/main/java/acr/browser/lightning/constant/Constants.java index 00c928700..2e76e7827 100644 --- a/app/src/main/java/acr/browser/lightning/constant/Constants.java +++ b/app/src/main/java/acr/browser/lightning/constant/Constants.java @@ -15,8 +15,6 @@ public final class Constants { private Constants() { } - public static final boolean FULL_VERSION = BuildConfig.FULL_VERSION; - // Hardcoded user agents public static final String DESKTOP_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36"; public static final String MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; U; Android 4.4; en-us; Nexus 4 Build/JOP24G) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"; diff --git a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java index 7365b485a..da03e5d65 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java @@ -22,6 +22,7 @@ import android.widget.EditText; import android.widget.LinearLayout; +import acr.browser.lightning.BuildConfig; import acr.browser.lightning.R; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.dialog.BrowserDialog; @@ -151,13 +152,13 @@ private void initPrefs() { boolean imagesBool = mPreferenceManager.getBlockImagesEnabled(); boolean enableJSBool = mPreferenceManager.getJavaScriptEnabled(); - cbAds.setEnabled(Constants.FULL_VERSION); + cbAds.setEnabled(BuildConfig.FULL_VERSION); cbFlash.setEnabled(API < Build.VERSION_CODES.KITKAT); cbImages.setChecked(imagesBool); cbJsScript.setChecked(enableJSBool); cbFlash.setChecked(flashNum > 0); - cbAds.setChecked(Constants.FULL_VERSION && mPreferenceManager.getAdBlockEnabled()); + cbAds.setChecked(BuildConfig.FULL_VERSION && mPreferenceManager.getAdBlockEnabled()); cbColorMode.setChecked(mPreferenceManager.getColorModeEnabled()); } diff --git a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java index 5c504a25e..43d8f1273 100644 --- a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java +++ b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java @@ -22,6 +22,7 @@ import javax.inject.Inject; import javax.inject.Singleton; +import acr.browser.lightning.BuildConfig; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.preference.PreferenceManager; @@ -48,7 +49,7 @@ public class AdBlock { AdBlock(@NonNull Application application, @NonNull PreferenceManager preferenceManager) { mApplication = application; mPreferenceManager = preferenceManager; - if (mBlockedDomainsList.isEmpty() && Constants.FULL_VERSION) { + if (mBlockedDomainsList.isEmpty() && BuildConfig.FULL_VERSION) { loadHostsFile().subscribeOn(Schedulers.io()).subscribe(); } mBlockAds = mPreferenceManager.getAdBlockEnabled(); From ffec083ecabaa6d5a93ec3fa4d7d8c73f7b7293c Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Thu, 11 May 2017 20:11:08 -0400 Subject: [PATCH 115/181] Adding setting for black status bar --- .../lightning/activity/SettingsActivity.java | 2 +- .../lightning/activity/TabsManager.java | 4 +- .../activity/ThemableBrowserActivity.java | 16 +++++ .../activity/ThemableSettingsActivity.java | 21 ++++++- .../fragment/DisplaySettingsFragment.java | 63 ++++++++++--------- .../preference/PreferenceManager.java | 9 +++ .../browser/lightning/utils/ThemeUtils.java | 6 ++ app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 4 +- app/src/main/res/xml/preference_display.xml | 4 ++ 10 files changed, 91 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java index 6fcdb29a9..498bd06bf 100644 --- a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java @@ -23,7 +23,7 @@ public class SettingsActivity extends ThemableSettingsActivity { - private static final List mFragments = new ArrayList<>(7); + @NonNull private static final List mFragments = new ArrayList<>(7); @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index e2bf71355..c8b494573 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -55,12 +55,12 @@ public class TabsManager { private static final String URL_KEY = "URL_KEY"; private static final String BUNDLE_STORAGE = "SAVED_TABS.parcel"; - private final List mTabList = new ArrayList<>(1); + @NonNull private final List mTabList = new ArrayList<>(1); @Nullable private LightningView mCurrentTab; @Nullable private TabNumberChangedListener mTabNumberListener; private boolean mIsInitialized = false; - private final List mPostInitializationWorkList = new ArrayList<>(); + @NonNull private final List mPostInitializationWorkList = new ArrayList<>(); @Inject PreferenceManager mPreferenceManager; @Inject Application mApp; diff --git a/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java index b4d112fdd..3a29986da 100644 --- a/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java @@ -2,6 +2,8 @@ import android.content.Intent; import android.content.res.Configuration; +import android.graphics.Color; +import android.os.Build; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; @@ -10,6 +12,7 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.preference.PreferenceManager; +import acr.browser.lightning.utils.ThemeUtils; public abstract class ThemableBrowserActivity extends AppCompatActivity { @@ -32,6 +35,18 @@ protected void onCreate(Bundle savedInstanceState) { setTheme(R.style.Theme_BlackTheme); } super.onCreate(savedInstanceState); + + resetPreferences(); + } + + private void resetPreferences() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (mPreferences.getUseBlackStatusBar()) { + getWindow().setStatusBarColor(Color.BLACK); + } else { + getWindow().setStatusBarColor(ThemeUtils.getStatusBarColor(this)); + } + } } @Override @@ -56,6 +71,7 @@ void onWindowVisibleToUserAfterResume() { @Override protected void onResume() { super.onResume(); + resetPreferences(); mShouldRunOnResumeActions = true; int theme = mPreferences.getUseTheme(); boolean drawerTabs = mPreferences.getShowTabsInDrawer(!isTablet()); diff --git a/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java b/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java index 4d3cbe5f9..ebc2c1e78 100644 --- a/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java @@ -1,6 +1,8 @@ package acr.browser.lightning.activity; +import android.graphics.Color; import android.graphics.drawable.ColorDrawable; +import android.os.Build; import android.os.Bundle; import javax.inject.Inject; @@ -14,12 +16,12 @@ public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivi private int mTheme; - @Inject PreferenceManager mPreferenceManager; + @Inject PreferenceManager mPreferences; @Override protected void onCreate(Bundle savedInstanceState) { BrowserApp.getAppComponent().inject(this); - mTheme = mPreferenceManager.getUseTheme(); + mTheme = mPreferences.getUseTheme(); // set the theme if (mTheme == 0) { @@ -33,12 +35,25 @@ protected void onCreate(Bundle savedInstanceState) { this.getWindow().setBackgroundDrawable(new ColorDrawable(ThemeUtils.getPrimaryColorDark(this))); } super.onCreate(savedInstanceState); + + resetPreferences(); + } + + private void resetPreferences() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (mPreferences.getUseBlackStatusBar()) { + getWindow().setStatusBarColor(Color.BLACK); + } else { + getWindow().setStatusBarColor(ThemeUtils.getStatusBarColor(this)); + } + } } @Override protected void onResume() { super.onResume(); - if (mPreferenceManager.getUseTheme() != mTheme) { + resetPreferences(); + if (mPreferences.getUseTheme() != mTheme) { restart(); } } diff --git a/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java index a76b7b5b5..0b566a81b 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java @@ -33,6 +33,7 @@ public class DisplaySettingsFragment extends LightningPreferenceFragment impleme private static final String SETTINGS_TEXTSIZE = "text_size"; private static final String SETTINGS_DRAWERTABS = "cb_drawertabs"; private static final String SETTINGS_SWAPTABS = "cb_swapdrawers"; + private static final String SETTINGS_BLACK_STATUS = "black_status_bar"; private static final float XXLARGE = 30.0f; private static final float XLARGE = 26.0f; @@ -42,8 +43,7 @@ public class DisplaySettingsFragment extends LightningPreferenceFragment impleme private static final float XSMALL = 10.0f; private Activity mActivity; - private CheckBoxPreference cbstatus, cbfullscreen, cbviewport, cboverview, cbreflow; - private Preference theme; + private Preference mTheme; private String[] mThemeOptions; private int mCurrentTheme; @@ -63,35 +63,38 @@ private void initPrefs() { mThemeOptions = this.getResources().getStringArray(R.array.themes); mCurrentTheme = mPreferenceManager.getUseTheme(); - theme = findPreference(SETTINGS_THEME); - Preference textsize = findPreference(SETTINGS_TEXTSIZE); - cbstatus = (CheckBoxPreference) findPreference(SETTINGS_HIDESTATUSBAR); - cbfullscreen = (CheckBoxPreference) findPreference(SETTINGS_FULLSCREEN); - cbviewport = (CheckBoxPreference) findPreference(SETTINGS_VIEWPORT); - cboverview = (CheckBoxPreference) findPreference(SETTINGS_OVERVIEWMODE); - cbreflow = (CheckBoxPreference) findPreference(SETTINGS_REFLOW); + mTheme = findPreference(SETTINGS_THEME); + Preference textSize = findPreference(SETTINGS_TEXTSIZE); + CheckBoxPreference cbStatus = (CheckBoxPreference) findPreference(SETTINGS_HIDESTATUSBAR); + CheckBoxPreference cbFullScreen = (CheckBoxPreference) findPreference(SETTINGS_FULLSCREEN); + CheckBoxPreference cbViewPort = (CheckBoxPreference) findPreference(SETTINGS_VIEWPORT); + CheckBoxPreference cbOverview = (CheckBoxPreference) findPreference(SETTINGS_OVERVIEWMODE); + CheckBoxPreference cbReflow = (CheckBoxPreference) findPreference(SETTINGS_REFLOW); + CheckBoxPreference cbBlackStatus = (CheckBoxPreference) findPreference(SETTINGS_BLACK_STATUS); CheckBoxPreference cbDrawerTabs = (CheckBoxPreference) findPreference(SETTINGS_DRAWERTABS); CheckBoxPreference cbSwapTabs = (CheckBoxPreference) findPreference(SETTINGS_SWAPTABS); - theme.setOnPreferenceClickListener(this); - textsize.setOnPreferenceClickListener(this); - cbstatus.setOnPreferenceChangeListener(this); - cbfullscreen.setOnPreferenceChangeListener(this); - cbviewport.setOnPreferenceChangeListener(this); - cboverview.setOnPreferenceChangeListener(this); - cbreflow.setOnPreferenceChangeListener(this); + mTheme.setOnPreferenceClickListener(this); + textSize.setOnPreferenceClickListener(this); + cbStatus.setOnPreferenceChangeListener(this); + cbFullScreen.setOnPreferenceChangeListener(this); + cbViewPort.setOnPreferenceChangeListener(this); + cbOverview.setOnPreferenceChangeListener(this); + cbReflow.setOnPreferenceChangeListener(this); + cbBlackStatus.setOnPreferenceChangeListener(this); cbDrawerTabs.setOnPreferenceChangeListener(this); cbSwapTabs.setOnPreferenceChangeListener(this); - cbstatus.setChecked(mPreferenceManager.getHideStatusBarEnabled()); - cbfullscreen.setChecked(mPreferenceManager.getFullScreenEnabled()); - cbviewport.setChecked(mPreferenceManager.getUseWideViewportEnabled()); - cboverview.setChecked(mPreferenceManager.getOverviewModeEnabled()); - cbreflow.setChecked(mPreferenceManager.getTextReflowEnabled()); + cbStatus.setChecked(mPreferenceManager.getHideStatusBarEnabled()); + cbFullScreen.setChecked(mPreferenceManager.getFullScreenEnabled()); + cbViewPort.setChecked(mPreferenceManager.getUseWideViewportEnabled()); + cbOverview.setChecked(mPreferenceManager.getOverviewModeEnabled()); + cbReflow.setChecked(mPreferenceManager.getTextReflowEnabled()); + cbBlackStatus.setChecked(mPreferenceManager.getUseBlackStatusBar()); cbDrawerTabs.setChecked(mPreferenceManager.getShowTabsInDrawer(true)); cbSwapTabs.setChecked(mPreferenceManager.getBookmarksAndTabsSwapped()); - theme.setSummary(mThemeOptions[mPreferenceManager.getUseTheme()]); + mTheme.setSummary(mThemeOptions[mPreferenceManager.getUseTheme()]); } @Override @@ -118,23 +121,18 @@ public boolean onPreferenceChange(@NonNull Preference preference, Object newValu switch (preference.getKey()) { case SETTINGS_HIDESTATUSBAR: mPreferenceManager.setHideStatusBarEnabled(checked); - cbstatus.setChecked(checked); return true; case SETTINGS_FULLSCREEN: mPreferenceManager.setFullScreenEnabled(checked); - cbfullscreen.setChecked(checked); return true; case SETTINGS_VIEWPORT: mPreferenceManager.setUseWideViewportEnabled(checked); - cbviewport.setChecked(checked); return true; case SETTINGS_OVERVIEWMODE: mPreferenceManager.setOverviewModeEnabled(checked); - cboverview.setChecked(checked); return true; case SETTINGS_REFLOW: mPreferenceManager.setTextReflowEnabled(checked); - cbreflow.setChecked(checked); return true; case SETTINGS_DRAWERTABS: mPreferenceManager.setShowTabsInDrawer(checked); @@ -142,6 +140,9 @@ public boolean onPreferenceChange(@NonNull Preference preference, Object newValu case SETTINGS_SWAPTABS: mPreferenceManager.setBookmarkAndTabsSwapped(checked); return true; + case SETTINGS_BLACK_STATUS: + mPreferenceManager.setUseBlackStatusBar(checked); + return true; default: return false; } @@ -205,7 +206,7 @@ private void themePicker() { public void onClick(DialogInterface dialog, int which) { mPreferenceManager.setUseTheme(which); if (which < mThemeOptions.length) { - theme.setSummary(mThemeOptions[which]); + mTheme.setSummary(mThemeOptions[which]); } } }); @@ -233,13 +234,13 @@ public void onCancel(DialogInterface dialog) { private static class TextSeekBarListener implements SeekBar.OnSeekBarChangeListener { - private final TextView sample; + private final TextView mSample; - public TextSeekBarListener(TextView sample) {this.sample = sample;} + public TextSeekBarListener(TextView sample) {this.mSample = sample;} @Override public void onProgressChanged(SeekBar view, int size, boolean user) { - this.sample.setTextSize(getTextSize(size)); + this.mSample.setTextSize(getTextSize(size)); } @Override diff --git a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java index b62b1d84b..d3233933e 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -55,6 +55,7 @@ private static class Name { static final String IDENTIFYING_HEADERS = "removeIdentifyingHeaders"; static final String SWAP_BOOKMARKS_AND_TABS = "swapBookmarksAndTabs"; static final String SEARCH_SUGGESTIONS = "searchSuggestions"; + static final String BLACK_STATUS_BAR = "blackStatusBar"; static final String USE_PROXY = "useProxy"; static final String PROXY_CHOICE = "proxyChoice"; @@ -295,6 +296,10 @@ public boolean getRemoveIdentifyingHeadersEnabled() { return mPrefs.getBoolean(Name.IDENTIFYING_HEADERS, false); } + public boolean getUseBlackStatusBar() { + return mPrefs.getBoolean(Name.BLACK_STATUS_BAR, false); + } + private void putBoolean(@NonNull String name, boolean value) { mPrefs.edit().putBoolean(name, value).apply(); } @@ -307,6 +312,10 @@ private void putString(@NonNull String name, @Nullable String value) { mPrefs.edit().putString(name, value).apply(); } + public void setUseBlackStatusBar(boolean enabled) { + putBoolean(Name.BLACK_STATUS_BAR, enabled); + } + public void setRemoveIdentifyingHeadersEnabled(boolean enabled) { putBoolean(Name.IDENTIFYING_HEADERS, enabled); } diff --git a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java index 0660f39a2..f92589450 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java @@ -1,5 +1,6 @@ package acr.browser.lightning.utils; +import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -37,6 +38,11 @@ public static int getAccentColor(@NonNull Context context) { return getColor(context, R.attr.colorAccent); } + @TargetApi(21) + public static int getStatusBarColor(@NonNull Context context) { + return getColor(context, android.R.attr.statusBarColor); + } + public static int getColor(@NonNull Context context, @AttrRes int resource) { TypedArray a = context.obtainStyledAttributes(sTypedValue.data, new int[]{resource}); int color = a.getColor(0, 0); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4e41fab89..6a447498a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -216,6 +216,7 @@ Invert color Dark Theme + Black status bar Tabs App Theme Light Theme diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 7f6e35b54..24a8d5dcc 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -44,7 +44,7 @@ @color/primary_color - @color/secondary_color + @color/primary_color @color/accent_color @color/drawer_background @color/divider_light @@ -67,7 +67,7 @@ @color/primary_color_dark - @color/secondary_color + @color/primary_color_dark @color/accent_color @color/drawer_background_dark @color/divider_dark diff --git a/app/src/main/res/xml/preference_display.xml b/app/src/main/res/xml/preference_display.xml index 8aad3a311..11e11c6cb 100644 --- a/app/src/main/res/xml/preference_display.xml +++ b/app/src/main/res/xml/preference_display.xml @@ -18,6 +18,10 @@ android:defaultValue="true" android:key="fullscreen" android:title="@string/fullscreen"/> + Date: Thu, 11 May 2017 20:39:43 -0400 Subject: [PATCH 116/181] Darkening the status bar --- app/src/main/res/values-v21/styles.xml | 2 +- app/src/main/res/values/colors.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index bb3d86776..53e8ef074 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -11,7 +11,7 @@ @null @color/primary_color_dark - + @color/secondary_color_settings_dark diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 0cf106bbd..1e21279d6 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -8,7 +8,7 @@ #0d000000 #E0E0E0 - #4D000000 + #66000000 #0073EF #ffffff From 4b07ac013d42cdb96dfad2cbdbe7a5989ee9252e Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Thu, 11 May 2017 21:05:22 -0400 Subject: [PATCH 117/181] Adding documentation for ThemeUtils --- .../browser/lightning/utils/ThemeUtils.java | 95 +++++++++++++++++++ .../browser/lightning/view/LightningView.java | 2 +- 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java index f92589450..f28c369cc 100644 --- a/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java @@ -26,23 +26,60 @@ public class ThemeUtils { private static final TypedValue sTypedValue = new TypedValue(); + /** + * Gets the primary color of the current theme. + * + * @param context the context to get the theme from. + * @return the primary color of the current theme. + */ + @ColorInt public static int getPrimaryColor(@NonNull Context context) { return getColor(context, R.attr.colorPrimary); } + /** + * Gets the primary dark color of the current theme. + * + * @param context the context to get the theme from. + * @return the primary dark color of the current theme. + */ + @ColorInt public static int getPrimaryColorDark(@NonNull Context context) { return getColor(context, R.attr.colorPrimaryDark); } + /** + * Gets the accent color of the current theme. + * + * @param context the context to get the theme from. + * @return the accent color of the current theme. + */ + @ColorInt public static int getAccentColor(@NonNull Context context) { return getColor(context, R.attr.colorAccent); } + /** + * Gets the color of the status bar as set in styles + * for the current theme. + * + * @param context the context to get the theme from. + * @return the status bar color of the current theme. + */ + @ColorInt @TargetApi(21) public static int getStatusBarColor(@NonNull Context context) { return getColor(context, android.R.attr.statusBarColor); } + /** + * Gets the color attribute from the current theme. + * + * @param context the context to get the theme from. + * @param resource the color attribute resource. + * @return the color for the given attribute. + */ + @ColorInt public static int getColor(@NonNull Context context, @AttrRes int resource) { TypedArray a = context.obtainStyledAttributes(sTypedValue.data, new int[]{resource}); int color = a.getColor(0, 0); @@ -50,16 +87,37 @@ public static int getColor(@NonNull Context context, @AttrRes int resource) { return color; } + /** + * Gets the icon color for the light theme. + * + * @param context the context to use. + * @return the color of the icon. + */ @ColorInt public static int getIconLightThemeColor(@NonNull Context context) { return ContextCompat.getColor(context, R.color.icon_light_theme); } + /** + * Gets the icon color for the dark theme. + * + * @param context the context to use. + * @return the color of the icon. + */ @ColorInt public static int getIconDarkThemeColor(@NonNull Context context) { return ContextCompat.getColor(context, R.color.icon_dark_theme); } + /** + * Gets the color icon for the light or + * dark theme. + * + * @param context the context to use. + * @param dark true for the dark theme, + * false for the light theme. + * @return the color of the icon. + */ @ColorInt public static int getIconThemeColor(@NonNull Context context, boolean dark) { return (dark) ? getIconDarkThemeColor(context) : getIconLightThemeColor(context); @@ -91,9 +149,20 @@ private static Bitmap getBitmapFromVectorDrawable(@NonNull Context context, int return bitmap; } + /** + * Gets the icon with an applied color filter + * for the correct theme. + * + * @param context the context to use. + * @param res the drawable resource to use. + * @param dark true for icon suitable for use with a dark theme, + * false for icon suitable for use with a light theme. + * @return a themed icon. + */ @NonNull public static Bitmap getThemedBitmap(@NonNull Context context, @DrawableRes int res, boolean dark) { int color = dark ? getIconDarkThemeColor(context) : getIconLightThemeColor(context); + Bitmap sourceBitmap = getBitmapFromVectorDrawable(context, res); Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight(), Bitmap.Config.ARGB_8888); @@ -106,19 +175,45 @@ public static Bitmap getThemedBitmap(@NonNull Context context, @DrawableRes int return resultBitmap; } + /** + * Gets the icon with an applied color filter + * for the correct theme. + * + * @param context the context to use. + * @param res the drawable resource to use. + * @param dark true for icon suitable for use with a dark theme, + * false for icon suitable for use with a light theme. + * @return a themed icon. + */ @NonNull public static Drawable getThemedDrawable(@NonNull Context context, @DrawableRes int res, boolean dark) { int color = dark ? getIconDarkThemeColor(context) : getIconLightThemeColor(context); + final Drawable drawable = getVectorDrawable(context, res); drawable.mutate(); drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); return drawable; } + /** + * The text hint color for dark theme or light theme. + * + * @param dark true for a text color suitable for use with a dark theme, + * false for a text color suitable for use with a light theme. + * @return a text color. + */ + @ColorInt public static int getThemedTextHintColor(boolean dark) { return 0x80ffffff & (dark ? Color.WHITE : Color.BLACK); } + /** + * Gets the edit text text color for the current theme. + * + * @param context the context to use. + * @return a text color. + */ + @ColorInt public static int getTextColor(@NonNull Context context) { return getColor(context, android.R.attr.editTextColor); } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 4148fe5e5..1f137f0b7 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -1209,7 +1209,7 @@ private static class WebViewHandler extends Handler { @NonNull private final WeakReference mReference; - public WebViewHandler(LightningView view) { + WebViewHandler(@NonNull LightningView view) { mReference = new WeakReference<>(view); } From 1b36d65b54368803aae85c51ecaf41c9e33c79bf Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Fri, 12 May 2017 11:28:19 -0400 Subject: [PATCH 118/181] Updating grade plugin --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ad168f3fd..77dfcac51 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' + classpath 'com.android.tools.build:gradle:2.3.2' classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.3' } } From cd06cbf6969e97c1606b49b6580764418d0f9b56 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Fri, 12 May 2017 13:49:46 -0400 Subject: [PATCH 119/181] Fixing inconsistency between browser and settings activities --- app/src/main/res/values-v21/styles.xml | 6 +++--- app/src/main/res/values/styles.xml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index 53e8ef074..ad8837743 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -24,7 +24,7 @@ \n" + + "

"; + + private static final String PART1 = "
\n" + + "
\n" + + "
\n" + + "

"; + + private static final String PART3 = "

\n

"; + + private static final String PART4 = "

"; + + private static final String END = "
"; + + private File mFilesDir; + + @Inject Application mApp; + @Inject DownloadsModel mManager; + + @NonNull private final String mTitle; + + public DownloadsPage() { + BrowserApp.getAppComponent().inject(this); + mTitle = mApp.getString(R.string.action_downloads); + } + + @NonNull + public Single getDownloadsPage() { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + mFilesDir = mApp.getFilesDir(); + + buildDownloadsPage(null); + + File downloadsWebPage = new File(mFilesDir, FILENAME); + + subscriber.onItem(Constants.FILE + downloadsWebPage); + subscriber.onComplete(); + } + }); + } + + private void buildDownloadsPage(@Nullable final String folder) { + mManager.getAllDownloads() + .subscribe(new SingleOnSubscribe>() { + @Override + public void onItem(@Nullable List list) { + Preconditions.checkNonNull(list); + + final File downloadsWebPage; + if (folder == null || folder.isEmpty()) { + downloadsWebPage = new File(mFilesDir, FILENAME); + } else { + downloadsWebPage = new File(mFilesDir, folder + '-' + FILENAME); + } + final StringBuilder downloadsBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2); + + for (int n = 0, size = list.size(); n < size; n++) { + final DownloadItem item = list.get(n); + downloadsBuilder.append(PART1); + downloadsBuilder.append(item.getUrl()); + downloadsBuilder.append(PART2); + downloadsBuilder.append(item.getTitle()); + downloadsBuilder.append(PART3); + downloadsBuilder.append(item.getContentSize()); + downloadsBuilder.append(PART4); + } + downloadsBuilder.append(END); + FileWriter bookWriter = null; + try { + //noinspection IOResourceOpenedButNotSafelyClosed + bookWriter = new FileWriter(downloadsWebPage, false); + bookWriter.write(downloadsBuilder.toString()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + Utils.close(bookWriter); + } + } + }); + } + +} diff --git a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadItem.java b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadItem.java new file mode 100644 index 000000000..884e05219 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadItem.java @@ -0,0 +1,96 @@ +/* + * Copyright 2014 A.C.R. Development + */ +package acr.browser.lightning.database.downloads; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import acr.browser.lightning.utils.Preconditions; + +public class DownloadItem implements Comparable { + + // private variables + @NonNull + private String mUrl = ""; + + @NonNull + private String mTitle = ""; + + @NonNull + private String mContentSize = ""; + + public DownloadItem() {} + + public DownloadItem(@NonNull String url, @NonNull String title, @NonNull String size) { + Preconditions.checkNonNull(url); + Preconditions.checkNonNull(title); + this.mUrl = url; + this.mTitle = title; + this.mContentSize = size; + } + + @NonNull + public String getUrl() { + return this.mUrl; + } + + public void setUrl(@Nullable String url) { + this.mUrl = (url == null) ? "" : url; + } + + @NonNull + public String getTitle() { + return this.mTitle; + } + + public void setTitle(@Nullable String title) { + this.mTitle = (title == null) ? "" : title; + } + + @NonNull + public String getContentSize() { + return this.mContentSize; + } + + public void setContentSize(@Nullable String size) { + this.mContentSize = (size == null) ? "" : size; + } + + @NonNull + @Override + public String toString() { + return mTitle; + } + + @Override + public int compareTo(@NonNull DownloadItem another) { + int compare = this.mTitle.compareTo(another.mTitle); + if (compare == 0) { + return this.mUrl.compareTo(another.mUrl); + } + return compare; + } + + @Override + public boolean equals(@Nullable Object object) { + + if (this == object) return true; + if (object == null) return false; + if (!(object instanceof DownloadItem)) return false; + + DownloadItem that = (DownloadItem) object; + + return this.mTitle.equals(that.mTitle) && this.mUrl.equals(that.mUrl) + && this.mContentSize.equals(that.mContentSize); + } + + @Override + public int hashCode() { + + int result = mUrl.hashCode(); + result = 31 * result + mTitle.hashCode(); + + return result; + } +} diff --git a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsDatabase.java b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsDatabase.java new file mode 100644 index 000000000..db2f83c35 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsDatabase.java @@ -0,0 +1,261 @@ +package acr.browser.lightning.database.downloads; + +import android.app.Application; +import android.content.ContentValues; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.WorkerThread; + +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.CompletableAction; +import com.anthonycr.bonsai.CompletableSubscriber; +import com.anthonycr.bonsai.Single; +import com.anthonycr.bonsai.SingleAction; +import com.anthonycr.bonsai.SingleSubscriber; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import acr.browser.lightning.R; + +/** + * The disk backed download database. + * See {@link DownloadsModel} for method + * documentation. + */ +@Singleton +public class DownloadsDatabase extends SQLiteOpenHelper implements DownloadsModel { + + private static final String TAG = "DownloadsDatabase"; + + // Database Version + private static final int DATABASE_VERSION = 1; + + // Database Name + private static final String DATABASE_NAME = "downloadManager"; + + // HistoryItems table name + private static final String TABLE_DOWNLOADS = "download"; + + // HistoryItems Table Columns names + private static final String KEY_ID = "id"; + private static final String KEY_URL = "url"; + private static final String KEY_TITLE = "title"; + private static final String KEY_SIZE = "size"; + + @NonNull private final String DEFAULT_DOWNLOADS_TITLE; + + @Nullable private SQLiteDatabase mDatabase; + + @Inject + public DownloadsDatabase(@NonNull Application application) { + super(application, DATABASE_NAME, null, DATABASE_VERSION); + DEFAULT_DOWNLOADS_TITLE = application.getString(R.string.untitled); + } + + /** + * Lazily initializes the database + * field when called. + * + * @return a non null writable database. + */ + @WorkerThread + @NonNull + private SQLiteDatabase lazyDatabase() { + if (mDatabase == null || !mDatabase.isOpen()) { + mDatabase = getWritableDatabase(); + } + + return mDatabase; + } + + // Creating Tables + @Override + public void onCreate(@NonNull SQLiteDatabase db) { + String CREATE_BOOKMARK_TABLE = "CREATE TABLE " + + DatabaseUtils.sqlEscapeString(TABLE_DOWNLOADS) + '(' + + DatabaseUtils.sqlEscapeString(KEY_ID) + " INTEGER PRIMARY KEY," + + DatabaseUtils.sqlEscapeString(KEY_URL) + " TEXT," + + DatabaseUtils.sqlEscapeString(KEY_TITLE) + " TEXT," + + DatabaseUtils.sqlEscapeString(KEY_SIZE) + " TEXT" + ')'; + db.execSQL(CREATE_BOOKMARK_TABLE); + } + + // Upgrading database + @Override + public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) { + // Drop older table if it exists + db.execSQL("DROP TABLE IF EXISTS " + DatabaseUtils.sqlEscapeString(TABLE_DOWNLOADS)); + // Create tables again + onCreate(db); + } + + @NonNull + private static ContentValues bindBookmarkToContentValues(@NonNull DownloadItem downloadItem) { + ContentValues contentValues = new ContentValues(3); + contentValues.put(KEY_TITLE, downloadItem.getTitle()); + contentValues.put(KEY_URL, downloadItem.getUrl()); + contentValues.put(KEY_SIZE, downloadItem.getContentSize()); + + return contentValues; + } + + @NonNull + private static DownloadItem bindCursorToDownloadItem(@NonNull Cursor cursor) { + DownloadItem download = new DownloadItem(); + + download.setUrl(cursor.getString(cursor.getColumnIndex(KEY_URL))); + download.setTitle(cursor.getString(cursor.getColumnIndex(KEY_TITLE))); + download.setContentSize(cursor.getString(cursor.getColumnIndex(KEY_SIZE))); + + return download; + } + + @NonNull + private static List bindCursorToDownloadItemList(@NonNull Cursor cursor) { + List downloads = new ArrayList<>(); + + while (cursor.moveToNext()) { + downloads.add(bindCursorToDownloadItem(cursor)); + } + + cursor.close(); + + return downloads; + } + + @NonNull + @Override + public Single findDownloadForUrl(@NonNull final String url) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + Cursor cursor = lazyDatabase().query(TABLE_DOWNLOADS, null, KEY_URL + "=?", new String[]{url}, null, null, "1"); + + if (cursor.moveToFirst()) { + subscriber.onItem(bindCursorToDownloadItem(cursor)); + } else { + subscriber.onItem(null); + } + + cursor.close(); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single isDownload(@NonNull final String url) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + Cursor cursor = lazyDatabase().query(TABLE_DOWNLOADS, null, KEY_URL + "=?", new String[]{url}, null, null, null, "1"); + + subscriber.onItem(cursor.moveToFirst()); + + cursor.close(); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single addDownloadIfNotExists(@NonNull final DownloadItem item) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + Cursor cursor = lazyDatabase().query(TABLE_DOWNLOADS, null, KEY_URL + "=?", new String[]{item.getUrl()}, null, null, "1"); + + if (cursor.moveToFirst()) { + cursor.close(); + subscriber.onItem(false); + subscriber.onComplete(); + return; + } + + cursor.close(); + + long id = lazyDatabase().insert(TABLE_DOWNLOADS, null, bindBookmarkToContentValues(item)); + + subscriber.onItem(id != -1); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Completable addDownloadsList(@NonNull final List bookmarkItems) { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + lazyDatabase().beginTransaction(); + + for (DownloadItem item : bookmarkItems) { + addDownloadIfNotExists(item).subscribe(); + } + + lazyDatabase().setTransactionSuccessful(); + lazyDatabase().endTransaction(); + + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single deleteDownload(@NonNull final DownloadItem bookmark) { + return Single.create(new SingleAction() { + @Override + public void onSubscribe(@NonNull SingleSubscriber subscriber) { + int rows = lazyDatabase().delete(TABLE_DOWNLOADS, KEY_URL + "=?", new String[]{bookmark.getUrl()}); + + subscriber.onItem(rows > 0); + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Completable deleteAllDownloads() { + return Completable.create(new CompletableAction() { + @Override + public void onSubscribe(@NonNull CompletableSubscriber subscriber) { + lazyDatabase().delete(TABLE_DOWNLOADS, null, null); + + subscriber.onComplete(); + } + }); + } + + @NonNull + @Override + public Single> getAllDownloads() { + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull SingleSubscriber> subscriber) { + Cursor cursor = lazyDatabase().query(TABLE_DOWNLOADS, null, null, null, null, null, null); + + subscriber.onItem(bindCursorToDownloadItemList(cursor)); + subscriber.onComplete(); + } + }); + } + + @Override + public long count() { + return DatabaseUtils.queryNumEntries(lazyDatabase(), TABLE_DOWNLOADS); + } + +} diff --git a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java new file mode 100644 index 000000000..7ce5f3e89 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java @@ -0,0 +1,97 @@ +package acr.browser.lightning.database.downloads; + +import android.support.annotation.NonNull; +import android.support.annotation.WorkerThread; + +import com.anthonycr.bonsai.Completable; +import com.anthonycr.bonsai.Single; + +import java.util.List; + +/** + * The interface that should be used to + * communicate with the download database. + *

+ * Created by anthonycr on 5/6/17. + */ +public interface DownloadsModel { + + /** + * Determines if a URL is associated with a download. + * + * @param url the URL to check. + * @return an observable that will emit true if + * the URL is a download, false otherwise. + */ + @NonNull + Single isDownload(@NonNull String url); + + /** + * Gets the download associated with the URL. + * + * @param url the URL to look for. + * @return an observable that will emit either + * the download associated with the URL or null. + */ + @NonNull + Single findDownloadForUrl(@NonNull String url); + + /** + * Adds a download if one does not already exist with + * the same URL. + * + * @param item the download to add. + * @return an observable that emits true if the download + * was added, false otherwise. + */ + @NonNull + Single addDownloadIfNotExists(@NonNull DownloadItem item); + + /** + * Adds a list of downloads to the database. + * + * @param downloadItems the downloads to add. + * @return an observable that emits a complete event + * when all the downloads have been added. + */ + @NonNull + Completable addDownloadsList(@NonNull List downloadItems); + + /** + * Deletes a download from the database. + * + * @param download the download to delete. + * @return an observable that emits true when + * the download is deleted, false otherwise. + */ + @NonNull + Single deleteDownload(@NonNull DownloadItem download); + + /** + * Deletes all downloads in the database. + * + * @return an observable that emits a completion + * event when all downloads have been deleted. + */ + @NonNull + Completable deleteAllDownloads(); + + /** + * Emits a list of all downloads + * + * @return an observable that emits a list + * of all downloads. + */ + @NonNull + Single> getAllDownloads(); + + /** + * A synchronous call to the model + * that returns the number of downloads. + * Should be called from a background thread. + * + * @return the number of downloads in the database. + */ + @WorkerThread + long count(); +} diff --git a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java index 31ed7cb83..fba4cbaf1 100644 --- a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java +++ b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java @@ -7,6 +7,7 @@ import android.app.Activity; import android.app.Dialog; import android.content.DialogInterface; +import android.support.annotation.Nullable; import android.support.v7.app.AlertDialog; import android.text.format.Formatter; import android.util.Log; @@ -15,9 +16,12 @@ import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; +import acr.browser.lightning.database.downloads.DownloadItem; +import acr.browser.lightning.database.downloads.DownloadsModel; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.preference.PreferenceManager; +import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.grant.PermissionsManager; import com.anthonycr.grant.PermissionsResultAction; @@ -31,6 +35,8 @@ public class LightningDownloadListener implements DownloadListener { @Inject PreferenceManager mPreferenceManager; + @Inject DownloadsModel downloadsModel; + public LightningDownloadListener(Activity context) { BrowserApp.getAppComponent().inject(this); mActivity = context; @@ -75,6 +81,16 @@ public void onClick(DialogInterface dialog, int which) { dialogClickListener).show(); BrowserDialog.setDialogSize(mActivity, dialog); Log.i(TAG, "Downloading: " + fileName); + + downloadsModel.addDownloadIfNotExists(new DownloadItem(url, fileName, downloadSize)).subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean item) { + super.onItem(item); + + if (item != null && !item) + Log.i(TAG, "error saving download to database"); + } + }); } @Override diff --git a/app/src/main/java/acr/browser/lightning/utils/UrlUtils.java b/app/src/main/java/acr/browser/lightning/utils/UrlUtils.java index 63ba7980a..654e41789 100644 --- a/app/src/main/java/acr/browser/lightning/utils/UrlUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/UrlUtils.java @@ -25,6 +25,7 @@ import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; +import acr.browser.lightning.constant.DownloadsPage; import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.constant.StartPage; @@ -91,6 +92,7 @@ public static String smartUrlFilter(@NonNull String url, boolean canBeSearch, St public static boolean isSpecialUrl(@Nullable String url) { return url != null && url.startsWith(Constants.FILE) && (url.endsWith(BookmarkPage.FILENAME) || + url.endsWith(DownloadsPage.FILENAME) || url.endsWith(HistoryPage.FILENAME) || url.endsWith(StartPage.FILENAME)); } @@ -105,6 +107,16 @@ public static boolean isBookmarkUrl(@Nullable String url) { return url != null && url.startsWith(Constants.FILE) && url.endsWith(BookmarkPage.FILENAME); } + /** + * Determines if the url is a url for the bookmark page. + * + * @param url the url to check, may be null. + * @return true if the url is a bookmark url, false otherwise. + */ + public static boolean isDownloadsUrl(@Nullable String url) { + return url != null && url.startsWith(Constants.FILE) && url.endsWith(DownloadsPage.FILENAME); + } + /** * Determines if the url is a url for the history page. * diff --git a/app/src/main/res/menu-large/main.xml b/app/src/main/res/menu-large/main.xml index 92b63e110..958acfaa1 100644 --- a/app/src/main/res/menu-large/main.xml +++ b/app/src/main/res/menu-large/main.xml @@ -47,6 +47,9 @@ + diff --git a/app/src/main/res/menu-xlarge/main.xml b/app/src/main/res/menu-xlarge/main.xml index 92b63e110..958acfaa1 100644 --- a/app/src/main/res/menu-xlarge/main.xml +++ b/app/src/main/res/menu-xlarge/main.xml @@ -47,6 +47,9 @@ + diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml index 9bfa01bf0..f620979fd 100644 --- a/app/src/main/res/menu/main.xml +++ b/app/src/main/res/menu/main.xml @@ -29,6 +29,9 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ee47f618b..7479d7907 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,6 +6,7 @@ Share History Bookmarks + Downloads Add bookmark Copy link Forward From c3df77677196710d5f6a3a6643e4401ee47f0e37 Mon Sep 17 00:00:00 2001 From: DF1E Date: Sun, 28 May 2017 14:28:48 +0200 Subject: [PATCH 146/181] add delete downloads dialog --- .../lightning/activity/BrowserActivity.java | 12 ++++++ .../lightning/controller/UIController.java | 2 + .../database/downloads/DownloadsDatabase.java | 4 +- .../database/downloads/DownloadsModel.java | 4 +- .../dialog/LightningDialogBuilder.java | 41 +++++++++++++++++++ .../browser/lightning/view/LightningView.java | 26 ++++++++++++ app/src/main/res/values/strings.xml | 2 + 7 files changed, 87 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 8e1a41620..16eed9ee4 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -2130,6 +2130,18 @@ public void handleBookmarksChange() { } } + @Override + public void handleDownloadDeleted() { + final LightningView currentTab = mTabsManager.getCurrentTab(); + if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) + && currentTab.getUrl().endsWith(DownloadsPage.FILENAME)) { + currentTab.loadDownloadspage(); + } + if (currentTab != null) { + mBookmarksView.handleUpdatedUrl(currentTab.getUrl()); + } + } + @Override public void handleBookmarkDeleted(@NonNull HistoryItem item) { mBookmarksView.handleBookmarkDeleted(item); diff --git a/app/src/main/java/acr/browser/lightning/controller/UIController.java b/app/src/main/java/acr/browser/lightning/controller/UIController.java index a39a1bd23..a9021a715 100644 --- a/app/src/main/java/acr/browser/lightning/controller/UIController.java +++ b/app/src/main/java/acr/browser/lightning/controller/UIController.java @@ -86,6 +86,8 @@ public interface UIController { void handleBookmarksChange(); + void handleDownloadDeleted(); + void handleBookmarkDeleted(@NonNull HistoryItem item); void handleNewTab(@NonNull LightningDialogBuilder.NewTab newTabType, @NonNull String url); diff --git a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsDatabase.java b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsDatabase.java index db2f83c35..a14faff43 100644 --- a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsDatabase.java @@ -214,11 +214,11 @@ public void onSubscribe(@NonNull CompletableSubscriber subscriber) { @NonNull @Override - public Single deleteDownload(@NonNull final DownloadItem bookmark) { + public Single deleteDownload(@NonNull final String url) { return Single.create(new SingleAction() { @Override public void onSubscribe(@NonNull SingleSubscriber subscriber) { - int rows = lazyDatabase().delete(TABLE_DOWNLOADS, KEY_URL + "=?", new String[]{bookmark.getUrl()}); + int rows = lazyDatabase().delete(TABLE_DOWNLOADS, KEY_URL + "=?", new String[]{url}); subscriber.onItem(rows > 0); subscriber.onComplete(); diff --git a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java index 7ce5f3e89..d8dc67e61 100644 --- a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java +++ b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java @@ -60,12 +60,12 @@ public interface DownloadsModel { /** * Deletes a download from the database. * - * @param download the download to delete. + * @param url the download url to delete. * @return an observable that emits true when * the download is deleted, false otherwise. */ @NonNull - Single deleteDownload(@NonNull DownloadItem download); + Single deleteDownload(@NonNull String url); /** * Deletes all downloads in the database. diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 490a9f888..46f23d85c 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -8,6 +8,7 @@ import android.support.annotation.Nullable; import android.support.v7.app.AlertDialog; import android.text.TextUtils; +import android.util.Log; import android.view.View; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; @@ -26,15 +27,20 @@ import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; +import acr.browser.lightning.constant.DownloadsPage; import acr.browser.lightning.controller.UIController; import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.database.bookmark.BookmarkModel; +import acr.browser.lightning.database.downloads.DownloadItem; +import acr.browser.lightning.database.downloads.DownloadsModel; import acr.browser.lightning.database.history.HistoryModel; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.IntentUtils; import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.Utils; +import static android.content.ContentValues.TAG; + /** * TODO Rename this class it doesn't build dialogs only for bookmarks *

@@ -49,6 +55,7 @@ public enum NewTab { } @Inject BookmarkModel mBookmarkManager; + @Inject DownloadsModel mDownloadsModel; @Inject PreferenceManager mPreferenceManager; @Inject @@ -152,6 +159,40 @@ public void onClick() { }); } + /** + * Show the appropriated dialog for the long pressed link. + * + * @param activity used to show the dialog + * @param url the long pressed url + */ + public void showLongPressedDialogForDownloadUrl(@NonNull final Activity activity, + @NonNull final UIController uiController, + @NonNull final String url) { + + BrowserDialog.show(activity, R.string.action_bookmarks, + new BrowserDialog.Item(R.string.dialog_delete_download) { + @Override + public void onClick() { + mDownloadsModel.deleteDownload(url).subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean item) { + if (item != null && !item) + Log.i(TAG, "error deleting download from database"); + else + uiController.handleDownloadDeleted(); + } + }); + } + }, + new BrowserDialog.Item(R.string.dialog_delete_all_downloads) { + @Override + public void onClick() { + // TODO: fix refreshing downloads page + mDownloadsModel.deleteAllDownloads().subscribeOn(Schedulers.io()).subscribe(); + } + }); + } + private void showEditBookmarkDialog(@NonNull final Activity activity, @NonNull final UIController uiController, @NonNull final HistoryItem item) { diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 1f137f0b7..8532deae4 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -47,6 +47,7 @@ import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; +import acr.browser.lightning.constant.DownloadsPage; import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.constant.StartPage; import acr.browser.lightning.controller.UIController; @@ -242,6 +243,24 @@ public void onItem(@Nullable String item) { }); } + /** + * This method gets the bookmark page URL from the {@link BookmarkPage} + * class asynchronously and loads the URL in the WebView on the + * UI thread. It also caches the default folder icon locally. + */ + public void loadDownloadspage() { + new DownloadsPage().getDownloadsPage() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + loadUrl(item); + } + }); + } + /** * Initialize the preference driven settings of the WebView. This method * must be called whenever the preferences are changed within SharedPreferences. @@ -984,6 +1003,13 @@ private void longClickPage(@Nullable final String url) { final String newUrl = result.getExtra(); mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, mUIController, newUrl); } + } else if (currentUrl.endsWith(DownloadsPage.FILENAME)) { + if (url != null) { + mBookmarksDialogBuilder.showLongPressedDialogForDownloadUrl(mActivity, mUIController, url); + } else if (result != null && result.getExtra() != null) { + final String newUrl = result.getExtra(); + mBookmarksDialogBuilder.showLongPressedDialogForDownloadUrl(mActivity, mUIController, newUrl); + } } } else { if (url != null) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7479d7907..71a594cf8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -246,4 +246,6 @@ Rename folder Remove folder Close browser + Delete download + Delete all downloads From fd3336b27047016552189759d91cb87868b52775 Mon Sep 17 00:00:00 2001 From: DF1E Date: Mon, 29 May 2017 09:14:22 +0200 Subject: [PATCH 147/181] slightly improved history and downloads html --- .../lightning/constant/DownloadsPage.java | 18 +++++++---------- .../lightning/constant/HistoryPage.java | 20 +++++++++++++------ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/constant/DownloadsPage.java b/app/src/main/java/acr/browser/lightning/constant/DownloadsPage.java index 8b701d8b1..9bc0a4ee1 100644 --- a/app/src/main/java/acr/browser/lightning/constant/DownloadsPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/DownloadsPage.java @@ -40,22 +40,18 @@ public final class DownloadsPage { "\n" + ""; - private static final String HEADING_2 = "\n" + - "\n" + - "\n" + - "

"; + private static final String HEADING_2 = "" + + "" + + "" + + "
"; private static final String PART1 = "
\n" + - "
\n" + - "
\n" + - "

"; + private static final String PART2 = "'>

"; - private static final String PART3 = "

\n

"; + private static final String PART3 = "

"; - private static final String PART4 = "

"; + private static final String PART4 = "

"; private static final String END = "
"; diff --git a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java index b175082aa..94a36c843 100644 --- a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java @@ -37,17 +37,25 @@ public class HistoryPage { public static final String FILENAME = "history.html"; - private static final String HEADING_1 = ""; + private static final String HEADING_1 = "<!DOCTYPE html><html xmlns=http://www.w3.org/1999/xhtml>\n" + + "<head>\n" + + "<meta content=en-us http-equiv=Content-Language />\n" + + "<meta content='text/html; charset=utf-8' http-equiv=Content-Type />\n" + + "<meta name=viewport content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>\n" + + "<title>"; - private static final String HEADING_2 = "
"; + private static final String HEADING_2 = "" + + "" + + "" + + "
"; - private static final String PART1 = "

"; + private static final String PART2 = "'>

"; - private static final String PART3 = "

"; + private static final String PART3 = "

"; - private static final String PART4 = "

"; + private static final String PART4 = "

"; private static final String END = "
"; From c07c925ada16f44a7529f237036bc31e287e9aa6 Mon Sep 17 00:00:00 2001 From: DF1E Date: Mon, 29 May 2017 09:30:29 +0200 Subject: [PATCH 148/181] fix refreshing page after deleting all bookmarks simple forgot to add handleDownloadDeleted() --- .../acr/browser/lightning/dialog/LightningDialogBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 46f23d85c..506debda2 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -187,8 +187,8 @@ public void onItem(@Nullable Boolean item) { new BrowserDialog.Item(R.string.dialog_delete_all_downloads) { @Override public void onClick() { - // TODO: fix refreshing downloads page mDownloadsModel.deleteAllDownloads().subscribeOn(Schedulers.io()).subscribe(); + uiController.handleDownloadDeleted(); } }); } From eddba7e480c1d02ba90c0d57638a0a0e8eb4c018 Mon Sep 17 00:00:00 2001 From: DF1E Date: Wed, 31 May 2017 12:20:02 +0200 Subject: [PATCH 149/181] fixes for downloads page - fixes open downloads - fix if download dialog canceled - save image downloads --- app/src/main/AndroidManifest.xml | 10 ++++++ .../lightning/constant/DownloadsPage.java | 29 +++++++++------ .../dialog/LightningDialogBuilder.java | 27 ++++++-------- .../lightning/download/DownloadHandler.java | 11 +----- .../lightning/download/FetchUrlMimeType.java | 2 +- .../download/LightningDownloadListener.java | 35 ++++++++++--------- .../acr/browser/lightning/utils/Utils.java | 9 +++++ .../lightning/view/LightningWebClient.java | 30 +++++++++++++--- app/src/main/res/xml/filepaths.xml | 5 +++ 9 files changed, 99 insertions(+), 59 deletions(-) create mode 100644 app/src/main/res/xml/filepaths.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 15d8177f9..f955ce5b3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -157,6 +157,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/java/acr/browser/lightning/constant/DownloadsPage.java b/app/src/main/java/acr/browser/lightning/constant/DownloadsPage.java index 9bc0a4ee1..5e5eb8ad7 100644 --- a/app/src/main/java/acr/browser/lightning/constant/DownloadsPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/DownloadsPage.java @@ -23,6 +23,7 @@ import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.downloads.DownloadItem; import acr.browser.lightning.database.downloads.DownloadsModel; +import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.Utils; @@ -58,6 +59,7 @@ public final class DownloadsPage { private File mFilesDir; @Inject Application mApp; + @Inject PreferenceManager mPreferenceManager; @Inject DownloadsModel mManager; @NonNull private final String mTitle; @@ -74,7 +76,7 @@ public Single getDownloadsPage() { public void onSubscribe(@NonNull SingleSubscriber subscriber) { mFilesDir = mApp.getFilesDir(); - buildDownloadsPage(null); + buildDownloadsPage(); File downloadsWebPage = new File(mFilesDir, FILENAME); @@ -84,36 +86,41 @@ public void onSubscribe(@NonNull SingleSubscriber subscriber) { }); } - private void buildDownloadsPage(@Nullable final String folder) { + private void buildDownloadsPage() { mManager.getAllDownloads() .subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable List list) { Preconditions.checkNonNull(list); + String directory = mPreferenceManager.getDownloadDirectory(); - final File downloadsWebPage; - if (folder == null || folder.isEmpty()) { - downloadsWebPage = new File(mFilesDir, FILENAME); - } else { - downloadsWebPage = new File(mFilesDir, folder + '-' + FILENAME); - } final StringBuilder downloadsBuilder = new StringBuilder(HEADING_1 + mTitle + HEADING_2); for (int n = 0, size = list.size(); n < size; n++) { final DownloadItem item = list.get(n); downloadsBuilder.append(PART1); - downloadsBuilder.append(item.getUrl()); + downloadsBuilder.append("file://"); + downloadsBuilder.append(directory); + downloadsBuilder.append("/"); + downloadsBuilder.append(item.getTitle()); downloadsBuilder.append(PART2); downloadsBuilder.append(item.getTitle()); + + if (!item.getContentSize().isEmpty()) { + downloadsBuilder.append(" ["); + downloadsBuilder.append(item.getContentSize()); + downloadsBuilder.append("]"); + } + downloadsBuilder.append(PART3); - downloadsBuilder.append(item.getContentSize()); + downloadsBuilder.append(item.getUrl()); downloadsBuilder.append(PART4); } downloadsBuilder.append(END); FileWriter bookWriter = null; try { //noinspection IOResourceOpenedButNotSafelyClosed - bookWriter = new FileWriter(downloadsWebPage, false); + bookWriter = new FileWriter(new File(mFilesDir, FILENAME), false); bookWriter.write(downloadsBuilder.toString()); } catch (IOException e) { e.printStackTrace(); diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 506debda2..706e7f481 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -10,6 +10,7 @@ import android.text.TextUtils; import android.util.Log; import android.view.View; +import android.webkit.URLUtil; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.EditText; @@ -27,7 +28,6 @@ import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; -import acr.browser.lightning.constant.DownloadsPage; import acr.browser.lightning.controller.UIController; import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.database.bookmark.BookmarkModel; @@ -169,21 +169,7 @@ public void showLongPressedDialogForDownloadUrl(@NonNull final Activity activity @NonNull final UIController uiController, @NonNull final String url) { - BrowserDialog.show(activity, R.string.action_bookmarks, - new BrowserDialog.Item(R.string.dialog_delete_download) { - @Override - public void onClick() { - mDownloadsModel.deleteDownload(url).subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable Boolean item) { - if (item != null && !item) - Log.i(TAG, "error deleting download from database"); - else - uiController.handleDownloadDeleted(); - } - }); - } - }, + BrowserDialog.show(activity, R.string.action_downloads, new BrowserDialog.Item(R.string.dialog_delete_all_downloads) { @Override public void onClick() { @@ -393,6 +379,15 @@ public void onClick() { @Override public void onClick() { Utils.downloadFile(activity, mPreferenceManager, url, userAgent, "attachment"); + + mDownloadsModel.addDownloadIfNotExists(new DownloadItem(url, URLUtil.guessFileName(url, null, null), "")) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean item) { + if (item != null && !item) + Log.i(TAG, "error saving download to database"); + } + }); } }); } diff --git a/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java index 7fdab9b4f..6f02b92dc 100644 --- a/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java +++ b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java @@ -47,15 +47,6 @@ public class DownloadHandler { Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) .getPath(); - @Nullable - static String guessFileExtension(@NonNull String filename) { - int lastIndex = filename.lastIndexOf('.') + 1; - if (lastIndex > 0 && filename.length() > lastIndex) { - return filename.substring(lastIndex, filename.length()); - } - return null; - } - /** * Notify the host application a download should be done, or that the data * should be streamed if a streaming viewer is available. @@ -222,7 +213,7 @@ private static void onDownloadStartNoStream(@NonNull final Activity context, @No Utils.showSnackbar(context, R.string.problem_location_download); return; } - String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(guessFileExtension(filename)); + String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(Utils.guessFileExtension(filename)); Log.d(TAG, "New mimetype: " + newMimeType); request.setMimeType(newMimeType); request.setDestinationUri(Uri.parse(Constants.FILE + location + filename)); diff --git a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java index fcef5ce71..96b707816 100644 --- a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java +++ b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java @@ -93,7 +93,7 @@ public void run() { if (mimeType.equalsIgnoreCase("text/plain") || mimeType.equalsIgnoreCase("application/octet-stream")) { String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension( - DownloadHandler.guessFileExtension(mUri)); + Utils.guessFileExtension(mUri)); if (newMimeType != null) { mRequest.setMimeType(newMimeType); } diff --git a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java index fba4cbaf1..a38bb93cd 100644 --- a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java +++ b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java @@ -50,7 +50,15 @@ public void onDownloadStart(final String url, final String userAgent, new PermissionsResultAction() { @Override public void onGranted() { - String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); + final String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); + final String downloadSize; + + if (contentLength > 0) { + downloadSize = Formatter.formatFileSize(mActivity, contentLength); + } else { + downloadSize = mActivity.getString(R.string.unknown_size); + } + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -58,6 +66,15 @@ public void onClick(DialogInterface dialog, int which) { case DialogInterface.BUTTON_POSITIVE: DownloadHandler.onDownloadStart(mActivity, mPreferenceManager, url, userAgent, contentDisposition, mimetype); + + downloadsModel.addDownloadIfNotExists(new DownloadItem(url, fileName, downloadSize)) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable Boolean item) { + if (item != null && !item) + Log.i(TAG, "error saving download to database"); + } + }); break; case DialogInterface.BUTTON_NEGATIVE: break; @@ -66,12 +83,6 @@ public void onClick(DialogInterface dialog, int which) { }; AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); // dialog - String downloadSize; - if (contentLength > 0) { - downloadSize = Formatter.formatFileSize(mActivity, contentLength); - } else { - downloadSize = mActivity.getString(R.string.unknown_size); - } String message = mActivity.getString(R.string.dialog_download, downloadSize); Dialog dialog = builder.setTitle(fileName) .setMessage(message) @@ -81,16 +92,6 @@ public void onClick(DialogInterface dialog, int which) { dialogClickListener).show(); BrowserDialog.setDialogSize(mActivity, dialog); Log.i(TAG, "Downloading: " + fileName); - - downloadsModel.addDownloadIfNotExists(new DownloadItem(url, fileName, downloadSize)).subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable Boolean item) { - super.onItem(item); - - if (item != null && !item) - Log.i(TAG, "error saving download to database"); - } - }); } @Override diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index 62a266992..0bb7682ea 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -456,4 +456,13 @@ public static int calculateInSampleSize(@NonNull BitmapFactory.Options options, return inSampleSize; } + @Nullable + public static String guessFileExtension(@NonNull String filename) { + int lastIndex = filename.lastIndexOf('.') + 1; + if (lastIndex > 0 && filename.length() > lastIndex) { + return filename.substring(lastIndex, filename.length()); + } + return null; + } + } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index 0d1fd336b..62cdbda10 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -8,30 +8,31 @@ import android.content.Intent; import android.graphics.Bitmap; import android.net.MailTo; +import android.net.Uri; import android.net.http.SslError; import android.os.Build; import android.os.Message; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.view.LayoutInflaterCompat; +import android.support.v4.content.FileProvider; import android.support.v7.app.AlertDialog; -import android.text.InputType; -import android.text.method.PasswordTransformationMethod; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.webkit.HttpAuthHandler; +import android.webkit.MimeTypeMap; import android.webkit.SslErrorHandler; +import android.webkit.URLUtil; import android.webkit.ValueCallback; import android.webkit.WebResourceRequest; import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.EditText; -import android.widget.LinearLayout; import android.widget.TextView; import java.io.ByteArrayInputStream; +import java.io.File; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; @@ -39,6 +40,7 @@ import javax.inject.Inject; +import acr.browser.lightning.BuildConfig; import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; @@ -358,6 +360,26 @@ private boolean isMailOrIntent(@NonNull String url, @NonNull WebView view) { } return true; } + } else if (url.startsWith("file://")) { + File file = new File(url.replace("file://", "")); + + if (file.exists()) { + String newMimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension(Utils.guessFileExtension(file.toString())); + + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + Uri contentUri = FileProvider.getUriForFile(mActivity, BuildConfig.APPLICATION_ID + ".fileprovider", file); + intent.setDataAndType(contentUri, newMimeType); + + try { + mActivity.startActivity(intent); + } catch (Exception e) { + System.out.println("LightningWebClient: cannot open downloaded file"); + } + return true; + } } return false; } diff --git a/app/src/main/res/xml/filepaths.xml b/app/src/main/res/xml/filepaths.xml new file mode 100644 index 000000000..065dee8d6 --- /dev/null +++ b/app/src/main/res/xml/filepaths.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From 7485bc35e7d2298ffe5615e6660064dfd1551ffb Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Thu, 1 Jun 2017 22:13:15 -0400 Subject: [PATCH 150/181] Updating butterknife --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 83e6432dd..0ed906dcd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -82,8 +82,8 @@ dependencies { provided 'javax.annotation:jsr250-api:1.0' // view binding - compile 'com.jakewharton:butterknife:8.5.1' - annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' + compile 'com.jakewharton:butterknife:8.6.0' + annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0' // permissions compile 'com.anthonycr.grant:permissions:1.1.2' From 1532351775ea27f924381cc2d8f1b11de5b59578 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Thu, 1 Jun 2017 22:16:45 -0400 Subject: [PATCH 151/181] Updating dagger --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 0ed906dcd..2fac20a1a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -76,7 +76,7 @@ dependencies { compile 'org.jsoup:jsoup:1.10.2' // dependency injection - def daggerVersion = '2.10' + def daggerVersion = '2.11' compile "com.google.dagger:dagger:$daggerVersion" annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion" provided 'javax.annotation:jsr250-api:1.0' From 4f37f0f19658155ae68ae86314f119f0a6e3221f Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Thu, 1 Jun 2017 22:19:36 -0400 Subject: [PATCH 152/181] Removing unused imports --- app/src/main/java/acr/browser/lightning/app/BrowserApp.java | 2 -- .../main/java/acr/browser/lightning/constant/Constants.java | 2 -- .../main/java/acr/browser/lightning/dialog/BrowserDialog.java | 2 -- app/src/main/java/acr/browser/lightning/utils/AdBlock.java | 1 - app/src/main/java/acr/browser/lightning/utils/FileUtils.java | 2 -- .../main/java/acr/browser/lightning/utils/IntentUtils.java | 1 - .../java/acr/browser/lightning/view/LightningWebClient.java | 4 ---- 7 files changed, 14 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java index a6ab11bf1..1bbc19a56 100644 --- a/app/src/main/java/acr/browser/lightning/app/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -17,8 +17,6 @@ import com.squareup.leakcanary.LeakCanary; import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import javax.inject.Inject; diff --git a/app/src/main/java/acr/browser/lightning/constant/Constants.java b/app/src/main/java/acr/browser/lightning/constant/Constants.java index 2e76e7827..731d4a5fd 100644 --- a/app/src/main/java/acr/browser/lightning/constant/Constants.java +++ b/app/src/main/java/acr/browser/lightning/constant/Constants.java @@ -8,8 +8,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import acr.browser.lightning.BuildConfig; - public final class Constants { private Constants() { diff --git a/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java b/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java index 9d3b96414..e6e8f2826 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java +++ b/app/src/main/java/acr/browser/lightning/dialog/BrowserDialog.java @@ -16,7 +16,6 @@ import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; -import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; @@ -26,7 +25,6 @@ import acr.browser.lightning.R; import acr.browser.lightning.utils.DeviceUtils; import acr.browser.lightning.utils.ResourceUtils; -import acr.browser.lightning.utils.Utils; /** * Copyright 7/31/2016 Anthony Restaino diff --git a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java index 43d8f1273..0fd6fc07a 100644 --- a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java +++ b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java @@ -23,7 +23,6 @@ import javax.inject.Singleton; import acr.browser.lightning.BuildConfig; -import acr.browser.lightning.constant.Constants; import acr.browser.lightning.preference.PreferenceManager; @Singleton diff --git a/app/src/main/java/acr/browser/lightning/utils/FileUtils.java b/app/src/main/java/acr/browser/lightning/utils/FileUtils.java index f28445136..0ac81358c 100644 --- a/app/src/main/java/acr/browser/lightning/utils/FileUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/FileUtils.java @@ -20,8 +20,6 @@ import java.io.InputStreamReader; import java.io.PrintStream; -import acr.browser.lightning.app.BrowserApp; - /** * A utility class containing helpful methods * pertaining to file storage. diff --git a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java index 2f5261a61..17eba2bf6 100644 --- a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java @@ -20,7 +20,6 @@ import acr.browser.lightning.R; import acr.browser.lightning.constant.Constants; -import acr.browser.lightning.controller.UIController; public class IntentUtils { diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index 0d1fd336b..2faf3de1d 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -13,10 +13,7 @@ import android.os.Message; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.view.LayoutInflaterCompat; import android.support.v7.app.AlertDialog; -import android.text.InputType; -import android.text.method.PasswordTransformationMethod; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -28,7 +25,6 @@ import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.EditText; -import android.widget.LinearLayout; import android.widget.TextView; import java.io.ByteArrayInputStream; From a7147e726512f2e86037d9aa9a921667c6b8b40a Mon Sep 17 00:00:00 2001 From: Jiao Jianhua <16467515@qq.com> Date: Wed, 31 May 2017 21:14:29 +0800 Subject: [PATCH 153/181] Add Baidu searc suggestion --- .../fragment/GeneralSettingsFragment.java | 14 ++++- .../preference/PreferenceManager.java | 1 + .../search/BaiduSuggestionsModel.java | 57 +++++++++++++++++++ .../lightning/search/SuggestionsAdapter.java | 2 + .../lightning/search/SuggestionsManager.java | 15 +++++ app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values/arrays.xml | 1 + app/src/main/res/values/strings.xml | 1 + 8 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/search/BaiduSuggestionsModel.java diff --git a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java index e6a039887..368e3fa70 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java @@ -117,6 +117,9 @@ private void initPrefs() { case SUGGESTION_DUCK: searchsSuggestions.setSummary(R.string.powered_by_duck); break; + case SUGGESTION_BAIDU: + searchsSuggestions.setSummary(R.string.powered_by_baidu); + break; case SUGGESTION_NONE: searchsSuggestions.setSummary(R.string.search_suggestions_off); break; @@ -360,7 +363,7 @@ private void suggestionsDialog() { AlertDialog.Builder picker = new AlertDialog.Builder(mActivity); picker.setTitle(getResources().getString(R.string.search_suggestions)); - int currentChoice = 2; + int currentChoice = 3; switch (mPreferenceManager.getSearchSuggestionChoice()) { case SUGGESTION_GOOGLE: @@ -369,9 +372,12 @@ private void suggestionsDialog() { case SUGGESTION_DUCK: currentChoice = 1; break; - case SUGGESTION_NONE: + case SUGGESTION_BAIDU: currentChoice = 2; break; + case SUGGESTION_NONE: + currentChoice = 3; + break; } picker.setSingleChoiceItems(R.array.suggestions, currentChoice, @@ -388,6 +394,10 @@ public void onClick(DialogInterface dialog, int which) { searchsSuggestions.setSummary(R.string.powered_by_duck); break; case 2: + mPreferenceManager.setSearchSuggestionChoice(Suggestion.SUGGESTION_BAIDU); + searchsSuggestions.setSummary(R.string.powered_by_baidu); + break; + case 3: mPreferenceManager.setSearchSuggestionChoice(Suggestion.SUGGESTION_NONE); searchsSuggestions.setSummary(R.string.search_suggestions_off); break; diff --git a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java index 42d4d243c..8be0ac56b 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -70,6 +70,7 @@ private static class Name { public enum Suggestion { SUGGESTION_GOOGLE, SUGGESTION_DUCK, + SUGGESTION_BAIDU, SUGGESTION_NONE } diff --git a/app/src/main/java/acr/browser/lightning/search/BaiduSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/BaiduSuggestionsModel.java new file mode 100644 index 000000000..680018382 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/search/BaiduSuggestionsModel.java @@ -0,0 +1,57 @@ +package acr.browser.lightning.search; + +import android.app.Application; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.util.List; + +import acr.browser.lightning.R; +import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.utils.FileUtils; + +// http://unionsug.baidu.com/su?wd=encodeURIComponent(U) +// http://suggestion.baidu.com/s?wd=encodeURIComponent(U)&action=opensearch + + +class BaiduSuggestionsModel extends BaseSuggestionsModel { + + @NonNull private static final String ENCODING = "UTF-8"; + @Nullable private static XmlPullParser sXpp; + @NonNull private final String mSearchSubtitle; + + BaiduSuggestionsModel(@NonNull Application application) { + super(application, ENCODING); + mSearchSubtitle = application.getString(R.string.suggestion); + } + + @NonNull + protected String createQueryUrl(@NonNull String query, @NonNull String language) { + return "http://suggestion.baidu.com/s?wd=" + query + "&action=opensearch"; + } + + @Override + protected void parseResults(@NonNull InputStream inputStream, @NonNull List results) throws Exception { + String content = FileUtils.readStringFromStream(inputStream, "GBK"); + JSONArray respArray = new JSONArray(content); + JSONArray jsonArray = respArray.getJSONArray(1); + int counter = 0; + for (int n = 0, size = jsonArray.length(); n < size; n++) { + String suggestion = jsonArray.getString(n); + results.add(new HistoryItem(mSearchSubtitle + " \"" + suggestion + '"', + suggestion, R.drawable.ic_search)); + counter++; + if (counter >= MAX_RESULTS) { + break; + } + } + } +} diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index 2937f7035..dae2a33c2 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -304,6 +304,8 @@ private Single> getSuggestionsForQuery(@NonNull final String q return SuggestionsManager.createGoogleQueryObservable(query, mApplication); } else if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_DUCK) { return SuggestionsManager.createDuckQueryObservable(query, mApplication); + } else if (mSuggestionChoice == PreferenceManager.Suggestion.SUGGESTION_BAIDU) { + return SuggestionsManager.createBaiduQueryObservable(query, mApplication); } else { return Single.empty(); } diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java index 2855f40f1..13edb8c81 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsManager.java @@ -34,6 +34,21 @@ public void onSubscribe(@NonNull final SingleSubscriber> subsc }); } + @NonNull + static Single> createBaiduQueryObservable(@NonNull final String query, + @NonNull final Application application) { + return Single.create(new SingleAction>() { + @Override + public void onSubscribe(@NonNull final SingleSubscriber> subscriber) { + sIsTaskExecuting = true; + List results = new BaiduSuggestionsModel(application).getResults(query); + subscriber.onItem(results); + subscriber.onComplete(); + sIsTaskExecuting = false; + } + }); + } + @NonNull static Single> createDuckQueryObservable(@NonNull final String query, @NonNull final Application application) { diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index af1b7e21d..a947e3f4e 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -186,6 +186,7 @@ 不受信任的证书 由DuckDuckGo提供技术支持 + 由百度提供技术支持 关闭搜索建议 HTTP代理 diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index d3d67168e..0577edd8b 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -22,6 +22,7 @@ @string/powered_by_google @string/powered_by_duck + @string/powered_by_baidu @string/search_suggestions_off diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ee47f618b..906d4f25d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -133,6 +133,7 @@ Search suggestions Powered by Google Powered by DuckDuckGo + Powered by Baidu No search suggestions HTTP proxy From af58c93ed5eccdcffafabf9ce1980cddc395a0cd Mon Sep 17 00:00:00 2001 From: Jiao Jianhua <16467515@qq.com> Date: Wed, 31 May 2017 21:35:14 +0800 Subject: [PATCH 154/181] New: Baidu search suggestion --- .../acr/browser/lightning/search/BaiduSuggestionsModel.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/search/BaiduSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/BaiduSuggestionsModel.java index 680018382..412bfd8d7 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaiduSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/BaiduSuggestionsModel.java @@ -5,12 +5,8 @@ import android.support.annotation.Nullable; import org.json.JSONArray; -import org.json.JSONObject; import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; -import java.io.BufferedInputStream; import java.io.InputStream; import java.util.List; From 20ca7047f3b479531f8c2abad99e5f9c2c4ca6d1 Mon Sep 17 00:00:00 2001 From: DF1E Date: Sat, 3 Jun 2017 10:54:16 +0200 Subject: [PATCH 155/181] minor changes --- .../acr/browser/lightning/constant/Constants.java | 2 -- .../database/downloads/DownloadItem.java | 1 + .../database/downloads/DownloadsModel.java | 2 +- .../lightning/dialog/LightningDialogBuilder.java | 15 +++++++++++---- .../lightning/view/LightningWebClient.java | 5 ++--- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/constant/Constants.java b/app/src/main/java/acr/browser/lightning/constant/Constants.java index 2e76e7827..731d4a5fd 100644 --- a/app/src/main/java/acr/browser/lightning/constant/Constants.java +++ b/app/src/main/java/acr/browser/lightning/constant/Constants.java @@ -8,8 +8,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import acr.browser.lightning.BuildConfig; - public final class Constants { private Constants() { diff --git a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadItem.java b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadItem.java index 884e05219..90025ba37 100644 --- a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadItem.java +++ b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadItem.java @@ -25,6 +25,7 @@ public DownloadItem() {} public DownloadItem(@NonNull String url, @NonNull String title, @NonNull String size) { Preconditions.checkNonNull(url); Preconditions.checkNonNull(title); + Preconditions.checkNonNull(size); this.mUrl = url; this.mTitle = title; this.mContentSize = size; diff --git a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java index d8dc67e61..a5545ef3e 100644 --- a/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java +++ b/app/src/main/java/acr/browser/lightning/database/downloads/DownloadsModel.java @@ -12,7 +12,7 @@ * The interface that should be used to * communicate with the download database. *

- * Created by anthonycr on 5/6/17. + * Created by df1e on 29/5/17. */ public interface DownloadsModel { diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 706e7f481..9763383ed 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -16,6 +16,7 @@ import android.widget.EditText; import com.anthonycr.bonsai.CompletableOnSubscribe; +import com.anthonycr.bonsai.CompletableSubscriber; import com.anthonycr.bonsai.Schedulers; import com.anthonycr.bonsai.SingleOnSubscribe; @@ -39,14 +40,13 @@ import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.Utils; -import static android.content.ContentValues.TAG; - /** * TODO Rename this class it doesn't build dialogs only for bookmarks *

* Created by Stefano Pacifici on 02/09/15, based on Anthony C. Restaino's code. */ public class LightningDialogBuilder { + public static final String TAG = "LightningDialogBuilder"; public enum NewTab { FOREGROUND, @@ -173,8 +173,15 @@ public void showLongPressedDialogForDownloadUrl(@NonNull final Activity activity new BrowserDialog.Item(R.string.dialog_delete_all_downloads) { @Override public void onClick() { - mDownloadsModel.deleteAllDownloads().subscribeOn(Schedulers.io()).subscribe(); - uiController.handleDownloadDeleted(); + mDownloadsModel.deleteAllDownloads() + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + uiController.handleDownloadDeleted(); + } + }); } }); } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index 62cdbda10..8e3f4bb25 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -22,7 +22,6 @@ import android.webkit.HttpAuthHandler; import android.webkit.MimeTypeMap; import android.webkit.SslErrorHandler; -import android.webkit.URLUtil; import android.webkit.ValueCallback; import android.webkit.WebResourceRequest; import android.webkit.WebResourceResponse; @@ -360,8 +359,8 @@ private boolean isMailOrIntent(@NonNull String url, @NonNull WebView view) { } return true; } - } else if (url.startsWith("file://")) { - File file = new File(url.replace("file://", "")); + } else if (url.startsWith(Constants.FILE)) { + File file = new File(url.replace(Constants.FILE, "")); if (file.exists()) { String newMimeType = MimeTypeMap.getSingleton() From b5096a9d05356d16b37daabd9842d9196824ee80 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 3 Jun 2017 09:21:08 -0400 Subject: [PATCH 156/181] Fixing Brazilian translations --- .../main/res/values-pt-br/values-pt-br.xml | 202 --------- .../strings.xml} | 402 +++++++++--------- 2 files changed, 201 insertions(+), 403 deletions(-) delete mode 100644 app/src/main/res/values-pt-br/values-pt-br.xml rename app/src/main/res/{values-br/values-pt-br.xml => values-pt-rBR/strings.xml} (98%) diff --git a/app/src/main/res/values-pt-br/values-pt-br.xml b/app/src/main/res/values-pt-br/values-pt-br.xml deleted file mode 100644 index 54f4735c0..000000000 --- a/app/src/main/res/values-pt-br/values-pt-br.xml +++ /dev/null @@ -1,202 +0,0 @@ - - - - - Lightning - Nova aba - Compartilhar - Histórico - Favoritos - Adicionar favoritos - Copiar link da página - Avançar - Configurações - Acesso de localização - Salvar senhas - Agente - Ativar Adobe Flash - Página inicial - Modo de tela completa - Ativar JavaScript - Pasta de download - Configurações avançadas - Apache License 2.0 - Versão da aplicação - Limpar cache ao sair - Ativar ajuste de texto - Bloquear imagens - Permitir que sites abram novas janelas - Ativar cookies - Importar favoritos do navegador - Tamanho do texto - Recomendado - Mecanismo de pesquisa - Pesquisa - Utilizar viewport amplo - Carregar páginas no modo panorâmico - Restaurar abas ao iniciar - Navegador não detectado - Navegador detetado - Ocultar barra de estado ao navegar - Limpar cookies - Limpar histórico - O que gostaria de fazer com esta imagem? - Salvar - Abrir - O que gostaria de fazer com este link? - Compartilhar esta página - O que gostaria de fazer com este favorito? - Remover - Página vazia - Padrão - Desktop - Mobile - Personalizado - Mecanismo de pesquisa - OK - Gostaria de transferir este arquivo? - Cancelar - Aviso - O Adobe Flash Player não foi detectado.\nNecessário instalar o Flash Player. - Agente de utilizador - Local das transferências - Página inicial personalizada - Página web - Limpar histórico - Limpar cookies - Gostaria de limpar todo o histórico do navegador? - Gostaria de limpar todos os cookies do navegador? - Sim - Não - Tamanho do texto - Maior - Grande - Normal - Pequeno - Menor - Erro - Não foi detectado qualquer navegador para importar os favoritos. - Título - URL - Editar favorito - Editar - Nova aba anônima - Padrão - Voltar - Localizar na página - A iniciar transferência\u2026 - Apenas possível para as URLs \"http\" ou \"https\". - Cartão SD não encontrado - Necessita-se de um cartão SD para salvar o arquivo transferido. - Cartão SD não disponível - O cartão SD está ocupado. Para poder transferir arquivos, desative a opção Desativar armazenamento USB na notificação. - Permitir cookies no modo anônimo - Adobe Flash - Manual - Automático - Contato - twitter.com/RestainoAnthony - Limpar cache - Cache limpo - Favoritos importados - Histórico removido - Cookies removidos - Atingido número máximo de abas - Texto copiado para a área de transferência - Link copiado para a área de transferência - URL personalizado - Bloqueado o carregamento do arquivo local - Licenças Open Source - Pesquisar por - Bloquear anúncios - Submissão de formulário - Gostaria de reenviar os dados? - \nGostaria de utilizar a sua localização - Sim - Não - Iniciar sessão - Usuário - Senha - Sugestões de pesquisa - Disponibilizado por Google - Proxy HTTP - - Não - Orbot - I2P - Manual - - Proxy manual - Servidor: - Porta: - Parece que você tem o Orbot instalado. Gostaria de utilizar a rede Tor? - Parece que você tem o I2P instalado. Gostaria de utilizar a rede I2P? - Por favor instale o Orbot para poder utilizar a rede Tor. - I2P não está em execução. - Os canais I2P ainda não estão prontos. - Sim - Não - Limpar cookies ao sair - Limpar histórico ao sair - Padrão - Personalizado - Sem título - Mozilla Public License v. 2.0 - Freeware - Projeto Android Open Source - hpHosts Ad Server List - Reabrir última aba - Modo de renderização - Invertido - Escala cinza - Escala cinza invertida - Normal - Sincronizar histórico com Google - Seletor de arquivos - NetCipher - GNU Lesser General Public License - Exportar favoritos para backup - Importar favoritos de um backup - Favoritos salvos em - Configurações de favoritos - Não foi possível importar os favoritos do arquivo - Escolha um arquivo - Configurações gerais - Configurações de exibição - Configurações de privacidade - Sobre - Detalhes da versão, do autor e da licença - Fechar aba - Fechar todas as abas - Bloquear cookies de terceiros - Ativar modo de cor - Modo de leitura - A carregar… - A página não foi carregada. - Snacktory - jsoup: Java HTML Parser - MIT License - Conteúdo da caixa do URL - - Domínio (padrão) - URL - Título - - Inverter cores - Tema escuro - Abas - \ No newline at end of file diff --git a/app/src/main/res/values-br/values-pt-br.xml b/app/src/main/res/values-pt-rBR/strings.xml similarity index 98% rename from app/src/main/res/values-br/values-pt-br.xml rename to app/src/main/res/values-pt-rBR/strings.xml index 54f4735c0..7ba6b8e0e 100644 --- a/app/src/main/res/values-br/values-pt-br.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1,202 +1,202 @@ - - - - - Lightning - Nova aba - Compartilhar - Histórico - Favoritos - Adicionar favoritos - Copiar link da página - Avançar - Configurações - Acesso de localização - Salvar senhas - Agente - Ativar Adobe Flash - Página inicial - Modo de tela completa - Ativar JavaScript - Pasta de download - Configurações avançadas - Apache License 2.0 - Versão da aplicação - Limpar cache ao sair - Ativar ajuste de texto - Bloquear imagens - Permitir que sites abram novas janelas - Ativar cookies - Importar favoritos do navegador - Tamanho do texto - Recomendado - Mecanismo de pesquisa - Pesquisa - Utilizar viewport amplo - Carregar páginas no modo panorâmico - Restaurar abas ao iniciar - Navegador não detectado - Navegador detetado - Ocultar barra de estado ao navegar - Limpar cookies - Limpar histórico - O que gostaria de fazer com esta imagem? - Salvar - Abrir - O que gostaria de fazer com este link? - Compartilhar esta página - O que gostaria de fazer com este favorito? - Remover - Página vazia - Padrão - Desktop - Mobile - Personalizado - Mecanismo de pesquisa - OK - Gostaria de transferir este arquivo? - Cancelar - Aviso - O Adobe Flash Player não foi detectado.\nNecessário instalar o Flash Player. - Agente de utilizador - Local das transferências - Página inicial personalizada - Página web - Limpar histórico - Limpar cookies - Gostaria de limpar todo o histórico do navegador? - Gostaria de limpar todos os cookies do navegador? - Sim - Não - Tamanho do texto - Maior - Grande - Normal - Pequeno - Menor - Erro - Não foi detectado qualquer navegador para importar os favoritos. - Título - URL - Editar favorito - Editar - Nova aba anônima - Padrão - Voltar - Localizar na página - A iniciar transferência\u2026 - Apenas possível para as URLs \"http\" ou \"https\". - Cartão SD não encontrado - Necessita-se de um cartão SD para salvar o arquivo transferido. - Cartão SD não disponível - O cartão SD está ocupado. Para poder transferir arquivos, desative a opção Desativar armazenamento USB na notificação. - Permitir cookies no modo anônimo - Adobe Flash - Manual - Automático - Contato - twitter.com/RestainoAnthony - Limpar cache - Cache limpo - Favoritos importados - Histórico removido - Cookies removidos - Atingido número máximo de abas - Texto copiado para a área de transferência - Link copiado para a área de transferência - URL personalizado - Bloqueado o carregamento do arquivo local - Licenças Open Source - Pesquisar por - Bloquear anúncios - Submissão de formulário - Gostaria de reenviar os dados? - \nGostaria de utilizar a sua localização - Sim - Não - Iniciar sessão - Usuário - Senha - Sugestões de pesquisa - Disponibilizado por Google - Proxy HTTP - - Não - Orbot - I2P - Manual - - Proxy manual - Servidor: - Porta: - Parece que você tem o Orbot instalado. Gostaria de utilizar a rede Tor? - Parece que você tem o I2P instalado. Gostaria de utilizar a rede I2P? - Por favor instale o Orbot para poder utilizar a rede Tor. - I2P não está em execução. - Os canais I2P ainda não estão prontos. - Sim - Não - Limpar cookies ao sair - Limpar histórico ao sair - Padrão - Personalizado - Sem título - Mozilla Public License v. 2.0 - Freeware - Projeto Android Open Source - hpHosts Ad Server List - Reabrir última aba - Modo de renderização - Invertido - Escala cinza - Escala cinza invertida - Normal - Sincronizar histórico com Google - Seletor de arquivos - NetCipher - GNU Lesser General Public License - Exportar favoritos para backup - Importar favoritos de um backup - Favoritos salvos em - Configurações de favoritos - Não foi possível importar os favoritos do arquivo - Escolha um arquivo - Configurações gerais - Configurações de exibição - Configurações de privacidade - Sobre - Detalhes da versão, do autor e da licença - Fechar aba - Fechar todas as abas - Bloquear cookies de terceiros - Ativar modo de cor - Modo de leitura - A carregar… - A página não foi carregada. - Snacktory - jsoup: Java HTML Parser - MIT License - Conteúdo da caixa do URL - - Domínio (padrão) - URL - Título - - Inverter cores - Tema escuro - Abas + + + + + Lightning + Nova aba + Compartilhar + Histórico + Favoritos + Adicionar favoritos + Copiar link da página + Avançar + Configurações + Acesso de localização + Salvar senhas + Agente + Ativar Adobe Flash + Página inicial + Modo de tela completa + Ativar JavaScript + Pasta de download + Configurações avançadas + Apache License 2.0 + Versão da aplicação + Limpar cache ao sair + Ativar ajuste de texto + Bloquear imagens + Permitir que sites abram novas janelas + Ativar cookies + Importar favoritos do navegador + Tamanho do texto + Recomendado + Mecanismo de pesquisa + Pesquisa + Utilizar viewport amplo + Carregar páginas no modo panorâmico + Restaurar abas ao iniciar + Navegador não detectado + Navegador detetado + Ocultar barra de estado ao navegar + Limpar cookies + Limpar histórico + O que gostaria de fazer com esta imagem? + Salvar + Abrir + O que gostaria de fazer com este link? + Compartilhar esta página + O que gostaria de fazer com este favorito? + Remover + Página vazia + Padrão + Desktop + Mobile + Personalizado + Mecanismo de pesquisa + OK + Gostaria de transferir este arquivo? + Cancelar + Aviso + O Adobe Flash Player não foi detectado.\nNecessário instalar o Flash Player. + Agente de utilizador + Local das transferências + Página inicial personalizada + Página web + Limpar histórico + Limpar cookies + Gostaria de limpar todo o histórico do navegador? + Gostaria de limpar todos os cookies do navegador? + Sim + Não + Tamanho do texto + Maior + Grande + Normal + Pequeno + Menor + Erro + Não foi detectado qualquer navegador para importar os favoritos. + Título + URL + Editar favorito + Editar + Nova aba anônima + Padrão + Voltar + Localizar na página + A iniciar transferência\u2026 + Apenas possível para as URLs \"http\" ou \"https\". + Cartão SD não encontrado + Necessita-se de um cartão SD para salvar o arquivo transferido. + Cartão SD não disponível + O cartão SD está ocupado. Para poder transferir arquivos, desative a opção Desativar armazenamento USB na notificação. + Permitir cookies no modo anônimo + Adobe Flash + Manual + Automático + Contato + twitter.com/RestainoAnthony + Limpar cache + Cache limpo + Favoritos importados + Histórico removido + Cookies removidos + Atingido número máximo de abas + Texto copiado para a área de transferência + Link copiado para a área de transferência + URL personalizado + Bloqueado o carregamento do arquivo local + Licenças Open Source + Pesquisar por + Bloquear anúncios + Submissão de formulário + Gostaria de reenviar os dados? + \nGostaria de utilizar a sua localização + Sim + Não + Iniciar sessão + Usuário + Senha + Sugestões de pesquisa + Disponibilizado por Google + Proxy HTTP + + Não + Orbot + I2P + Manual + + Proxy manual + Servidor: + Porta: + Parece que você tem o Orbot instalado. Gostaria de utilizar a rede Tor? + Parece que você tem o I2P instalado. Gostaria de utilizar a rede I2P? + Por favor instale o Orbot para poder utilizar a rede Tor. + I2P não está em execução. + Os canais I2P ainda não estão prontos. + Sim + Não + Limpar cookies ao sair + Limpar histórico ao sair + Padrão + Personalizado + Sem título + Mozilla Public License v. 2.0 + Freeware + Projeto Android Open Source + hpHosts Ad Server List + Reabrir última aba + Modo de renderização + Invertido + Escala cinza + Escala cinza invertida + Normal + Sincronizar histórico com Google + Seletor de arquivos + NetCipher + GNU Lesser General Public License + Exportar favoritos para backup + Importar favoritos de um backup + Favoritos salvos em + Configurações de favoritos + Não foi possível importar os favoritos do arquivo + Escolha um arquivo + Configurações gerais + Configurações de exibição + Configurações de privacidade + Sobre + Detalhes da versão, do autor e da licença + Fechar aba + Fechar todas as abas + Bloquear cookies de terceiros + Ativar modo de cor + Modo de leitura + A carregar… + A página não foi carregada. + Snacktory + jsoup: Java HTML Parser + MIT License + Conteúdo da caixa do URL + + Domínio (padrão) + URL + Título + + Inverter cores + Tema escuro + Abas \ No newline at end of file From cc0696e005021c2ff808467ab870ab24253097bf Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 3 Jun 2017 09:32:24 -0400 Subject: [PATCH 157/181] Fixed problems with German translation file --- app/src/main/res/values-de/strings.xml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7d1039d57..a6b6bf320 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -101,10 +101,10 @@ Auf Seite suchen Herunterladen läuft\u2026 Herunterladen nur bei \"http\" oder \"https\" URLs möglich! - Keine SD-Karte - USB-Speicher ist für das Herunterladen der Datei notwendig! + Keine SD-Karte + USB-Speicher ist für das Herunterladen der Datei notwendig! USB-Speicher nicht verfügbar - Speicher aktiv. Um ein Herunterladen zu ermöglichen, schalten Sie den USB-Speicher in der Benachrichtigung aus. + Speicher aktiv. Um ein Herunterladen zu ermöglichen, schalten Sie den USB-Speicher in der Benachrichtigung aus. Cookies im Inkognito-Modus aktivieren Adobe Flash Manuell @@ -180,9 +180,9 @@ MIT Lizenz URL-Box Inhalt - Domain (Standard) - URL - Titel + Domain (Standard) + URL + Titel Ordner Umbenennen @@ -218,7 +218,6 @@ Es sieht aus, als ob I2P installiert wäre. Möchten Sie es verwenden? Textcodierung Tabs in Drawer anzeigen - Zum Homescreen hinzufügen Alle Lesezeichen löschen Bitte schließen Sie die App um die Änderungen anzuwenden. Ordner löschen @@ -226,7 +225,6 @@ In neuem Tab öffnen In Inkognito-Tab öffnen Lesezeichen bearbeiten - Andere Tabs schließen Debug Einstellungen Link kopieren Bild herunterladen @@ -237,7 +235,6 @@ \"Nicht verfolgen\"-Funktion anfordern FAQ Häufige Fragen - Lesezeichen zum Homescreen hinzugefügt Kontrast erhöhen Unterstützt durch DuckDuckGo Identifizierbare Header entfernen From 2ff3a6b71d06313335b1496ecd733e2d9d2ac62f Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 3 Jun 2017 18:50:36 -0400 Subject: [PATCH 158/181] Updating build tools and okhttp --- .travis.yml | 2 +- app/build.gradle | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index b929ee7ea..d0075eb88 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ jdk: android: components: - tools - - build-tools-25.0.2 + - build-tools-25.0.3 - android-25 - extra-android-support - extra-android-m2repository diff --git a/app/build.gradle b/app/build.gradle index 2fac20a1a..758e8eed7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'com.getkeepsafe.dexcount' android { compileSdkVersion 25 - buildToolsVersion '25.0.2' + buildToolsVersion '25.0.3' defaultConfig { minSdkVersion 14 @@ -82,8 +82,9 @@ dependencies { provided 'javax.annotation:jsr250-api:1.0' // view binding - compile 'com.jakewharton:butterknife:8.6.0' - annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0' + def butterknifeVersion = '8.6.0' + compile "com.jakewharton:butterknife:$butterknifeVersion" + annotationProcessor "com.jakewharton:butterknife-compiler:$butterknifeVersion" // permissions compile 'com.anthonycr.grant:permissions:1.1.2' @@ -91,7 +92,7 @@ dependencies { // proxy support compile 'net.i2p.android:client:0.8' - compile 'com.squareup.okhttp3:okhttp:3.7.0' + compile 'com.squareup.okhttp3:okhttp:3.8.0' // tor proxy def netcipherVersion = '2.0.0-alpha1' From 5c8773cd9872cf9e432c9febe3304d0bce7a0bcf Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 3 Jun 2017 18:51:23 -0400 Subject: [PATCH 159/181] Fixing Greek and Lithuanian languages --- app/src/main/res/{values-gr => values-el}/strings.xml | 0 app/src/main/res/values-lt/strings.xml | 9 +++++---- 2 files changed, 5 insertions(+), 4 deletions(-) rename app/src/main/res/{values-gr => values-el}/strings.xml (100%) diff --git a/app/src/main/res/values-gr/strings.xml b/app/src/main/res/values-el/strings.xml similarity index 100% rename from app/src/main/res/values-gr/strings.xml rename to app/src/main/res/values-el/strings.xml diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 2f05a20f7..7fbbbfb77 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -30,10 +30,11 @@ Tinklalapis Taip Naudotojo agentas - - - - + Default + Desktop + Mobile + Custom + FAQ Taip Skaitymo rėžimas Ne From 63e77995acfa49cb504109e2c941bd18e15812cb Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sat, 3 Jun 2017 18:51:34 -0400 Subject: [PATCH 160/181] Fixing potential null pointers --- .../lightning/activity/BrowserActivity.java | 49 +++++++++++-------- .../dialog/LightningDialogBuilder.java | 1 - .../lightning/favicon/ImageFetcher.java | 25 ++++++++-- .../search/BaseSuggestionsModel.java | 8 +-- 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 200001df6..3da0cfb9b 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -750,7 +750,7 @@ public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) { // Keyboard shortcuts if (event.isCtrlPressed() && event.getAction() == KeyEvent.ACTION_DOWN) { - switch(event.getKeyCode()) { + switch (event.getKeyCode()) { case KeyEvent.KEYCODE_T: // Open new tab newTab(null, true); @@ -765,23 +765,32 @@ public boolean dispatchKeyEvent(KeyEvent event) { return true; case KeyEvent.KEYCODE_R: // Refresh current tab - mTabsManager.getCurrentTab().reload(); + LightningView currentTab = mTabsManager.getCurrentTab(); + if (currentTab != null) { + currentTab.reload(); + } return true; case KeyEvent.KEYCODE_TAB: int nextIndex = 0; - if(event.isShiftPressed()) { + if (event.isShiftPressed()) { // Go back one tab - if(mTabsManager.indexOfCurrentTab() > 0) nextIndex = mTabsManager.indexOfCurrentTab() - 1; - else nextIndex = mTabsManager.last(); + if (mTabsManager.indexOfCurrentTab() > 0) { + nextIndex = mTabsManager.indexOfCurrentTab() - 1; + } else { + nextIndex = mTabsManager.last(); + } } else { // Go forward one tab - if(mTabsManager.indexOfCurrentTab() < mTabsManager.last()) nextIndex = mTabsManager.indexOfCurrentTab() + 1; - else nextIndex = 0; + if (mTabsManager.indexOfCurrentTab() < mTabsManager.last()) { + nextIndex = mTabsManager.indexOfCurrentTab() + 1; + } else { + nextIndex = 0; + } } mPresenter.tabChanged(nextIndex); return true; } - } else if(event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_SEARCH) { + } else if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_SEARCH) { // Highlight search field mSearch.requestFocus(); mSearch.selectAll(); @@ -1648,18 +1657,18 @@ public void onItem(@Nullable String item) { private void openDownloads() { new DownloadsPage().getDownloadsPage() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new SingleOnSubscribe() { - @Override - public void onItem(@Nullable String item) { - Preconditions.checkNonNull(item); - LightningView view = mTabsManager.getCurrentTab(); - if (view != null) { - view.loadUrl(item); - } + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new SingleOnSubscribe() { + @Override + public void onItem(@Nullable String item) { + Preconditions.checkNonNull(item); + LightningView view = mTabsManager.getCurrentTab(); + if (view != null) { + view.loadUrl(item); } - }); + } + }); } private View getBookmarkDrawer() { @@ -2178,7 +2187,7 @@ public void handleBookmarksChange() { public void handleDownloadDeleted() { final LightningView currentTab = mTabsManager.getCurrentTab(); if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) - && currentTab.getUrl().endsWith(DownloadsPage.FILENAME)) { + && currentTab.getUrl().endsWith(DownloadsPage.FILENAME)) { currentTab.loadDownloadspage(); } if (currentTab != null) { diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 9763383ed..f5b0a2909 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -16,7 +16,6 @@ import android.widget.EditText; import com.anthonycr.bonsai.CompletableOnSubscribe; -import com.anthonycr.bonsai.CompletableSubscriber; import com.anthonycr.bonsai.Schedulers; import com.anthonycr.bonsai.SingleOnSubscribe; diff --git a/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java b/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java index cbef07b3a..337e40844 100644 --- a/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java +++ b/app/src/main/java/acr/browser/lightning/favicon/ImageFetcher.java @@ -8,12 +8,14 @@ import android.util.Log; import java.io.File; +import java.io.IOException; import java.io.InputStream; import acr.browser.lightning.utils.Utils; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; +import okhttp3.ResponseBody; /** * An image fetcher that creates image @@ -65,11 +67,17 @@ private Bitmap retrieveBitmapFromUrl(@NonNull String url) { Request imageRequest = new Request.Builder().url(url).build(); Response boundsResponse = mHttpClient.newCall(imageRequest).execute(); - boundsStream = boundsResponse.body().byteStream(); + ResponseBody boundsBody = boundsResponse.body(); + + if (boundsBody == null) { + return null; + } + + boundsStream = boundsBody.byteStream(); BitmapFactory.decodeStream(boundsStream, null, mLoaderOptions); - boundsResponse.body().close(); + boundsBody.close(); int size = Utils.dpToPx(24); @@ -77,12 +85,19 @@ private Bitmap retrieveBitmapFromUrl(@NonNull String url) { mLoaderOptions.inJustDecodeBounds = false; Response imageResponse = mHttpClient.newCall(imageRequest).execute(); - iconStream = imageResponse.body().byteStream(); + + ResponseBody imageBody = imageResponse.body(); + + if (imageBody == null) { + return null; + } + + iconStream = imageBody.byteStream(); icon = BitmapFactory.decodeStream(iconStream, null, mLoaderOptions); - imageResponse.body().close(); - } catch (Exception e) { + imageBody.close(); + } catch (IOException exception) { Log.d(TAG, "Unable to download icon: " + url); } finally { Utils.close(boundsStream); diff --git a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java index 05e1b93b5..7dfcf47e0 100644 --- a/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java +++ b/app/src/main/java/acr/browser/lightning/search/BaseSuggestionsModel.java @@ -26,6 +26,7 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; +import okhttp3.ResponseBody; abstract class BaseSuggestionsModel { @@ -112,9 +113,10 @@ private InputStream downloadSuggestionsForQuery(@NonNull String query, @NonNull Response suggestionsResponse = mHttpClient.newCall(suggestionsRequest).execute(); - return suggestionsResponse.body().byteStream(); - } catch (Exception e) { - Log.e(TAG, "Problem getting search suggestions", e); + ResponseBody responseBody = suggestionsResponse.body(); + return responseBody != null ? responseBody.byteStream() : null; + } catch (IOException exception) { + Log.e(TAG, "Problem getting search suggestions", exception); } return null; From cd479cd931d194fa12c473dabe20f01cb465fd16 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 4 Jun 2017 09:51:59 -0400 Subject: [PATCH 161/181] Cleaning up recent merge problems --- .../dialog/LightningDialogBuilder.java | 18 +++++++++--------- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 -- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 46c4f0ec1..5b7fac1cb 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -173,14 +173,14 @@ public void showLongPressedDialogForDownloadUrl(@NonNull final Activity activity @Override public void onClick() { mDownloadsModel.deleteAllDownloads() - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.main()) - .subscribe(new CompletableOnSubscribe() { - @Override - public void onComplete() { - uiController.handleDownloadDeleted(); - } - }); + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) + .subscribe(new CompletableOnSubscribe() { + @Override + public void onComplete() { + uiController.handleDownloadDeleted(); + } + }); } }); } @@ -363,7 +363,7 @@ public void onClick() { uiController.handleNewTab(NewTab.BACKGROUND, url); } }, - new BrowserDialog.Item(R.string.dialog_open_incognito_tab) { + new BrowserDialog.Item(R.string.dialog_open_incognito_tab, activity instanceof MainActivity) { @Override public void onClick() { uiController.handleNewTab(NewTab.INCOGNITO, url); diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index edb060353..5683968a0 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -36,7 +36,6 @@ Scegli un percorso Avanzate Apache License 2.0 - Versione App Cancella la cache in chiusura Abilità il reflow del testo Blocca immagini @@ -104,6 +103,7 @@ Indietro Trova nella pagina Avvio download\u2026 + È possibile scaricare solo da URL \"http\" o \"https\". URL non supportato: scaricamento fallito Impssibile scaricare nella posizione scelta Nessuna scheda SD trovata. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 12afb5b47..51cf5bb7f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -243,8 +243,6 @@ Remove bookmark Edit bookmark Remove from history - Open image in new tab - Open image in background tab Download image Copy link Rename folder From 7f0e5f563d85689fe9e9c9ac2d5c36aa30c58d14 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 4 Jun 2017 12:48:14 -0400 Subject: [PATCH 162/181] Fixing strings --- app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 72664ee1b..9fbd09ba5 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -72,7 +72,7 @@ Aangepast Zoekmachine OK - Wil je dit bestand downloaden? + Wil je dit bestand downloaden? (%1$s) Annuleer Waarschuwing Adobe Flash Player werd niet gevonden.\nGelieve Flash Player te installeren. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 7ba6b8e0e..a76ab5abe 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -68,7 +68,7 @@ Personalizado Mecanismo de pesquisa OK - Gostaria de transferir este arquivo? + Gostaria de transferir este arquivo? (%1$s) Cancelar Aviso O Adobe Flash Player não foi detectado.\nNecessário instalar o Flash Player. From 8a66a3f1888c6729e63cf40a37b838669c91fed6 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 4 Jun 2017 18:52:56 -0400 Subject: [PATCH 163/181] Cleaning up lint --- .../acr/browser/lightning/dialog/LightningDialogBuilder.java | 2 +- .../acr/browser/lightning/fragment/BookmarksFragment.java | 2 +- .../java/acr/browser/lightning/fragment/TabsFragment.java | 4 ++-- .../java/acr/browser/lightning/search/SuggestionsAdapter.java | 2 +- app/src/main/res/layout/tab_list_item.xml | 2 +- app/src/main/res/layout/tab_list_item_horizontal.xml | 2 +- app/src/main/res/values-nl/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - 8 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 5b7fac1cb..ee4c0dd30 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -45,7 +45,7 @@ * Created by Stefano Pacifici on 02/09/15, based on Anthony C. Restaino's code. */ public class LightningDialogBuilder { - public static final String TAG = "LightningDialogBuilder"; + private static final String TAG = "LightningDialogBuilder"; public enum NewTab { FOREGROUND, diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 97583c2db..5145e48e2 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -67,7 +67,7 @@ public static BookmarksFragment createFragment(boolean isIncognito) { private static final String TAG = "BookmarksFragment"; - public final static String INCOGNITO_MODE = TAG + ".INCOGNITO_MODE"; + private final static String INCOGNITO_MODE = TAG + ".INCOGNITO_MODE"; // Managers @Inject BookmarkModel mBookmarkManager; diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index 7d077dae0..62642cfe2 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -76,8 +76,8 @@ public static TabsFragment createTabsFragment(boolean isIncognito, boolean showT * Arguments boolean to tell the fragment it is displayed in the drawner or on the tab strip * If true, the fragment is in the left drawner in the strip otherwise. */ - public static final String VERTICAL_MODE = TAG + ".VERTICAL_MODE"; - public static final String IS_INCOGNITO = TAG + ".IS_INCOGNITO"; + private static final String VERTICAL_MODE = TAG + ".VERTICAL_MODE"; + private static final String IS_INCOGNITO = TAG + ".IS_INCOGNITO"; private boolean mIsIncognito, mDarkTheme; private int mIconColor; diff --git a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java index dae2a33c2..a14a9192b 100644 --- a/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java +++ b/app/src/main/java/acr/browser/lightning/search/SuggestionsAdapter.java @@ -49,7 +49,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable { private static final Scheduler FILTER_SCHEDULER = Schedulers.newSingleThreadedScheduler(); - static final String CACHE_FILE_TYPE = ".sgg"; + private static final String CACHE_FILE_TYPE = ".sgg"; private final List mFilteredList = new ArrayList<>(5); diff --git a/app/src/main/res/layout/tab_list_item.xml b/app/src/main/res/layout/tab_list_item.xml index 6cbb5e9d1..dcbb69983 100644 --- a/app/src/main/res/layout/tab_list_item.xml +++ b/app/src/main/res/layout/tab_list_item.xml @@ -48,7 +48,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:contentDescription="Delete Tab" + android:contentDescription="@string/close_tab" app:srcCompat="@drawable/ic_action_delete"/> \ No newline at end of file diff --git a/app/src/main/res/layout/tab_list_item_horizontal.xml b/app/src/main/res/layout/tab_list_item_horizontal.xml index 1651425d6..545e3a51e 100644 --- a/app/src/main/res/layout/tab_list_item_horizontal.xml +++ b/app/src/main/res/layout/tab_list_item_horizontal.xml @@ -47,7 +47,7 @@ android:layout_width="20dp" android:layout_height="20dp" android:layout_gravity="center" - android:contentDescription="Delete Tab" + android:contentDescription="@string/close_tab" app:srcCompat="@drawable/ic_action_delete"/> diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 9fbd09ba5..1220d29f5 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -144,7 +144,6 @@ Inloggen Gebruiksnaam Paswoord - Zoeksuggesties Ondersteund door Google HTTP Proxy diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index a76ab5abe..e19b5d957 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -131,7 +131,6 @@ Iniciar sessão Usuário Senha - Sugestões de pesquisa Disponibilizado por Google Proxy HTTP From b39d264d4611931e9615cd5b307a879478c82ba1 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 4 Jun 2017 19:19:10 -0400 Subject: [PATCH 164/181] Bumping version for beta --- app/build.gradle | 6 +++--- build.gradle | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 758e8eed7..451c6d713 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 25 - versionName "4.4.2" + versionName project.versionName vectorDrawables.useSupportLibrary = true } @@ -35,13 +35,13 @@ android { lightningPlus { buildConfigField "boolean", "FULL_VERSION", "Boolean.parseBoolean(\"true\")" applicationId "acr.browser.lightning" - versionCode 91 + versionCode project.versionCode_plus } lightningLite { buildConfigField "boolean", "FULL_VERSION", "Boolean.parseBoolean(\"false\")" applicationId "acr.browser.barebones" - versionCode 93 + versionCode project.versionCode_lite } } diff --git a/build.gradle b/build.gradle index 77dfcac51..4428d205b 100644 --- a/build.gradle +++ b/build.gradle @@ -19,4 +19,8 @@ ext { minSdkVersion = 14 targetSdkVersion = 25 buildToolsVersion = '25.0.2' + + versionName = '4.4.3' + versionCode_lite = 94 + versionCode_plus = 92 } From 652daa2c3c6423b7f61d381ab2a6060127594098 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 4 Jun 2017 19:21:35 -0400 Subject: [PATCH 165/181] Adding proguard warning exemptions for okhttp --- app/proguard-project.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/proguard-project.txt b/app/proguard-project.txt index 40cddda10..4c1bb3ddb 100644 --- a/app/proguard-project.txt +++ b/app/proguard-project.txt @@ -111,3 +111,8 @@ -dontwarn org.apache.http.conn.ssl.DefaultHostnameVerifier -dontwarn org.apache.http.HttpHost + +# Needed for okhttp +-dontwarn okio.** +-dontwarn javax.annotation.Nullable +-dontwarn javax.annotation.ParametersAreNonnullByDefault From 5f222e2d5b704dfa5dc963eb0ca3cb6c06b0b8be Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Sun, 4 Jun 2017 21:24:41 -0400 Subject: [PATCH 166/181] Fixing bug where icon could be the wrong color Without mutating icon could be the wrong color after theme change --- .../lightning/activity/ReadingActivity.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java index 9111c0a03..f554c6fd8 100644 --- a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java @@ -131,11 +131,17 @@ public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.reading, menu); MenuItem invert = menu.findItem(R.id.invert_item); MenuItem textSize = menu.findItem(R.id.text_size_item); - int iconColor = mInvert ? ThemeUtils.getIconDarkThemeColor(this) : ThemeUtils.getIconLightThemeColor(this); - if (invert != null && invert.getIcon() != null) - invert.getIcon().setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); - if (textSize != null && textSize.getIcon() != null) - textSize.getIcon().setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + + int iconColor = ThemeUtils.getIconThemeColor(this, mInvert); + + if (invert != null && invert.getIcon() != null) { + invert.getIcon().mutate().setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + } + + if (textSize != null && textSize.getIcon() != null) { + textSize.getIcon().mutate().setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + } + return super.onCreateOptionsMenu(menu); } From c8a2fd826259d1770829a802611a8e97df6f52cd Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 5 Jun 2017 08:22:05 -0400 Subject: [PATCH 167/181] Fixing crashes resulting from fragment lifecycle mismanagement --- .../fragment/BookmarkSettingsFragment.java | 10 ++++- .../lightning/fragment/BookmarksFragment.java | 6 ++- .../acr/browser/lightning/utils/Utils.java | 45 ++++++++++++------- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index 5a7e1aff4..4e965ffd5 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -5,6 +5,7 @@ import android.Manifest; import android.app.Activity; +import android.app.Application; import android.app.Dialog; import android.content.DialogInterface; import android.content.pm.ApplicationInfo; @@ -61,6 +62,8 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @Nullable private Activity mActivity; @Inject BookmarkModel mBookmarkManager; + @Inject Application mApplication; + private File[] mFileList; private String[] mFileNameList; @Nullable private BookmarkLocalSync mSync; @@ -454,7 +457,12 @@ public void onComplete() { @Override public void onError(@NonNull Throwable throwable) { Log.e(TAG, "onError: importing bookmarks", throwable); - Utils.createInformativeDialog(getActivity(), R.string.title_error, R.string.import_bookmark_error); + Activity activity = getActivity(); + if (activity != null) { + Utils.createInformativeDialog(activity, R.string.title_error, R.string.import_bookmark_error); + } else { + Utils.showToast(mApplication, R.string.import_bookmark_error); + } } }); } diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 5145e48e2..936ff620d 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -233,12 +233,16 @@ private void updateBookmarkIndicator(final String url) { @Override public void onItem(@Nullable Boolean item) { Preconditions.checkNonNull(item); + Activity activity = getActivity(); + if (mBookmarkImage == null || activity == null) { + return; + } if (!item) { mBookmarkImage.setImageResource(R.drawable.ic_action_star); mBookmarkImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); } else { mBookmarkImage.setImageResource(R.drawable.ic_bookmark); - mBookmarkImage.setColorFilter(ThemeUtils.getAccentColor(getContext()), PorterDuff.Mode.SRC_IN); + mBookmarkImage.setColorFilter(ThemeUtils.getAccentColor(activity), PorterDuff.Mode.SRC_IN); } } }); diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index 0bb7682ea..b626582aa 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -34,6 +34,7 @@ import android.util.Log; import android.view.View; import android.webkit.URLUtil; +import android.widget.Toast; import com.anthonycr.grant.PermissionsManager; import com.anthonycr.grant.PermissionsResultAction; @@ -75,7 +76,7 @@ public static boolean doesSupportHeaders() { public static void downloadFile(@NonNull final Activity activity, @NonNull final PreferenceManager manager, final String url, final String userAgent, final String contentDisposition) { PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsResultAction() { + Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsResultAction() { @Override public void onGranted() { String fileName = URLUtil.guessFileName(url, null, null); @@ -125,13 +126,13 @@ public static void createInformativeDialog(@NonNull Activity activity, @StringRe AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle(title); builder.setMessage(message) - .setCancelable(true) - .setPositiveButton(activity.getResources().getString(R.string.action_ok), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - } - }); + .setCancelable(true) + .setPositiveButton(activity.getResources().getString(R.string.action_ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + } + }); AlertDialog alert = builder.create(); alert.show(); BrowserDialog.setDialogSize(activity, alert); @@ -175,6 +176,18 @@ public static void showSnackbar(@NonNull Activity activity, @NonNull String mess Snackbar.make(view, message, Snackbar.LENGTH_SHORT).show(); } + /** + * Shows a toast to the user. + * Should only be used if an activity is + * not available to show a snackbar. + * + * @param context the context needed to show the toast. + * @param resource the string shown by the toast to the user. + */ + public static void showToast(@NonNull Context context, @StringRes int resource) { + Toast.makeText(context, resource, Toast.LENGTH_SHORT).show(); + } + /** * Converts Density Pixels (DP) to Pixels (PX). * @@ -261,7 +274,7 @@ public static Bitmap padFavicon(@NonNull Bitmap bitmap) { int padding = Utils.dpToPx(4); Bitmap paddedBitmap = Bitmap.createBitmap(bitmap.getWidth() + padding, bitmap.getHeight() - + padding, Bitmap.Config.ARGB_8888); + + padding, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(paddedBitmap); canvas.drawARGB(0x00, 0x00, 0x00, 0x00); // this represents white color @@ -305,10 +318,10 @@ public static File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + '_'; File storageDir = Environment - .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); return File.createTempFile(imageFileName, /* prefix */ - ".jpg", /* suffix */ - storageDir /* directory */ + ".jpg", /* suffix */ + storageDir /* directory */ ); } @@ -382,9 +395,9 @@ public static void drawTrapezoid(@NonNull Canvas canvas, int color, boolean with paint.setDither(true); if (withShader) { paint.setShader(new LinearGradient(0, 0.9f * canvas.getHeight(), - 0, canvas.getHeight(), - color, mixTwoColors(Color.BLACK, color, 0.5f), - Shader.TileMode.CLAMP)); + 0, canvas.getHeight(), + color, mixTwoColors(Color.BLACK, color, 0.5f), + Shader.TileMode.CLAMP)); } else { paint.setShader(null); } @@ -448,7 +461,7 @@ public static int calculateInSampleSize(@NonNull BitmapFactory.Options options, // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) >= reqHeight - && (halfWidth / inSampleSize) >= reqWidth) { + && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } From 981ecc1696da1104ae8152415240a2d04379381e Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 5 Jun 2017 20:00:55 -0400 Subject: [PATCH 168/181] Fixing problem with unsafe URIs --- .../main/java/acr/browser/lightning/favicon/FaviconUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java b/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java index a25e69115..a32420b0f 100644 --- a/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java +++ b/app/src/main/java/acr/browser/lightning/favicon/FaviconUtils.java @@ -17,7 +17,7 @@ static Uri safeUri(@NonNull String url) { Uri uri = Uri.parse(url); - if (uri.getHost() == null || uri.getScheme() == null) { + if (TextUtils.isEmpty(uri.getScheme()) || TextUtils.isEmpty(uri.getHost())) { return null; } From 32d7e509e1274526498961c04775fb419ecb129e Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 5 Jun 2017 20:08:53 -0400 Subject: [PATCH 169/181] Catch fileuriexposedexception for now --- .../main/java/acr/browser/lightning/utils/IntentUtils.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java index 17eba2bf6..7f953f4eb 100644 --- a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java @@ -8,6 +8,7 @@ import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Build; +import android.os.FileUriExposedException; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; @@ -75,8 +76,9 @@ public boolean startActivityForUrl(@Nullable WebView tab, @NonNull String url) { if (mActivity.startActivityIfNeeded(intent, -1)) { return true; } - } catch (ActivityNotFoundException ex) { - ex.printStackTrace(); + } catch (Exception exception) { + exception.printStackTrace(); + // TODO: 6/5/17 fix case where this could throw a FileUriExposedException due to file:// urls } return false; } From 6061db0b14572d788a1556d8ca33d5dacea88e86 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 5 Jun 2017 20:09:50 -0400 Subject: [PATCH 170/181] Bumping version for beta --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 4428d205b..00246856d 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ ext { targetSdkVersion = 25 buildToolsVersion = '25.0.2' - versionName = '4.4.3' - versionCode_lite = 94 - versionCode_plus = 92 + versionName = '4.5.0' + versionCode_lite = 95 + versionCode_plus = 93 } From fbb820faf670d60a2058ed5d0df021280a288eb1 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 5 Jun 2017 21:12:17 -0400 Subject: [PATCH 171/181] Fix favicon retrieval from cache, disable preemptive favicon fetching --- .../lightning/favicon/FaviconModel.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java index 5942623df..27cfb395f 100644 --- a/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java +++ b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java @@ -136,14 +136,15 @@ public void onSubscribe(@NonNull SingleSubscriber subscriber) { File faviconCacheFile = createFaviconCacheFile(mApplication, uri); + Bitmap favicon = getFaviconFromMemCache(url); - if (faviconCacheFile.exists() && favicon != null) { + if (faviconCacheFile.exists() && favicon == null) { favicon = mImageFetcher.retrieveFaviconFromCache(faviconCacheFile); } if (favicon == null) { - favicon = mImageFetcher.retrieveBitmapFromDomain(uri); + // favicon = mImageFetcher.retrieveBitmapFromDomain(uri); } else { Bitmap newFavicon = Utils.padFavicon(favicon); @@ -153,18 +154,18 @@ public void onSubscribe(@NonNull SingleSubscriber subscriber) { return; } - if (favicon == null && allowGoogleService) { - favicon = mImageFetcher.retrieveBitmapFromGoogle(uri); - } + // if (favicon == null && allowGoogleService) { + // favicon = mImageFetcher.retrieveBitmapFromGoogle(uri); + // } - if (favicon != null) { - addFaviconToMemCache(url, favicon); - cacheFaviconForUrl(favicon, url).subscribe(); - } + // if (favicon != null) { + // addFaviconToMemCache(url, favicon); + // cacheFaviconForUrl(favicon, url).subscribe(); + // } - if (favicon == null) { - favicon = defaultFavicon; - } + // if (favicon == null) { + favicon = defaultFavicon; + // } Bitmap newFavicon = Utils.padFavicon(favicon); From b59f610c22ef14938ea38e15940f0bb16e5b6171 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Mon, 5 Jun 2017 21:20:30 -0400 Subject: [PATCH 172/181] Adding todo --- .../main/java/acr/browser/lightning/favicon/FaviconModel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java index 27cfb395f..e9ecf6c80 100644 --- a/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java +++ b/app/src/main/java/acr/browser/lightning/favicon/FaviconModel.java @@ -144,6 +144,7 @@ public void onSubscribe(@NonNull SingleSubscriber subscriber) { } if (favicon == null) { + // TODO: 6/5/17 figure out if optimistic favicon retrieval should be added back or dropped // favicon = mImageFetcher.retrieveBitmapFromDomain(uri); } else { Bitmap newFavicon = Utils.padFavicon(favicon); From 3711f81bd1747a1d0f4f8e90eb421668743ab6e4 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 6 Jun 2017 20:19:07 -0400 Subject: [PATCH 173/181] Fixing bugs resulting from not unsubscribing --- .../lightning/fragment/BookmarksFragment.java | 74 +++++++++++++------ .../lightning/utils/SubscriptionUtils.java | 26 +++++++ 2 files changed, 79 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/utils/SubscriptionUtils.java diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 936ff620d..62776b26b 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -26,9 +26,10 @@ import com.anthonycr.bonsai.SingleOnSubscribe; import com.anthonycr.bonsai.Subscription; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import javax.inject.Inject; @@ -47,6 +48,7 @@ import acr.browser.lightning.favicon.FaviconModel; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Preconditions; +import acr.browser.lightning.utils.SubscriptionUtils; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.view.LightningView; import butterknife.BindView; @@ -94,19 +96,18 @@ public static BookmarksFragment createFragment(boolean isIncognito) { @BindView(R.id.starIcon) ImageView mBookmarkTitleImage; @BindView(R.id.icon_star) ImageView mBookmarkImage; - @Nullable - private Unbinder mUnbinder; + @Nullable private Unbinder mUnbinder; // Colors private int mIconColor, mScrollIndex; private boolean mIsIncognito; - @Nullable - private Subscription mBookmarksSubscription; + @Nullable private Subscription mBookmarksSubscription; + @Nullable private Subscription mFoldersSubscription; + @Nullable private Subscription mBookmarkUpdateSubscription; - @NonNull - private final BookmarkUiModel mUiModel = new BookmarkUiModel(); + @NonNull private final BookmarkUiModel mUiModel = new BookmarkUiModel(); @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -194,10 +195,15 @@ public void onClick(View v) { @Override public void onDestroyView() { super.onDestroyView(); - if (mBookmarksSubscription != null) { - mBookmarksSubscription.unsubscribe(); - mBookmarksSubscription = null; + + SubscriptionUtils.safeUnsubscribe(mBookmarksSubscription); + SubscriptionUtils.safeUnsubscribe(mFoldersSubscription); + SubscriptionUtils.safeUnsubscribe(mBookmarkUpdateSubscription); + + if (mBookmarkAdapter != null) { + mBookmarkAdapter.cleanupSubscriptions(); } + if (mUnbinder != null) { mUnbinder.unbind(); mUnbinder = null; @@ -207,9 +213,13 @@ public void onDestroyView() { @Override public void onDestroy() { super.onDestroy(); - if (mBookmarksSubscription != null) { - mBookmarksSubscription.unsubscribe(); - mBookmarksSubscription = null; + + SubscriptionUtils.safeUnsubscribe(mBookmarksSubscription); + SubscriptionUtils.safeUnsubscribe(mFoldersSubscription); + SubscriptionUtils.safeUnsubscribe(mBookmarkUpdateSubscription); + + if (mBookmarkAdapter != null) { + mBookmarkAdapter.cleanupSubscriptions(); } } @@ -226,12 +236,14 @@ public void reinitializePreferences() { } private void updateBookmarkIndicator(final String url) { - mBookmarkManager.isBookmark(url) + SubscriptionUtils.safeUnsubscribe(mBookmarkUpdateSubscription); + mBookmarkUpdateSubscription = mBookmarkManager.isBookmark(url) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe() { @Override public void onItem(@Nullable Boolean item) { + mBookmarkUpdateSubscription = null; Preconditions.checkNonNull(item); Activity activity = getActivity(); if (mBookmarkImage == null || activity == null) { @@ -258,6 +270,7 @@ public void handleBookmarkDeleted(@NonNull HistoryItem item) { } private void setBookmarksShown(@Nullable final String folder, final boolean animate) { + SubscriptionUtils.safeUnsubscribe(mBookmarksSubscription); mBookmarksSubscription = mBookmarkManager.getBookmarksFromFolderSorted(folder) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) @@ -269,12 +282,14 @@ public void onItem(@Nullable final List item) { mUiModel.setCurrentFolder(folder); if (folder == null) { - mBookmarkManager.getFoldersSorted() + SubscriptionUtils.safeUnsubscribe(mFoldersSubscription); + mFoldersSubscription = mBookmarkManager.getFoldersSorted() .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable List folders) { + mFoldersSubscription = null; Preconditions.checkNonNull(folders); item.addAll(folders); setBookmarkDataSet(item, animate); @@ -424,6 +439,7 @@ private static class BookmarkListAdapter extends RecyclerView.Adapter mFaviconFetchSubscriptions = new ConcurrentHashMap<>(); @Nullable private OnItemLongClickListener mOnItemLongCLickListener; @Nullable private OnItemClickListener mOnItemClickListener; @@ -484,6 +500,13 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { diffResult.dispatchUpdatesTo(this); } + void cleanupSubscriptions() { + for (Subscription subscription : mFaviconFetchSubscriptions.values()) { + subscription.unsubscribe(); + } + mFaviconFetchSubscriptions.clear(); + } + @Override public BookmarkViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); @@ -493,7 +516,12 @@ public BookmarkViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { } @Override - public void onBindViewHolder(BookmarkViewHolder holder, int position) { + public void onViewRecycled(BookmarkViewHolder holder) { + super.onViewRecycled(holder); + } + + @Override + public void onBindViewHolder(final BookmarkViewHolder holder, int position) { ViewCompat.jumpDrawablesToCurrentState(holder.itemView); final HistoryItem web = mBookmarks.get(position); @@ -505,23 +533,27 @@ public void onBindViewHolder(BookmarkViewHolder holder, int position) { holder.favicon.setTag(web.getUrl().hashCode()); final String url = web.getUrl(); - final WeakReference imageViewReference = new WeakReference<>(holder.favicon); - mFaviconModel.faviconForUrl(url, mWebpageBitmap, true) + Subscription oldSubscription = mFaviconFetchSubscriptions.get(url); + SubscriptionUtils.safeUnsubscribe(oldSubscription); + + final Subscription faviconSubscription = mFaviconModel.faviconForUrl(url, mWebpageBitmap, true) .subscribeOn(Schedulers.worker()) .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe() { @Override public void onItem(@Nullable Bitmap item) { - ImageView imageView = imageViewReference.get(); - Object tag = imageView != null ? imageView.getTag() : null; + mFaviconFetchSubscriptions.remove(url); + Object tag = holder.favicon.getTag(); if (tag != null && tag.equals(url.hashCode())) { - imageView.setImageBitmap(item); + holder.favicon.setImageBitmap(item); } web.setBitmap(item); } }); + + mFaviconFetchSubscriptions.put(url, faviconSubscription); } else { holder.favicon.setImageBitmap(web.getBitmap()); } diff --git a/app/src/main/java/acr/browser/lightning/utils/SubscriptionUtils.java b/app/src/main/java/acr/browser/lightning/utils/SubscriptionUtils.java new file mode 100644 index 000000000..0c6756f63 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/utils/SubscriptionUtils.java @@ -0,0 +1,26 @@ +package acr.browser.lightning.utils; + +import android.support.annotation.Nullable; + +import com.anthonycr.bonsai.Subscription; + +/** + * Utilities used when working with bonsai code. + *

+ * Created by anthonycr on 6/6/17. + */ +public final class SubscriptionUtils { + + private SubscriptionUtils() {} + + /** + * Unsubscribes from a subscription if the subscription is not null. + * + * @param subscription the subscription from which to unsubscribe. + */ + public static void safeUnsubscribe(@Nullable Subscription subscription) { + if (subscription != null) { + subscription.unsubscribe(); + } + } +} From bee7d4b8dd8ef428697807ca3b3271d212f643b4 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 6 Jun 2017 20:26:31 -0400 Subject: [PATCH 174/181] Ensuring that bookmark export failures are handled --- .../lightning/fragment/BookmarkSettingsFragment.java | 11 +++++++++++ app/src/main/res/values/strings.xml | 1 + 2 files changed, 12 insertions(+) diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index 4e965ffd5..48c4e5ea3 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -211,6 +211,17 @@ public void onComplete() { + ' ' + exportFile.getPath()); } } + + @Override + public void onError(@NonNull Throwable throwable) { + Log.e(TAG, "onError: exporting bookmarks", throwable); + Activity activity = getActivity(); + if (activity != null) { + Utils.createInformativeDialog(activity, R.string.title_error, R.string.bookmark_export_failure); + } else { + Utils.showToast(mApplication, R.string.bookmark_export_failure); + } + } }); } }); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 51cf5bb7f..cda38c490 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -176,6 +176,7 @@ Export bookmarks to backup Import bookmarks from backup Bookmarks exported to + Sorry, bookmarks could not be exported! Bookmark Settings Could not import bookmarks from file Choose a file From 84f004706f1ae4628f5ffbc9dfd8efa8a9d85d5c Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 6 Jun 2017 20:37:05 -0400 Subject: [PATCH 175/181] Safeguarding against runtime exceptions when importing and exporting --- .../fragment/BookmarkSettingsFragment.java | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index 48c4e5ea3..c09453647 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -24,6 +24,7 @@ import com.anthonycr.bonsai.CompletableOnSubscribe; import com.anthonycr.bonsai.SingleOnSubscribe; +import com.anthonycr.bonsai.Subscription; import com.anthonycr.grant.PermissionsManager; import com.anthonycr.grant.PermissionsResultAction; @@ -48,6 +49,7 @@ import acr.browser.lightning.database.bookmark.BookmarkModel; import acr.browser.lightning.dialog.BrowserDialog; import acr.browser.lightning.utils.Preconditions; +import acr.browser.lightning.utils.SubscriptionUtils; import acr.browser.lightning.utils.Utils; public class BookmarkSettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener { @@ -66,8 +68,12 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref private File[] mFileList; private String[] mFileNameList; + @Nullable private BookmarkLocalSync mSync; + @Nullable private Subscription mImportSubscription; + @Nullable private Subscription mExportSubscription; + private static final String[] REQUIRED_PERMISSIONS = new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE @@ -153,9 +159,21 @@ public void onCreate(Bundle savedInstanceState) { } } + @Override + public void onDestroyView() { + super.onDestroyView(); + + SubscriptionUtils.safeUnsubscribe(mExportSubscription); + SubscriptionUtils.safeUnsubscribe(mImportSubscription); + } + @Override public void onDestroy() { super.onDestroy(); + + SubscriptionUtils.safeUnsubscribe(mExportSubscription); + SubscriptionUtils.safeUnsubscribe(mImportSubscription); + mActivity = null; } @@ -197,14 +215,21 @@ public void onGranted() { .subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable List item) { + if (!isAdded()) { + return; + } + Preconditions.checkNonNull(item); final File exportFile = BookmarkExporter.createNewExportFile(); - BookmarkExporter.exportBookmarksToFile(item, exportFile) + SubscriptionUtils.safeUnsubscribe(mExportSubscription); + mExportSubscription = BookmarkExporter.exportBookmarksToFile(item, exportFile) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) .subscribe(new CompletableOnSubscribe() { @Override public void onComplete() { + mExportSubscription = null; + Activity activity = getActivity(); if (activity != null) { Utils.showSnackbar(activity, activity.getString(R.string.bookmark_export_path) @@ -214,9 +239,11 @@ public void onComplete() { @Override public void onError(@NonNull Throwable throwable) { + mExportSubscription = null; + Log.e(TAG, "onError: exporting bookmarks", throwable); Activity activity = getActivity(); - if (activity != null) { + if (activity != null && !activity.isFinishing() && isAdded()) { Utils.createInformativeDialog(activity, R.string.title_error, R.string.bookmark_export_failure); } else { Utils.showToast(mApplication, R.string.bookmark_export_failure); @@ -229,7 +256,12 @@ public void onError(@NonNull Throwable throwable) { @Override public void onDenied(String permission) { - //TODO Show message + Activity activity = getActivity(); + if (activity != null && !activity.isFinishing() && isAdded()) { + Utils.createInformativeDialog(activity, R.string.title_error, R.string.bookmark_export_failure); + } else { + Utils.showToast(mApplication, R.string.bookmark_export_failure); + } } }); return true; @@ -445,11 +477,14 @@ public void onClick(DialogInterface dialog, int which) { Dialog dialog1 = builder.show(); BrowserDialog.setDialogSize(mActivity, dialog1); } else { - BookmarkExporter.importBookmarksFromFile(mFileList[which]) + SubscriptionUtils.safeUnsubscribe(mImportSubscription); + mImportSubscription = BookmarkExporter.importBookmarksFromFile(mFileList[which]) .subscribeOn(Schedulers.io()) .subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable final List importList) { + mImportSubscription = null; + Preconditions.checkNonNull(importList); mBookmarkManager.addBookmarkList(importList) .observeOn(Schedulers.main()) @@ -467,9 +502,11 @@ public void onComplete() { @Override public void onError(@NonNull Throwable throwable) { + mImportSubscription = null; + Log.e(TAG, "onError: importing bookmarks", throwable); Activity activity = getActivity(); - if (activity != null) { + if (activity != null && !activity.isFinishing() && isAdded()) { Utils.createInformativeDialog(activity, R.string.title_error, R.string.import_bookmark_error); } else { Utils.showToast(mApplication, R.string.import_bookmark_error); From a2ac0e30783cba7aea4703455902ac7277c13160 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Tue, 6 Jun 2017 20:55:45 -0400 Subject: [PATCH 176/181] Bumping version codes for beta bugfix --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 00246856d..afe703ba1 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,6 @@ ext { buildToolsVersion = '25.0.2' versionName = '4.5.0' - versionCode_lite = 95 - versionCode_plus = 93 + versionCode_lite = 96 + versionCode_plus = 94 } From a79a5e8a9b4dedcd2e2bd192af6f7ba5f3f14266 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 7 Jun 2017 08:24:32 -0400 Subject: [PATCH 177/181] Fixing exception thrown due to observable using the wrong thread --- .../browser/lightning/fragment/BookmarkSettingsFragment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index c09453647..4e9b8808f 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -480,6 +480,7 @@ public void onClick(DialogInterface dialog, int which) { SubscriptionUtils.safeUnsubscribe(mImportSubscription); mImportSubscription = BookmarkExporter.importBookmarksFromFile(mFileList[which]) .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.main()) .subscribe(new SingleOnSubscribe>() { @Override public void onItem(@Nullable final List importList) { @@ -487,6 +488,7 @@ public void onItem(@Nullable final List importList) { Preconditions.checkNonNull(importList); mBookmarkManager.addBookmarkList(importList) + .subscribeOn(Schedulers.io()) .observeOn(Schedulers.main()) .subscribe(new CompletableOnSubscribe() { @Override From b951b5a0b5b211c1b1b750ef0ac247c3dd243133 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 7 Jun 2017 08:25:06 -0400 Subject: [PATCH 178/181] Bumping version for beta --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index afe703ba1..1325d31f3 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,6 @@ ext { buildToolsVersion = '25.0.2' versionName = '4.5.0' - versionCode_lite = 96 - versionCode_plus = 94 + versionCode_lite = 97 + versionCode_plus = 95 } From ef86b7d54ddab5406801ef014b4d131eaa73e0b9 Mon Sep 17 00:00:00 2001 From: anthony restaino Date: Wed, 7 Jun 2017 21:31:46 -0400 Subject: [PATCH 179/181] Updating bookmark page and history page with changes from @ByteHamster --- .../acr/browser/lightning/constant/BookmarkPage.java | 10 ++++++++-- .../acr/browser/lightning/constant/HistoryPage.java | 10 ++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java index afdc43929..e4179329f 100644 --- a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java @@ -47,8 +47,14 @@ public final class BookmarkPage { private static final String HEADING_2 = "\n" + "\n" + - "\n" + + "\n" + "

"; private static final String PART1 = "
\n" + ""; - private static final String HEADING_2 = "" + - "" + - "" + - "