From 8640a9fa44f3e54e88eae5cb7fe80014408abd5c Mon Sep 17 00:00:00 2001 From: Kieron Quinn Date: Fri, 19 Jul 2024 23:29:22 +0100 Subject: [PATCH] 2.6.5 - Fixed search box replacement not working on Android 15 - Enabled in-app predictive back - Improved proxy widget support - Target Android 15 --- app/build.gradle | 32 ++++----- app/release/baselineProfiles/0/app-release.dm | Bin 4819 -> 4907 bytes app/release/baselineProfiles/1/app-release.dm | Bin 4749 -> 4835 bytes app/release/output-metadata.json | 4 +- .../repositories/ProxyAppWidgetRepository.kt | 35 +++++++--- .../service/PixelLauncherModsRootService.kt | 14 +++- .../ui/base/FragmentOptions.kt | 1 + .../ui/screens/container/ContainerFragment.kt | 63 +++++++++++++----- .../Extensions+ActivityOptionsCompat.kt | 1 - .../utils/extensions/Extensions+Fragment.kt | 8 +++ .../utils/extensions/Extensions+Lifecycle.kt | 14 ++++ .../utils/extensions/Extensions+Navigation.kt | 53 ++++++++++++++- .../utils/extensions/Extensions+Resources.kt | 12 +++- app/src/main/res/layout/activity_main.xml | 5 +- app/src/main/res/layout/fragment_root.xml | 1 + app/src/main/res/layout/widget_wrapper.xml | 1 + .../res/navigation/nav_graph_activity.xml | 14 ++++ 17 files changed, 208 insertions(+), 50 deletions(-) create mode 100644 app/src/main/res/navigation/nav_graph_activity.xml diff --git a/app/build.gradle b/app/build.gradle index 4b19ac2..730aaed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ plugins { id 'com.google.android.gms.oss-licenses-plugin' } -def tagName = '2.6.4' -def tagCode = 264 +def tagName = '2.6.5' +def tagCode = 265 def getKeystoreProperties() { def properties = new Properties() @@ -29,12 +29,12 @@ def getKeystoreProperties() { } android { - compileSdk 34 + compileSdk 35 defaultConfig { applicationId "com.kieronquinn.app.pixellaunchermods" minSdk 31 - targetSdk 34 + targetSdk 35 versionCode tagCode versionName tagName @@ -76,26 +76,26 @@ android { dependencies { implementation 'androidx.core:core-ktx:1.13.1' - implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'com.google.android.material:material:1.12.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version" implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation 'androidx.palette:palette-ktx:1.0.0' - implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.7.0" - implementation "androidx.lifecycle:lifecycle-service:2.7.0" - implementation "androidx.fragment:fragment-ktx:1.7.0" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.3" + implementation "androidx.lifecycle:lifecycle-service:2.8.3" + implementation "androidx.fragment:fragment-ktx:1.8.1" implementation "androidx.activity:activity-ktx:1.9.0" implementation "com.simplecityapps:recyclerview-fastscroll:2.0.1" - implementation 'me.zhanghai.android.appiconloader:appiconloader:1.3.1' + implementation 'me.zhanghai.android.appiconloader:appiconloader:1.5.0' implementation 'androidx.core:core-splashscreen:1.0.1' implementation "io.noties.markwon:core:4.6.2" - implementation 'com.google.android.gms:play-services-oss-licenses:17.0.1' - implementation 'com.squareup.retrofit2:retrofit:2.9.0' - implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation 'com.google.android.gms:play-services-oss-licenses:17.1.0' + implementation 'com.squareup.retrofit2:retrofit:2.11.0' + implementation 'com.squareup.retrofit2:converter-gson:2.11.0' - implementation "io.insert-koin:koin-android:3.5.3" + implementation "io.insert-koin:koin-android:3.5.6" implementation files('libs/apksigner.jar') implementation 'androidx.work:work-runtime-ktx:2.9.0' compileOnly project(path: ':systemstubs') @@ -111,7 +111,7 @@ dependencies { implementation "com.github.topjohnwu.libsu:service:${libsuVersion}" implementation 'com.github.graviton57:sqlite-android:1.0.1' - implementation 'com.google.code.gson:gson:2.10.1' + implementation 'com.google.code.gson:gson:2.11.0' def room_version = "2.6.1" implementation "androidx.room:room-runtime:$room_version" @@ -123,6 +123,6 @@ dependencies { implementation 'com.arasthel:spannedgridlayoutmanager:3.0.2' testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.5' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' } \ No newline at end of file diff --git a/app/release/baselineProfiles/0/app-release.dm b/app/release/baselineProfiles/0/app-release.dm index 1bcf0f14531bbb16cc1add24741f95f5144c7b60..38ac715c13ddb485673b358562b7686fcde7a5c9 100644 GIT binary patch delta 4702 zcmY+IcTm&m)4-#gfYMY1>Cxi^HS{ViSV2IVl+b$-2sIQTA>YFjR9X%>dQ&4Hz4zXN z)JX3jC3NW_2_fO--kJCJzVFWL?98+K*Y2}rJ|lMuMA!^;7=F6}VrFIr_0}K8u?aCO zUloXxxC4+uAkf2$AP~d3b-Mrpg>ZmCFW-Vd7ePX|TrE;WKp^*15Qqij2)9QdoDmXE z&adxq6V&niAka1z1Y-Rkhs?j8*B71{YO!CGW_kn`y1O!ArsgmuZqE+787}U2rL)WvUxXQkdh+ zW+~yci}5M^ZYj~oWG!;Iud{BDu>f|tRlY*MpkLJj;lEm|CBPz_=f%lfwm&O7bAn2m z)O2AgeA*Bg^}MWc`F^3-Hjf%(g>Kt?mkv3H@AZZoXRd*LxNeaW5$y-q$BgUzvF+0) zV6Ok|CSvWaB38xbvqlS+J}#b+G8b;5U&c6iS2y_g>4am1?huglCP&*`-$p6im`rf> z>wzj=AYbg#WsH1%;a57_-x(&s-C3mh2E`!71|O|k^Uoj8TPHf*E|BoO{m5XxFbeLL z9Tvf-G7{2}lwx@MM#1M>KxojDc2nKC$}5&Wb`ZJn>X9#wD&$KO?+smBFUL-fY0tek zQ-1UG-XB+-km%i}vw_9>M~(p+vTGSiB-OQGI=-9I0!ALs22H?e;FN(fpWhhKPk3v; zNxB;+*2HB85wutBw115|6njN;F!^88; zCC-chxC!4_`cUixTf4u3gWC;;OQOI)hd2xGip*i|3o? zRZ0j}@Iz;XZr+_2{1s?aCNXfl(OcqtB6m+bk{^-Ic6UzpI>6qrTlU!ZK$6=NS=k+- z;ZT9pwnk8^B?~MjUYEOPn8Qw2IW;Y#JmZSyris0JeZ`O{PE8+;ZF^Bx_OP(lhjzE5 zuJVw@oj#$44A2Ak(Tx6A+IOPhnjZAQ5ymB5$d%n5&*z!ea*eY>UM>0mR6g~Flu7Vb zj)<7W8eb7i1e(>v(PAM7m^sX8TC>05KZ!FD@HL?to603YP3tmZAEZUi`)GWl8Cy{I z)y}dnSZ7Vl*~C0_^`qy|Xi;vB(^evfrE%{>ddO<>Xh=@;Z}MAUs2iCciTTGO$f^#8=(|9rC z!jP;%*&0Sa&6f>*SA4B0ETQ#;T(#ueSz?ojOAvaM8cJs{zhP@D2CJ<=T3HJAfccxt z;k9qtlmp`d*656EK=x=SV4=_QR|{hViJl!r4kVnlpHMlrD-~<)NoGn~enmxd;q7MP zfTio$bq=|-xBgoP|ol4z(sPNa zJke1LeXu{1Nk1YKiKerE*!jj52rVNg@886$(feP0I~uBJIXQiTT*B^%nGBbW*2f>J zC)1V=Ce$l`rsB=%K8aCA2zteATR&#had%2{v%kIZB163WRX*S} zpVy2^!I7rCY>WN-o?2q45o&$X+$QnxW%%K*W5O%%8zy?aNBlbM2M--PWCI(jHtZB5 zQgo|X0~#|Di1SPf_Ya9h2f-rxR;Q$-qV<`f9rxt?XM-J{lTchPTV~ehD=Io?&0Fw- zS=3a~SdG}a2MXL6G{2KWE9>;E0Lr;iAce7g|CK2TdCexoN+iTOgVeRn+sc9)tIBU`Y&4Jf=4s5bQIm7@vbz zx=KDLf17fu@kJ#Gc26xgeL)Gpuwhn|b}l!iybdb7yqUogtPuLLd3i{%ZZKw}FYA=` z*iJB`=N(Dfo}e9Yl20ei+V8hts~MRNfO&iFRm<@eag(h0re00Ah}&2wWnV2aC)3#! zYk$7DPe61nI$v2o?_l8H7G`EWJ(l^q@YnY9@~kb%l#XbT*dn`SotYp2E2l~vIB?p^ zRmlon#et`PdVtp}m#<7@*w=OTc3@5g7cRm2a&rS`RwrV(cY{l!_Np1E7VuA^vD(z) zfbm`?TT-5fMCSZa!#>vtCL^J`egXtx@ahR{Cldx!p>j0f1Umw0sd`{pQ`p0`bc{=F zzo{Te(2V2~`{E;MuGylt4S;KE)hvL(=7M6WLV=c?ve z;D^x7UXmJVp+sut?1Lff9req!%r?tH@aCT=K3cGXm94b~hS2L4zfXuTaoz4qlqL1o z^iWKBdjYm)?7;9C1>RJ4zj|H;qIMJIJbL8`H;3m;g;NAl5{{HFKWq@PX_?dAo~{#D zNvh*T8Mhwu+n#RBo}!t+I*elOzXBI}lH#psmb6C83{Ap^afXs#S*0Hlc~kA3k4Vn* z3EEw{^~$O9V3oPE-S?ifwKGaLxNb_JQJCcj_=P&b>NJMW3L2*BE9xoD^ba2)M@Yy& z&4(BEnN&RSOwdD`V^AG&-`U&RXXoA&lH2HHz#$G9x745DMRVD0UdeH$u~@uA8}mI^ zyi>$t+DQew-%G5{44~`+2b5QbqM6=PshROJ<;oL=O_XUW+NVz|O{5`;_>6uk&S|hK zSO~3IvDW8a8jN8wRckr`E0pkU_h&+sN zi$g)GxlnrTX^4+|xvUGj-S=*=&8>oa)q`9i6q_xlF3b77MNC98OU!F}0LT=9)95#{ zen@y(LWaAYK+7R(TN#3ar%@bm@`xiAV4wP7OGpLg-cTVEtuHxFBV}>9ez}O>{!&+3kp$!VFTgP#y;!OtV!W|!xgc1E zsb}(gHfr>J4Bda?eNk=uF!n6M!>dI-e(Jk3ogB#|wQ?u0i;V}uA@l1I>5=NHq&lkf z9;UQ{=yOZ09QAc#5+f>bI1J1x0dkp#?QfoFmeha9J^4XV7z?wR?WkI^>lVp;EBemw zAWNoonZuMwEngaf6FF(G-xma4$i89x8aLY!zjT#^g zgF6;CP06pe1`|?Y8NKho^!0$4?>S_&b-xbcY02w+jG5gJNUW3<&^K%tzofI)9nT7m z%uW6o03~d#b!*Z`g`ur48;UR6-?%A860`Evy{;(_!E7FfstCqPm$|iXQX~r9-@4i- z^9Rd`fM3TDwlHxJ-3R`WlHe?+ZS->8Aj)k$Xth!aoD95|rO0iqO2MFN(O|qXe_bT;ub!iNXskwcVe|f0rv>?2kpg5 z-_R&7Bj3^w2&c@r_JWDJ_IJrgqxfK@Zu!M^u7wGCpzo$4>f5zb14l8yzg#PK-y^m3 zgz|N37Qfp^=F|yA=&E|7(sm(*{sWCCzTt701?qmN8Z=e2!Uk&hUB?5e8N%orx>&-O zsDO(M(_Q0;_Sp=zrL2>faTWz($OMlNG*vn;>{yijH$D8_F3TN%w2%|LzME!|>S?uW z=LXE`_ZGZ9=!z{|gHA-iLzP0 zfu?&?1oD~Q#ni9p*f=?SnV?}kE~^GmkU|H?g+Rvu&_*4um zU^s-L{l3B2!4Px&wSzF2o)dx7R83*5uaWBsw6k@PM+KdVIa)uG1*L;6D zF84Kal;aMZqhIJAU|~g2ApzAwxSc#BgH0pFcLl?4n@T?L*b8+5;`fcji0iHH(Jx+P z5|2i|T9prQ^Jh2=L>w+t>BAmElb!rBD6((fB{B4RK+(D@r-Fa}!dYEj{ho=9wQT3h z7h|H)ICKnDbdr|b-e*fRGOEZzZP3WkRYF~0_0(dHE>j6&DwCsBblS2|zG-c{KCR2^ zQ!Tn=%S!&+TB8hw65zE*i$xqb3Rs{|S597JjFeC(1&O8Xe%&`xF*2(}{0N_nBN$s|)3Rdn!lq>ul6-==zGOcF`5Zz^kZv9*ao)s7 z-+%?TQYeJAnb7E?%`zJJW+Ee>fesUMhpg1|^{XJz^11#$QV~CW6%0Txw9$S1JV8=Y zGUr^v@tjtOos){!7ffF2=v_3tT8PHjr(cMB_2v5WSsumf4wJ8$IXM+~V#*yA`6Yke zu4RJR4I~t9W{Soo37rJMOaPZZuR&|T)-@ZZwrRU_45g(I9{n$4J3aUvXI8c1^e=xw z`6%36ySs9q|N4A(+Y^Y4AWM6`y&SB}WwF$$g%VL89y9dsJ^Adf%l1q!Reo1qLeQhu zQKPQYtev+yVKFgtNU|xS*dX6ZMCLv}_0@M6Q@&Mx&Z@$-Sr`DQ%mn~A|K*VX z;eoN-Gc&k&<_>3I&6UeMFYY-v?Xq9j{+w*OeUXqPq99~pz$@-Q1E{HzzMvf!S|I&k z=*e9UdM&iAhr=CvGbq|V{deqHd8bYzDcMZbzTAdfk%X0?;Ww=7au8y9Or4^?)3o)N zBtPbz%?RXs&-%M=$2V%T=2e9Txe*((eGvh)WCN@Gka>tn!=7lWa|WzWCi&c;<6*jb z9`4?Z7Zn8ZN7xCa>toc~Z$B(k$#b|aRTOo86f`=(Y*o`v5{1PJNenYpXS%Y~9IUCb zCc|WzBd1;;tD6??=tjPzl4r|bi>48eV0)~0P`)Mr_{TeJUNDwTRMaa6x2Vo&^6Z<2 z&{pGsy-DNq^Inz9=gRFBb+9ejjR48J;&QgmQ4M@%9gl+~J~TT8gc!VQSFAKs?>}3v z!Ji>gRQucqS+yXMWCdukC)-ESJQgpOCL`ZXcTb%PYz z5uvGuqINL-hCF)?cMqrt#rd6OJC>E-K1TWDurJd?IZaIZdg`37l@y-K%c4{iewYym z4qB$8cg=B>ZvwcsUwetckDqu3BuylIs+17PB&r$IU6km&Fd-O9`jC>iI39jq9+K>p z*J>`Pwc4%V>d`r%Hf8vIB)+V?>Ch)<)F>i+zpvH|H|&~fvFMnn9F*2c7h;E6Fl}6w zVSWJ*9fJCgqbd*2n|WHP_ND4+RhRIG?$meEt};^dFKSfQJ5@VR@b{+n|Di2sT^%qZ z!0$8bD}m)VPvl@t7|Zq=o9}qEywgc1sEwgNXA0;pt(LVXmZqi2Hdc8muoa5CA4$L3 z>8)~I&CB5=PFCKUv>Cr@#UYsX#WT|d`pLNmChqZ};%=$!mUM_g*uGlB{K}`3*~-y{ zFKFYvnoS4KnW!!2@k~uG1>akI7>&gvY8NqIV*oRN?Ylj0wluwzf=u!&jtJh26O-e) ze4g_x+ZonQ5bMNHX4q;iSwJJt;8LPDW1**+yB9BJYIRV>eIHb-3?Cxm_cTz-8ieAJ zpSD(S(&3+){VmF5R2b%pWlf4qHNkmZ4jELMg?Q-H$0JSEbb==JVU1?+cLZdAPRTaQ zGV%4((oF>RL3Vd;-!_z6%Y$9E9`mY@a1Gc0;P}y^5p4%~X}U8EZvQBn()HQvE4@b0 z%39eQ`b)KI-w-`h8ag%}?@-#>v}ZmX4ySjO_+}{`?@y0ktSA3j#OigF_+GPN$=}-} z?OSHANyW;z=#_;1ny_VX+xGyke2tAdk#iWz!0ji6Z#SR0<#WuQq{IpIm+#&{HmT2p z*b{}N7>iqjUWYcrLLi%wh;2(UJwdZ1B8*w-dlHVscN#dbjwwo4)r7Y1=!ikeQ|q;* z2qnH%@@~a-kgJ&d{1Pa2&m>4Z_fh4`V5zHW)baXmRLZWoiOQ&G?P^@j1Y&vVg%$R= z1Km2_VWI5Y&Ez-94TO{>!#Cxe&J^z~NEw2U3fbqXmqKt{6#P=cRFm9KUhP#kYx^r% z2TkVFC^N@*8J_|O=LYWnNu??^5e`bvHFjTG@+NyJO#heQ%hp^RYDnum!^C+J6^d2o|T16 zP~*Q93{l)e)-P^;s6Nv{6pvc!2_4k4d2}iQP<_TMYSQRtB==vOKmI_H7E;%FbP z+0*nfMF9!|*?0%bi)-P<>pY&i$iXAzFZudZ1WoT$eCH^AZCL|)S6kY0uUMmdam91z zPR($Zu_MqplwNEpwQqd8MtldAF4Z02I&(2)6Zwh01g&|PJ!nup^cF12`{AM_SY3*s z&*I2+~hrxSTM?QoTg9S?i<7&A*0csRMt*l zC$<{-%r&5Gwv9Q=NgCXu{2C)|I}zd#{KwIsi8K}8tEw&P5U%lM(x5-FC+vU;Thh%U zP(Q7KlO1t?IqJJKv};YddLQ%$6X}Lo#~)P#NRX*r=dGYQeZh5;sFhmVK~w*S)w%w9 zi}veG#GEYk9ZC~o?!NlVcIsz>7}AGI`beac;j`{yAZA-Z@|MfVe(Bcm7p=2=P$%Ks zi0EQjw=BXsMSt)8@Fu;SKV>sDRex%aT&%VEJuw6mbT1mdd>zVpzY4mCQ6|6cLFrmy zad(jxl&IaW-u;jCjPf7jZqziXGSe6VhZWLsM+y#Ykht2Von&911fPK3tvrR^g)0j6 zy-RsW^1a@02cYGw2x0(LGYjh|hNQQxf;&CaUor}&J=cYR8lQXu3UeDD;pXWS{P&rI z3DRKS&rL}}W!h<>XjvQ?`*Xfz`1D=!09>h_BIoq9d?K({ruU-uPAXI!EIP5>TIlVd z7{M1W3V+=)59hC^pn27n5a=Cz#@?rn14m$Jfh7AP@3Q6GVOY-PGKcN1*FbzmDg3zq z^JK^8SqB4OkHZM^M#EOd70EL6gP_4@DKG6v8}NhAlj}7o>cnTA;P!$BaNRo4a*%>{ z#0}h98`wgVtm*5aM~q~o-Q&4G7`cj9)M?o#jdyMbe~n1ebD8W#X{<0|TKAPj%208H zGpzsB#DAM#qZ48ra2yh8JgGx|CA$K6J3;mnzit11J2tYAN8jJN{$ z-Uquc_LA`n5;vQWNLh8_=k2l83qF5AT4V9gN3x(nSZcaB_}0_k5TIzoB#Lj{Z;@V{ z-(*y@H=mdHG5w`*9RlL9?T zo?BkKEvQiH#Pm#;$;UaLwKU*+OLTXc{b7+i6{FeK&enmfUT)OqHqi|s?z23Pgs8X? zcUdueaV7+2d)xwQvTZ~bFZY5B=5QKQPETqDO3QjAlG@ElXUn&sc`0;W6bC|=fB-1*}2W=t8P>yshbN8O^ZA%s<~lO5Xwvg%PTAj8)rqf zT!<}W4#)hA+!*_itGv%iERBV6Zme)KomusE+qj{PC{H?Gf*R(cqspB zSj=VdxVnuie3UHuU3#nITBGyRgY|{X7Ui!U_k4y}$?0>2JguF-E+QOBFFYSaHp$R0 znXd2;QVg>tQ{+k#t3QT;;(?~}_}ilD^TFEbt%C>zbCnCrEJ96JLOU+LJrJ??H@>8& zB#Bsi3k)n2?rU>Dk2%OIFZmfAm!pC*_50@X)`4&=ltHnJysF-gL=3WqL=TA_$q$VP z9{a_a+=;X~j+}YsK#E!GlmSgx8uBp`^pI~Ap2ZmoLR-DOIIect|;Q<+mu$Yw6; zDvldCW@MxdWRBNsCm76eWPP7|gdE^jeVm`m24b(2`<9BeQTMbVR^{f(o@B4#c7G~7 zaJd9Y7RF3(yOgK|wYlhvM|&>U$BAvM{YG8Hyn7jIOj55r(Ub6l(yjU*SSAZ5ewbq^b@19BLso>p@`4i^7O!Op{=B5VyQCzVi_; z-BOq&Y|Tc(g+I`wIqMOlkb$yUTfT=v%RxlAL^4bLxAgopd{BkkgRD*FS}Z zM}(D%WFnur2_U+7lNp)ec++hXL>0Cm--WSJV;-(N^XSiwE~LYqs@w}q++pvE+?SR! z?(Gc!Qsyy0c<;LO3gN!5hl^<`xV&(m(5IRB22A3z_N!-$jFP;_X}!vCHTd;#4c~)L z3oNzWnUCxxKT%Ni8odGD{gsy&KMSgV+x$=vbluXP=Gl)uxDs4R>=WgI_J8}Dd993s zFtTUEKSDJtaXBhei?p9X-VPunA~43V@cWjL{a;YTDg#OBOVo)oJpv^HFy>qugmB__^-f1781TjDTDvjnGwMXuTSQf6WVij$l!F zZ~~9qc1qL51sqy;*CSqWHwOGF`Mx}}qS%pc$w}j3)qrjs76Vs@R}}!+Ks%+s_PnuC zS(L?I0(T{G*Dcw|c-O_UR9p0_X7)^*Cl^~IY;Um(C_>=eSt5O97+qg1w9Xuk857EQ zH@%)wY*6Q#bxT>jJ@Y)d^WZ4o3OL>-EFXF3Uwlpqz7kxzg1aEBK1PZ5DUpdxw<2*? z@I9nn$gKwF4qgZW6>RTX9gU8ziG$ri+E6XT0s^Q@ig%Vox>H+(IM<1_dKmtX+apYN zpPbrb?7F?uljTMlE!by!hMdj3tcL_zD-(+Y=|GTURler=y2axOyXm>UbdvfP&x2?< z{zQ$PejxuH_pd+C|IEBj zepX6Q)6gj57HvM~nCB@l61~c%%(d~F>S73o6@ylWxF5IVKuST5ypG2&+c&u9wp{W^ zNt;aoAKZzVnIZf6&)1qkZ+HNJlv6hQf58l{Q!L`2V1_q~220zqUw}72PEP(5nQ%MB zD_3K)yAd4ox-4o@~-W2)l9b@N|ip52Xk_Ir%ZAEpKw@<5*7uK%R2!dJx<>pJ$MXM1`rUAlsEl(0=VR@<%X%8YCv@CkflHu_$X=s@s zqZOMGEA0#kWO*LH^O8ualGYs)ALq9T5iJHDH?Vbyn9Z`KuIrJRB( zXfB1tJhZv!ARk@CmSkQNaC2vC`&&jxclMX(5ZxM>_NF?@y4p$bzMVj%-Kvn~;Hos^ zZr5#4)bmeCQ!kE!AT6a5te&$0b*pE+H@r&9mY H59|K`j9_wm diff --git a/app/release/baselineProfiles/1/app-release.dm b/app/release/baselineProfiles/1/app-release.dm index 3b6ec5e7f34de08bbd1459ab5112c28776d4c7aa..ec51dea8a33c077ce583f94ecc0be60b10163517 100644 GIT binary patch literal 4835 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 diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 049e52e..78d0812 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -11,8 +11,8 @@ "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 264, - "versionName": "2.6.4", + "versionCode": 265, + "versionName": "2.6.5", "outputFile": "app-release.apk" } ], diff --git a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/repositories/ProxyAppWidgetRepository.kt b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/repositories/ProxyAppWidgetRepository.kt index d002db3..d1ea581 100644 --- a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/repositories/ProxyAppWidgetRepository.kt +++ b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/repositories/ProxyAppWidgetRepository.kt @@ -9,7 +9,10 @@ import android.content.Context import android.content.Intent import android.content.IntentSender import android.os.Bundle +import android.util.Log +import android.util.SizeF import androidx.activity.result.ActivityResultLauncher +import com.kieronquinn.app.pixellaunchermods.utils.extensions.dp import com.kieronquinn.app.pixellaunchermods.utils.extensions.getIntentSenderForConfigureActivity import com.kieronquinn.app.pixellaunchermods.utils.widget.LauncherProxyAppWidgetHost import com.kieronquinn.app.pixellaunchermods.utils.widget.PreviewAppWidgetHost @@ -88,15 +91,31 @@ class ProxyAppWidgetRepositoryImpl( } } - /** - * Rejects size bundles that would render the widget down to 0x0 (making it invisible) - */ private fun AppWidgetHostView.updateAppWidgetOptionsIfValid(options: Bundle) { - if(options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT) == 0) return - if(options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) == 0) return - if(options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) == 0) return - if(options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) == 0) return - updateAppWidgetOptions(options) + val sizes = ArrayList().apply { + val minWidth = options.getIntOrNull(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) + ?: return@apply + val minHeight = options.getIntOrNull(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) + ?: return@apply + val maxWidth = options.getIntOrNull(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) + ?: return@apply + val maxHeight = options.getIntOrNull(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT) + ?: return@apply + add(SizeF(minWidth.dp.toFloat(), minHeight.dp.toFloat())) + add(SizeF(maxWidth.dp.toFloat(), maxHeight.dp.toFloat())) + } + Log.d("PA", "Setting size: $sizes from $options") + updateAppWidgetSize(Bundle.EMPTY, sizes) + } + + private fun Bundle.getIntOrNull(key: String): Int? { + return getInt(key).takeIf { it >= 0 } + } + + private fun Bundle.copy(to: Bundle, key: String) { + if(getInt(key) != 0) { + to.putInt(key, getInt(key)) + } } override fun setListening(listening: Boolean) { diff --git a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/service/PixelLauncherModsRootService.kt b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/service/PixelLauncherModsRootService.kt index 413f80d..9d1f708 100644 --- a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/service/PixelLauncherModsRootService.kt +++ b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/service/PixelLauncherModsRootService.kt @@ -109,6 +109,7 @@ class PixelLauncherModsRootServiceImpl: IPixelLauncherModsRootService.Stub() { ) private const val SEARCH_PROVIDER_SETTINGS_KEY = "SEARCH_PROVIDER_PACKAGE_NAME" + private const val SEARCH_PROVIDER_SETTINGS_KEY_VARIANT = "selected_search_engine" } private val context by lazy { @@ -763,12 +764,21 @@ class PixelLauncherModsRootServiceImpl: IPixelLauncherModsRootService.Stub() { } override fun setSearchWidgetPackageEnabled(enabled: Boolean) { + val key: String + val table: String + if(Build.VERSION.SDK_INT >= 35) { + key = SEARCH_PROVIDER_SETTINGS_KEY_VARIANT + table = "secure" + }else{ + key = SEARCH_PROVIDER_SETTINGS_KEY + table = "global" + } if(enabled) { //Set it to PLM package name so it uses our Proxy Widget - execRootCommand("settings put global $SEARCH_PROVIDER_SETTINGS_KEY ${BuildConfig.APPLICATION_ID}") + execRootCommand("settings put $table $key ${BuildConfig.APPLICATION_ID}") }else{ //Delete to set it back to default (null) - execRootCommand("settings delete global $SEARCH_PROVIDER_SETTINGS_KEY") + execRootCommand("settings delete $table $key") } } diff --git a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/ui/base/FragmentOptions.kt b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/ui/base/FragmentOptions.kt index 740708b..c0140b9 100644 --- a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/ui/base/FragmentOptions.kt +++ b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/ui/base/FragmentOptions.kt @@ -11,6 +11,7 @@ interface Root interface ProvidesBack { fun onBackPressed(): Boolean + fun interceptBack() = true } interface ProvidesTitle { diff --git a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/ui/screens/container/ContainerFragment.kt b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/ui/screens/container/ContainerFragment.kt index 22a7a74..47ab1c8 100644 --- a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/ui/screens/container/ContainerFragment.kt +++ b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/ui/screens/container/ContainerFragment.kt @@ -1,10 +1,11 @@ package com.kieronquinn.app.pixellaunchermods.ui.screens.container +import android.annotation.SuppressLint import android.graphics.drawable.GradientDrawable import android.os.Bundle import android.view.MenuInflater import android.view.View -import androidx.activity.addCallback +import androidx.activity.OnBackPressedCallback import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat @@ -17,7 +18,6 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.NavigationUI -import com.google.android.material.appbar.AppBarLayout import com.google.android.material.elevation.ElevationOverlayProvider import com.google.android.material.snackbar.Snackbar import com.kieronquinn.app.pixellaunchermods.R @@ -26,8 +26,26 @@ import com.kieronquinn.app.pixellaunchermods.components.navigation.setupWithNavi import com.kieronquinn.app.pixellaunchermods.components.notifications.requestNotificationPermission import com.kieronquinn.app.pixellaunchermods.databinding.FragmentContainerBinding import com.kieronquinn.app.pixellaunchermods.repositories.RemoteAppsRepository -import com.kieronquinn.app.pixellaunchermods.ui.base.* -import com.kieronquinn.app.pixellaunchermods.utils.extensions.* +import com.kieronquinn.app.pixellaunchermods.ui.base.BackAvailable +import com.kieronquinn.app.pixellaunchermods.ui.base.BoundFragment +import com.kieronquinn.app.pixellaunchermods.ui.base.CanShowSnackbar +import com.kieronquinn.app.pixellaunchermods.ui.base.LockCollapsed +import com.kieronquinn.app.pixellaunchermods.ui.base.ProvidesBack +import com.kieronquinn.app.pixellaunchermods.ui.base.ProvidesOverflow +import com.kieronquinn.app.pixellaunchermods.ui.base.ProvidesTitle +import com.kieronquinn.app.pixellaunchermods.utils.extensions.awaitPost +import com.kieronquinn.app.pixellaunchermods.utils.extensions.collapsedState +import com.kieronquinn.app.pixellaunchermods.utils.extensions.getRememberedAppBarCollapsed +import com.kieronquinn.app.pixellaunchermods.utils.extensions.getTopFragment +import com.kieronquinn.app.pixellaunchermods.utils.extensions.onApplyInsets +import com.kieronquinn.app.pixellaunchermods.utils.extensions.onDestinationChanged +import com.kieronquinn.app.pixellaunchermods.utils.extensions.onNavDestinationSelected +import com.kieronquinn.app.pixellaunchermods.utils.extensions.onNavigationIconClicked +import com.kieronquinn.app.pixellaunchermods.utils.extensions.onSwipeDismissed +import com.kieronquinn.app.pixellaunchermods.utils.extensions.rememberAppBarCollapsed +import com.kieronquinn.app.pixellaunchermods.utils.extensions.setOnBackPressedCallback +import com.kieronquinn.app.pixellaunchermods.utils.extensions.setTypeface +import com.kieronquinn.app.pixellaunchermods.utils.extensions.whenResumed import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import org.koin.androidx.viewmodel.ext.android.viewModel @@ -92,6 +110,11 @@ class ContainerFragment: BoundFragment(FragmentContain setupApplyState() setupUpdateSnackbar() NavigationUI.setupWithNavController(binding.containerBottomNavigation, navController) + binding.containerBottomNavigation.setOnItemSelectedListener { item -> + //Clear the back stack back to the root, to prevent going back between tabs + navController.popBackStack(R.id.nav_graph_main, false) + navController.onNavDestinationSelected(item) + } requireActivity().requestNotificationPermission() } @@ -138,34 +161,38 @@ class ContainerFragment: BoundFragment(FragmentContain } } + @SuppressLint("RestrictedApi") private fun setupBack() { - val callback = requireActivity().onBackPressedDispatcher.addCallback( - this, - shouldBackDispatcherBeEnabled() - ) { - (navHostFragment.getTopFragment() as? ProvidesBack)?.let { - if(it.onBackPressed()) return@addCallback - } - if(!navController.popBackStack()) { - requireActivity().finish() + val callback = object: OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + (navHostFragment.getTopFragment() as? ProvidesBack)?.let { + if(!it.interceptBack()) return@let + if(it.onBackPressed()) return + } + if(!navController.popBackStack()) { + requireActivity().finish() + } } } - viewLifecycleOwner.lifecycleScope.launchWhenResumed { + navController.setOnBackPressedCallback(callback) + navController.enableOnBackPressed(shouldBackDispatcherBeEnabled()) + navController.setOnBackPressedDispatcher(requireActivity().onBackPressedDispatcher) + whenResumed { navController.onDestinationChanged().collect { - callback.isEnabled = shouldBackDispatcherBeEnabled() + navController.enableOnBackPressed(shouldBackDispatcherBeEnabled()) } } } private fun shouldBackDispatcherBeEnabled(): Boolean { val top = navHostFragment.getTopFragment() - return top is ProvidesBack || top !is Root + return top is ProvidesBack && top.interceptBack() } private fun setupAppBar() { - binding.containerAppBar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> + binding.containerAppBar.addOnOffsetChangedListener { appBarLayout, verticalOffset -> binding.navHostFragment.updatePadding(bottom = appBarLayout.totalScrollRange + verticalOffset) - }) + } } private fun setupApplyState() { diff --git a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+ActivityOptionsCompat.kt b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+ActivityOptionsCompat.kt index b939f1b..45b09f8 100644 --- a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+ActivityOptionsCompat.kt +++ b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+ActivityOptionsCompat.kt @@ -14,7 +14,6 @@ fun ActivityOptionsCompat.allowBackground() = apply { }.get(this) as ActivityOptions inner.apply { pendingIntentBackgroundActivityStartMode = MODE_BACKGROUND_ACTIVITY_START_ALLOWED - pendingIntentCreatorBackgroundActivityStartMode = MODE_BACKGROUND_ACTIVITY_START_ALLOWED } } } \ No newline at end of file diff --git a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Fragment.kt b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Fragment.kt index 149ee27..014f930 100644 --- a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Fragment.kt +++ b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Fragment.kt @@ -2,6 +2,7 @@ package com.kieronquinn.app.pixellaunchermods.utils.extensions import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow @@ -19,4 +20,11 @@ fun Fragment.childBackStackTopFragment() = callbackFlow { fun Fragment.getTopFragment(): Fragment? { if(!isAdded) return null return childFragmentManager.fragments.firstOrNull() +} + +/** + * Helper for [LifecycleOwner].[whenResumed] + */ +fun Fragment.whenResumed(block: suspend CoroutineScope.() -> Unit) { + viewLifecycleOwner.whenResumed(block) } \ No newline at end of file diff --git a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Lifecycle.kt b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Lifecycle.kt index 2059d22..bc0f3b2 100644 --- a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Lifecycle.kt +++ b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Lifecycle.kt @@ -2,7 +2,13 @@ package com.kieronquinn.app.pixellaunchermods.utils.extensions import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.OnLifecycleEvent +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch fun Lifecycle.runOnDestroy(block: () -> Unit) { addObserver(object: LifecycleObserver { @@ -11,4 +17,12 @@ fun Lifecycle.runOnDestroy(block: () -> Unit) { block() } }) +} + +fun LifecycleOwner.whenResumed(block: suspend CoroutineScope.() -> Unit): Job { + return lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { + block() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Navigation.kt b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Navigation.kt index df01d21..03a44af 100644 --- a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Navigation.kt +++ b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Navigation.kt @@ -1,6 +1,16 @@ package com.kieronquinn.app.pixellaunchermods.utils.extensions +import android.annotation.SuppressLint +import android.util.Log +import android.view.Menu +import android.view.MenuItem +import androidx.activity.OnBackPressedCallback +import androidx.annotation.IdRes import androidx.navigation.NavController +import androidx.navigation.NavDestination +import androidx.navigation.NavDestination.Companion.hierarchy +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.NavOptions import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.debounce @@ -16,4 +26,45 @@ fun NavController.onDestinationChanged() = callbackFlow { awaitClose { removeOnDestinationChangedListener(listener) } -}.debounce(TAP_DEBOUNCE) \ No newline at end of file +}.debounce(TAP_DEBOUNCE) + +fun NavController.setOnBackPressedCallback(callback: OnBackPressedCallback) { + NavController::class.java.getDeclaredField("onBackPressedCallback").apply { + isAccessible = true + }.set(this, callback) +} + +/** + * Copy of [NavigationUI.onNavDestinationSelected] but without the force unwrap on the animation + * which breaks if the stack is cleared before it is used. + */ +@SuppressLint("RestrictedApi") +fun NavController.onNavDestinationSelected(item: MenuItem): Boolean { + val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(true) + if (item.order and Menu.CATEGORY_SECONDARY == 0) { + builder.setPopUpTo( + graph.findStartDestination().id, + inclusive = false, + saveState = true + ) + } + val options = builder.build() + return try { + // TODO provide proper API instead of using Exceptions as Control-Flow. + navigate(item.itemId, null, options) + // Return true only if the destination we've navigated to matches the MenuItem + currentDestination?.matchDestination(item.itemId) == true + } catch (e: IllegalArgumentException) { + val name = NavDestination.getDisplayName(context, item.itemId) + Log.i( + "NavigationUI", + "Ignoring onNavDestinationSelected for MenuItem $name as it cannot be found " + + "from the current destination $currentDestination", + e + ) + false + } +} + +internal fun NavDestination.matchDestination(@IdRes destId: Int): Boolean = + hierarchy.any { it.id == destId } \ No newline at end of file diff --git a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Resources.kt b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Resources.kt index 621b224..b633d02 100644 --- a/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Resources.kt +++ b/app/src/main/java/com/kieronquinn/app/pixellaunchermods/utils/extensions/Extensions+Resources.kt @@ -31,4 +31,14 @@ fun Resources.getResourceIdArray(@ArrayRes resourceId: Int): Array { } array.recycle() return items.toTypedArray() -} \ No newline at end of file +} + +fun Resources.px(value: Int): Int = (value / displayMetrics.density).toInt() + +val Int.px + get() = Resources.getSystem().px(this) + +fun Resources.dip(value: Int): Int = (value * displayMetrics.density).toInt() + +val Int.dp + get() = Resources.getSystem().dip(this) \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 45eb9d9..c2f474e 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:fitsSystemWindows="false" tools:context=".ui.activities.MainActivity"> @@ -11,6 +12,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/fragment_root" - android:name="com.kieronquinn.app.pixellaunchermods.ui.screens.root.RootFragment"/> + android:name="androidx.navigation.fragment.NavHostFragment" + app:defaultNavHost="true" + app:navGraph="@navigation/nav_graph_activity" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_root.xml b/app/src/main/res/layout/fragment_root.xml index 1bed0c1..65d6e74 100644 --- a/app/src/main/res/layout/fragment_root.xml +++ b/app/src/main/res/layout/fragment_root.xml @@ -10,6 +10,7 @@ android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" + app:defaultNavHost="true" app:navGraph="@navigation/nav_graph_root" /> \ No newline at end of file diff --git a/app/src/main/res/layout/widget_wrapper.xml b/app/src/main/res/layout/widget_wrapper.xml index c3c802a..2880df5 100644 --- a/app/src/main/res/layout/widget_wrapper.xml +++ b/app/src/main/res/layout/widget_wrapper.xml @@ -2,4 +2,5 @@ \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph_activity.xml b/app/src/main/res/navigation/nav_graph_activity.xml new file mode 100644 index 0000000..d1b10d1 --- /dev/null +++ b/app/src/main/res/navigation/nav_graph_activity.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file