diff options
author | Xavier Ducrohet <xav@android.com> | 2012-04-23 17:47:06 -0700 |
---|---|---|
committer | android code review <noreply-gerritcodereview@google.com> | 2012-04-23 17:47:06 -0700 |
commit | 57dc74c376c4456eb669523b68e3af4309209a86 (patch) | |
tree | 3625c79d21a4efcbe99da9f35bd29202ca5965a1 | |
parent | cf57e9d328bed8fb9d41f8b08ab247dd282d0056 (diff) | |
parent | e6ec57d99bfda23f18ec7ec27022c5321b7368e5 (diff) | |
download | sdk-57dc74c376c4456eb669523b68e3af4309209a86.zip sdk-57dc74c376c4456eb669523b68e3af4309209a86.tar.gz sdk-57dc74c376c4456eb669523b68e3af4309209a86.tar.bz2 |
Merge changes I4f89b469,I33b49c9f,I425e7b75
* changes:
Revert the disable flag of the manifest merger to be enable instead.
Minor fixes in Ant.
Manifest merger in Ant build.
-rw-r--r-- | anttasks/.classpath | 1 | ||||
-rw-r--r-- | anttasks/Android.mk | 1 | ||||
-rw-r--r-- | anttasks/etc/manifest.txt | 2 | ||||
-rw-r--r-- | anttasks/src/anttasks.properties | 19 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/ComputeDependencyTask.java | 21 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/ManifestMergerTask.java | 143 | ||||
-rw-r--r-- | anttasks/src/com/android/ant/SingleDependencyTask.java | 2 | ||||
-rw-r--r-- | build/tools.atree | 3 | ||||
-rw-r--r-- | files/ant/build.xml | 170 | ||||
-rw-r--r-- | testapps/testProjectTest/app/AndroidManifest.xml | 9 | ||||
-rw-r--r-- | testapps/testProjectTest/lib/AndroidManifest.xml | 11 | ||||
-rw-r--r-- | testapps/testProjectTest/lib/res/values/strings.xml | 6 | ||||
-rw-r--r-- | testapps/testProjectTest/testlib/AndroidManifest.xml | 11 |
13 files changed, 261 insertions, 138 deletions
diff --git a/anttasks/.classpath b/anttasks/.classpath index b936073..283606e 100644 --- a/anttasks/.classpath +++ b/anttasks/.classpath @@ -5,5 +5,6 @@ <classpathentry combineaccessrules="false" kind="src" path="/SdkLib"/> <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/ant/ant.jar"/> <classpathentry combineaccessrules="false" kind="src" path="/common"/> + <classpathentry combineaccessrules="false" kind="src" path="/ManifestMerger"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/anttasks/Android.mk b/anttasks/Android.mk index e75a7cd..5139400 100644 --- a/anttasks/Android.mk +++ b/anttasks/Android.mk @@ -23,6 +23,7 @@ LOCAL_JAR_MANIFEST := etc/manifest.txt LOCAL_JAVA_LIBRARIES := \ sdklib \ + manifmerger \ ant LOCAL_MODULE := anttasks diff --git a/anttasks/etc/manifest.txt b/anttasks/etc/manifest.txt index 257f2aa..9118df7 100644 --- a/anttasks/etc/manifest.txt +++ b/anttasks/etc/manifest.txt @@ -1 +1 @@ -Class-Path: common.jar sdklib.jar +Class-Path: common.jar sdklib.jar manifmerger.jar diff --git a/anttasks/src/anttasks.properties b/anttasks/src/anttasks.properties new file mode 100644 index 0000000..446bbe1 --- /dev/null +++ b/anttasks/src/anttasks.properties @@ -0,0 +1,19 @@ +checkenv: com.android.ant.CheckEnvTask +gettype: com.android.ant.GetTypeTask +gettarget: com.android.ant.GetTargetTask +getlibs: com.android.ant.GetLibraryListTask +dependency: com.android.ant.ComputeDependencyTask +testedprojectclasspath: com.android.ant.ComputeProjectClasspathTask +getemmafilter: com.android.ant.GetEmmaFilterTask +mergemanifest: com.android.ant.ManifestMergerTask +aapt: com.android.ant.AaptExecTask +aidl: com.android.ant.AidlExecTask +renderscript: com.android.ant.RenderScriptTask +buildconfig: com.android.ant.BuildConfigTask +dex: com.android.ant.DexExecTask +apkbuilder: com.android.ant.ApkBuilderTask +signapk: com.android.ant.SignApkTask +zipalign: com.android.ant.ZipAlignTask +xpath: com.android.ant.XPathTask +if: com.android.ant.IfElseTask +propertybyreplace: com.android.ant.PropertyByReplaceTask diff --git a/anttasks/src/com/android/ant/ComputeDependencyTask.java b/anttasks/src/com/android/ant/ComputeDependencyTask.java index 17b68d6..62d5917 100644 --- a/anttasks/src/com/android/ant/ComputeDependencyTask.java +++ b/anttasks/src/com/android/ant/ComputeDependencyTask.java @@ -53,6 +53,7 @@ import java.util.List; */ public class ComputeDependencyTask extends GetLibraryListTask { + private String mLibraryManifestFilePathOut; private String mLibraryResFolderPathOut; private String mLibraryPackagesOut; private String mJarLibraryPathOut; @@ -60,6 +61,10 @@ public class ComputeDependencyTask extends GetLibraryListTask { private int mTargetApi = -1; private boolean mVerbose = false; + public void setLibraryManifestFilePathOut(String libraryManifestFilePathOut) { + mLibraryManifestFilePathOut = libraryManifestFilePathOut; + } + public void setLibraryResFolderPathOut(String libraryResFolderPathOut) { mLibraryResFolderPathOut = libraryResFolderPathOut; } @@ -90,6 +95,9 @@ public class ComputeDependencyTask extends GetLibraryListTask { @Override public void execute() throws BuildException { + if (mLibraryManifestFilePathOut == null) { + throw new BuildException("Missing attribute libraryManifestFilePathOut"); + } if (mLibraryResFolderPathOut == null) { throw new BuildException("Missing attribute libraryResFolderPathOut"); } @@ -112,6 +120,7 @@ public class ComputeDependencyTask extends GetLibraryListTask { File sdkDir = TaskHelper.getSdkLocation(antProject); // prepare several paths for future tasks + final Path manifestFilePath = new Path(antProject); final Path resFolderPath = new Path(antProject); final Path nativeFolderPath = new Path(antProject); final StringBuilder packageStrBuilder = new StringBuilder(); @@ -122,9 +131,14 @@ public class ComputeDependencyTask extends GetLibraryListTask { // let the super class handle the jar files super.processLibrary(libRootPath); - // get the res path. Always $PROJECT/res as well as the crunch cache. - // FIXME: support renamed folder. - PathElement element = resFolderPath.createPathElement(); + // get the AndroidManifest.xml path. + // FIXME: support renamed location. + PathElement element = manifestFilePath.createPathElement(); + element.setPath(libRootPath + "/" + SdkConstants.FN_ANDROID_MANIFEST_XML); + + // get the res path. $PROJECT/res as well as the crunch cache. + // FIXME: support renamed folders. + element = resFolderPath.createPathElement(); element.setPath(libRootPath + "/" + SdkConstants.FD_OUTPUT + "/" + SdkConstants.FD_RES); element = resFolderPath.createPathElement(); @@ -191,6 +205,7 @@ public class ComputeDependencyTask extends GetLibraryListTask { // even with no libraries, always setup these so that various tasks in Ant don't complain // (the task themselves can handle a ref to an empty Path) antProject.addReference(mLibraryNativeFolderPathOut, nativeFolderPath); + antProject.addReference(mLibraryManifestFilePathOut, manifestFilePath); // the rest is done only if there's a library. if (hasLibraries) { diff --git a/anttasks/src/com/android/ant/ManifestMergerTask.java b/anttasks/src/com/android/ant/ManifestMergerTask.java new file mode 100644 index 0000000..a20df4e --- /dev/null +++ b/anttasks/src/com/android/ant/ManifestMergerTask.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ant; + +import com.android.manifmerger.ManifestMerger; +import com.android.sdklib.StdSdkLog; +import com.android.sdklib.io.FileOp; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Path; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ManifestMergerTask extends SingleDependencyTask { + + private String mAppManifest; + private String mOutManifest; + + private ArrayList<Path> mLibraryPaths; + private boolean mEnabled = false; + + public void setAppManifest(Path appManifest) { + mAppManifest = TaskHelper.checkSinglePath("appManifest", appManifest); + } + + public void setOutManifest(Path outManifest) { + mOutManifest = TaskHelper.checkSinglePath("outManifest", outManifest); + } + + public void setEnable(boolean enabled) { + mEnabled = enabled; + } + + /** + * Returns an object representing a nested <var>library</var> element. + */ + public Object createLibrary() { + if (mLibraryPaths == null) { + mLibraryPaths = new ArrayList<Path>(); + } + + Path path = new Path(getProject()); + mLibraryPaths.add(path); + + return path; + } + + @Override + public void execute() throws BuildException { + if (mAppManifest == null) { + throw new BuildException("Missing attribute appManifest"); + } + if (mOutManifest == null) { + throw new BuildException("Missing attribute outManifest"); + } + + // if we merge, then get the rest of the input paths. + List<File> libraries = new ArrayList<File>(); + if (mLibraryPaths != null) { + for (Path pathList : mLibraryPaths) { + for (String path : pathList.list()) { + libraries.add(new File(path)); + } + } + } + + // prepare input files + ArrayList<File> allInputs = new ArrayList<File>(libraries.size() + 1); + + // always: the input manifest. + File appManifestFile = new File(mAppManifest); + allInputs.add(appManifestFile); + + // if enabled: add the libraries + if (mEnabled) { + allInputs.addAll(libraries); + } + + // figure out the path to the dependency file. + String depFile = mOutManifest + ".d"; + + // get InputPath with no extension restrictions + List<InputPath> inputPaths = getInputPaths(allInputs, null /*extensionsToCheck*/, + null /*factory*/); + + if (initDependencies(depFile, inputPaths) && dependenciesHaveChanged() == false) { + System.out.println( + "No changes in the AndroidManifest files."); + return; + } + + System.out.println("Merging AndroidManifest files into one."); + + if (mEnabled == false || libraries.size() == 0) { + if (mEnabled == false) { + System.out.println("Manifest merger disabled. Using project manifest only."); + } else { + System.out.println("No libraries. Using project manifest only."); + } + // no merge (disabled or nothing to merge)? do a simple copy. + try { + new FileOp().copyFile(appManifestFile, new File(mOutManifest)); + } catch (IOException e) { + throw new BuildException(e); + } + } else { + System.out.println(String.format("Merging manifests from project and %d libraries.", + libraries.size())); + ManifestMerger merger = new ManifestMerger(new StdSdkLog()); + if (merger.process( + new File(mOutManifest), + appManifestFile, + libraries.toArray(new File[libraries.size()])) == false) { + throw new BuildException(); + } + } + + // generate the dependency file. + generateDependencyFile(depFile, inputPaths, mOutManifest); + } + + @Override + protected String getExecTaskName() { + return "ManifestMerger"; + } +} diff --git a/anttasks/src/com/android/ant/SingleDependencyTask.java b/anttasks/src/com/android/ant/SingleDependencyTask.java index c179b3e..4cc8f3e 100644 --- a/anttasks/src/com/android/ant/SingleDependencyTask.java +++ b/anttasks/src/com/android/ant/SingleDependencyTask.java @@ -26,7 +26,7 @@ import java.util.List; import java.util.Set; /** - * A base class for ant tasks that use a single dependency files to control (re)execution. + * A base class for ant tasks that use a single dependency file to control (re)execution. */ public abstract class SingleDependencyTask extends BuildTypedTask { diff --git a/build/tools.atree b/build/tools.atree index 89401e2..16fdaf5 100644 --- a/build/tools.atree +++ b/build/tools.atree @@ -107,6 +107,8 @@ framework/mkidentity-prebuilt.jar tools/lib/mkidentity.jar framework/lint.jar tools/lib/lint.jar framework/lint_api.jar tools/lib/lint_api.jar framework/lint_checks.jar tools/lib/lint_checks.jar +framework/manifmerger.jar tools/lib/manifmerger.jar + # 3rd Party java libraries framework/commons-compress-1.0.jar tools/lib/commons-compress-1.0.jar @@ -162,6 +164,5 @@ framework/sdklib-tests.jar tests/libtests/sdklib-tests.jar framework/sdkuilib-tests.jar tests/libtests/sdkuilib-tests.jar framework/layoutlib_api.jar tests/libtests/layoutlib_api.jar #FIXME breaks build, manifmerger jar files not properly built -#framework/manifmerger.jar tests/libtests/manifmerger.jar #framework/manifmerger-tests.jar tests/libtests/manifmerger-tests.jar diff --git a/files/ant/build.xml b/files/ant/build.xml index 601c8e9..0f9bb87 100644 --- a/files/ant/build.xml +++ b/files/ant/build.xml @@ -56,6 +56,9 @@ <property name="renderscript.debug.opt.level" value="O0" /> <property name="renderscript.release.opt.level" value="O3" /> + <!-- manifest merger default value --> + <property name="manifestmerger.enabled" value="false" /> + <!-- instrumentation options --> <property name="emma.filter" value="" /> @@ -72,77 +75,7 @@ </path> <!-- Custom tasks --> - <taskdef name="checkenv" - classname="com.android.ant.CheckEnvTask" - classpathref="android.antlibs" /> - - <taskdef name="gettype" - classname="com.android.ant.GetTypeTask" - classpathref="android.antlibs" /> - - <taskdef name="gettarget" - classname="com.android.ant.GetTargetTask" - classpathref="android.antlibs" /> - - <taskdef name="getlibs" - classname="com.android.ant.GetLibraryListTask" - classpathref="android.antlibs" /> - - <taskdef name="dependency" - classname="com.android.ant.ComputeDependencyTask" - classpathref="android.antlibs" /> - - <taskdef name="testedprojectclasspath" - classname="com.android.ant.ComputeProjectClasspathTask" - classpathref="android.antlibs" /> - - <taskdef name="getemmafilter" - classname="com.android.ant.GetEmmaFilterTask" - classpathref="android.antlibs" /> - - <taskdef name="aapt" - classname="com.android.ant.AaptExecTask" - classpathref="android.antlibs" /> - - <taskdef name="aidl" - classname="com.android.ant.AidlExecTask" - classpathref="android.antlibs" /> - - <taskdef name="renderscript" - classname="com.android.ant.RenderScriptTask" - classpathref="android.antlibs" /> - - <taskdef name="buildconfig" - classname="com.android.ant.BuildConfigTask" - classpathref="android.antlibs" /> - - <taskdef name="dex" - classname="com.android.ant.DexExecTask" - classpathref="android.antlibs" /> - - <taskdef name="apkbuilder" - classname="com.android.ant.ApkBuilderTask" - classpathref="android.antlibs" /> - - <taskdef name="signapk" - classname="com.android.ant.SignApkTask" - classpathref="android.antlibs" /> - - <taskdef name="zipalign" - classname="com.android.ant.ZipAlignTask" - classpathref="android.antlibs" /> - - <taskdef name="xpath" - classname="com.android.ant.XPathTask" - classpathref="android.antlibs" /> - - <taskdef name="if" - classname="com.android.ant.IfElseTask" - classpathref="android.antlibs" /> - - <taskdef name="propertybyreplace" - classname="com.android.ant.PropertyByReplaceTask" - classpathref="android.antlibs" /> + <taskdef resource="anttasks.properties" classpathref="android.antlibs" /> <!-- Emma configuration --> <property name="emma.dir" value="${sdk.dir}/tools/lib" /> @@ -171,11 +104,15 @@ <property name="jar.libs.absolute.dir" location="${jar.libs.dir}" /> <property name="native.libs.absolute.dir" location="libs" /> + <property name="manifest.file" value="AndroidManifest.xml" /> + <property name="manifest.abs.file" location="${manifest.file}" /> + <!-- Output directories --> <property name="out.dir" value="bin" /> <property name="out.absolute.dir" location="${out.dir}" /> <property name="out.classes.absolute.dir" location="${out.dir}/classes" /> <property name="out.res.absolute.dir" location="${out.dir}/res" /> + <property name="out.manifest.abs.file" location="${out.dir}/AndroidManifest.xml" /> <!-- tools location --> <property name="android.tools.dir" location="${sdk.dir}/tools" /> @@ -456,8 +393,44 @@ </then> </if> + <!-- If the "debug" build type changed, clear out the compiled code. + This is to make sure the new BuildConfig.DEBUG value is picked up + as javac can't deal with this type of change in its dependency computation. --> + <if> + <condition> + <and> + <length string="${build.last.is.packaging.debug}" trim="true" when="greater" length="0" /> + <not><equals + arg1="${build.is.packaging.debug}" + arg2="${build.last.is.packaging.debug}" /></not> + </and> + </condition> + <then> + <echo level="info">Switching between debug and non debug build: Deleting previous compilation output...</echo> + <delete dir="${out.classes.absolute.dir}" verbose="${verbose}" /> + </then> + <else> + <!-- Else, we may still need to clean the code, for another reason. + special case for instrumented: if the previous build was + instrumented but not this one, clear out the compiled code --> + <if> + <condition> + <and> + <istrue value="${build.last.is.instrumented}" /> + <isfalse value="${build.is.instrumented}" /> + </and> + </condition> + <then> + <echo level="info">Switching from instrumented to non-instrumented build: Deleting previous compilation output...</echo> + <delete dir="${out.classes.absolute.dir}" verbose="${verbose}" /> + </then> + </if> + </else> + </if> + + <!-- get the project manifest package --> - <xpath input="AndroidManifest.xml" + <xpath input="${manifest.abs.file}" expression="/manifest/@package" output="project.app.package" /> </target> @@ -532,7 +505,7 @@ minSdkVersionOut="project.minSdkVersion" /> <!-- Value of the hasCode attribute (Application node) extracted from manifest file --> - <xpath input="AndroidManifest.xml" expression="/manifest/application/@android:hasCode" + <xpath input="${manifest.abs.file}" expression="/manifest/application/@android:hasCode" output="manifest.hasCode" default="true"/> <echo level="info">----------</echo> @@ -551,6 +524,7 @@ <dependency libraryFolderPathOut="project.library.folder.path" libraryPackagesOut="project.library.packages" + libraryManifestFilePathOut="project.library.manifest.file.path" libraryResFolderPathOut="project.library.res.folder.path" libraryNativeFolderPathOut="project.library.native.folder.path" jarLibraryPathOut="project.all.jars.path" @@ -613,42 +587,6 @@ <path id="tested.project.classpath" /> </else> </if> - - - <!-- If the "debug" build type changed, clear out the compiled code. - This is to make sure the new BuildConfig.DEBUG value is picked up - as javac can't deal with this type of change in its dependency computation. --> - <if> - <condition> - <and> - <length string="${build.last.is.packaging.debug}" trim="true" when="greater" length="0" /> - <not><equals - arg1="${build.is.packaging.debug}" - arg2="${build.last.is.packaging.debug}" /></not> - </and> - </condition> - <then> - <echo level="info">Switching between debug and non debug build: Deleting previous compilation output...</echo> - <delete dir="${out.classes.absolute.dir}" verbose="${verbose}" /> - </then> - <else> - <!-- Else, we may still need to clean the code, for another reason. - special case for instrumented: if the previous build was - instrumented but not this one, clear out the compiled code --> - <if> - <condition> - <and> - <istrue value="${build.last.is.instrumented}" /> - <isfalse value="${build.is.instrumented}" /> - </and> - </condition> - <then> - <echo level="info">Switching from instrumented to non-instrumented build: Deleting previous compilation output...</echo> - <delete dir="${out.classes.absolute.dir}" verbose="${verbose}" /> - </then> - </if> - </else> - </if> </target> <!-- empty default pre-build target. Create a similar target in @@ -657,6 +595,14 @@ <!-- Code Generation: compile resources (aapt -> R.java), aidl, renderscript --> <target name="-code-gen"> + <!-- always merge manifest --> + <mergemanifest + appManifest="${manifest.abs.file}" + outManifest="${out.manifest.abs.file}" + enabled="${manifestmerger.enabled}"> + <library refid="project.library.manifest.file.path" /> + </mergemanifest> + <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping aidl/renderscript/R.java"> <echo level="info">Handling aidl files...</echo> @@ -684,7 +630,7 @@ <aapt executable="${aapt}" command="package" verbose="${verbose}" - manifest="AndroidManifest.xml" + manifest="${out.manifest.abs.file}" androidjar="${project.target.android.jar}" rfolder="${gen.absolute.dir}" nonConstantId="${android.library}" @@ -922,7 +868,7 @@ versioncode="${version.code}" versionname="${version.name}" debug="${build.is.packaging.debug}" - manifest="AndroidManifest.xml" + manifest="${out.manifest.abs.file}" assets="${asset.absolute.dir}" androidjar="${project.target.android.jar}" apkfolder="${out.absolute.dir}" @@ -1094,7 +1040,7 @@ <!-- release mode is only valid if the manifest does not explicitly set debuggable to true. default is false. --> - <xpath input="AndroidManifest.xml" expression="/manifest/application/@android:debuggable" + <xpath input="${manifest.abs.file}" expression="/manifest/application/@android:debuggable" output="build.is.packaging.debug" default="false"/> <!-- signing mode: release --> diff --git a/testapps/testProjectTest/app/AndroidManifest.xml b/testapps/testProjectTest/app/AndroidManifest.xml index 821ae78..41e6b82 100644 --- a/testapps/testProjectTest/app/AndroidManifest.xml +++ b/testapps/testProjectTest/app/AndroidManifest.xml @@ -9,15 +9,6 @@ <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > - <activity - android:name="com.android.tests.testprojecttest.lib.LibActivity" - android:label="@string/app_name" > - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> </application> </manifest>
\ No newline at end of file diff --git a/testapps/testProjectTest/lib/AndroidManifest.xml b/testapps/testProjectTest/lib/AndroidManifest.xml index f8cc83d..b8bc11c 100644 --- a/testapps/testProjectTest/lib/AndroidManifest.xml +++ b/testapps/testProjectTest/lib/AndroidManifest.xml @@ -6,4 +6,15 @@ <uses-sdk android:minSdkVersion="15" /> + <application> + <activity + android:name="com.android.tests.testprojecttest.lib.LibActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + </manifest>
\ No newline at end of file diff --git a/testapps/testProjectTest/lib/res/values/strings.xml b/testapps/testProjectTest/lib/res/values/strings.xml new file mode 100644 index 0000000..fdb2272 --- /dev/null +++ b/testapps/testProjectTest/lib/res/values/strings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">TestProjectTest-lib</string> + +</resources>
\ No newline at end of file diff --git a/testapps/testProjectTest/testlib/AndroidManifest.xml b/testapps/testProjectTest/testlib/AndroidManifest.xml index acfe650..93b02e4 100644 --- a/testapps/testProjectTest/testlib/AndroidManifest.xml +++ b/testapps/testProjectTest/testlib/AndroidManifest.xml @@ -13,17 +13,6 @@ --> <application android:label="testProjectTest-testlib"> <uses-library android:name="android.test.runner" /> - - <activity - android:name="com.android.tests.testprojecttest.lib.LibActivity" - android:label="@string/app_name" > - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> <!-- |