1 package com.jayway.maven.plugins.android.standalonemojos;
2
3 import com.jayway.maven.plugins.android.AbstractAndroidMojo;
4 import com.jayway.maven.plugins.android.common.AndroidExtension;
5 import com.jayway.maven.plugins.android.common.XmlHelper;
6 import com.jayway.maven.plugins.android.configuration.Manifest;
7 import com.jayway.maven.plugins.android.configuration.UsesSdk;
8 import org.apache.commons.io.IOUtils;
9 import org.apache.commons.lang.BooleanUtils;
10 import org.apache.commons.lang.StringUtils;
11 import org.apache.commons.lang.math.NumberUtils;
12 import org.apache.maven.artifact.versioning.ArtifactVersion;
13 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
14 import org.apache.maven.plugin.MojoExecutionException;
15 import org.apache.maven.plugin.MojoFailureException;
16 import org.w3c.dom.Attr;
17 import org.w3c.dom.Document;
18 import org.w3c.dom.Element;
19 import org.w3c.dom.Node;
20 import org.w3c.dom.NodeList;
21 import org.xml.sax.SAXException;
22
23 import javax.xml.parsers.DocumentBuilder;
24 import javax.xml.parsers.DocumentBuilderFactory;
25 import javax.xml.parsers.ParserConfigurationException;
26 import javax.xml.transform.OutputKeys;
27 import javax.xml.transform.Result;
28 import javax.xml.transform.Source;
29 import javax.xml.transform.Transformer;
30 import javax.xml.transform.TransformerException;
31 import javax.xml.transform.TransformerFactory;
32 import javax.xml.transform.dom.DOMSource;
33 import javax.xml.transform.stream.StreamResult;
34 import java.io.File;
35 import java.io.FileWriter;
36 import java.io.IOException;
37 import java.util.ArrayList;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Properties;
41
42
43
44
45
46
47
48
49
50
51
52 public class ManifestUpdateMojo extends AbstractAndroidMojo
53 {
54
55 private static final String ATTR_VERSION_NAME = "android:versionName";
56 private static final String ATTR_VERSION_CODE = "android:versionCode";
57 private static final String ATTR_SHARED_USER_ID = "android:sharedUserId";
58 private static final String ATTR_DEBUGGABLE = "android:debuggable";
59
60
61 private static final String ATTR_SCREEN_DENSITY = "android:screenDensity";
62 private static final String ATTR_SCREEN_SIZE = "android:screenSize";
63
64
65 private static final String ATTR_ANY_DENSITY = "android:anyDensity";
66 private static final String ATTR_SMALL_SCREENS = "android:smallScreens";
67 private static final String ATTR_NORMAL_SCREENS = "android:normalScreens";
68 private static final String ATTR_LARGE_SCREENS = "android:largeScreens";
69 private static final String ATTR_XLARGE_SCREENS = "android:xlargeScreens";
70 private static final String ATTR_RESIZEABLE = "android:resizeable";
71 private static final String ATTR_REQUIRES_SMALLEST_WIDTH_DP = "android:requiresSmallestWidthDp";
72 private static final String ATTR_LARGEST_WIDTH_LIMIT_DP = "android:largestWidthLimitDp";
73 private static final String ATTR_COMPATIBLE_WIDTH_LIMIT_DP = "android:compatibleWidthLimitDp";
74
75
76 private static final String ATTR_MIN_SDK_VERSION = "android:minSdkVersion";
77 private static final String ATTR_MAX_SDK_VERSION = "android:maxSdkVersion";
78 private static final String ATTR_TARGET_SDK_VERSION = "android:targetSdkVersion";
79
80
81 private static final String ATTR_NAME = "android:name";
82 private static final String ATTR_AUTHORITIES = "android:authorities";
83
84 private static final String ATTR_APPLICATION_ICON = "android:icon";
85 private static final String ATTR_APPLICATION_LABEL = "android:label";
86 private static final String ATTR_APPLICATION_THEME = "android:theme";
87
88 private static final String ELEM_APPLICATION = "application";
89 private static final String ELEM_PROVIDER = "provider";
90 private static final String ELEM_SUPPORTS_SCREENS = "supports-screens";
91 private static final String ELEM_COMPATIBLE_SCREENS = "compatible-screens";
92 private static final String ELEM_SCREEN = "screen";
93 private static final String ELEM_USES_SDK = "uses-sdk";
94
95
96 private static final int INCREMENTAL_VERSION_POSITION = 1;
97 private static final int MINOR_VERSION_POSITION = 1000;
98 private static final int MAJOR_VERSION_POSITION = 1000000;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 private Manifest manifest;
169
170
171
172
173
174
175
176
177 protected String manifestVersionName;
178
179
180
181
182
183
184
185 protected Integer manifestVersionCode;
186
187
188
189
190
191
192
193
194 private Boolean manifestVersionCodeAutoIncrement = false;
195
196
197
198
199
200
201
202 private String manifestApplicationIcon;
203
204
205
206
207
208
209
210 private String manifestApplicationLabel;
211
212
213
214
215
216
217
218 private String manifestApplicationTheme;
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234 protected Boolean manifestVersionCodeUpdateFromVersion = false;
235
236
237
238
239
240
241
242 protected String manifestSharedUserId;
243
244
245
246
247
248
249
250 protected Boolean manifestDebuggable;
251
252
253
254
255
256
257
258 protected Properties manifestProviderAuthorities;
259
260
261
262
263 protected SupportsScreens manifestSupportsScreens;
264
265
266
267
268 protected List<CompatibleScreen> manifestCompatibleScreens;
269
270
271
272
273
274 protected UsesSdk manifestUsesSdk;
275
276 private String parsedVersionName;
277 private Integer parsedVersionCode;
278 private boolean parsedVersionCodeAutoIncrement;
279 private String parsedApplicationIcon;
280 private String parsedApplicationLabel;
281 private String parsedApplicationTheme;
282 private Boolean parsedVersionCodeUpdateFromVersion;
283 private String parsedSharedUserId;
284 private Boolean parsedDebuggable;
285 private SupportsScreens parsedSupportsScreens;
286 private List<CompatibleScreen> parsedCompatibleScreens;
287 private Properties parsedProviderAuthorities;
288 private UsesSdk parsedUsesSdk;
289
290
291
292
293
294
295 public void execute() throws MojoExecutionException, MojoFailureException
296 {
297 if ( ! AndroidExtension.isAndroidPackaging( project.getPackaging() ) )
298 {
299 return;
300 }
301
302 if ( androidManifestFile == null )
303 {
304 return;
305 }
306
307 parseConfiguration();
308
309 getLog().info( "Attempting to update manifest " + androidManifestFile );
310 getLog().debug( " usesSdk=" + parsedUsesSdk );
311 getLog().debug( " versionName=" + parsedVersionName );
312 getLog().debug( " versionCode=" + parsedVersionCode );
313 getLog().debug( " versionCodeAutoIncrement=" + parsedVersionCodeAutoIncrement );
314 getLog().debug( " versionCodeUpdateFromVersion=" + parsedVersionCodeUpdateFromVersion );
315
316 getLog().debug( " applicationIcon=" + parsedApplicationIcon );
317 getLog().debug( " applicationLabel=" + parsedApplicationLabel );
318 getLog().debug( " applicationTheme=" + parsedApplicationTheme );
319
320 getLog().debug( " sharedUserId=" + parsedSharedUserId );
321 getLog().debug( " debuggable=" + parsedDebuggable );
322 getLog().debug( " providerAuthorities: " + parsedProviderAuthorities );
323 getLog().debug( " supports-screens: " + ( parsedSupportsScreens == null ? "not set" : "set" ) );
324 getLog().debug( " compatible-screens: " + ( parsedCompatibleScreens == null ? "not set" : "set" ) );
325
326 if ( ! androidManifestFile.exists() )
327 {
328 return;
329 }
330
331 try
332 {
333 updateManifest( androidManifestFile );
334 }
335 catch ( IOException e )
336 {
337 throw new MojoFailureException( "XML I/O error: " + androidManifestFile, e );
338 }
339 catch ( ParserConfigurationException e )
340 {
341 throw new MojoFailureException( "Unable to prepare XML parser", e );
342 }
343 catch ( SAXException e )
344 {
345 throw new MojoFailureException( "Unable to parse XML: " + androidManifestFile, e );
346 }
347 catch ( TransformerException e )
348 {
349 throw new MojoFailureException( "Unable write XML: " + androidManifestFile, e );
350 }
351 }
352
353 private void parseConfiguration()
354 {
355
356 if ( manifest != null )
357 {
358 if ( StringUtils.isNotEmpty( manifest.getVersionName() ) )
359 {
360 parsedVersionName = manifest.getVersionName();
361 }
362 else
363 {
364 parsedVersionName = manifestVersionName;
365 }
366 if ( manifest.getVersionCode() != null )
367 {
368 parsedVersionCode = manifest.getVersionCode();
369 }
370 else
371 {
372 parsedVersionCode = manifestVersionCode;
373 }
374 if ( manifest.getVersionCodeAutoIncrement() != null )
375 {
376 parsedVersionCodeAutoIncrement = manifest.getVersionCodeAutoIncrement();
377 }
378 else
379 {
380 parsedVersionCodeAutoIncrement = manifestVersionCodeAutoIncrement;
381 }
382 if ( manifest.getVersionCodeUpdateFromVersion() != null )
383 {
384 parsedVersionCodeUpdateFromVersion = manifest.getVersionCodeUpdateFromVersion();
385 }
386 else
387 {
388 parsedVersionCodeUpdateFromVersion = manifestVersionCodeUpdateFromVersion;
389 }
390
391 if ( StringUtils.isNotEmpty( manifest.getApplicationIcon() ) )
392 {
393 parsedApplicationIcon = manifest.getApplicationIcon();
394 }
395 else
396 {
397 parsedApplicationIcon = manifestApplicationIcon;
398 }
399
400 if ( StringUtils.isNotEmpty( manifest.getApplicationLabel() ) )
401 {
402 parsedApplicationLabel = manifest.getApplicationLabel();
403 }
404 else
405 {
406 parsedApplicationLabel = manifestApplicationLabel;
407 }
408
409 if ( StringUtils.isNotEmpty( manifest.getApplicationTheme() ) )
410 {
411 parsedApplicationTheme = manifest.getApplicationTheme();
412 }
413 else
414 {
415 parsedApplicationTheme = manifestApplicationTheme;
416 }
417
418
419 if ( StringUtils.isNotEmpty( manifest.getSharedUserId() ) )
420 {
421 parsedSharedUserId = manifest.getSharedUserId();
422 }
423 else
424 {
425 parsedSharedUserId = manifestSharedUserId;
426 }
427 if ( manifest.getDebuggable() != null )
428 {
429 parsedDebuggable = manifest.getDebuggable();
430 }
431 else
432 {
433 parsedDebuggable = manifestDebuggable;
434 }
435 if ( manifest.getSupportsScreens() != null )
436 {
437 parsedSupportsScreens = manifest.getSupportsScreens();
438 }
439 else
440 {
441 parsedSupportsScreens = manifestSupportsScreens;
442 }
443 if ( manifest.getCompatibleScreens() != null )
444 {
445 parsedCompatibleScreens = manifest.getCompatibleScreens();
446 }
447 else
448 {
449 parsedCompatibleScreens = manifestCompatibleScreens;
450 }
451 if ( manifest.getProviderAuthorities() != null )
452 {
453 parsedProviderAuthorities = manifest.getProviderAuthorities();
454 }
455 else
456 {
457 parsedProviderAuthorities = manifestProviderAuthorities;
458 }
459 if ( manifest.getUsesSdk() != null )
460 {
461 parsedUsesSdk = manifest.getUsesSdk();
462 }
463 else
464 {
465 parsedUsesSdk = manifestUsesSdk;
466 }
467 }
468 else
469 {
470 parsedVersionName = manifestVersionName;
471 parsedVersionCode = manifestVersionCode;
472 parsedVersionCodeAutoIncrement = manifestVersionCodeAutoIncrement;
473 parsedVersionCodeUpdateFromVersion = manifestVersionCodeUpdateFromVersion;
474 parsedApplicationIcon = manifestApplicationIcon;
475 parsedApplicationLabel = manifestApplicationLabel;
476 parsedApplicationTheme = manifestApplicationTheme;
477 parsedSharedUserId = manifestSharedUserId;
478 parsedDebuggable = manifestDebuggable;
479 parsedSupportsScreens = manifestSupportsScreens;
480 parsedCompatibleScreens = manifestCompatibleScreens;
481 parsedProviderAuthorities = manifestProviderAuthorities;
482 parsedUsesSdk = manifestUsesSdk;
483 }
484 }
485
486
487
488
489 private Document readManifest( File manifestFile ) throws IOException, ParserConfigurationException, SAXException
490 {
491 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
492 DocumentBuilder db = dbf.newDocumentBuilder();
493 Document doc = db.parse( manifestFile );
494 return doc;
495 }
496
497
498
499
500 private void writeManifest( File manifestFile, Document doc ) throws IOException, TransformerException
501 {
502 TransformerFactory xfactory = TransformerFactory.newInstance();
503 Transformer xformer = xfactory.newTransformer();
504 xformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );
505 Source source = new DOMSource( doc );
506
507 FileWriter writer = null;
508 try
509 {
510 writer = new FileWriter( manifestFile, false );
511 if ( doc.getXmlEncoding() != null && doc.getXmlVersion() != null )
512 {
513 String xmldecl = String
514 .format( "<?xml version=\"%s\" encoding=\"%s\"?>%n", doc.getXmlVersion(), doc.getXmlEncoding() );
515 writer.write( xmldecl );
516 }
517 Result result = new StreamResult( writer );
518
519 xformer.transform( source, result );
520 }
521 finally
522 {
523 IOUtils.closeQuietly( writer );
524 }
525 }
526
527
528
529
530
531
532
533
534
535
536 public void updateManifest( File manifestFile )
537 throws IOException, ParserConfigurationException, SAXException, TransformerException, MojoFailureException
538 {
539 Document doc = readManifest( manifestFile );
540 Element manifestElement = doc.getDocumentElement();
541 boolean dirty = false;
542
543 if ( StringUtils.isEmpty( parsedVersionName ) )
544 {
545 parsedVersionName = project.getVersion();
546 }
547 Attr versionNameAttrib = manifestElement.getAttributeNode( ATTR_VERSION_NAME );
548 if ( versionNameAttrib == null || ! StringUtils.equals( parsedVersionName, versionNameAttrib.getValue() ) )
549 {
550 getLog().info( "Setting " + ATTR_VERSION_NAME + " to " + parsedVersionName );
551 manifestElement.setAttribute( ATTR_VERSION_NAME, parsedVersionName );
552 dirty = true;
553 }
554 if ( ( parsedVersionCodeAutoIncrement && parsedVersionCode != null )
555 || ( parsedVersionCodeUpdateFromVersion && parsedVersionCode != null )
556 || ( parsedVersionCodeAutoIncrement && parsedVersionCodeUpdateFromVersion ) )
557 {
558 throw new MojoFailureException( "versionCodeAutoIncrement, versionCodeUpdateFromVersion and versionCode "
559 + "are mutual exclusive. They cannot be specified at the same time. Please specify either "
560 + "versionCodeAutoIncrement, versionCodeUpdateFromVersion or versionCode!" );
561 }
562 exportProperties();
563 if ( parsedVersionCodeAutoIncrement )
564 {
565 performVersioCodeAutoIncrement( manifestElement );
566 dirty = true;
567 }
568 if ( parsedVersionCodeUpdateFromVersion )
569 {
570 performVersionCodeUpdateFromVersion( manifestElement );
571 dirty = true;
572 }
573 if ( parsedVersionCode != null )
574 {
575 Attr versionCodeAttr = manifestElement.getAttributeNode( ATTR_VERSION_CODE );
576 int currentVersionCode = 0;
577 if ( versionCodeAttr != null )
578 {
579 currentVersionCode = NumberUtils.toInt( versionCodeAttr.getValue(), 0 );
580 }
581 if ( currentVersionCode != parsedVersionCode )
582 {
583 getLog().info( "Setting " + ATTR_VERSION_CODE + " to " + parsedVersionCode );
584 manifestElement.setAttribute( ATTR_VERSION_CODE, String.valueOf( parsedVersionCode ) );
585 dirty = true;
586 }
587 project.getProperties().setProperty( "android.manifest.versionCode", String.valueOf( parsedVersionCode ) );
588 }
589 if ( !StringUtils.isEmpty( parsedApplicationIcon ) )
590 {
591 dirty = updateApplicationAttribute( manifestElement, ATTR_APPLICATION_ICON, parsedApplicationIcon, dirty );
592 project.getProperties()
593 .setProperty( "android.manifest.applicationIcon", String.valueOf( parsedApplicationIcon ) );
594 }
595
596 if ( ! StringUtils.isEmpty( parsedApplicationLabel ) )
597 {
598 dirty =
599 updateApplicationAttribute( manifestElement, ATTR_APPLICATION_LABEL, parsedApplicationLabel, dirty );
600 project.getProperties()
601 .setProperty( "android.manifest.applicationLabel", String.valueOf( parsedApplicationLabel ) );
602 }
603
604 if ( ! StringUtils.isEmpty( parsedApplicationTheme ) )
605 {
606 dirty =
607 updateApplicationAttribute( manifestElement, ATTR_APPLICATION_THEME, parsedApplicationTheme, dirty );
608 project.getProperties()
609 .setProperty( "android.manifest.applicationTheme", String.valueOf( parsedApplicationTheme ) );
610 }
611
612 if ( ! StringUtils.isEmpty( parsedSharedUserId ) )
613 {
614 Attr sharedUserIdAttrib = manifestElement.getAttributeNode( ATTR_SHARED_USER_ID );
615
616 if ( sharedUserIdAttrib == null || ! StringUtils
617 .equals( parsedSharedUserId, sharedUserIdAttrib.getValue() ) )
618 {
619 getLog().info( "Setting " + ATTR_SHARED_USER_ID + " to " + parsedSharedUserId );
620 manifestElement.setAttribute( ATTR_SHARED_USER_ID, parsedSharedUserId );
621 dirty = true;
622 }
623 }
624
625 if ( parsedDebuggable != null )
626 {
627 NodeList appElems = manifestElement.getElementsByTagName( ELEM_APPLICATION );
628
629
630 for ( int i = 0; i < appElems.getLength(); ++ i )
631 {
632 Node node = appElems.item( i );
633 getLog().info( "Testing if node " + node.getNodeName() + " is application" );
634 if ( node.getNodeType() == Node.ELEMENT_NODE )
635 {
636 Element element = ( Element ) node;
637 Attr debuggableAttrib = element.getAttributeNode( ATTR_DEBUGGABLE );
638 if ( debuggableAttrib == null || parsedDebuggable != BooleanUtils
639 .toBoolean( debuggableAttrib.getValue() ) )
640 {
641 getLog().info( "Setting " + ATTR_DEBUGGABLE + " to " + parsedDebuggable );
642 element.setAttribute( ATTR_DEBUGGABLE, String.valueOf( parsedDebuggable ) );
643 dirty = true;
644 }
645 }
646 }
647 }
648
649 if ( parsedSupportsScreens != null )
650 {
651 boolean madeDirty = performSupportScreenModification( doc, manifestElement );
652 if ( madeDirty )
653 {
654 dirty = true;
655 }
656 }
657
658 if ( parsedCompatibleScreens != null )
659 {
660 getLog().info( "Setting " + ELEM_COMPATIBLE_SCREENS );
661 updateCompatibleScreens( doc, manifestElement );
662 dirty = true;
663 }
664
665 dirty = processProviderAuthorities( manifestElement, dirty );
666
667 dirty = processUsesSdk( doc, manifestElement, dirty );
668
669 if ( dirty )
670 {
671 if ( ! manifestFile.delete() )
672 {
673 getLog().warn( "Could not remove old " + manifestFile );
674 }
675 getLog().info( "Made changes to manifest file, updating " + manifestFile );
676 writeManifest( manifestFile, doc );
677 }
678 else
679 {
680 getLog().info( "No changes found to write to manifest file" );
681 }
682 }
683
684 private boolean processProviderAuthorities( Element manifestElement, boolean dirty )
685 {
686 if ( parsedProviderAuthorities != null )
687 {
688 boolean madeDirty = updateProviderAuthorities( manifestElement );
689 if ( madeDirty )
690 {
691 dirty = true;
692 }
693 }
694 return dirty;
695 }
696
697 private boolean processUsesSdk( Document doc, Element manifestElement, boolean dirty )
698 {
699 if ( parsedUsesSdk != null )
700 {
701 boolean madeDirty = performUsesSdkModification( doc, manifestElement );
702 if ( madeDirty )
703 {
704 dirty = true;
705 }
706 }
707 return dirty;
708 }
709
710 private boolean updateApplicationAttribute( Element manifestElement,
711 String attribute, String value, boolean dirty )
712 {
713 NodeList appElements =
714 manifestElement.getElementsByTagName( ELEM_APPLICATION );
715
716
717 for ( int i = 0; i < appElements.getLength(); ++i )
718 {
719 Node node = appElements.item( i );
720 getLog().info( "Testing if node " + node.getNodeName()
721 + " is application" );
722 if ( node.getNodeType() == Node.ELEMENT_NODE )
723 {
724 Element element = (Element) node;
725 Attr labelAttrib = element.getAttributeNode( attribute );
726 if ( labelAttrib == null
727 || !value.equals( labelAttrib.getValue() ) )
728 {
729 getLog().info( "Setting " + attribute + " to " + value );
730 element.setAttribute( attribute, String.valueOf( value ) );
731 dirty = true;
732 }
733 }
734 }
735 return dirty;
736 }
737
738
739
740
741 private void exportProperties()
742 {
743 project.getProperties().setProperty( "android.manifest.versionName", parsedVersionName );
744 project.getProperties().setProperty( "android.manifest.versionCodeAutoIncrement",
745 String.valueOf( parsedVersionCodeAutoIncrement ) );
746 project.getProperties().setProperty( "android.manifest.versionCodeUpdateFromVersion",
747 String.valueOf( parsedVersionCodeUpdateFromVersion ) );
748 project.getProperties().setProperty( "android.manifest.debuggable", String.valueOf( parsedDebuggable ) );
749 if ( parsedSharedUserId != null )
750 {
751 project.getProperties().setProperty( "android.manifest.sharedUserId", parsedSharedUserId );
752 }
753 }
754
755 private void performVersioCodeAutoIncrement( Element manifestElement )
756 {
757 Attr versionCode = manifestElement.getAttributeNode( ATTR_VERSION_CODE );
758 int currentVersionCode = 0;
759 if ( versionCode != null )
760 {
761 currentVersionCode = NumberUtils.toInt( versionCode.getValue(), 0 );
762 }
763 currentVersionCode++;
764 manifestElement.setAttribute( ATTR_VERSION_CODE, String.valueOf( currentVersionCode ) );
765 project.getProperties().setProperty( "android.manifest.versionCode", String.valueOf( currentVersionCode ) );
766 }
767
768
769
770
771
772
773
774
775 private void performVersionCodeUpdateFromVersion( Element manifestElement )
776 {
777 String verString = project.getVersion();
778 getLog().debug( "Generating versionCode for " + verString );
779 ArtifactVersion artifactVersion = new DefaultArtifactVersion( verString );
780 String verCode;
781 if ( artifactVersion.getMajorVersion() < 1 && artifactVersion.getMinorVersion() < 1
782 && artifactVersion.getIncrementalVersion() < 1 )
783 {
784 getLog().warn( "Problem parsing version number occurred. Using fall back to determine version code. " );
785
786 verCode = verString.replaceAll( "\\D", "" );
787
788 Attr versionCodeAttr = manifestElement.getAttributeNode( ATTR_VERSION_CODE );
789 int currentVersionCode = 0;
790 if ( versionCodeAttr != null )
791 {
792 currentVersionCode = NumberUtils.toInt( versionCodeAttr.getValue(), 0 );
793 }
794
795 if ( Integer.parseInt( verCode ) < currentVersionCode )
796 {
797 getLog().info( verCode + " < " + currentVersionCode + " so padding versionCode" );
798 verCode = StringUtils.rightPad( verCode, versionCodeAttr.getValue().length(), "0" );
799 }
800 }
801 else
802 {
803 verCode = Integer.toString( artifactVersion.getMajorVersion() * MAJOR_VERSION_POSITION
804 + artifactVersion.getMinorVersion() * MINOR_VERSION_POSITION
805 + artifactVersion.getIncrementalVersion() * INCREMENTAL_VERSION_POSITION );
806 }
807 getLog().info( "Setting " + ATTR_VERSION_CODE + " to " + verCode );
808 manifestElement.setAttribute( ATTR_VERSION_CODE, verCode );
809 project.getProperties().setProperty( "android.manifest.versionCode", String.valueOf( verCode ) );
810 }
811
812 private boolean performSupportScreenModification( Document doc, Element manifestElement )
813 {
814 boolean dirty = false;
815 Element supportsScreensElem = XmlHelper.getOrCreateElement( doc, manifestElement,
816 ELEM_SUPPORTS_SCREENS );
817
818 getLog().info( "Setting " + ELEM_SUPPORTS_SCREENS );
819
820 if ( parsedSupportsScreens.getAnyDensity() != null )
821 {
822 supportsScreensElem.setAttribute( ATTR_ANY_DENSITY, parsedSupportsScreens.getAnyDensity() );
823 dirty = true;
824 }
825 if ( parsedSupportsScreens.getSmallScreens() != null )
826 {
827 supportsScreensElem.setAttribute( ATTR_SMALL_SCREENS, parsedSupportsScreens.getSmallScreens() );
828 dirty = true;
829 }
830 if ( parsedSupportsScreens.getNormalScreens() != null )
831 {
832 supportsScreensElem.setAttribute( ATTR_NORMAL_SCREENS, parsedSupportsScreens.getNormalScreens() );
833 dirty = true;
834 }
835 if ( parsedSupportsScreens.getLargeScreens() != null )
836 {
837 supportsScreensElem.setAttribute( ATTR_LARGE_SCREENS, parsedSupportsScreens.getLargeScreens() );
838 dirty = true;
839 }
840 if ( parsedSupportsScreens.getXlargeScreens() != null )
841 {
842 supportsScreensElem.setAttribute( ATTR_XLARGE_SCREENS, parsedSupportsScreens.getXlargeScreens() );
843 dirty = true;
844 }
845 if ( parsedSupportsScreens.getCompatibleWidthLimitDp() != null )
846 {
847 supportsScreensElem.setAttribute( ATTR_COMPATIBLE_WIDTH_LIMIT_DP,
848 parsedSupportsScreens.getCompatibleWidthLimitDp() );
849 dirty = true;
850 }
851 if ( parsedSupportsScreens.getLargestWidthLimitDp() != null )
852 {
853 supportsScreensElem
854 .setAttribute( ATTR_LARGEST_WIDTH_LIMIT_DP, parsedSupportsScreens.getLargestWidthLimitDp() );
855 dirty = true;
856 }
857 if ( parsedSupportsScreens.getRequiresSmallestWidthDp() != null )
858 {
859 supportsScreensElem.setAttribute( ATTR_REQUIRES_SMALLEST_WIDTH_DP,
860 parsedSupportsScreens.getRequiresSmallestWidthDp() );
861 dirty = true;
862 }
863 if ( parsedSupportsScreens.getResizeable() != null )
864 {
865 supportsScreensElem.setAttribute( ATTR_RESIZEABLE, parsedSupportsScreens.getResizeable() );
866 dirty = true;
867 }
868 return dirty;
869 }
870
871 private boolean performUsesSdkModification ( Document doc, Element manifestElement )
872 {
873 boolean dirty = false;
874 Element usesSdkElem = XmlHelper.getOrCreateElement( doc, manifestElement,
875 ELEM_USES_SDK );
876
877 if ( parsedUsesSdk.getMinSdkVersion() != null )
878 {
879 usesSdkElem.setAttribute( ATTR_MIN_SDK_VERSION, parsedUsesSdk.getMinSdkVersion() );
880 dirty = true;
881 }
882 if ( parsedUsesSdk.getMaxSdkVersion() != null )
883 {
884 usesSdkElem.setAttribute( ATTR_MAX_SDK_VERSION, parsedUsesSdk.getMaxSdkVersion() );
885 dirty = true;
886 }
887 if ( parsedUsesSdk.getTargetSdkVersion() != null )
888 {
889 usesSdkElem.setAttribute( ATTR_TARGET_SDK_VERSION, parsedUsesSdk.getTargetSdkVersion() );
890 dirty = true;
891 }
892
893 return dirty;
894 }
895
896 private void updateCompatibleScreens( Document doc, Element manifestElement )
897 {
898 Element compatibleScreensElem = XmlHelper.getOrCreateElement( doc, manifestElement, ELEM_COMPATIBLE_SCREENS );
899
900
901 NodeList manifestScreenElems = compatibleScreensElem.getElementsByTagName( ELEM_SCREEN );
902 int numManifestScreens = manifestScreenElems.getLength();
903 ArrayList<CompatibleScreen> manifestScreens = new ArrayList<CompatibleScreen>( numManifestScreens );
904 for ( int i = 0; i < numManifestScreens; i++ )
905 {
906 Element screenElem = ( Element ) manifestScreenElems.item( i );
907
908 CompatibleScreen screen = new CompatibleScreen();
909 screen.setScreenDensity( screenElem.getAttribute( ATTR_SCREEN_DENSITY ) );
910 screen.setScreenSize( screenElem.getAttribute( ATTR_SCREEN_SIZE ) );
911
912 manifestScreens.add( screen );
913 getLog().debug( "Found Manifest compatible-screen: " + screen );
914 }
915
916
917 XmlHelper.removeDirectChildren( compatibleScreensElem );
918
919 for ( CompatibleScreen screen : parsedCompatibleScreens )
920 {
921 getLog().debug( "Found POM compatible-screen: " + screen );
922 }
923
924
925
926 HashSet<CompatibleScreen> mergedScreens = new HashSet<CompatibleScreen>();
927 mergedScreens.addAll( manifestScreens );
928 mergedScreens.addAll( parsedCompatibleScreens );
929
930 for ( CompatibleScreen screen : mergedScreens )
931 {
932 getLog().debug( "Using compatible-screen: " + screen );
933 Element screenElem = doc.createElement( ELEM_SCREEN );
934 screenElem.setAttribute( ATTR_SCREEN_SIZE, screen.getScreenSize() );
935 screenElem.setAttribute( ATTR_SCREEN_DENSITY, screen.getScreenDensity() );
936
937 compatibleScreensElem.appendChild( screenElem );
938 }
939 }
940
941 private boolean updateProviderAuthorities( Element manifestElement )
942 {
943 boolean dirty = false;
944 NodeList appElems = manifestElement.getElementsByTagName( ELEM_APPLICATION );
945
946
947 for ( int i = 0; i < appElems.getLength(); ++ i )
948 {
949 Node node = appElems.item( i );
950 if ( node.getNodeType() == Node.ELEMENT_NODE )
951 {
952 NodeList providerElems = manifestElement.getElementsByTagName( ELEM_PROVIDER );
953 for ( int j = 0; j < providerElems.getLength(); ++ j )
954 {
955 Node providerNode = providerElems.item( j );
956 if ( providerNode.getNodeType() == Node.ELEMENT_NODE )
957 {
958 Element providerElem = (Element) providerNode;
959 Attr providerName = providerElem.getAttributeNode( ATTR_NAME );
960 getLog().debug( "Checking provider " + providerName.getValue() );
961 if ( shouldPerformProviderUpdate( providerName ) )
962 {
963 dirty = true;
964 String name = providerName.getValue();
965 String newAuthorities = parsedProviderAuthorities.getProperty( name );
966 getLog().info( "Updating provider " + name + " authorities attr to " + newAuthorities );
967 performProviderUpdate( providerElem, newAuthorities );
968 }
969 }
970 }
971 }
972 }
973
974 return dirty;
975 }
976
977 private boolean shouldPerformProviderUpdate( Attr providerName )
978 {
979 if ( providerName == null )
980 {
981 return false;
982 }
983
984 for ( String propName: parsedProviderAuthorities.stringPropertyNames() )
985 {
986 if ( propName.equals( providerName.getValue() ) )
987 {
988 return true;
989 }
990 }
991 return false;
992 }
993
994 private void performProviderUpdate( Element providerElem, String newAuthorities )
995 {
996 Attr providerAuthorities = providerElem.getAttributeNode( ATTR_AUTHORITIES );
997 providerAuthorities.setValue( newAuthorities );
998 }
999
1000 }