2626import com .reandroid .utils .StringsUtil ;
2727import com .reandroid .utils .collection .ArrayCollection ;
2828import com .reandroid .utils .collection .CollectionUtil ;
29- import com .reandroid .utils .collection .CombiningIterator ;
3029import com .reandroid .utils .collection .ComputeIterator ;
3130import com .reandroid .xml .XMLPath ;
3231
@@ -53,17 +52,33 @@ public ResXmlElement getOrCreateNamedElement(XMLPath xmlPath, String value) {
5352 element = newChildElement (xmlPath );
5453 element .getOrCreateAndroidAttribute (NAME_name , ID_name )
5554 .setValueAsString (value );
55+ ensureAboveApplication (element );
5656 }
5757 return element ;
5858 }
59- public ResXmlElement getNamedElement (XMLPath xmlPath , String value ) {
60- Iterator <ResXmlElement > iterator = xmlPath .find (this );
61- while (iterator .hasNext ()) {
62- ResXmlElement element = iterator .next ();
63- if (value .equals (getAndroidNameValue (element ))) {
64- return element ;
59+ private void ensureAboveApplication (ResXmlElement element ) {
60+ String tag = element .getName ();
61+ ResXmlElement parent = element .getParentElement ();
62+ if (parent != null && !element .equalsName (TAG_application ) && parent .equalsName (TAG_manifest )) {
63+ int i = parent .lastIndexOf (tag );
64+ if (i < 0 ) {
65+ i = parent .lastIndexOf (TAG_application );
66+ } else if (i == element .getIndex ()) {
67+ return ;
68+ }
69+ if (i >= 0 ) {
70+ parent .moveTo (element , i );
6571 }
6672 }
73+ }
74+ public ResXmlElement getNamedElement (XMLPath xmlPath , String value ) {
75+ ResXmlAttribute attribute = xmlPath .attribute (ID_name )
76+ .value (value )
77+ .alternateValue (value .startsWith ("." ) ? fullClassName (value ) : relativeClassName (value ))
78+ .findFirst (this );
79+ if (attribute != null ) {
80+ return attribute .getParentElement ();
81+ }
6782 return null ;
6883 }
6984 public ApkFile .ApkType guessApkType () {
@@ -129,57 +144,37 @@ public void setSplit(String split, boolean forceCreate) {
129144 }
130145
131146 /**
132- * Returns "include" value from split manifest
133- *
147+ * Returns "include" value from split module/fusing
134148 * e.g.
135149 * <dist:module type="asset-pack">
136150 * <dist:fusing include="true" />
137151 * </dist:module>
138152 */
139153 public boolean isFusingInclude () {
140- ResXmlElement manifestElement = getManifestElement ();
141- if (manifestElement != null ) {
142- Iterator <ResXmlElement > modules = manifestElement .getElements ("module" );
143- while (modules .hasNext ()) {
144- Iterator <ResXmlElement > iterator = modules .next ().getElements ("fusing" );
145- while (iterator .hasNext ()) {
146- ResXmlAttribute attribute = iterator .next ()
147- .searchAttributeByName ("include" );
148- if (attribute != null && attribute .getValueType () == ValueType .BOOLEAN ) {
149- return attribute .getValueAsBoolean ();
150- }
151- }
152- }
154+ ResXmlAttribute attribute = PATH_MANIFEST .parse ("/module/fusing;include=true" )
155+ .findFirst (this );
156+ if (attribute != null && attribute .getValueType () == ValueType .BOOLEAN ) {
157+ return attribute .getValueAsBoolean ();
153158 }
154159 return false ;
155160 }
156161 public String [] getFusedModuleNames () {
157- ResXmlElement applicationElement = getApplicationElement ();
158- if (applicationElement != null ) {
159- ResXmlElement metaData = CollectionUtil .getFirst (
160- applicationElement .getElements (PREDICATE_FUSED_MODULES ));
161- if (metaData != null ) {
162- ResXmlAttribute attribute = metaData .searchAttributeByResourceId (ID_value );
163- if (attribute != null && attribute .getValueType () == ValueType .STRING ) {
164- return StringsUtil .split (attribute .getValueAsString (), ',' );
165- }
166- }
162+ ResXmlAttribute attribute = PATH_APPLICATION_META_DATA_NAME
163+ .value (VALUE_com_android_dynamic_apk_fused_modules )
164+ .findFirst (this );
165+ if (attribute != null && attribute .getValueType () == ValueType .STRING ) {
166+ return StringsUtil .split (attribute .getValueAsString (), ',' );
167167 }
168168 return null ;
169169 }
170170 public void addFusedModuleNames (String ... names ) {
171171 if (names == null || names .length == 0 ) {
172172 return ;
173173 }
174- ResXmlElement applicationElement = getOrCreateApplicationElement ();
175- ResXmlElement metaData = CollectionUtil .getFirst (
176- applicationElement .getElements (PREDICATE_FUSED_MODULES ));
177- if (metaData == null ) {
178- metaData = applicationElement .newElement (TAG_meta_data );
179- metaData .getOrCreateAndroidAttribute (NAME_name , ID_name )
180- .setValueAsString (VALUE_com_android_dynamic_apk_fused_modules );
181- }
182- ResXmlAttribute attribute = metaData .getOrCreateAndroidAttribute (NAME_value , ID_value );
174+ ResXmlAttribute attribute = getOrCreateNamedElement (PATH_APPLICATION_META_DATA ,
175+ VALUE_com_android_dynamic_apk_fused_modules )
176+ .getOrCreateAndroidAttribute (NAME_value , ID_value );
177+
183178 ArrayCollection <String > nameList = new ArrayCollection <>();
184179 String value = attribute .getValueAsString ();
185180 if (value != null ) {
@@ -193,11 +188,9 @@ public void addFusedModuleNames(String ... names) {
193188 attribute .setValueAsString (StringsUtil .join (nameList , ',' ));
194189 }
195190 public boolean clearFusedModuleNames () {
196- ResXmlElement applicationElement = getApplicationElement ();
197- if (applicationElement != null ) {
198- return applicationElement .removeElementsIf (PREDICATE_FUSED_MODULES );
199- }
200- return false ;
191+ return removeElements (PATH_APPLICATION_META_DATA_NAME
192+ .attribute (ID_name )
193+ .value (VALUE_com_android_dynamic_apk_fused_modules ));
201194 }
202195 // TODO: find a better way
203196 public int guessCurrentPackageId () {
@@ -343,39 +336,39 @@ public void setDebuggable(boolean debuggable) {
343336 }
344337 }
345338 public ResXmlElement getMainActivity () {
346- Iterator <ResXmlElement > iterator = getActivities (true );
347- while (iterator .hasNext ()) {
348- ResXmlElement activity = iterator .next ();
349- Iterator <ResXmlElement > actions = activity
350- .getElementsWithChild (TAG_intent_filter , TAG_action );
351- while (actions .hasNext ()) {
352- ResXmlElement action = actions .next ();
353- ResXmlAttribute attribute = action .searchAttributeByResourceId (ID_name );
354- if (attribute == null ) {
355- continue ;
356- }
357- if (VALUE_android_intent_action_MAIN .equals (attribute .getValueAsString ())) {
358- return activity ;
359- }
360- }
339+ ResXmlElement element = getNamedElement (
340+ PATH_APPLICATION .element (TAG_activity ).alternate (TAG_activity_alias )
341+ .element (TAG_intent_filter )
342+ .element (TAG_action ),
343+ VALUE_android_intent_action_MAIN );
344+ if (element != null ) {
345+ return element .getParentElement ().getParentElement ();
361346 }
362347 return null ;
363348 }
364349 public ResXmlElement getOrCreateMainActivity (String name ) {
365350 ResXmlElement activity = getMainActivity ();
366351 if (activity == null ) {
367- ResXmlElement application = getOrCreateApplicationElement ();
368- activity = application .newElementAt (0 , TAG_activity );
369- ResXmlElement intentFilter = activity .newElement (TAG_intent_filter );
370- ResXmlElement action = intentFilter .newElement (TAG_action );
371- ResXmlAttribute attribute = action .getOrCreateAndroidAttribute (NAME_name , ID_name );
372- attribute .setValueAsString (VALUE_android_intent_action_MAIN );
373- ResXmlElement category = intentFilter .newElement (TAG_category );
374- attribute = category .getOrCreateAndroidAttribute (NAME_name , ID_name );
375- attribute .setValueAsString ("android.intent.category.DEFAULT" );
376- category = intentFilter .newElement (TAG_category );
377- attribute = category .getOrCreateAndroidAttribute (NAME_name , ID_name );
378- attribute .setValueAsString ("android.intent.category.LAUNCHER" );
352+ ResXmlElement action = newChildElement (
353+ PATH_APPLICATION .element (TAG_activity )
354+ .element (TAG_intent_filter )
355+ .element (TAG_action ));
356+ action .getOrCreateAndroidAttribute (NAME_name , ID_name )
357+ .setValueAsString (VALUE_android_intent_action_MAIN );
358+
359+ ResXmlElement intentFilter = action .getParentElement ();
360+
361+ intentFilter .newElement (TAG_category )
362+ .getOrCreateAndroidAttribute (NAME_name , ID_name )
363+ .setValueAsString ("android.intent.category.DEFAULT" );
364+ intentFilter .newElement (TAG_category )
365+ .getOrCreateAndroidAttribute (NAME_name , ID_name )
366+ .setValueAsString ("android.intent.category.LAUNCHER" );
367+
368+ activity = intentFilter .getParentElement ();
369+
370+ activity .getOrCreateAndroidAttribute (NAME_exported , ID_exported )
371+ .setValueAsBoolean (true );
379372 }
380373 ResXmlAttribute attribute = activity .getOrCreateAndroidAttribute (NAME_name , ID_name );
381374 attribute .setValueAsString (name );
@@ -395,10 +388,10 @@ public ResXmlElement getOrCreateActivity(String name, boolean activityAlias) {
395388 }
396389 public ResXmlElement getActivity (String name , boolean activityAlias ) {
397390 name = fullClassName (name );
398- Iterator <ResXmlElement > iterator = getActivities (true );
391+ Iterator <ResXmlElement > iterator = getActivities (activityAlias );
399392 while (iterator .hasNext ()) {
400393 ResXmlElement element = iterator .next ();
401- if (ObjectsUtil .equals (name , getAndroidNameValue (element ))) {
394+ if (ObjectsUtil .equals (name , fullClassName ( getAndroidNameValue (element ) ))) {
402395 return element ;
403396 }
404397 }
@@ -410,64 +403,27 @@ public List<ResXmlElement> listActivities() {
410403 results .addAll (getActivities (true ));
411404 return results ;
412405 }
413- @ Deprecated
414- public List <ResXmlElement > listActivities (boolean includeActivityAlias ) {
415- ArrayCollection <ResXmlElement > results = new ArrayCollection <>();
416- results .addAll (getActivities (includeActivityAlias ));
417- return results ;
418- }
419406 public Iterator <ResXmlElement > getActivities (boolean includeAlias ) {
420- Iterator <ResXmlElement > iterator = getElementsWithChild (
421- TAG_manifest ,
422- TAG_application ,
423- TAG_activity );
424- if (!includeAlias ) {
425- return iterator ;
426- }
427- return CombiningIterator .two (iterator , getElementsWithChild (
428- TAG_manifest ,
429- TAG_application ,
430- TAG_activity_alias ));
407+ XMLPath xmlPath = PATH_APPLICATION .element (TAG_activity );
408+ if (includeAlias ) {
409+ xmlPath = xmlPath .alternate (TAG_activity_alias );
410+ }
411+ return xmlPath .find (this );
431412 }
432413 public List <ResXmlElement > listApplicationElementsByTag (String tag ) {
433- return CollectionUtil .toList (getApplicationElementsByTag (tag ));
434- }
435- public Iterator <ResXmlElement > getApplicationElementsByTag (String tag ) {
436- return getElementsWithChild (TAG_manifest , TAG_application , tag );
414+ return PATH_APPLICATION .element (tag ).list (this );
437415 }
438416 public List <String > getUsesPermissions () {
439- Iterator <String > iterator = ComputeIterator .of (
440- getElementsWithChild (TAG_manifest , TAG_uses_permission ),
441- AndroidManifestBlock ::getAndroidNameValue
442- );
443- return CollectionUtil .toList (iterator );
417+ Iterator <ResXmlAttribute > iterator = PATH_MANIFEST .element (TAG_uses_permission )
418+ .attribute (ID_name )
419+ .find (this );
420+ return CollectionUtil .toList (ComputeIterator .of (iterator , ResXmlAttribute ::getValueAsString ));
444421 }
445422 public ResXmlElement getUsesPermission (String permissionName ) {
446- Iterator <ResXmlElement > iterator = getElementsWithChild (TAG_manifest , TAG_uses_permission );
447- while (iterator .hasNext ()) {
448- ResXmlElement element = iterator .next ();
449- if (ObjectsUtil .equals (permissionName , getAndroidNameValue (element ))) {
450- return element ;
451- }
452- }
453- return null ;
423+ return getNamedElement (PATH_MANIFEST .element (TAG_uses_permission ), permissionName );
454424 }
455425 public ResXmlElement addUsesPermission (String permissionName ) {
456- ResXmlElement manifestElement = getManifestElement ();
457- if (manifestElement == null ) {
458- return null ;
459- }
460- ResXmlElement exist = getUsesPermission (permissionName );
461- if (exist != null ) {
462- return exist ;
463- }
464- int i = manifestElement .lastIndexOf (TAG_uses_permission );
465- i ++;
466- ResXmlElement result = manifestElement .newElement (TAG_uses_permission );
467- ResXmlAttribute attr = result .getOrCreateAndroidAttribute (AndroidManifest .NAME_name , ID_name );
468- attr .setValueAsString (permissionName );
469- manifestElement .moveTo (result , i );
470- return result ;
426+ return getOrCreateNamedElement (PATH_MANIFEST .element (TAG_uses_permission ), permissionName );
471427 }
472428 @ Override
473429 public String getPackageName () {
@@ -490,13 +446,11 @@ public void setPackageName(String packageName) {
490446 }
491447 @ Override
492448 public String getApplicationClassName () {
493- ResXmlElement applicationElement = getApplicationElement ();
494- if (applicationElement != null ) {
495- ResXmlAttribute attribute = applicationElement
496- .searchAttributeByResourceId (ID_name );
497- if (attribute != null ) {
498- return fullClassName (attribute .getValueAsString ());
499- }
449+ ResXmlAttribute attribute = PATH_APPLICATION
450+ .attribute (ID_name )
451+ .findFirst (this );
452+ if (attribute != null ) {
453+ return fullClassName (attribute .getValueAsString ());
500454 }
501455 return null ;
502456 }
@@ -735,6 +689,20 @@ public String fullClassName(String name) {
735689 }
736690 return packageName + name ;
737691 }
692+ public String relativeClassName (String name ) {
693+ if (name == null || name .length () == 0 || name .charAt (0 ) == '.' ) {
694+ return name ;
695+ }
696+ String packageName = getPackageName ();
697+ if (packageName == null || !name .startsWith (packageName )) {
698+ return name ;
699+ }
700+ int i = packageName .length ();
701+ if (name .length () == i || name .charAt (i ) != '.' ) {
702+ return name ;
703+ }
704+ return name .substring (i );
705+ }
738706 private ResXmlElement getOrCreateManifestElement () {
739707 return getOrCreateElement (AndroidManifest .TAG_manifest );
740708 }
0 commit comments