1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.jayway.maven.plugins.android;
17
18 import com.android.SdkConstants;
19 import com.android.sdklib.BuildToolInfo;
20 import com.android.sdklib.IAndroidTarget;
21 import com.android.sdklib.SdkManager;
22 import com.android.utils.NullLogger;
23 import org.apache.maven.plugin.MojoExecutionException;
24
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.IOException;
28 import java.util.Properties;
29
30
31
32
33
34
35
36 public class AndroidSdk
37 {
38
39
40
41
42 private static final String SOURCE_PROPERTIES_FILENAME = "source.properties";
43
44
45
46 private static final String SDK_TOOLS_REVISION_PROPERTY = "Pkg.Revision";
47
48
49
50
51 private static final String PLATFORMS_FOLDER_NAME = "platforms";
52
53 private static final String PARAMETER_MESSAGE = "Please provide a proper Android SDK directory path as "
54 + "configuration parameter <sdk><path>...</path></sdk> in the plugin <configuration/>. As an alternative,"
55 + " you may add the parameter to commandline: -Dandroid.sdk.path=... or set environment variable "
56 + AbstractAndroidMojo.ENV_ANDROID_HOME + ".";
57
58 private final File sdkPath;
59 private File platformToolsPath;
60 private File toolsPath;
61
62 private IAndroidTarget androidTarget;
63 private SdkManager sdkManager;
64 private int sdkMajorVersion;
65
66 public AndroidSdk( File sdkPath, String platformOrApiLevel )
67 {
68 this.sdkPath = sdkPath;
69
70 if ( sdkPath != null )
71 {
72 sdkManager = SdkManager.createManager( sdkPath.getPath(), new NullLogger() );
73 platformToolsPath = new File( sdkPath, SdkConstants.FD_PLATFORM_TOOLS );
74 toolsPath = new File( sdkPath, SdkConstants.FD_TOOLS );
75
76 if ( sdkManager == null )
77 {
78 throw invalidSdkException( sdkPath, platformOrApiLevel );
79 }
80 }
81 loadSDKToolsMajorVersion();
82
83 if ( platformOrApiLevel == null )
84 {
85 throw new InvalidConfigurationException( " No Android Platform Version/API Level has been configured. "
86 + " Add e.g. <sdk><platform>17</platform></sdk> to the plugin configuration." );
87 }
88 else
89 {
90 androidTarget = findPlatformByNameOrApiLevel( platformOrApiLevel );
91 if ( androidTarget == null )
92 {
93 throw invalidSdkException( sdkPath, platformOrApiLevel );
94 }
95 }
96 }
97
98 private InvalidSdkException invalidSdkException( File sdkPath, String platformOrApiLevel )
99 {
100 throw new InvalidSdkException( "Invalid SDK: Platform/API level " + platformOrApiLevel
101 + " not available. This command should give you all you need:\n" + sdkPath.getAbsolutePath()
102 + File.separator + "tools" + File.separator + "android update sdk --no-ui --obsolete --force" );
103 }
104
105 private IAndroidTarget findPlatformByNameOrApiLevel( String platformOrApiLevel )
106 {
107
108 IAndroidTarget target = sdkManager.getTargetFromHashString(
109 IAndroidTarget.PLATFORM_HASH_PREFIX + platformOrApiLevel );
110 if ( target != null )
111 {
112 return target;
113 }
114
115
116 for ( IAndroidTarget t: sdkManager.getTargets() )
117 {
118 if ( t.isPlatform() && t.getVersionName().equals( platformOrApiLevel ) )
119 {
120 return t;
121 }
122 }
123 return null;
124 }
125
126
127
128
129
130
131
132 public enum Layout
133 {
134 LAYOUT_1_5, LAYOUT_2_3;
135 }
136 public Layout getLayout()
137 {
138
139 assertPathIsDirectory( sdkPath );
140
141
142 if ( platformToolsPath.exists() && platformToolsPath.isDirectory() )
143 {
144 return Layout.LAYOUT_2_3;
145 }
146
147 final File platforms = new File( sdkPath, PLATFORMS_FOLDER_NAME );
148 if ( platforms.exists() && platforms.isDirectory() )
149 {
150 return Layout.LAYOUT_1_5;
151 }
152
153 throw new InvalidSdkException( "Android SDK could not be identified from path \"" + sdkPath + "\". "
154 + PARAMETER_MESSAGE );
155 }
156
157 private void assertPathIsDirectory( final File path )
158 {
159 if ( path == null )
160 {
161 throw new InvalidSdkException( PARAMETER_MESSAGE );
162 }
163 if ( !path.isDirectory() )
164 {
165 throw new InvalidSdkException( "Path \"" + path + "\" is not a directory. " + PARAMETER_MESSAGE );
166 }
167 }
168
169
170
171
172
173
174 public String getAaptPath()
175 {
176 return getPathForBuildTool( BuildToolInfo.PathId.AAPT );
177 }
178
179
180
181
182
183 public String getAidlPath()
184 {
185 return getPathForBuildTool( BuildToolInfo.PathId.AIDL );
186 }
187
188
189
190
191
192 public String getDxJarPath()
193 {
194 return getPathForBuildTool( BuildToolInfo.PathId.DX_JAR );
195 }
196
197
198
199
200
201
202 public String getAdbPath()
203 {
204 return getPathForPlatformTool( SdkConstants.FN_ADB );
205 }
206
207
208
209
210
211
212 public String getZipalignPath()
213 {
214 return getPathForTool( SdkConstants.FN_ZIPALIGN );
215 }
216
217
218
219
220
221
222 public String getLintPath()
223 {
224 return getPathForTool( "lint" + ext( ".bat", "" ) );
225 }
226
227
228
229
230
231
232 public String getMonkeyRunnerPath()
233 {
234 return getPathForTool( "monkeyrunner" + ext( ".bat", "" ) );
235 }
236
237
238
239
240
241
242 public String getApkBuilderPath()
243 {
244 return getPathForTool( "apkbuilder" + ext( ".bat", "" ) );
245 }
246
247
248
249
250
251
252 public String getAndroidPath()
253 {
254 return getPathForTool( SdkConstants.androidCmdName() );
255 }
256
257
258
259
260
261 public File getToolsPath()
262 {
263 return toolsPath;
264 }
265
266 private String getPathForBuildTool( BuildToolInfo.PathId pathId )
267 {
268 if ( androidTarget != null )
269 {
270 return androidTarget.getBuildToolInfo().getPath( pathId );
271 }
272
273 return sdkManager.getLatestBuildTool().getPath( pathId );
274 }
275
276 private String getPathForPlatformTool( String tool )
277 {
278 return new File( platformToolsPath, tool ).getAbsolutePath();
279 }
280
281 private String getPathForTool( String tool )
282 {
283 return new File( toolsPath, tool ).getAbsolutePath();
284 }
285
286 private static String ext( String windowsExtension, String nonWindowsExtension )
287 {
288 if ( SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS )
289 {
290 return windowsExtension;
291 }
292 else
293 {
294 return nonWindowsExtension;
295 }
296 }
297
298
299
300
301
302
303 public String getPathForFrameworkAidl()
304 {
305 return androidTarget.getPath( IAndroidTarget.ANDROID_AIDL );
306 }
307
308
309
310
311
312
313
314
315 public File getAndroidJar() throws MojoExecutionException
316 {
317 return new File( androidTarget.getPath( IAndroidTarget.ANDROID_JAR ) );
318 }
319
320
321
322
323
324
325
326
327 public File getSDKLibJar() throws MojoExecutionException
328 {
329
330 File sdklib = new File( sdkPath + "/tools/lib/sdklib.jar" );
331 if ( sdklib.exists() )
332 {
333 return sdklib;
334 }
335 throw new MojoExecutionException( "Can't find the 'sdklib.jar' : " + sdklib.getAbsolutePath() );
336 }
337
338
339
340
341
342
343
344
345 public File getSdkPath() throws MojoExecutionException
346 {
347 if ( sdkPath.exists() )
348 {
349 return sdkPath;
350 }
351 throw new MojoExecutionException( "Can't find the SDK directory : " + sdkPath.getAbsolutePath() );
352 }
353
354
355
356
357
358 public File getPlatform()
359 {
360 assertPathIsDirectory( sdkPath );
361
362 final File platformsDirectory = new File( sdkPath, PLATFORMS_FOLDER_NAME );
363 assertPathIsDirectory( platformsDirectory );
364
365 final File platformDirectory;
366 if ( androidTarget == null )
367 {
368 IAndroidTarget latestTarget = null;
369 for ( IAndroidTarget target: sdkManager.getTargets() )
370 {
371 if ( target.isPlatform() )
372 {
373 if ( latestTarget == null
374 || target.getVersion().getApiLevel() > latestTarget.getVersion().getApiLevel() )
375 {
376 latestTarget = target;
377 }
378 }
379 }
380 platformDirectory = new File ( latestTarget.getLocation() );
381 }
382 else
383 {
384 platformDirectory = new File( androidTarget.getLocation() );
385 }
386 assertPathIsDirectory( platformDirectory );
387 return platformDirectory;
388 }
389
390
391
392
393 private void loadSDKToolsMajorVersion()
394 {
395 File propFile = new File( sdkPath, "tools/" + SOURCE_PROPERTIES_FILENAME );
396 Properties properties = new Properties();
397 try
398 {
399 properties.load( new FileInputStream( propFile ) );
400 }
401 catch ( IOException e )
402 {
403 throw new InvalidSdkException( "Error reading " + propFile.getAbsoluteFile() );
404 }
405
406 if ( properties.containsKey( SDK_TOOLS_REVISION_PROPERTY ) )
407 {
408 try
409 {
410 String versionString = properties.getProperty( SDK_TOOLS_REVISION_PROPERTY );
411 String majorVersion;
412 if ( versionString.matches( ".*[\\.| ].*" ) )
413 {
414 String[] versions = versionString.split( "[\\.| ]" );
415 majorVersion = versions[ 0 ];
416 }
417 else
418 {
419 majorVersion = versionString;
420 }
421 sdkMajorVersion = Integer.parseInt( majorVersion );
422 }
423 catch ( NumberFormatException e )
424 {
425 throw new InvalidSdkException( "Error - The property '" + SDK_TOOLS_REVISION_PROPERTY
426 + "' in the SDK source.properties file number is not an Integer: "
427 + properties.getProperty( SDK_TOOLS_REVISION_PROPERTY ) );
428 }
429 }
430 }
431
432
433
434
435
436
437 public int getSdkMajorVersion()
438 {
439 return sdkMajorVersion;
440 }
441 }