From 5878c9b221285a43707145f8668e1f268aa3df6b Mon Sep 17 00:00:00 2001 From: Matthew Date: Mon, 1 Jul 2024 00:36:09 +0800 Subject: [PATCH] Initial Commit --- app/.gitignore | 1 + app/build.gradle | 66 +++ app/libs/common-release.aar | Bin 0 -> 48359 bytes app/proguard-rules.pro | 21 + .../mpremote/ExampleInstrumentedTest.java | 26 ++ app/src/main/AndroidManifest.xml | 46 ++ app/src/main/cpp/CMakeLists.txt | 48 +++ app/src/main/cpp/native-lib.cpp | 10 + .../com/xypower/mpremote/ImageActivity.java | 155 +++++++ .../com/xypower/mpremote/MainActivity.java | 394 ++++++++++++++++++ .../xypower/mpremote/WifiScanActivity.java | 14 + .../drawable-v24/ic_launcher_foreground.xml | 30 ++ .../res/drawable/ic_launcher_background.xml | 170 ++++++++ app/src/main/res/layout/activity_image.xml | 33 ++ app/src/main/res/layout/activity_main.xml | 31 ++ .../main/res/layout/activity_wifi_scan.xml | 9 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes app/src/main/res/values-night/themes.xml | 16 + app/src/main/res/values/colors.xml | 10 + app/src/main/res/values/strings.xml | 5 + app/src/main/res/values/themes.xml | 16 + app/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 + .../main/res/xml/network_security_config.xml | 4 + .../com/xypower/mpremote/ExampleUnitTest.java | 17 + build.gradle | 9 + gradle.properties | 21 + gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 ++++++++ gradlew.bat | 89 ++++ settings.gradle | 16 + 42 files changed, 1490 insertions(+) create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/libs/common-release.aar create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/xypower/mpremote/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/cpp/CMakeLists.txt create mode 100644 app/src/main/cpp/native-lib.cpp create mode 100644 app/src/main/java/com/xypower/mpremote/ImageActivity.java create mode 100644 app/src/main/java/com/xypower/mpremote/MainActivity.java create mode 100644 app/src/main/java/com/xypower/mpremote/WifiScanActivity.java create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/layout/activity_image.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/activity_wifi_scan.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/values-night/themes.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/main/res/xml/network_security_config.xml create mode 100644 app/src/test/java/com/xypower/mpremote/ExampleUnitTest.java create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..4be26b7 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,66 @@ +plugins { + id 'com.android.application' +} + +android { + compileSdk 32 + + defaultConfig { + applicationId "com.xypower.mpremote" + minSdk 24 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + externalNativeBuild { + cmake { + cppFlags '' + } + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.18.1' + } + } + buildFeatures { + viewBinding true + } + + packagingOptions { + exclude 'META-INF/LICENSE-notice.md' + exclude 'META-INF/LICENSE.md' + + } + +} + +dependencies { + + implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10" + + // https://mvnrepository.com/artifact/dev.mobile/dadb + implementation 'dev.mobile:dadb:1.2.7' + implementation files('libs/common-release.aar') + + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + +} \ No newline at end of file diff --git a/app/libs/common-release.aar b/app/libs/common-release.aar new file mode 100644 index 0000000000000000000000000000000000000000..79a6c02d9dcd6284f1247e022a98971f12373feb GIT binary patch literal 48359 zcmV)BK*PUKO9KQ7000OG0000%0000000IC20000000jU508%b=cyt2*P)h>@3IG5I z2mk;8K>+v0pAMz~008{}000vJ002R5WO8q5WKCgiX=Y_}bS`*pY-P{E3WG2V2H?Bk zJCxkD+t@**)rT1DUToCj+DcP5_x97Nhq2u9^YN32dbSVt#6ZS73FrI-3|-^3ah-%I zwpjsnl?bbxX^|pZxT8`z9lX&J`WVNOb833Dit;_r8*jN92Og04o;azUl>+yy#rRI$)?0aNEzv2Ti4lZN^9Ir5BKBZ%N71jRH4K8!wO*hTQB(WOZ5Rz zO9KQ7000OG0000%0H=Ql`j5E)09eKV01E&B0Ap-nb8}^LE^1+NoV;UfuHD$Tc!Pj1Sk5-+dP zx3XX`u{CmW@l%?VANYyEPpXI_gpzM*tXl<-i|&D)j7dYRPS%CCnNS$RRRSyn3J6T5 zM#2mB#j|W<7S(KSZn_-j@LF8^`UUucag7S$GGCH4W)BgH6j`5c;evOXjH&Bd9J`F( zIPsz|D+e1*)?ConE)%h}Oth%8LLpv_7*b`Re-Ei;^P03=`7Ge1t5C6&JlSv6An|;a zB@PG#I};O}8L$k+DR?8?Me(8`aI5eXp~{92T-+AY4|vrLUlG2TMqrt41|+bCkuExy zpHE&Cf6(!zzE@sUc>lOUh3rW`VA0!f2cJdLU;!Sb&qy0hAv9@PaD4_K;QZZo<;{Va zEY~ferROVc4<|l@)w#{=!%;`MrVb<7mz?Xs5T=zxlQ(+8Du=D7-$QVtLl9$^h`}}b z;q;F5j45@mni`?nAjHm!Rq$*2tyi?_ib(NaD9p9!PgdYSK$-#n5rv46otd+dnyZzq z%YUKB)$nmuc_R4xX}_?YoxOn>gcT74R4tejE;OtWT1wzRvBI;}o@>-%l(Gc3LR-|K z5;z%IYCk(ZUgF-u&o*)Ccw2)zzg&Z-$hKE`agA>tUC;k+B$&Osyj=71=R6b13aUx? z@bM+;y?J=(d|B#bi~(Ky)q4uFR}h8gM&;ZkH8{<)*(Nqz%cHtkwl|pM+KGftG=Hnq z&Q-E!lH?g4#p^cJuZJse-4AlT^7a}MrC{AAalcc&r{er~@!lyvYPRCFCJx@QH*EII z69n1XQ!*}p^|oQjr~dFGD5@(=f{m|gKN`2EWRDrqV8u~$P=oBNng$M+aCJVae*6g) z(I7qCPlO?F?pBUlpmLuYacAMyZd`&lZ{;>7%)*T?{HEfyE=nnIVsc>}=-2+M+UN)g z)PpNs7Iw+Cq`9(guYapjIKG8>~;s z(X3vouPqbu3WX*)tEl_6Z`DBCZCzqH8M?|eW*p!>SZy*KbdB)+FEvSaN_;`>tOxae zT>K=CvKk@nUdk;&UB?jKTE1m9ggaO9(=I);Se9t-fh8OAOI2ci({glE1Ky9wJ!do) z5V0^z<+3W-$Ev7Dd0Lx!mB6rO0;TaI$ zoic!qq5IDquE<}oNOzNz>JLwX1^%sHgus-8dB&>w1kowt=8@ziZ67Ew!+VAFmm0-Y z{ha8t@yvao0C(U@PKENPkJrbKb9-_f<#`uQ?3s&G1d;;Vi@WPtS5^p-S2!9%ZOWO) zu6i^>01f-Ld*+1{^c%+OGm0qZSCOz&`Hed`a30BuoWVa<=j*mL9l9JOfVH`NPZs;@ zgorPX?!VJ{JG$vHnQ!sVUX$XU>pTsBv}oDK9+o~nzf($YSgd;4Z+XW%9fcJvPP2Nh zpXukZ#Y9lYAAP#)caf7SdvXRO>G01_NzG(t)g{idlUj~}9H^Q+sw zn6WP*9RpYW+S|PAd$M8dn12*d57eJsMZe%*($k}BPK28kh>$*iSa76>0V7@28Z z)&lR}R5{Kz%WuGs%6_OfyP(%)BF;B?wpDC?r-X$ji_hG4*VZtf_*O3;Qd{wQ2q8 zDst5IaOFn0y$p90U+M7|61Jj#FwG!Y-CRe%xc(03F(Z;F((&#jp!u-t{K-BYjkxh< z#H;UHtJ(LN640E%Ymy9G{yO8jK;CxhT}PpAVj@VSW3+Q6f&QyGRx>tx_7Q=xFmHmPdEI9_sBRC?TCQ z-%gj^S&=mN38IL^`n<~;f<{>zdM4y#WCyQE>fEYH0>wABv4x8C%annJ=6D5J=1bp z!HQ)Ea{Dk<)tK(p*eg4CL_xXKjCD{R>0EG!0nxB-?+HYn&Ep$c@XiC>aqNEA0aLJd zv4J4$H0NI!w(+(C&({H1fq=-_jnfzTdoLN^q&?s8y`X|U&f}$cW2c4*Km|wjmzqg< z>?8N76T2 zaSycCW}l_CaW{;kE4No0)|0O@mcVy*IOL~w2g<{IpB5`-5v0HE!HE_l=3cO73`CmZ zqVl=6xZM->fEac^+-6WJSBP30a;zu5oF`iK+jmRY4U3HzeBIzqBca3H#=V^`-8m}C zq*J9PVy|ZWq}8<9KAJ5Wo|bSEA)zqhlltu@(rJojxV)>=O@7H}1Hm%i5vp#iy>fnd zESH6T9-0L56`SXZ+FD?4O&vd1q>UrJjWynP7_wpdqsr2JGBPs>{1Az5xPW+(7>usM zwEdqw_Zcef@OZLG4R(C|Y%rgSH!}Dh_FUAIq4zxTti`K30KP!WHDL-0eAhxRU%+lM<(ilUhZ2W*3Z#Adxl}A;ci;?|~mB)&ij>@(?6K~*X0q2|gq?=0RB%AxXfYlT3 z=()MoC9LRC@w5Ss>espEPZvnOve6|ZlUxIKejA-9sl`?0aj-A!6{*Eo>P2L)iWjxY z-=z>F=Ot6#>mTP-94UNx6cmsQ3^+w^>{h{;kFWeDpj&|3EPa)94o}&eKk6pR20#B8 zrZo2R8V!=iO|0yyjxnZkc#>5>l2@Sq;!I;U1KWWq7V~}R01LBv?H>9)`K7;T39Bww z)g@b1lNINnM((@8Hcb)CLGYqCle0uL2#}3l8TOsBquI-r3ehG>lwB{?<&1QwM|J7T zT8f|(*k+{Y^g*3Bh4tx*Yir8U+mZaVB=@!@@xLSsib3JG-@BAI9_1H}hmORLN8^n{ z;mjj(#wWM#65ZsIn(_?AzJr?IlbiSkd=0gMe&Shm1$PgG`wji>-d8>ph45;`;*0>N zipXXrBm6}l=j;nhx{rYr_1h`AXxDr=S||0bO-?IjBh@a)AXa38VN)#rTJhbnJgILB zNt}>UeKnP-DX5iDI4sZ8)0_Y*a)w8NY6jt4`{0LVs`9jr7D+{*dMP3IA@xTZHdzvu z;&{Dpa@z)Cs`__uoA!_UT#^+e6G1-UwKlYY+n=_reho%n>7{;UELrmXAGO))n5awS zAH5+3&J^?M4m=Z2NNF@kX$-;KGpedwk_&=?EXk7X7R3=NP+n84#P(2O&zU zC8rQT8m`?guGrmje7CSWh+tQ=@4uk`_F@DyKJ{I25Rf%!5DsNc}J{W!P;f=vGR!QT`F`JGxOS!JiD$2~b8IVXHCn=Tx^f1f5@ zK(Ovo17US>hq)N=+Je-;#cC?AHmuvM4IytT_VmCn+R97@`+Piieg$6e*q^pl7Lze8 zY&z!t6o7?TFq^FOsncUzN*RZRn^#i$F;BN4z^sBi5noGCJ=c(PB}{&6Ymr@kFx}L0 z(i&Vv?;+y`Dztx?b+y*77Wj6V*j1`rM^j+e=0@#UW6OIl-`P&yEoW0LG-qksX;_WC^I@-j+5{A7R_;(A&$&efy~Q|%+((^C~8}AiICX4I^Koo z1Qn6WB>KtZ^Stu7q#sQ4a`NL|YYiD|R^y3S6v@xoN8YawUo!PWY6rn;cHi9&Wyt`=pz!%#qaSj7EP%A+sq2#MMSA zDFlWsz$oJ-BjP?N2zOo34R&P$FaOfxM&TQFnZGr8aB(_vo#uE6RYAz(OM7cNE%(?U zxWd__8fmr~VQPKDuWuIC-Io}g3Pt&mgoC{flw7vnc38s&VobVQ2G}6;r|UVsoyyOA zNjROld(bzq)d2KWUq+!n7|xf%jvmld*1ty(VjsCV42?nm_>bR#PgY7T&xB`ld*svj z;n;?q%{-EF5Nhd*`7frqG8|WF?!LHz#RPE~SE;}8$5q}VSg2E-K+LLejo)E-2qfa3 z$bM5seC`VvzYQbpHxpQXNFJU%Cw?-!%Dc$UvxINri44ha8;|5jwkU`mtTnqO|6EUKR{| z1dawUTPk{z3R!WhR3f2%1QsMkGN?*?4_CzrQ$yEd#W0ZqBGWW6VXjI*J|1Rb$_+=EX2 z-8bx^{I((!G0N_~Y$KBGcf5bs3Zo!CWHuNO5L9Fk5X%2^tq`}eH4}C4u(x$EGX390 zLS4%heHG`st|f*I*8$ALl%tt!j6>Wu@P`PlEdm$zfgyOS74FEw8jNWyc5H*xhU@H# zUwvn(9M*3{JxlHNNR_nKLObb~yq*{0lgGzGzf;=UkFEJ2$dSmnufHyTKXwAXuJ7Of z>bHX#LVs5kA)cs`F_#U*rhuv31A`uDx*EvFsT%yo-W`QPi4Kxv+kOS)r5Rw6dkH6b z(0Hat73iW5b&`82C%s7C>q~8)h=d2dR9p6O6AAoygZ6t(I8>0j2S!=k)&!lX)(nQ1 zj>k*hE8%R7V)*I~i~9?2-bc z%!&>Tp7&^J+y|6z)gWhSU$cIBD3GK!5TQASX3N90@lLf7D{kdV;_$CG8V#PWh9{>$ zbWUgF@fGU8ax=heJ!guF8~S-n;YZ8r%4Q#g0rp-pGNbS%$zs2bJ!!1Yod&JZZ-?PY z17r8Do8KY%la^G969qP;OT;&>)7TK1t4b2lQ1rk6BOyPx_-bb&GZI_T&7)fNv}man zQ}g9;+z($HuQ_n?nbR1?(aX?N5QZg(r?~vax~}hKTn5)sz4?~qS7jF!F5b8q2nr+h zw**KF0O(2TkV_ev(m2dGiG33rh4@WZY=dW1(+fgRr-~X58Z@~rR;zQP5G#jRrdOgY z_o5^O+?sWL?0}{vw^G&X3^wle8a6LBo7sFfEvRzH3$1mFi$)iTN8q9mq=Ck5P>=)F zsoJfa{AiN-$f=0{HLq9V^)cu9>8%#U9EH)o$79r3n@s5NDQmO()R>036gMV^j31&; zgGT>vHeWmy+@9bYxTQ^wrGT))QFdQs#-_Q44H_){g0Td1boY zev?pE$qZky znw%hHTei_N*T9FVrPOy`mD6Uji9a0**s$@6BcyINS&pilC=dNCJ~I?e8wOQkmW4el zet2B%Im=Xr%HX@75FMuPG!3LDZE!8@R#s;b8FT~Kh&$=%IU zM$4RO1WwmB8GoyvaTV+Mjl9v#;tX<+(wJyX8VlXGmAyEsyyRM*w8EMqbgoKgs0(Mg zhIbyCSL^HoQ|@V4?MjYGdkQUq4Qdl{IX~oxl8Mbu18M2c_UH+RT-7I!Abq|fnFptu zR@CC8`1R2$FfKWBStd`z4~0t|>F%qTDbR3u4|Lh-B025J5H}K9jGkNPO=3>sqks0> z_B`g@&Lya(FC^E<=$|hy%I1aI>Q!)gM8e?#uaLg>BU>YSW;vp{Xl}I5nkuM`2iJ49 zDA(4*RAxxTtE1Y+Oc)h!?A!D zT`2b;&mjsele_!}m#}z6j+;k)%dAOL=AQiO<(Y+7o19;1gvp$ye2LVB{Rfx+HAkJL zi1+`rpdMgnBKTrsknQDOxce-EG`Aee^`yE{;ZiMKV9$lQx&`1L57Ar2zWvL}rqOw6 zII6M(2OVTZ_NY%06&j*|RrwtR-D`Zl=3AszS&_(hk#Bt8)!q0Gk?R6ngu{Z+%@&!w z@xr8_D*P%D`??C)#HAS$t~M)NnIdb+X`?f;&!pAd6jz+ejZ_i8Kt{?N*f8^XCazdO ze=2v4^A1qb43XyGSWUuvwa~DKE45I&^HNRoKtn=)BSjTuw#>qKT6;7Q72TQ zeSmS^U=8Q~0-HVLVR^J3P8A0J3%D6%k; z_af7rbKAZIIuuGPQdq4mEw|IQka8;H4BOXO4ARy%bSv=Gn|KHkCs&3_hegg0x zN#h@63j4u<2ZNpUi2d{g|_GG9%fF!16U$T

QGUIpScm1%P$@%@T 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 N3kU!Z)cK#*{{mjh6AJ(U literal 0 HcmV?d00001 diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/xypower/mpremote/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/xypower/mpremote/ExampleInstrumentedTest.java new file mode 100644 index 0000000..c34baa5 --- /dev/null +++ b/app/src/androidTest/java/com/xypower/mpremote/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.xypower.mpremote; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.xypower.mpremote", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c3bfd51 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..dd89586 --- /dev/null +++ b/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,48 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.18.1) + +# Declares and names the project. + +project("mpremote") + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. + +add_library( # Sets the name of the library. + mpremote + + # Sets the library as a shared library. + SHARED + + # Provides a relative path to your source file(s). + native-lib.cpp) + +# Searches for a specified prebuilt library and stores the path as a +# variable. Because CMake includes system libraries in the search path by +# default, you only need to specify the name of the public NDK library +# you want to add. CMake verifies that the library exists before +# completing its build. + +find_library( # Sets the name of the path variable. + log-lib + + # Specifies the name of the NDK library that + # you want CMake to locate. + log) + +# Specifies libraries CMake should link to your target library. You +# can link multiple libraries, such as libraries you define in this +# build script, prebuilt third-party libraries, or system libraries. + +target_link_libraries( # Specifies the target library. + mpremote + + # Links the target library to the log library + # included in the NDK. + ${log-lib}) \ No newline at end of file diff --git a/app/src/main/cpp/native-lib.cpp b/app/src/main/cpp/native-lib.cpp new file mode 100644 index 0000000..b781097 --- /dev/null +++ b/app/src/main/cpp/native-lib.cpp @@ -0,0 +1,10 @@ +#include +#include + +extern "C" JNIEXPORT jstring JNICALL +Java_com_xypower_mpremote_MainActivity_stringFromJNI( + JNIEnv* env, + jobject /* this */) { + std::string hello = "Hello from C++"; + return env->NewStringUTF(hello.c_str()); +} \ No newline at end of file diff --git a/app/src/main/java/com/xypower/mpremote/ImageActivity.java b/app/src/main/java/com/xypower/mpremote/ImageActivity.java new file mode 100644 index 0000000..ba32970 --- /dev/null +++ b/app/src/main/java/com/xypower/mpremote/ImageActivity.java @@ -0,0 +1,155 @@ +package com.xypower.mpremote; + +import android.annotation.SuppressLint; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowInsets; + +import com.xypower.mpremote.databinding.ActivityImageBinding; + +import java.io.File; + +/** + * An example full-screen activity that shows and hides the system UI (i.e. + * status bar and navigation/system bar) with user interaction. + */ +public class ImageActivity extends AppCompatActivity { + /** + * Whether or not the system UI should be auto-hidden after + * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds. + */ + private static final boolean AUTO_HIDE = true; + + /** + * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after + * user interaction before hiding the system UI. + */ + private static final int AUTO_HIDE_DELAY_MILLIS = 3000; + + /** + * Some older devices needs a small delay between UI widget updates + * and a change of the status and navigation bar. + */ + private static final int UI_ANIMATION_DELAY = 300; + private final Handler mHideHandler = new Handler(Looper.myLooper()); + + /** + * Touch listener to use for in-layout UI controls to delay hiding the + * system UI. This is to prevent the jarring behavior of controls going away + * while interacting with activity UI. + */ + private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + + break; + case MotionEvent.ACTION_UP: + ImageActivity.this.finish(); + break; + default: + break; + } + return false; + } + }; + private ActivityImageBinding binding; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + binding = ActivityImageBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + binding.imageViewOpt.setImageDrawable(null); + binding.imageViewAE.setImageDrawable(null); + + binding.imageViewOpt.setVisibility(View.GONE); + + binding.imageViewAE.setClickable(true); + binding.imageViewAE.setOnTouchListener(mDelayHideTouchListener); + + binding.imageViewAE.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ImageActivity.this.finish(); + } + }); + + binding.imageViewOpt.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ImageActivity.this.finish(); + } + }); + + Intent intent = getIntent(); + String path = intent.getStringExtra("path"); + if (path != null) { + loadImage(path); + } + + } + + private boolean loadImage(String path) { + + binding.imageViewOpt.setVisibility(View.GONE); + binding.imageViewAE.setVisibility(View.GONE); + + File file = new File(path); + if (!file.exists()) { + return false; + } + Drawable drawable = loadDrawable(path); + Drawable drawableAE = loadDrawable(path + ".ae.jpg"); + if (drawableAE == null && drawable == null) { + return false; + } + if (drawableAE != null && drawable != null) { + binding.imageViewOpt.setImageDrawable(drawable); + binding.imageViewAE.setImageDrawable(drawableAE); + binding.imageViewOpt.setVisibility(View.VISIBLE); + binding.imageViewAE.setVisibility(View.VISIBLE); + } + else if (drawable != null) { + binding.imageViewOpt.setImageDrawable(drawable); + binding.imageViewAE.setImageDrawable(null); + binding.imageViewOpt.setVisibility(View.VISIBLE); + // binding.imageViewAE.setVisibility(View.VISIBLE); + } + + return true; + } + + private Drawable loadDrawable(String file) { + if (file == null || file.isEmpty()) { + return null; + } + + Drawable drawable = null; + try { + Bitmap bitmap = BitmapFactory.decodeFile(file); + drawable = new BitmapDrawable(getResources(), bitmap); + } catch (Exception e) { + e.printStackTrace(); + } + + return drawable; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/xypower/mpremote/MainActivity.java b/app/src/main/java/com/xypower/mpremote/MainActivity.java new file mode 100644 index 0000000..e834ed2 --- /dev/null +++ b/app/src/main/java/com/xypower/mpremote/MainActivity.java @@ -0,0 +1,394 @@ +package com.xypower.mpremote; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.Handler; +import android.text.TextUtils; +import android.text.format.Formatter; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.xypower.common.FileUtils; +import com.xypower.common.MicroPhotoContext; +import com.xypower.mpremote.databinding.ActivityMainBinding; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.Socket; +import java.security.PrivateKey; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import dadb.AdbKeyPair; +import dadb.AdbShellResponse; +import dadb.AdbShellStream; +import dadb.AdbStream; +import dadb.Dadb; + +public class MainActivity extends AppCompatActivity { + + // Used to load the 'mpremote' library on application startup. + static { + System.loadLibrary("mpremote"); + } + + private static final String PACKAGE_NAME_MP = "com.xypower.mpapp"; + private static final String REMOTE_PATH_ROOT = "/sdcard/" + PACKAGE_NAME_MP + "/"; + private static final String REMOTE_PATH_DATA = REMOTE_PATH_ROOT + "data/"; + private static final String REMOTE_PATH_PHOTOS = REMOTE_PATH_ROOT + "photos/"; + private static final String REMOTE_PATH_TMP = REMOTE_PATH_ROOT + "tmp/"; + + private static final String KEY_APP_BV = "app.bv"; + private static final String KEY_APP_BCV = "app.bcv"; + private static final String KEY_RO_SERIALNO = "ro.serialno"; + + private static final int ADB_SERVER_PORT = 5555; + + private static final String WIFI_IP_PREFIX = "192.168.50."; + // private static final String WIFI_IP_DEVIDE = "192.168.50.1"; + private static final String WIFI_IP_DEVIDE = "192.168.50.137"; + + // [vendor.ril.nw.signalstrength.lte.1]: [-85,27] + //[vendor.ril.nw.signalstrength.lte.2]: [-86,27] + + private ActivityMainBinding binding; + private Handler mHandler; + private Dadb mAdb; + + private Map mProps = new HashMap<>(); + + private int mBatteryVoltage = -1; + private int mBatteryChargingVoltage = -1; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + binding = ActivityMainBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + mHandler = new Handler(); + + File file = new File(getFilesDir(), ".keypair"); + if (!file.exists()) { + file.mkdirs(); + } + + final File pubKeyFile = new File(file, "pub.key"); + final File priKeyFile = new File(file, "pri.key"); + if (!priKeyFile.exists() || !pubKeyFile.exists()) { + AdbKeyPair.generate(priKeyFile, pubKeyFile); + } + + final File fileTmp = new File(getFilesDir(), "tmp"); + if (!fileTmp.exists()) { + fileTmp.mkdirs(); + } + + final AdbKeyPair adbKeyPair = AdbKeyPair.read(priKeyFile, pubKeyFile); + final Context context = getApplicationContext(); + + (new Thread(new Runnable() { + @Override + public void run() { + + WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); + + String ipAddressByWifi = null; + if (wifiManager != null) { + ipAddressByWifi = Formatter.formatIpAddress(wifiManager.getDhcpInfo().ipAddress); + } + + if (ipAddressByWifi.contains(WIFI_IP_PREFIX)) { + + Socket mSocket = null; + try { + mSocket = new Socket(WIFI_IP_DEVIDE, ADB_SERVER_PORT); + if (mSocket.isConnected()) { + mSocket.close(); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + + Dadb adb = Dadb.discover(WIFI_IP_DEVIDE, adbKeyPair); + + if (adb != null) { + + mAdb = adb; + + AdbShellResponse adbShellResponse = null; + try { + adbShellResponse = mAdb.shell("getprop"); + } catch (Exception ex) { + ex.printStackTrace(); + } + + if (adbShellResponse.getExitCode() == 0) { + String[] lines = FileUtils.splitLines(adbShellResponse.getAllOutput()); + for (String line : lines) { + int pos = line.indexOf("]: ["); + if (pos != -1) { + String key = line.substring(1, pos); + String val = line.substring(pos + 4, line.length() - 1); + mProps.put(key, val); + } + } + } + + String remoteFilePath = REMOTE_PATH_TMP + "bv.txt"; + String cmd = "am start -n " + PACKAGE_NAME_MP + "/" + PACKAGE_NAME_MP + ".BridgeActivity --es action \"query_bv\" --es path \"" + remoteFilePath + "\""; + adbShellResponse = null; + try { + adbShellResponse = mAdb.shell(cmd); + } catch (Exception ex) { + ex.printStackTrace(); + } + + if (adbShellResponse.getExitCode() == 0) { + File localFilePath = new File(fileTmp, "bv.txt"); + if (localFilePath.exists()) { + localFilePath.delete(); + } + + for (int idx = 0; idx < 10; idx++) { + + boolean res = pullFile(mAdb, remoteFilePath, localFilePath); + + if (res) { + String content = FileUtils.readTextFile(localFilePath.getAbsolutePath()); + if (!TextUtils.isEmpty(content)) { + int pos = content.indexOf(" "); + if (pos != -1) { + String bv = content.substring(0, pos); + String bcv = content.substring(pos + 1); + + if (!TextUtils.isEmpty(bv)) { + mBatteryVoltage = Integer.parseInt(bv); + } + if (!TextUtils.isEmpty(bcv)) { + mBatteryChargingVoltage = Integer.parseInt(bcv); + } + } + } + + localFilePath.delete(); + break; + } + + try { + Thread.sleep(1000); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + try { + mAdb.shell("rm " + remoteFilePath); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + File appConfigFile = new File(fileTmp, "App.json"); + boolean res = pullFile(adb, REMOTE_PATH_DATA + "App.json", appConfigFile); + if (res) { + + final MicroPhotoContext.AppConfig appConfig = MicroPhotoContext.getMpAppConfig(context, appConfigFile.getAbsolutePath()); + MainActivity.this.mHandler.post(new Runnable() { + @Override + public void run() { + MainActivity.this.showAppInfo(appConfig); + } + }); + } + + } else { + mHandler.post(new Runnable() { + @Override + public void run() { + Toast.makeText(MainActivity.this, R.string.err_dev_not_found, Toast.LENGTH_LONG).show(); + } + }); + } + + } + + // Dadb dadb = Dadb.create("localhost", 5555, adbKeyPair); + // Dadb.discover(); + + + + } + })).start(); + + binding.takePhoto1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + takePhoto(1, 255, true); + } + }); + + } + + + + protected boolean pullFile(Dadb adb, String remoteFilePath, File localFilePath) { + if (localFilePath.exists()) { + localFilePath.delete(); + } + + boolean res = false; + try { + adb.pull(localFilePath, remoteFilePath); + res = true; + } catch (Exception ex) { + ex.printStackTrace(); + } + + return res && localFilePath.exists(); + } + + protected long takePhoto(int channel, int preset, boolean photoOrVideo) { + if (mAdb == null) { + return 0; + } + + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss"); + Date dt = new Date(); + int cameraId = channel - 1; + + final String fileName = "IMG-" + Integer.toString(channel) + simpleDateFormat.format(dt) + ".jpg"; + final String remoteFilePath = REMOTE_PATH_TMP + fileName; + + String usb = (channel == 4) ? "true" : "false"; + final String cmd = "am start -n " + PACKAGE_NAME_MP + "/" + PACKAGE_NAME_MP + ".BridgeActivity --es action \"take_photo\" --es path \"" + + remoteFilePath + "\" --ez usb " + usb + " --ei cameraId " + Integer.toString(cameraId) + " --ei channel " + + Integer.toString(channel) + " --ei preset " + Integer.toString(preset); + // adbShellResponse = null; + + (new Thread(new Runnable() { + @Override + public void run() { + AdbShellResponse adbShellResponse = null; + try { + adbShellResponse = mAdb.shell(cmd); + } catch (Exception ex) { + ex.printStackTrace(); + } + + if (adbShellResponse != null) { + if (adbShellResponse.getExitCode() == 0) { + + File localFilePath = new File(getFilesDir(), fileName); + + for (int idx = 0; idx < 10; idx++) { + + boolean res = pullFile(mAdb, remoteFilePath, localFilePath); + + if (res) { + + mHandler.post(new Runnable() { + @Override + public void run() { + showPhoto(localFilePath.getAbsolutePath()); + } + }); + break; + } + + try { + Thread.sleep(1000); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + try { + mAdb.shell("rm " + remoteFilePath); + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + } + } + })).start(); + + return 0; + } + + private void showPhoto(final String filePath) { + Intent intent = new Intent(MainActivity.this, ImageActivity.class); + intent.putExtra("path", filePath); + // intent.putExtra("info", info); + startActivity(intent); + } + + private void showVideo(final String filePath) { + + } + + private void showAppInfo(final MicroPhotoContext.AppConfig appConfig) { + ActionBar actionBar = getSupportActionBar(); + + // 视频浏览,拍照,设备信息及状态查询(编号,版本,双SIM卡状态,电池及太阳能电压等),可以参考东视 + + Resources resources = getResources(); + // String buildTime = BuildConfig.BUILD_ + // Date date = new Date(BuildConfig.BUILD_TIMESTAMP); + // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + String title = resources.getString(R.string.app_name); + if (!TextUtils.isEmpty(appConfig.cmdid)) { + title += " - " + appConfig.cmdid; + } + actionBar.setTitle(title); + + StringBuilder stringBuilder = new StringBuilder(); + + if (mProps.containsKey(KEY_RO_SERIALNO)) { + String val = (String)mProps.get(KEY_RO_SERIALNO); + stringBuilder.append("序列号:" + val); + stringBuilder.append("\r\n"); + } + + stringBuilder.append("主站:" + appConfig.server + ":" + Integer.toString(appConfig.port)); + stringBuilder.append("\r\n"); + stringBuilder.append("通道数:" + Integer.toString(appConfig.channels)); + stringBuilder.append("\r\n"); + + if (mBatteryVoltage != -1) { + stringBuilder.append("电池电压:" + Integer.toString(mBatteryVoltage / 1000) + "." + Integer.toString((mBatteryVoltage % 1000) / 100)); + stringBuilder.append("\r\n"); + } + if (mBatteryChargingVoltage != -1) { + stringBuilder.append("充电电压:" + Integer.toString(mBatteryChargingVoltage / 1000) + "." + Integer.toString((mBatteryChargingVoltage % 1000) / 100)); + stringBuilder.append("\r\n"); + } + + binding.deviceInfo.setText(stringBuilder.toString()); + } + + /** + * A native method that is implemented by the 'mpremote' native library, + * which is packaged with this application. + */ + public native String stringFromJNI(); +} \ No newline at end of file diff --git a/app/src/main/java/com/xypower/mpremote/WifiScanActivity.java b/app/src/main/java/com/xypower/mpremote/WifiScanActivity.java new file mode 100644 index 0000000..d1006a6 --- /dev/null +++ b/app/src/main/java/com/xypower/mpremote/WifiScanActivity.java @@ -0,0 +1,14 @@ +package com.xypower.mpremote; + +import androidx.appcompat.app.AppCompatActivity; + +import android.os.Bundle; + +public class WifiScanActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_wifi_scan); + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_image.xml b/app/src/main/res/layout/activity_image.xml new file mode 100644 index 0000000..6c1602a --- /dev/null +++ b/app/src/main/res/layout/activity_image.xml @@ -0,0 +1,33 @@ + + + + + + + + + \ 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 new file mode 100644 index 0000000..61fbbd7 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,31 @@ + + + + + +