11package com .mobilebox .repl .app ;
22
33import static com .google .common .base .Strings .nullToEmpty ;
4+ import static java .util .UUID .randomUUID ;
5+ import static org .zeroturnaround .zip .ZipUtil .containsEntry ;
6+ import static org .zeroturnaround .zip .ZipUtil .unpackEntry ;
47
8+ import java .awt .image .BufferedImage ;
9+ import java .io .ByteArrayOutputStream ;
510import java .io .File ;
11+ import java .io .FileInputStream ;
12+ import java .io .IOException ;
13+ import java .nio .charset .StandardCharsets ;
14+ import java .util .ArrayList ;
15+ import java .util .Base64 ;
16+ import java .util .List ;
617import java .util .Locale ;
18+ import java .util .regex .Matcher ;
19+ import java .util .regex .Pattern ;
720
8- import com .mobilebox .repl .exceptions .CommandsException ;
21+ import javax .imageio .ImageIO ;
22+
23+ import com .jcabi .xml .XML ;
24+ import com .jcabi .xml .XMLDocument ;
925
1026import net .dongliu .apk .parser .ApkParser ;
1127import net .dongliu .apk .parser .bean .ApkMeta ;
@@ -23,7 +39,7 @@ public class APKInspector {
2339 * @return An {@link ApkData} instance.
2440 * @throws CommandsException
2541 */
26- public ApkData inspect (final String appPath ) throws CommandsException {
42+ public ApkData inspect (final String appPath ) {
2743 File apkFile = new File (appPath );
2844 ApkData app = new ApkData ();
2945
@@ -32,22 +48,92 @@ public ApkData inspect(final String appPath) throws CommandsException {
3248 ApkParser parser = new ApkParser (appPath );
3349 parser .setPreferredLocale (Locale .getDefault ());
3450 ApkMeta data = parser .getApkMeta ();
35-
51+
3652 app .setPackageName (nullToEmpty (data .getPackageName ()))
37- .setLabel (nullToEmpty (data .getLabel ()))
38- .setVersionName (nullToEmpty (data .getVersionName ()))
39- .setMaxSdkVersion (nullToEmpty (data .getMaxSdkVersion ()))
40- .setMinSdkVersion (nullToEmpty (data .getMinSdkVersion ()))
41- .setTargetSdkVersion (nullToEmpty (data .getTargetSdkVersion ()))
42- .setUsesFeature (data .getUsesFeatures ())
43- .setUserPermissions (data .getUsesPermissions ());
53+ .setLabel (nullToEmpty (data .getLabel ()))
54+ .setVersionName (nullToEmpty (data .getVersionName ()))
55+ .setMaxSdkVersion (nullToEmpty (data .getMaxSdkVersion ()))
56+ .setMinSdkVersion (nullToEmpty (data .getMinSdkVersion ()))
57+ .setTargetSdkVersion (nullToEmpty (data .getTargetSdkVersion ()))
58+ .setUsesFeature (data .getUsesFeatures ()).setUserPermissions (data .getUsesPermissions ())
59+ .setActivities (getActivities (parser .getManifestXml ()))
60+ .setIcon (icon2Base64 (appPath , data .getIcon ()));
4461
4562 } catch (Exception e ) {
46- throw new CommandsException ("Error: " + e .getMessage ());
63+ throw new RuntimeException ("Error: " + e .getMessage ());
4764 }
4865 }
4966
5067 return app ;
5168 }
5269
70+ /**
71+ * Return information about activities in the package in activities.
72+ *
73+ * @param manifest The app manifest.
74+ * @return List of activities
75+ */
76+ private List <String > getActivities (final String manifest ) {
77+ List <String > activities = new ArrayList <String >();
78+ Pattern p = Pattern .compile ("android:name=\" (.*?)\" " );
79+
80+ XML xml = new XMLDocument (manifest );
81+ XML je = new XMLDocument (xml .toString ());
82+ List <XML > name = je .nodes ("//activity" );
83+
84+ for (XML node : name ) {
85+ Matcher m = p .matcher (node .toString ());
86+ if (m .find ()) {
87+ activities .add (m .group (1 ));
88+ }
89+ }
90+ return activities ;
91+ }
92+
93+ /**
94+ * Retrieve the icon associated with an application. If it has not defined an icon, the default
95+ * app icon is returned.
96+ *
97+ * @param appPath The aplication under test path.
98+ * @iconPath The path to the icon on the APK file.
99+ * @return The image of the icon, or the default application icon if it could not be found in
100+ * base64.
101+ * @throws MoneyException
102+ */
103+ public String icon2Base64 (final String appPath , final String iconPath ) {
104+ String icon =
105+ "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAABRZJREFUeJztm89vVFUUxz/3vJm22FakZVoTRFaGUliI8QcsXICu5EcTE2ICf4BGggYTaBDoy0AFiyILjZq6xehKEH+wsZi40BohkShWlmpIoENLkZZOmTfnuGjHFKaFDn1vXgnzWU0mZ84595tz37333DdQoUKFChXuX9xUXzb62RZn8rbD1oLURxPaXsvsq3o/Gt8zp0iARj/bIuZ6QeZHG1rzZtJ2eX/ym2jj3J4iARZ23DjucG1mdtyTxMuX0tIfZsBUR84Kn1V1WDyezaSrfw0zRinIrV+Mlz1EMfjJGHwgInWY+7rhTV0UVZw7USRAYc5HOXiAyy6xHfQkuEVeIv9Vyre6KONNxxQClIm0C3Q0+ZLCb8BK9MZnbDKv3GnEJwAw8I5cU5dYr6oXcbK+sSU4Uu4cYhUA4Era/Y3nNig6Ko5tqY4b28oZP3YBAAbSVac9ky2gBnZk4d7cunLFnhMCAPTvTx7D3E4Qz0w/T/ljj5cj7pwRACCzP3kY5ZNyLo9zSgBwlulPbDXT78q1PJZdAEVHAJp2afOUBt0ul5OqTSh/UIblsewCCO4UgCWC7ulEuJp2Q2LBekUzUS+PRWeBwl49sy855UlxtjTsyS7zxP1U6mErqnzKXgGDnTV9ebXVmJ0oTIc4ScQRdLCzpg9om4nt5NNjFMyxVaD8VASIO4G4Cf0ZsMS3mmHLbRXcFkVbBakOw+9snwWKjonKORM7WuuSH/2VdlkIuQIW+Pbo9XxwRnDvAivDGnwYCFKN8ITDvTdiwekFu3UxhFgBj2zXeWP54CRCK9CnRnviunfq0mGJfakDSPlWpwRrxTjkYLnn8t8u8e2p0AQYqwu24lwr0BeMJVZf6XJXw/IdBpm0GwZOzPfthyoLep2wYkRzr4Y3BZzbDGCOnXNt8JO5mnZDzmgHcM5tDk0ARVsBvGHv+7B8RoVJogdAVZeHNgUKD7yp5nyzP7ZClS51rBFk3kTw6yKuJ6/aPrEzBKZ/2is6IuZ6VLR9IF3z593aw/h0SHXkEJGayPcBzf7YCjV+xMkLhcEDiMgD4DZ4uN6GPdlld/IjSC3ObRRzvY1+tiUs+8jPAqp04aTezL5IBIlXLh6UDECzr015C7qdSJuHdQEbJ//u1tPf//ZIm6h1cctZolT7ApFXgDrWAEwePIxfvEgu8TKATtxG3Y6b7C08+8gFKJT95MEX6D8olyZsamfiy6pcST2BmdjfM2eBlG8PY7luACeuJyz7svUDSt3LF9lbADhQHTKsfbb2Be6ZCgC9Ztgx8+yZgc6a82HZl60CpuvpTVcZpfYA77ZneA9VQDRUBIg7gbipCBB3AnET2s1QY8dYVpBqGfHq5koXaDoad2i9zMv/q+hoaBUgKucAgrr8c2H5jAqvJv88gCC/hyaAOfsUQIxD8317KCy/YfOgrw3m6AIws6OhCVAryQ8NzgFLqyzobdqba4vr1bepaNyh9Sk/92Iyn/8ZeEzh7GVJfhzq7fCC3brY8/InHSwPIefIUDhrgbdu8IBcCHUVuPKW/FPrEk8a9gZwRtHRMP3PholcfjGz1wdc4unBA3JhSsNUR86ivpEthajzue/3ARUB4k4gbooEKLy20uxrU/nTuZnCS1SqOhxVjCIBxMb7Z3kLuuMUoWmXNlsimHEP8G4p/svMnuxSwfUiMjd2c6pDiq2aWRusdIoqYKCz5rxiqwz7Ms63uFR12MyOz7wHWKFChQql8x+anVpT1E4upAAAAABJRU5ErkJggg==" ;
106+ File apkFile = new File (appPath );
107+ if (apkFile .exists ()) {
108+ if (containsEntry (apkFile , iconPath )) {
109+ String tempIcon = randomUUID ().toString () + ".png" ;
110+ File icono = new File (tempIcon );
111+ unpackEntry (apkFile , iconPath , icono );
112+ icon = imageToBase64 (icono .getAbsolutePath ());
113+ icono .delete ();
114+ }
115+ }
116+ return icon ;
117+ }
118+
119+ /**
120+ * Image to Base64 converter
121+ *
122+ * @param imagePath - The image path.
123+ * @return The image as base64 data.
124+ * @throws MonkeyException
125+ */
126+ private String imageToBase64 (final String imagePath ) {
127+ final ByteArrayOutputStream os = new ByteArrayOutputStream ();
128+ try {
129+ FileInputStream inputStream = new FileInputStream (imagePath );
130+ BufferedImage inputImage = ImageIO .read (inputStream );
131+ ImageIO .write (inputImage , "png" , Base64 .getEncoder ().wrap (os ));
132+ return os .toString (StandardCharsets .ISO_8859_1 .name ());
133+ } catch (final IOException e ) {
134+ throw new RuntimeException (
135+ "We have an error with pseudo image to 64 route converter: " + e .getMessage ());
136+ }
137+ }
138+
53139}
0 commit comments