Add Renderscript support.
Xavier Ducrohet [Fri, 25 Jan 2013 23:59:06 +0000 (15:59 -0800)]
Change-Id: I4787cc88fddd23afdb7c8f6ac127318da7b0cff7

56 files changed:
.gitignore
builder/src/main/java/com/android/builder/AndroidBuilder.java
builder/src/main/java/com/android/builder/AndroidDependency.java
builder/src/main/java/com/android/builder/BuildType.java
builder/src/main/java/com/android/builder/BundleDependency.java
builder/src/main/java/com/android/builder/DefaultSdkParser.java
builder/src/main/java/com/android/builder/ProductFlavor.java
builder/src/main/java/com/android/builder/SdkParser.java
builder/src/main/java/com/android/builder/VariantConfiguration.java
builder/src/main/java/com/android/builder/internal/compiler/AidlProcessor.java
builder/src/main/java/com/android/builder/internal/compiler/LeafFolderProcessor.java [new file with mode: 0644]
builder/src/main/java/com/android/builder/internal/compiler/RenderscriptProcessor.java [new file with mode: 0644]
builder/src/main/java/com/android/builder/internal/packaging/Packager.java
builder/src/test/java/com/android/builder/ProductFlavorTest.java
gradle/src/build-test/groovy/com/android/build/gradle/BuildTest.groovy
gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy
gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy
gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy
gradle/src/main/groovy/com/android/build/gradle/internal/ApplicationVariant.groovy
gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeDsl.groovy
gradle/src/main/groovy/com/android/build/gradle/internal/tasks/DependencyBasedCompileTask.groovy
gradle/src/main/groovy/com/android/build/gradle/tasks/MergeResources.groovy
gradle/src/main/groovy/com/android/build/gradle/tasks/PackageApplication.groovy
gradle/src/main/groovy/com/android/build/gradle/tasks/RenderscriptCompile.groovy [new file with mode: 0644]
gradle/src/test/groovy/com/android/build/gradle/internal/dsl/BuildTypeDslTest.groovy
tests/renderscript/build.gradle [new file with mode: 0644]
tests/renderscript/src/main/AndroidManifest.xml [new file with mode: 0644]
tests/renderscript/src/main/java/com/example/android/rs/hellocompute/HelloCompute.java [new file with mode: 0644]
tests/renderscript/src/main/res/drawable/data.jpg [new file with mode: 0644]
tests/renderscript/src/main/res/layout/main.xml [new file with mode: 0644]
tests/renderscript/src/main/rs/com/example/android/rs/hellocompute/mono.rs [new file with mode: 0644]
tests/renderscriptInLib/app/build.gradle [new file with mode: 0644]
tests/renderscriptInLib/app/src/main/AndroidManifest.xml [new file with mode: 0644]
tests/renderscriptInLib/app/src/main/java/com/example/android/rs/balls/Balls.java [new file with mode: 0644]
tests/renderscriptInLib/app/src/main/java/com/example/android/rs/balls/BallsRS.java [new file with mode: 0644]
tests/renderscriptInLib/app/src/main/java/com/example/android/rs/balls/BallsView.java [new file with mode: 0644]
tests/renderscriptInLib/app/src/main/res/drawable/flares.png [new file with mode: 0644]
tests/renderscriptInLib/app/src/main/res/drawable/test_pattern.png [new file with mode: 0644]
tests/renderscriptInLib/app/src/main/rs/com/example/android/rs/balls/ball_physics.rs [new file with mode: 0644]
tests/renderscriptInLib/app/src/main/rs/com/example/android/rs/balls/balls.rs [new file with mode: 0644]
tests/renderscriptInLib/build.gradle [new file with mode: 0644]
tests/renderscriptInLib/lib/build.gradle [new file with mode: 0644]
tests/renderscriptInLib/lib/src/main/AndroidManifest.xml [new file with mode: 0644]
tests/renderscriptInLib/lib/src/main/rs/com/example/android/rs/balls/balls.rsh [new file with mode: 0644]
tests/renderscriptInLib/settings.gradle [new file with mode: 0644]
tests/renderscriptMultiSrc/build.gradle [new file with mode: 0644]
tests/renderscriptMultiSrc/src/debug/rs/com/example/android/rs/balls/balls.rsh [new file with mode: 0644]
tests/renderscriptMultiSrc/src/main/AndroidManifest.xml [new file with mode: 0644]
tests/renderscriptMultiSrc/src/main/java/com/example/android/rs/balls/Balls.java [new file with mode: 0644]
tests/renderscriptMultiSrc/src/main/java/com/example/android/rs/balls/BallsRS.java [new file with mode: 0644]
tests/renderscriptMultiSrc/src/main/java/com/example/android/rs/balls/BallsView.java [new file with mode: 0644]
tests/renderscriptMultiSrc/src/main/res/drawable/flares.png [new file with mode: 0644]
tests/renderscriptMultiSrc/src/main/res/drawable/test_pattern.png [new file with mode: 0644]
tests/renderscriptMultiSrc/src/main/rs/com/example/android/rs/balls/ball_physics.rs [new file with mode: 0644]
tests/renderscriptMultiSrc/src/main/rs/com/example/android/rs/balls/balls.rs [new file with mode: 0644]
tests/renderscriptMultiSrc/src/release/rs/com/example/android/rs/balls/balls.rsh [new file with mode: 0644]

index 4e7a8d5..7157013 100644 (file)
@@ -14,6 +14,7 @@ tests/applibtest/*/build
 tests/flavorlib/*/build
 tests/flavorlibWithFailedTests/*/build
 tests/libsTest/*/build
+tests/renderscriptInLib/*/build
 tests/repo/*/build
 /repo
 /out
index 19f074e..5cf95d9 100644 (file)
@@ -16,6 +16,7 @@
 
 package com.android.builder;
 
+import com.android.SdkConstants;
 import com.android.annotations.NonNull;
 import com.android.annotations.Nullable;
 import com.android.annotations.VisibleForTesting;
@@ -26,6 +27,8 @@ import com.android.builder.internal.SymbolLoader;
 import com.android.builder.internal.SymbolWriter;
 import com.android.builder.internal.TestManifestGenerator;
 import com.android.builder.internal.compiler.AidlProcessor;
+import com.android.builder.internal.compiler.LeafFolderProcessor;
+import com.android.builder.internal.compiler.RenderscriptProcessor;
 import com.android.builder.internal.compiler.SourceSearcher;
 import com.android.builder.internal.packaging.JavaResourceProcessor;
 import com.android.builder.internal.packaging.Packager;
@@ -517,10 +520,12 @@ public class AndroidBuilder {
         // launch aapt: create the command line
         ArrayList<String> command = Lists.newArrayList();
 
-        @SuppressWarnings("deprecation")
-        String aaptPath = mTarget.getPath(IAndroidTarget.AAPT);
+        File aapt = mSdkParser.getAapt();
+        if (aapt == null || !aapt.isFile()) {
+            throw new IllegalStateException(String.valueOf("aapt is missing"));
+        }
 
-        command.add(aaptPath);
+        command.add(aapt.getAbsolutePath());
         command.add("package");
 
         if (mVerboseExec) {
@@ -661,8 +666,10 @@ public class AndroidBuilder {
         checkNotNull(sourceOutputDir, "sourceOutputDir cannot be null.");
         checkNotNull(importFolders, "importFolders cannot be null.");
 
-        @SuppressWarnings("deprecation")
-        String aidlPath = mTarget.getPath(IAndroidTarget.AIDL);
+        File aidl = mSdkParser.getAidlCompiler();
+        if (aidl == null || !aidl.isFile()) {
+            throw new IllegalStateException(String.valueOf("aidl is missing"));
+        }
 
         List<File> fullImportList = Lists.newArrayListWithCapacity(
                 sourceFolders.size() + importFolders.size());
@@ -670,7 +677,7 @@ public class AndroidBuilder {
         fullImportList.addAll(importFolders);
 
         AidlProcessor processor = new AidlProcessor(
-                aidlPath,
+                aidl.getAbsolutePath(),
                 mTarget.getPath(IAndroidTarget.ANDROID_AIDL),
                 fullImportList,
                 sourceOutputDir,
@@ -688,7 +695,7 @@ public class AndroidBuilder {
      *
      * @param aidlFile the AIDL file to compile
      * @param sourceOutputDir the output dir in which to generate the source code
-     * @param importFolders all the import folders, including the source folder.
+     * @param importFolders all the import folders, including the source folders.
      * @param dependencyFileProcessor the dependencyFileProcessor to record the dependencies
      *                                of the compilation.
      * @throws IOException
@@ -704,11 +711,13 @@ public class AndroidBuilder {
         checkNotNull(sourceOutputDir, "sourceOutputDir cannot be null.");
         checkNotNull(importFolders, "importFolders cannot be null.");
 
-        @SuppressWarnings("deprecation")
-        String aidlPath = mTarget.getPath(IAndroidTarget.AIDL);
+        File aidl = mSdkParser.getAidlCompiler();
+        if (aidl == null || !aidl.isFile()) {
+            throw new IllegalStateException(String.valueOf("aidl is missing"));
+        }
 
         AidlProcessor processor = new AidlProcessor(
-                aidlPath,
+                aidl.getAbsolutePath(),
                 mTarget.getPath(IAndroidTarget.ANDROID_AIDL),
                 importFolders,
                 sourceOutputDir,
@@ -720,6 +729,179 @@ public class AndroidBuilder {
     }
 
     /**
+     * Compiles all the renderscript files found in the given source folders.
+     *
+     * @param sourceFolders all the source folders to find files to compile
+     * @param importFolders all the import folders.
+     * @param sourceOutputDir the output dir in which to generate the source code
+     * @param resOutputDir the output dir in which to generate the bitcode file
+     * @param targetApi the target api
+     * @param debugBuild whether the build is debug
+     * @param optimLevel the optimization level
+     * @param dependencyFileProcessor the dependencyFileProcessor to record the dependencies
+     *                                of the compilation.
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public void compileAllRenderscriptFiles(@NonNull List<File> sourceFolders,
+                                            @NonNull List<File> importFolders,
+                                            @NonNull File sourceOutputDir,
+                                            @NonNull File resOutputDir,
+                                            int targetApi,
+                                            boolean debugBuild,
+                                            int optimLevel,
+                                            @Nullable DependencyFileProcessor dependencyFileProcessor)
+            throws IOException, InterruptedException, ExecutionException {
+        checkState(mTarget != null, "Target not set.");
+        checkNotNull(sourceFolders, "sourceFolders cannot be null.");
+        checkNotNull(importFolders, "importFolders cannot be null.");
+        checkNotNull(sourceOutputDir, "sourceOutputDir cannot be null.");
+        checkNotNull(resOutputDir, "resOutputDir cannot be null.");
+
+        File renderscript = mSdkParser.getRenderscriptCompiler();
+        if (renderscript == null || !renderscript.isFile()) {
+            throw new IllegalStateException(String.valueOf("llvm-rs-cc is missing"));
+        }
+
+        List<File> fullImportList = Lists.newArrayListWithCapacity(importFolders.size() + 2);
+        fullImportList.addAll(importFolders);
+
+        @SuppressWarnings("deprecation")
+        String rsPath = mTarget.getPath(IAndroidTarget.ANDROID_RS);
+        fullImportList.add(new File(rsPath));
+
+        @SuppressWarnings("deprecation")
+        String rsClangPath = mTarget.getPath(IAndroidTarget.ANDROID_RS_CLANG);
+        fullImportList.add(new File(rsClangPath));
+
+        // the renderscript compiler doesn't expect the top res folder,
+        // but the raw folder directly.
+        File rawFolder = new File(resOutputDir, SdkConstants.FD_RES_RAW);
+
+        RenderscriptProcessor processor = new RenderscriptProcessor(
+                renderscript.getAbsolutePath(),
+                fullImportList,
+                sourceOutputDir.getAbsolutePath(),
+                rawFolder.getAbsolutePath(),
+                targetApi,
+                debugBuild,
+                optimLevel,
+                dependencyFileProcessor != null ?
+                        dependencyFileProcessor : sNoOpDependencyFileProcessor,
+                mCmdLineRunner);
+
+        SourceSearcher searcher = new SourceSearcher(sourceFolders, "rs", "fs");
+        searcher.setUseExecutor(true);
+        searcher.search(processor);
+    }
+
+
+    /**
+     * Computes and returns the leaf folders based on a given file extension.
+     *
+     * This looks through all the given root import folders, and recursively search for leaf
+     * folders containing files matching the given extensions. All the leaf folders are gathered
+     * and returned in the list.
+     *
+     * @param extension the extension to search for.
+     * @param importFolders an array of list of root folders.
+     * @return a list of leaf folder, never null.
+     */
+    @NonNull
+    public List<File> getLeafFolders(@NonNull String extension, List<File>... importFolders) {
+        List<File> results = Lists.newArrayList();
+
+        if (importFolders != null) {
+            for (List<File> folders : importFolders) {
+                SourceSearcher searcher = new SourceSearcher(folders, extension);
+                searcher.setUseExecutor(false);
+                LeafFolderProcessor processor = new LeafFolderProcessor();
+                try {
+                    searcher.search(processor);
+                } catch (InterruptedException e) {
+                    // wont happen as we're not using the executor, and our processor
+                    // doesn't throw those.
+                } catch (ExecutionException e) {
+                    // wont happen as we're not using the executor, and our processor
+                    // doesn't throw those.
+                } catch (IOException e) {
+                    // wont happen as we're not using the executor, and our processor
+                    // doesn't throw those.
+                }
+
+                results.addAll(processor.getFolders());
+            }
+        }
+
+        return results;
+    }
+
+    /**
+     * Compiles the given renderscript file.
+     *
+     * @param renderscriptFile the renderscript file to compile
+     * @param importFolders all the import folders.
+     * @param sourceOutputDir the output dir in which to generate the source code
+     * @param resOutputDir the output dir in which to generate the bitcode file
+     * @param targetApi the target api
+     * @param debugBuild whether the build is debug
+     * @param optimLevel the optimization level
+     * @param dependencyFileProcessor the dependencyFileProcessor to record the dependencies
+     *                                of the compilation.
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public void compileRenderscriptFile(@NonNull File renderscriptFile,
+                                        @NonNull List<File> importFolders,
+                                        @NonNull File sourceOutputDir,
+                                        @NonNull File resOutputDir,
+                                        int targetApi,
+                                        boolean debugBuild,
+                                        int optimLevel,
+                                        @Nullable DependencyFileProcessor dependencyFileProcessor)
+            throws IOException, InterruptedException {
+        checkState(mTarget != null, "Target not set.");
+        checkNotNull(renderscriptFile, "renderscriptFile cannot be null.");
+        checkNotNull(importFolders, "importFolders cannot be null.");
+        checkNotNull(sourceOutputDir, "sourceOutputDir cannot be null.");
+        checkNotNull(resOutputDir, "resOutputDir cannot be null.");
+
+        File renderscript = mSdkParser.getRenderscriptCompiler();
+        if (renderscript == null || !renderscript.isFile()) {
+            throw new IllegalStateException(String.valueOf("llvm-rs-cc is missing"));
+        }
+
+        List<File> fullImportList = Lists.newArrayListWithCapacity(importFolders.size() + 2);
+        fullImportList.addAll(importFolders);
+
+        @SuppressWarnings("deprecation")
+        String rsPath = mTarget.getPath(IAndroidTarget.ANDROID_RS);
+        fullImportList.add(new File(rsPath));
+
+        @SuppressWarnings("deprecation")
+        String rsClangPath = mTarget.getPath(IAndroidTarget.ANDROID_RS_CLANG);
+        fullImportList.add(new File(rsClangPath));
+
+        // the renderscript compiler doesn't expect the top res folder,
+        // but the raw folder directly.
+        File rawFolder = new File(resOutputDir, SdkConstants.FD_RES_RAW);
+
+        RenderscriptProcessor processor = new RenderscriptProcessor(
+                renderscript.getAbsolutePath(),
+                fullImportList,
+                sourceOutputDir.getAbsolutePath(),
+                rawFolder.getAbsolutePath(),
+                targetApi,
+                debugBuild,
+                optimLevel,
+                dependencyFileProcessor != null ?
+                        dependencyFileProcessor : sNoOpDependencyFileProcessor,
+                mCmdLineRunner);
+
+        processor.processFile(renderscriptFile);
+    }
+
+    /**
      * Converts the bytecode to Dalvik format
      * @param classesLocation the location of the compiler output
      * @param libraries the list of libraries
@@ -802,7 +984,7 @@ public class AndroidBuilder {
      * @param packagedJars the jars that are packaged (libraries + jar dependencies)
      * @param javaResourcesLocation the processed Java resource folder
      * @param jniLibsLocation the location of the compiled JNI libraries
-     * @param debugJni whether the app should include jni debug data
+     * @param jniDebugBuild whether the app should include jni debug data
      * @param signingConfig the signing configuration
      * @param outApkLocation location of the APK.
      * @throws DuplicateFileException
@@ -819,7 +1001,7 @@ public class AndroidBuilder {
             @NonNull List<File> packagedJars,
             @Nullable String javaResourcesLocation,
             @Nullable String jniLibsLocation,
-            boolean debugJni,
+            boolean jniDebugBuild,
             @Nullable SigningConfig signingConfig,
             @NonNull String outApkLocation) throws DuplicateFileException, FileNotFoundException,
             KeytoolException, PackagerException, SigningException {
@@ -841,7 +1023,7 @@ public class AndroidBuilder {
                     outApkLocation, androidResPkgLocation, classesDexLocation,
                     certificateInfo, mLogger);
 
-            packager.setDebugJniMode(debugJni);
+            packager.setJniDebugMode(jniDebugBuild);
 
             // figure out conflicts!
             JavaResourceProcessor resProcessor = new JavaResourceProcessor(packager);
index b907c49..07f13a4 100644 (file)
@@ -61,6 +61,11 @@ public interface AndroidDependency extends ManifestDependency, SymbolFileProvide
     File getAidlFolder();
 
     /**
+     * Returns the location of the renderscript import folder.
+     */
+    File getRenderscriptFolder();
+
+    /**
      * Returns the location of the proguard files.
      */
     File getProguardRules();
index 55a137c..2c38fae 100644 (file)
@@ -26,7 +26,9 @@ public class BuildType extends BuildConfig {
 
     private final String mName;
     private boolean mDebuggable = false;
-    private boolean mDebugJniBuild = false;
+    private boolean mJniDebugBuild = false;
+    private boolean mRenderscriptDebugBuild = false;
+    private int mRenderscriptOptimLevel = 3;
     private String mPackageNameSuffix = null;
     private String mVersionNameSuffix = null;
     private boolean mRunProguard = false;
@@ -52,13 +54,29 @@ public class BuildType extends BuildConfig {
         return mDebuggable;
     }
 
-    public BuildType setDebugJniBuild(boolean debugJniBuild) {
-        mDebugJniBuild = debugJniBuild;
+    public BuildType setJniDebugBuild(boolean jniDebugBuild) {
+        mJniDebugBuild = jniDebugBuild;
         return this;
     }
 
-    public boolean isDebugJniBuild() {
-        return mDebugJniBuild;
+    public boolean isJniDebugBuild() {
+        return mJniDebugBuild;
+    }
+
+    public boolean isRenderscriptDebugBuild() {
+        return mRenderscriptDebugBuild;
+    }
+
+    public void setRenderscriptDebugBuild(boolean renderscriptDebugBuild) {
+        mRenderscriptDebugBuild = renderscriptDebugBuild;
+    }
+
+    public int getRenderscriptOptimLevel() {
+        return mRenderscriptOptimLevel;
+    }
+
+    public void setRenderscriptOptimLevel(int renderscriptOptimLevel) {
+        mRenderscriptOptimLevel = renderscriptOptimLevel;
     }
 
     public BuildType setPackageNameSuffix(@Nullable String packageNameSuffix) {
@@ -116,8 +134,10 @@ public class BuildType extends BuildConfig {
         BuildType buildType = (BuildType) o;
 
         if (!mName.equals(buildType.mName)) return false;
-        if (mDebugJniBuild != buildType.mDebugJniBuild) return false;
         if (mDebuggable != buildType.mDebuggable) return false;
+        if (mJniDebugBuild != buildType.mJniDebugBuild) return false;
+        if (mRenderscriptDebugBuild != buildType.mRenderscriptDebugBuild) return false;
+        if (mRenderscriptOptimLevel != buildType.mRenderscriptOptimLevel) return false;
         if (mRunProguard != buildType.mRunProguard) return false;
         if (mZipAlign != buildType.mZipAlign) return false;
         if (mPackageNameSuffix != null ?
@@ -141,7 +161,9 @@ public class BuildType extends BuildConfig {
         int result = super.hashCode();
         result = 31 * result + (mName.hashCode());
         result = 31 * result + (mDebuggable ? 1 : 0);
-        result = 31 * result + (mDebugJniBuild ? 1 : 0);
+        result = 31 * result + (mJniDebugBuild ? 1 : 0);
+        result = 31 * result + (mRenderscriptDebugBuild ? 1 : 0);
+        result = 31 * result + mRenderscriptOptimLevel;
         result = 31 * result + (mPackageNameSuffix != null ? mPackageNameSuffix.hashCode() : 0);
         result = 31 * result + (mVersionNameSuffix != null ? mVersionNameSuffix.hashCode() : 0);
         result = 31 * result + (mRunProguard ? 1 : 0);
@@ -155,7 +177,9 @@ public class BuildType extends BuildConfig {
         return Objects.toStringHelper(this)
                 .add("name", mName)
                 .add("debuggable", mDebuggable)
-                .add("debugJniBuild", mDebugJniBuild)
+                .add("jniDebugBuild", mJniDebugBuild)
+                .add("renderscriptDebugBuild", mRenderscriptDebugBuild)
+                .add("renderscriptOptimLevel", mRenderscriptOptimLevel)
                 .add("packageNameSuffix", mPackageNameSuffix)
                 .add("versionNameSuffix", mVersionNameSuffix)
                 .add("runProguard", mRunProguard)
index f0121bb..d65c390 100644 (file)
@@ -96,6 +96,11 @@ public abstract class BundleDependency implements AndroidDependency {
     }
 
     @Override
+    public File getRenderscriptFolder() {
+        return new File(mBundleFolder, SdkConstants.FD_RENDERSCRIPT);
+    }
+
+    @Override
     public File getProguardRules() {
         return new File(mBundleFolder, "proguard.txt");
     }
index 3d1fab4..bb07854 100644 (file)
@@ -16,6 +16,7 @@
 
 package com.android.builder;
 
+import com.android.SdkConstants;
 import com.android.annotations.NonNull;
 import com.android.sdklib.IAndroidTarget;
 import com.android.sdklib.SdkManager;
@@ -79,7 +80,6 @@ public class DefaultSdkParser implements SdkParser {
             return null;
         }
 
-
         Reader reader = null;
         try {
             reader = new FileReader(new File(platformTools, FN_SOURCE_PROP));
@@ -102,4 +102,34 @@ public class DefaultSdkParser implements SdkParser {
 
         return null;
     }
+
+    @Override
+    public File getAapt() {
+        File platformTools = new File(mSdkLocation, FD_PLATFORM_TOOLS);
+        if (!platformTools.isDirectory()) {
+            return null;
+        }
+
+        return new File(platformTools, SdkConstants.FN_AAPT);
+    }
+
+    @Override
+    public File getAidlCompiler() {
+        File platformTools = new File(mSdkLocation, FD_PLATFORM_TOOLS);
+        if (!platformTools.isDirectory()) {
+            return null;
+        }
+
+        return new File(platformTools, SdkConstants.FN_AIDL);
+    }
+
+    @Override
+    public File getRenderscriptCompiler() {
+        File platformTools = new File(mSdkLocation, FD_PLATFORM_TOOLS);
+        if (!platformTools.isDirectory()) {
+            return null;
+        }
+
+        return new File(platformTools, SdkConstants.FN_RENDERSCRIPT);
+    }
 }
index 26ff3c9..cdc91f2 100644 (file)
@@ -37,6 +37,7 @@ public class ProductFlavor extends BuildConfig {
     private final String mName;
     private int mMinSdkVersion = -1;
     private int mTargetSdkVersion = -1;
+    private int mRenderscriptTargetApi = -1;
     private int mVersionCode = -1;
     private String mVersionName = null;
     private String mPackageName = null;
@@ -123,6 +124,14 @@ public class ProductFlavor extends BuildConfig {
         return mTargetSdkVersion;
     }
 
+    public int getRenderscriptTargetApi() {
+        return mRenderscriptTargetApi;
+    }
+
+    public void setRenderscriptTargetApi(int renderscriptTargetApi) {
+        mRenderscriptTargetApi = renderscriptTargetApi;
+    }
+
     public ProductFlavor setTestPackageName(String testPackageName) {
         mTestPackageName = testPackageName;
         return this;
@@ -160,6 +169,8 @@ public class ProductFlavor extends BuildConfig {
 
         flavor.mMinSdkVersion = chooseInt(mMinSdkVersion, base.mMinSdkVersion);
         flavor.mTargetSdkVersion = chooseInt(mTargetSdkVersion, base.mTargetSdkVersion);
+        flavor.mRenderscriptTargetApi = chooseInt(mRenderscriptTargetApi,
+                base.mRenderscriptTargetApi);
 
         flavor.mVersionCode = chooseInt(mVersionCode, base.mVersionCode);
         flavor.mVersionName = chooseString(mVersionName, base.mVersionName);
@@ -195,6 +206,7 @@ public class ProductFlavor extends BuildConfig {
         if (!mName.equals(that.mName)) return false;
         if (mMinSdkVersion != that.mMinSdkVersion) return false;
         if (mTargetSdkVersion != that.mTargetSdkVersion) return false;
+        if (mRenderscriptTargetApi != that.mRenderscriptTargetApi) return false;
         if (mVersionCode != that.mVersionCode) return false;
         if (mPackageName != null ?
                 !mPackageName.equals(that.mPackageName) :
@@ -223,6 +235,7 @@ public class ProductFlavor extends BuildConfig {
         result = 31 * result + mName.hashCode();
         result = 31 * result + mMinSdkVersion;
         result = 31 * result + mTargetSdkVersion;
+        result = 31 * result + mRenderscriptTargetApi;
         result = 31 * result + mVersionCode;
         result = 31 * result + (mVersionName != null ? mVersionName.hashCode() : 0);
         result = 31 * result + (mPackageName != null ? mPackageName.hashCode() : 0);
@@ -239,6 +252,7 @@ public class ProductFlavor extends BuildConfig {
                 .add("name", mName)
                 .add("minSdkVersion", mMinSdkVersion)
                 .add("targetSdkVersion", mTargetSdkVersion)
+                .add("renderscriptTargetApi", mRenderscriptTargetApi)
                 .add("versionCode", mVersionCode)
                 .add("versionName", mVersionName)
                 .add("packageName", mPackageName)
index 09c9abd..fe9441f 100644 (file)
@@ -21,6 +21,8 @@ import com.android.sdklib.IAndroidTarget;
 import com.android.sdklib.internal.repository.packages.FullRevision;
 import com.android.utils.ILogger;
 
+import java.io.File;
+
 /**
  * A parser able to parse the SDK and return valuable information to the build system.
  *
@@ -50,4 +52,19 @@ public interface SdkParser {
      * @return the FullRevision or null if the revision couldn't not be found
      */
     FullRevision getPlatformToolsRevision();
+
+    /**
+     * Returns the location of the aapt tool.
+     */
+    File getAapt();
+
+    /**
+     * Returns the location of the aidl compiler.
+     */
+    File getAidlCompiler();
+
+    /**
+     * Returns the location of the renderscript compiler.
+     */
+    File getRenderscriptCompiler();
 }
\ No newline at end of file
index 44757ad..d16ef99 100644 (file)
@@ -486,6 +486,7 @@ public class VariantConfiguration {
         return null;
     }
 
+    @NonNull
     public List<File> getManifestOverlays() {
         List<File> inputs = Lists.newArrayList();
 
@@ -516,7 +517,7 @@ public class VariantConfiguration {
      *
      * @return a list ResourceSet.
      */
-    @NonNull public List<ResourceSet> getResourceSets() {
+    @NonNull public List<ResourceSet> getResourceSets(@Nullable File generatedResFolder) {
         List<ResourceSet> resourceSets = Lists.newArrayList();
 
         // the list of dependency must be reversed to use the right overlay order.
@@ -534,6 +535,9 @@ public class VariantConfiguration {
 
         ResourceSet resourceSet = new ResourceSet(ProductFlavor.MAIN);
         resourceSet.addSources(mainResDirs);
+        if (generatedResFolder != null) {
+            resourceSet.addSource(generatedResFolder);
+        }
         resourceSets.add(resourceSet);
 
         // the list of flavor must be reversed to use the right overlay order.
@@ -558,16 +562,40 @@ public class VariantConfiguration {
         return resourceSets;
     }
 
-    public List<File> getAidlSourceList() {
+    /**
+     * Returns all the renderscript import folder that are outside of the current project.
+     */
+    @NonNull
+    public List<File> getRenderscriptImports() {
+        List<File> list = Lists.newArrayList();
+
+        for (AndroidDependency lib : mFlatLibraries) {
+            File rsLib = lib.getRenderscriptFolder();
+            if (rsLib != null && rsLib.isDirectory()) {
+                list.add(rsLib);
+            }
+        }
+
+        return list;
+    }
+
+    /**
+     * Returns all the renderscript source folder from the main config, the flavors and the
+     * build type.
+     *
+     * @return a list of folders.
+     */
+    @NonNull
+    public List<File> getRenderscriptSourceList() {
         List<File> sourceList = Lists.newArrayList();
-        sourceList.addAll(mDefaultSourceProvider.getAidlDirectories());
+        sourceList.addAll(mDefaultSourceProvider.getRenderscriptDirectories());
         if (mType != Type.TEST) {
-            sourceList.addAll(mBuildTypeSourceProvider.getAidlDirectories());
+            sourceList.addAll(mBuildTypeSourceProvider.getRenderscriptDirectories());
         }
 
         if (hasFlavors()) {
             for (SourceProvider flavorSourceSet : mFlavorSourceProviders) {
-                sourceList.addAll(flavorSourceSet.getAidlDirectories());
+                sourceList.addAll(flavorSourceSet.getRenderscriptDirectories());
             }
         }
 
@@ -577,6 +605,7 @@ public class VariantConfiguration {
     /**
      * Returns all the aidl import folder that are outside of the current project.
      */
+    @NonNull
     public List<File> getAidlImports() {
         List<File> list = Lists.newArrayList();
 
@@ -590,6 +619,23 @@ public class VariantConfiguration {
         return list;
     }
 
+    @NonNull
+    public List<File> getAidlSourceList() {
+        List<File> sourceList = Lists.newArrayList();
+        sourceList.addAll(mDefaultSourceProvider.getAidlDirectories());
+        if (mType != Type.TEST) {
+            sourceList.addAll(mBuildTypeSourceProvider.getAidlDirectories());
+        }
+
+        if (hasFlavors()) {
+            for (SourceProvider flavorSourceSet : mFlavorSourceProviders) {
+                sourceList.addAll(flavorSourceSet.getAidlDirectories());
+            }
+        }
+
+        return sourceList;
+    }
+
     /**
      * Returns the compile classpath for this config. If the config tests a library, this
      * will include the classpath of the tested config
index 561b09e..382ae82 100644 (file)
@@ -59,8 +59,7 @@ public class AidlProcessor implements SourceSearcher.SourceFileProcessor {
     }
 
     @Override
-    public void processFile(File sourceFile)
-            throws IOException, InterruptedException {
+    public void processFile(File sourceFile) throws IOException, InterruptedException {
         ArrayList<String> command = Lists.newArrayList();
 
         command.add(mAidlExecutable);
diff --git a/builder/src/main/java/com/android/builder/internal/compiler/LeafFolderProcessor.java b/builder/src/main/java/com/android/builder/internal/compiler/LeafFolderProcessor.java
new file mode 100644 (file)
index 0000000..ba0a75d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 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.builder.internal.compiler;
+
+import com.google.common.collect.Sets;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * Source Searcher processor, gathering a list of folders containing processed source files.
+ */
+public class LeafFolderProcessor implements SourceSearcher.SourceFileProcessor {
+
+    private final Set<File> mFolders = Sets.newHashSet();
+
+    @Override
+    public void processFile(File sourceFile) throws IOException, InterruptedException {
+        mFolders.add(sourceFile.getParentFile());
+    }
+
+    public Set<File> getFolders() {
+        return mFolders;
+    }
+}
diff --git a/builder/src/main/java/com/android/builder/internal/compiler/RenderscriptProcessor.java b/builder/src/main/java/com/android/builder/internal/compiler/RenderscriptProcessor.java
new file mode 100644 (file)
index 0000000..f94ac00
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2013 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.builder.internal.compiler;
+
+import com.android.annotations.NonNull;
+import com.android.builder.compiling.DependencyFileProcessor;
+import com.android.builder.internal.CommandLineRunner;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A Source File processor for Renderscript files. This compiles each Renderscript file
+ * found by the SourceSearcher.
+ */
+public class RenderscriptProcessor  implements SourceSearcher.SourceFileProcessor {
+
+    @NonNull private final String mCompilerPath;
+    @NonNull private final List<File> mImportPaths;
+    @NonNull private final String mSourceOutputDir;
+    @NonNull private final String mResOutputDir;
+    private final int mTargetApi;
+    private final boolean mDebugBuild;
+    private final int mOptimLevel;
+    @NonNull private final DependencyFileProcessor mDependencyFileProcessor;
+    @NonNull private final CommandLineRunner mCmdLineRunner;
+
+    public RenderscriptProcessor(@NonNull String compilerPath,
+                                 @NonNull List<File> importPaths,
+                                 @NonNull String sourceOutputDir,
+                                 @NonNull String resOutputDir,
+                                 int targetApi,
+                                 boolean debugBuild,
+                                 int optimLevel,
+                                 @NonNull DependencyFileProcessor dependencyFileProcessor,
+                                 @NonNull CommandLineRunner cmdLineRunner) {
+        mCompilerPath = compilerPath;
+        mImportPaths = importPaths;
+        mSourceOutputDir = sourceOutputDir;
+        mResOutputDir = resOutputDir;
+        mTargetApi = targetApi < 11 ? 11 : targetApi;
+        mDebugBuild = debugBuild;
+        mOptimLevel = optimLevel;
+        mDependencyFileProcessor = dependencyFileProcessor;
+        mCmdLineRunner = cmdLineRunner;
+    }
+
+    @Override
+    public void processFile(File sourceFile) throws IOException, InterruptedException {
+        ArrayList<String> command = Lists.newArrayList();
+
+        command.add(mCompilerPath);
+
+        if (mDebugBuild) {
+            command.add("-g");
+        }
+
+        command.add("-O");
+        command.add(Integer.toString(mOptimLevel));
+
+        for (File importPath : mImportPaths) {
+            if (importPath.isDirectory()) {
+                command.add("-I");
+                command.add(importPath.getAbsolutePath());
+            }
+        }
+
+        command.add("-p");
+        command.add(mSourceOutputDir);
+
+        command.add("-o");
+        command.add(mResOutputDir);
+
+        command.add("-target-api");
+        command.add(Integer.toString(mTargetApi));
+
+        // dependency file
+        File tempFolder = Files.createTempDir();
+        command.add("-d");
+        command.add(tempFolder.getAbsolutePath());
+        command.add("-MD");
+
+        // input file
+        command.add(sourceFile.getAbsolutePath());
+
+        mCmdLineRunner.runCmdLine(command);
+
+        // send the dependency file to the processor.
+        // since it's a temp folder, there should be only one file in it, so use that.
+        File[] files = tempFolder.listFiles();
+        if (files != null && files.length > 0) {
+            File depFile = files[0];
+            if (mDependencyFileProcessor.processFile(depFile)) {
+                depFile.delete();
+            }
+        }
+    }
+}
index 4035969..ece4c67 100644 (file)
@@ -157,7 +157,7 @@ public final class Packager implements IArchiveBuilder {
 
     private SignedJarBuilder mBuilder = null;
     private final ILogger mLogger;
-    private boolean mDebugJniMode = false;
+    private boolean mJniDebugMode = false;
     private boolean mIsSealed = false;
 
     private final NullZipFilter mNullFilter = new NullZipFilter();
@@ -273,7 +273,7 @@ public final class Packager implements IArchiveBuilder {
     }
 
     /**
-     * Sets the debug mode. In debug mode, when native libraries are present, the packaging
+     * Sets the JNI debug mode. In debug mode, when native libraries are present, the packaging
      * will also include one or more copies of gdbserver in the final APK file.
      *
      * These are used for debugging native code, to ensure that gdbserver is accessible to the
@@ -283,10 +283,10 @@ public final class Packager implements IArchiveBuilder {
      *
      * the gbdserver files are placed in the libs/abi/ folders automatically by the NDK.
      *
-     * @param debugJniMode the debug-jni mode flag.
+     * @param jniDebugMode the jni-debug mode flag.
      */
-    public void setDebugJniMode(boolean debugJniMode) {
-        mDebugJniMode = debugJniMode;
+    public void setJniDebugMode(boolean jniDebugMode) {
+        mJniDebugMode = jniDebugMode;
     }
 
     /**
@@ -401,7 +401,7 @@ public final class Packager implements IArchiveBuilder {
      * @throws DuplicateFileException if a file conflicts with another already added to the APK
      *                                   at the same location inside the APK archive.
      *
-     * @see #setDebugJniMode(boolean)
+     * @see #setJniDebugMode(boolean)
      */
     public void addNativeLibraries(String jniLibLocation)
             throws PackagerException, SealedPackageException, DuplicateFileException {
@@ -435,7 +435,7 @@ public final class Packager implements IArchiveBuilder {
                             // are gdbserver executables
                             if (lib.isFile() &&
                                     (PATTERN_NATIVELIB_EXT.matcher(lib.getName()).matches() ||
-                                            (mDebugJniMode &&
+                                            (mJniDebugMode &&
                                                     SdkConstants.FN_GDBSERVER.equals(
                                                             lib.getName())))) {
                                 String path =
index 87654d9..b8b5eea 100644 (file)
@@ -32,6 +32,7 @@ public class ProductFlavorTest extends TestCase {
         mCustom = new ProductFlavor("custom");
         mCustom.setMinSdkVersion(42);
         mCustom.setTargetSdkVersion(43);
+        mCustom.setRenderscriptTargetApi(17);
         mCustom.setVersionCode(44);
         mCustom.setVersionName("42.0");
         mCustom.setPackageName("com.forty.two");
@@ -44,6 +45,7 @@ public class ProductFlavorTest extends TestCase {
 
         assertEquals(42, flavor.getMinSdkVersion());
         assertEquals(43, flavor.getTargetSdkVersion());
+        assertEquals(17, flavor.getRenderscriptTargetApi());
         assertEquals(44, flavor.getVersionCode());
         assertEquals("42.0", flavor.getVersionName());
         assertEquals("com.forty.two", flavor.getPackageName());
@@ -56,6 +58,7 @@ public class ProductFlavorTest extends TestCase {
 
         assertEquals(42, flavor.getMinSdkVersion());
         assertEquals(43, flavor.getTargetSdkVersion());
+        assertEquals(17, flavor.getRenderscriptTargetApi());
         assertEquals(44, flavor.getVersionCode());
         assertEquals("42.0", flavor.getVersionName());
         assertEquals("com.forty.two", flavor.getPackageName());
@@ -68,6 +71,7 @@ public class ProductFlavorTest extends TestCase {
 
         assertEquals(-1, flavor.getMinSdkVersion());
         assertEquals(-1, flavor.getTargetSdkVersion());
+        assertEquals(-1, flavor.getRenderscriptTargetApi());
         assertEquals(-1, flavor.getVersionCode());
         assertNull(flavor.getVersionName());
         assertNull(flavor.getPackageName());
index e2f7ffd..a181320 100644 (file)
@@ -98,7 +98,7 @@ class BuildTest extends BaseTest {
 
     void testOverlay1() {
         File project = buildProject("overlay1")
-        File drawableOutput = new File(project, "build/res/debug/drawable" )
+        File drawableOutput = new File(project, "build/res/all/debug/drawable" )
 
         checkImageColor(drawableOutput, "no_overlay.png", (int) 0xFF00FF00)
         checkImageColor(drawableOutput, "type_overlay.png", (int) 0xFF00FF00)
@@ -106,7 +106,7 @@ class BuildTest extends BaseTest {
 
     void testOverlay2() {
         File project = buildProject("overlay2")
-        File drawableOutput = new File(project, "build/res/one/debug/drawable" )
+        File drawableOutput = new File(project, "build/res/all/one/debug/drawable" )
 
         checkImageColor(drawableOutput, "no_overlay.png", (int) 0xFF00FF00)
         checkImageColor(drawableOutput, "type_overlay.png", (int) 0xFF00FF00)
@@ -114,11 +114,19 @@ class BuildTest extends BaseTest {
         checkImageColor(drawableOutput, "type_flavor_overlay.png", (int) 0xFF00FF00)
     }
 
-    void testRepo() {
-        // this is not an actual project, but we add it so that the catch-all below doesn't
-        // try to build it again
-        builtProjects.add("repo")
+    void testRenderscript() {
+        buildProject("renderscript")
+    }
 
+    void testRenderscriptInLib() {
+        buildProject("renderscriptInLib")
+    }
+
+    void testRenderscriptMultiSrc() {
+        buildProject("renderscriptMultiSrc")
+    }
+
+    void testRepo() {
         File repo = new File(testDir, "repo")
 
         try {
@@ -159,6 +167,11 @@ class BuildTest extends BaseTest {
         File project = new File(testDir, name)
         builtProjects.add(name)
 
+        File buildGradle = new File(project, "build.gradle")
+        if (!buildGradle.isFile()) {
+            return null
+        }
+
         // build the project
         runGradleTasks(sdkDir, project, "clean", "assembleDebug")
 
index 4c62e2e..c5e7ad7 100644 (file)
@@ -484,6 +484,9 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
         // Add a task to process the manifest(s)
         createProcessManifestTask(variant, "manifests")
 
+        // Add a task to compile renderscript files.
+        createRenderscriptTask(variant)
+
         // Add a task to merge the resource folders
         createMergeResourcesTask(variant, true /*process9Patch*/)
 
index 8b8cf85..54512c0 100644 (file)
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 package com.android.build.gradle
-
 import com.android.SdkConstants
 import com.android.build.gradle.internal.ApplicationVariant
 import com.android.build.gradle.internal.LoggerWrapper
@@ -29,7 +28,6 @@ import com.android.build.gradle.internal.dependency.SymbolFileProviderImpl
 import com.android.build.gradle.internal.dsl.SigningConfigDsl
 import com.android.build.gradle.internal.tasks.AndroidTestTask
 import com.android.build.gradle.internal.tasks.DependencyReportTask
-import com.android.build.gradle.internal.tasks.IncrementalTask
 import com.android.build.gradle.internal.tasks.InstallTask
 import com.android.build.gradle.internal.tasks.PrepareDependenciesTask
 import com.android.build.gradle.internal.tasks.PrepareLibraryTask
@@ -46,6 +44,7 @@ import com.android.build.gradle.tasks.PackageApplication
 import com.android.build.gradle.tasks.ProcessAndroidResources
 import com.android.build.gradle.tasks.ProcessAppManifest
 import com.android.build.gradle.tasks.ProcessTestManifest
+import com.android.build.gradle.tasks.RenderscriptCompile
 import com.android.build.gradle.tasks.ZipAlign
 import com.android.builder.AndroidBuilder
 import com.android.builder.AndroidDependency
@@ -82,7 +81,6 @@ import org.gradle.api.tasks.compile.JavaCompile
 import org.gradle.internal.reflect.Instantiator
 import org.gradle.tooling.BuildException
 import org.gradle.util.GUtil
-
 /**
  * Base class for all Android plugins
  */
@@ -334,8 +332,37 @@ public abstract class BasePlugin {
         }
     }
 
+    protected void createRenderscriptTask(ApplicationVariant variant) {
+        VariantConfiguration config = variant.config
+
+        def renderscriptTask = project.tasks.add("compile${variant.name}Renderscript",
+                RenderscriptCompile)
+        variant.renderscriptCompileTask = renderscriptTask
+
+        renderscriptTask.dependsOn variant.prepareDependenciesTask
+        renderscriptTask.plugin = this
+        renderscriptTask.variant = variant
+        renderscriptTask.incrementalFolder =
+            project.file("$project.buildDir/incremental/rs/$variant.dirName")
+
+        renderscriptTask.targetApi = config.mergedFlavor.renderscriptTargetApi
+        renderscriptTask.debugBuild = config.buildType.renderscriptDebugBuild
+        renderscriptTask.optimLevel = config.buildType.renderscriptOptimLevel
+
+        renderscriptTask.conventionMapping.sourceDirs = { config.renderscriptSourceList }
+        renderscriptTask.conventionMapping.importDirs = { config.renderscriptImports }
+
+        renderscriptTask.conventionMapping.sourceOutputDir = {
+            project.file("$project.buildDir/source/rs/$variant.dirName")
+        }
+        renderscriptTask.conventionMapping.resOutputDir = {
+            project.file("$project.buildDir/res/rs/$variant.dirName")
+        }
+    }
+
     protected void createMergeResourcesTask(ApplicationVariant variant, boolean process9Patch) {
-        createMergeResourcesTask(variant, "$project.buildDir/res/$variant.dirName", process9Patch)
+        createMergeResourcesTask(variant, "$project.buildDir/res/all/$variant.dirName",
+                process9Patch)
     }
 
     protected void createMergeResourcesTask(ApplicationVariant variant, String location,
@@ -343,6 +370,7 @@ public abstract class BasePlugin {
         def mergeResourcesTask = project.tasks.add("merge${variant.name}Resources", MergeResources)
         variant.mergeResourcesTask = mergeResourcesTask
 
+        mergeResourcesTask.dependsOn variant.renderscriptCompileTask
         mergeResourcesTask.plugin = this
         mergeResourcesTask.variant = variant
         mergeResourcesTask.incrementalFolder =
@@ -350,15 +378,13 @@ public abstract class BasePlugin {
 
         mergeResourcesTask.process9Patch = process9Patch
 
-        mergeResourcesTask.conventionMapping.inputResourceSets = { variant.config.resourceSets }
-        mergeResourcesTask.conventionMapping.rawInputFolders = {
-            IncrementalTask.flattenSourceSets(variant.config.resourceSets)
+        mergeResourcesTask.conventionMapping.inputResourceSets = {
+            variant.config.getResourceSets(variant.renderscriptCompileTask.getResOutputDir())
         }
 
         mergeResourcesTask.conventionMapping.outputDir = {
             project.file(location)
         }
-
     }
 
     protected void createBuildConfigTask(ApplicationVariant variant) {
@@ -504,6 +530,7 @@ public abstract class BasePlugin {
         sourceList.add({ variant.processResourcesTask.sourceOutputDir })
         sourceList.add({ variant.generateBuildConfigTask.sourceOutputDir })
         sourceList.add({ variant.aidlCompileTask.sourceOutputDir })
+        sourceList.add({ variant.renderscriptCompileTask.sourceOutputDir })
 
         if (config.getType() != VariantConfiguration.Type.TEST) {
             sourceList.add(((AndroidSourceSet) config.buildTypeSourceSet).java)
@@ -575,6 +602,9 @@ public abstract class BasePlugin {
         // Add a task to process the manifest
         createProcessTestManifestTask(variant, "manifests")
 
+        // Add a task to compile renderscript files.
+        createRenderscriptTask(variant)
+
         // Add a task to merge the resource folders
         createMergeResourcesTask(variant, true /*process9Patch*/)
 
@@ -690,9 +720,9 @@ public abstract class BasePlugin {
             getOptionalDir(variant.processJavaResources.destinationDir)
         }
 
-        packageApp.conventionMapping.debugJni = { config.buildType.debugJniBuild }
+        packageApp.conventionMapping.jniDebugBuild = { config.buildType.jniDebugBuild }
 
-        SigningConfigDsl sc = config.signingConfig
+        SigningConfigDsl sc = (SigningConfigDsl) config.signingConfig
         packageApp.conventionMapping.signingConfig = { sc }
         if (sc != null) {
             ValidateSigningTask validateSigningTask = validateSigningTaskMap.get(sc)
index d4b5864..d1be77b 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.android.build.gradle
 
+import com.android.SdkConstants
 import com.android.build.gradle.internal.BuildTypeData
 import com.android.build.gradle.internal.DefaultBuildVariant
 import com.android.build.gradle.internal.ProductFlavorData
@@ -152,6 +153,9 @@ public class LibraryPlugin extends BasePlugin implements Plugin<Project> {
         // Add a task to process the manifest(s)
         createProcessManifestTask(variant, DIR_BUNDLES)
 
+        // Add a task to compile renderscript files.
+        createRenderscriptTask(variant)
+
         // Add a task to merge the resource folders
         createMergeResourcesTask(variant, "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/res",
                 false /*process9Patch*/)
@@ -186,8 +190,17 @@ public class LibraryPlugin extends BasePlugin implements Plugin<Project> {
         Copy packageAidl = project.tasks.add("package${variant.name}Aidl", Copy)
         // packageAidl from 3 sources. the order is important to make sure the override works well.
         packageAidl.from(defaultConfigData.sourceSet.aidl.directories,
-                buildTypeData.sourceSet.aidl.directories)
-        packageAidl.into(project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}/aidl"))
+                buildTypeData.sourceSet.aidl.directories).include("**/*.aidl")
+        packageAidl.into(project.file(
+                "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/$SdkConstants.FD_AIDL"))
+
+        // package the renderscript header files files into the bundle folder
+        Copy packageRenderscript = project.tasks.add("package${variant.name}Renderscript", Copy)
+        // packageAidl from 3 sources. the order is important to make sure the override works well.
+        packageRenderscript.from(defaultConfigData.sourceSet.renderscript.directories,
+                buildTypeData.sourceSet.renderscript.directories).include("**/*.rsh")
+        packageRenderscript.into(project.file(
+                "$project.buildDir/$DIR_BUNDLES/${variant.dirName}/$SdkConstants.FD_RENDERSCRIPT"))
 
         // package the R symbol text file into the bundle folder
         Copy packageSymbol = project.tasks.add("package${variant.name}Symbols", Copy)
@@ -196,7 +209,7 @@ public class LibraryPlugin extends BasePlugin implements Plugin<Project> {
         packageSymbol.into(project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}"))
 
         Zip bundle = project.tasks.add("bundle${variant.name}", Zip)
-        bundle.dependsOn jar, packageAidl, packageSymbol
+        bundle.dependsOn jar, packageAidl, packageSymbol, packageRenderscript
         bundle.setDescription("Assembles a bundle containing the library in ${variant.name}.");
         bundle.destinationDir = project.file("$project.buildDir/libs")
         bundle.extension = BuilderConstants.EXT_LIB_ARCHIVE
index a2239c3..b984176 100644 (file)
@@ -25,6 +25,7 @@ import com.android.build.gradle.tasks.MergeResources
 import com.android.build.gradle.tasks.PackageApplication
 import com.android.build.gradle.tasks.ProcessAndroidResources
 import com.android.build.gradle.tasks.ProcessManifest
+import com.android.build.gradle.tasks.RenderscriptCompile
 import com.android.build.gradle.tasks.ZipAlign
 import com.android.builder.AndroidBuilder
 import com.android.builder.ProductFlavor
@@ -44,6 +45,7 @@ public abstract class ApplicationVariant {
     PrepareDependenciesTask prepareDependenciesTask
 
     ProcessManifest processManifestTask
+    RenderscriptCompile renderscriptCompileTask
     AidlCompile aidlCompileTask
     MergeResources mergeResourcesTask
     ProcessAndroidResources processResourcesTask
index 848bc49..1fc1b8f 100644 (file)
@@ -34,20 +34,20 @@ public class BuildTypeDsl extends BuildType implements Serializable {
     public void init(SigningConfig debugSigningConfig) {
         if (BuilderConstants.DEBUG.equals(getName())) {
             setDebuggable(true)
-            setDebugJniBuild(true)
+            setJniDebugBuild(true)
             setZipAlign(false)
 
             assert debugSigningConfig != null
             setSigningConfig(debugSigningConfig)
         } else if (BuilderConstants.RELEASE.equals(getName())) {
             setDebuggable(false)
-            setDebugJniBuild(false)
+            setJniDebugBuild(false)
         }
     }
 
     public BuildTypeDsl initWith(BuildType that) {
         setDebuggable(that.isDebuggable())
-        setDebugJniBuild(that.isDebugJniBuild())
+        setJniDebugBuild(that.isJniDebugBuild())
         setPackageNameSuffix(that.getPackageNameSuffix())
         setVersionNameSuffix(that.getVersionNameSuffix())
         setRunProguard(that.isRunProguard())
index 2df9e50..5d2406b 100644 (file)
@@ -87,7 +87,8 @@ public abstract class DependencyBasedCompileTask extends IncrementalTask {
      *
      * @see #incrementalSetup()
      */
-    protected abstract void compileSingleFile(File file, Object data, DependencyFileProcessor dependencyFileProcessor)
+    protected abstract void compileSingleFile(File file, Object data,
+                                              DependencyFileProcessor dependencyFileProcessor)
 
     @Override
     protected void doFullTaskAction() {
index f956dad..13735eb 100644 (file)
@@ -35,7 +35,9 @@ public class MergeResources extends IncrementalTask {
 
     // fake input to detect changes. Not actually used by the task
     @InputFiles
-    Iterable<File> rawInputFolders
+    Iterable<File> getRawInputFolders() {
+        return IncrementalTask.flattenSourceSets(getInputResourceSets())
+    }
 
     @Input
     boolean process9Patch
index e8d9644..ccf3cb5 100644 (file)
@@ -52,7 +52,7 @@ public class PackageApplication extends IncrementalTask {
     List<File> packagedJars
 
     @Input
-    boolean debugJni
+    boolean jniDebugBuild
 
     @Nested @Optional
     SigningConfigDsl signingConfig
@@ -66,7 +66,7 @@ public class PackageApplication extends IncrementalTask {
                     getPackagedJars(),
                     getJavaResourceDir()?.absolutePath,
                     getJniDir()?.absolutePath,
-                    getDebugJni(),
+                    getJniDebugBuild(),
                     getSigningConfig(),
                     getOutputFile().absolutePath)
         } catch (DuplicateFileException e) {
diff --git a/gradle/src/main/groovy/com/android/build/gradle/tasks/RenderscriptCompile.groovy b/gradle/src/main/groovy/com/android/build/gradle/tasks/RenderscriptCompile.groovy
new file mode 100644 (file)
index 0000000..9192e25
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.build.gradle.tasks
+import com.android.build.gradle.internal.tasks.DependencyBasedCompileTask
+import com.android.builder.compiling.DependencyFileProcessor
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.OutputDirectory
+/**
+ * Task to compile Renderscript files. Supports incremental update.
+ */
+public class RenderscriptCompile extends DependencyBasedCompileTask {
+
+    // ----- PUBLIC TASK API -----
+
+    @OutputDirectory
+    File resOutputDir
+
+    // ----- PRIVATE TASK API -----
+
+    @InputFiles
+    List<File> sourceDirs
+
+    @InputFiles
+    List<File> importDirs
+
+    @Input
+    int optimLevel
+
+    @Input
+    int targetApi
+
+    @Input
+    boolean debugBuild
+
+    @Override
+    protected boolean isIncremental() {
+        return true
+    }
+
+    @Override
+    protected Collection<File> getOutputForIncrementalBuild() {
+        return Collections.singletonList(getSourceOutputDir())
+    }
+
+    @Override
+    protected void compileAllFiles(DependencyFileProcessor dependencyFileProcessor) {
+
+        List<File> importFolders = getBuilder().getLeafFolders("rsh",
+                getImportDirs(), getSourceDirs())
+
+        getBuilder().compileAllRenderscriptFiles(
+                getSourceDirs(),
+                importFolders,
+                getSourceOutputDir(),
+                getResOutputDir(),
+                getTargetApi(),
+                getDebugBuild(),
+                getOptimLevel(),
+                dependencyFileProcessor)
+    }
+
+    @Override
+    protected Object incrementalSetup() {
+        return getBuilder().getLeafFolders("rsh", getImportDirs(), getSourceDirs())
+    }
+
+    @Override
+    protected void compileSingleFile(File file,Object data,
+                                     DependencyFileProcessor dependencyFileProcessor) {
+        getBuilder().compileRenderscriptFile(
+                file,
+                (List<File>) data,
+                getSourceOutputDir(),
+                getResOutputDir(),
+                getTargetApi(),
+                getDebugBuild(),
+                getOptimLevel(),
+                dependencyFileProcessor)
+    }
+}
index 03ba885..64a9e14 100644 (file)
@@ -43,7 +43,7 @@ public class BuildTypeDslTest extends BaseTest {
         BuildType type = plugin.buildTypes.get(BuilderConstants.DEBUG).buildType
 
         assertTrue(type.isDebuggable());
-        assertTrue(type.isDebugJniBuild());
+        assertTrue(type.isJniDebugBuild());
         assertNotNull(type.getSigningConfig());
         assertTrue(type.getSigningConfig().isSigningReady());
     }
@@ -63,7 +63,7 @@ public class BuildTypeDslTest extends BaseTest {
         BuildType type = plugin.buildTypes.get(BuilderConstants.RELEASE).buildType
 
         assertFalse(type.isDebuggable());
-        assertFalse(type.isDebugJniBuild());
+        assertFalse(type.isJniDebugBuild());
     }
 
     public void testInitWith() {
@@ -94,7 +94,7 @@ public class BuildTypeDslTest extends BaseTest {
         BuildType fooType = plugin.buildTypes.get("foo").buildType
 
         assertEquals(debugType.isDebuggable(),         fooType.isDebuggable())
-        assertEquals(debugType.isDebugJniBuild(),      fooType.isDebugJniBuild())
+        assertEquals(debugType.isJniDebugBuild(),      fooType.isJniDebugBuild())
         assertEquals(debugType.isZipAlign(),           fooType.isZipAlign())
         assertEquals(debugType.getVersionNameSuffix(), fooType.getVersionNameSuffix())
         assertEquals(debugType.getSigningConfig(),     fooType.getSigningConfig())
diff --git a/tests/renderscript/build.gradle b/tests/renderscript/build.gradle
new file mode 100644 (file)
index 0000000..1a92390
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// A basic Android application that follows all the conventions
+//
+buildscript {
+    repositories {
+        maven { url '../../repo' }
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.3-SNAPSHOT'
+    }
+}
+apply plugin: 'android'
+
+android {
+    target "android-17"
+
+    defaultConfig {
+        renderscriptTargetApi = 17
+    }
+}
\ No newline at end of file
diff --git a/tests/renderscript/src/main/AndroidManifest.xml b/tests/renderscript/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..73e1110
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.hellocompute">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    
+    <uses-sdk android:minSdkVersion="14" />
+    <application android:label="RsHelloCompute">
+        <activity android:name="HelloCompute">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/renderscript/src/main/java/com/example/android/rs/hellocompute/HelloCompute.java b/tests/renderscript/src/main/java/com/example/android/rs/hellocompute/HelloCompute.java
new file mode 100644 (file)
index 0000000..0d6c47b
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 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.example.android.rs.hellocompute;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.renderscript.RenderScript;
+import android.renderscript.Allocation;
+import android.widget.ImageView;
+
+public class HelloCompute extends Activity {
+    private Bitmap mBitmapIn;
+    private Bitmap mBitmapOut;
+
+    private RenderScript mRS;
+    private Allocation mInAllocation;
+    private Allocation mOutAllocation;
+    private ScriptC_mono mScript;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        mBitmapIn = loadBitmap(R.drawable.data);
+        mBitmapOut = Bitmap.createBitmap(mBitmapIn.getWidth(), mBitmapIn.getHeight(),
+                                         mBitmapIn.getConfig());
+
+        ImageView in = (ImageView) findViewById(R.id.displayin);
+        in.setImageBitmap(mBitmapIn);
+
+        ImageView out = (ImageView) findViewById(R.id.displayout);
+        out.setImageBitmap(mBitmapOut);
+
+        createScript();
+    }
+
+
+    private void createScript() {
+        mRS = RenderScript.create(this);
+
+        mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
+                                                    Allocation.MipmapControl.MIPMAP_NONE,
+                                                    Allocation.USAGE_SCRIPT);
+        mOutAllocation = Allocation.createTyped(mRS, mInAllocation.getType());
+
+        mScript = new ScriptC_mono(mRS, getResources(), R.raw.mono);
+
+        mScript.forEach_root(mInAllocation, mOutAllocation);
+        mOutAllocation.copyTo(mBitmapOut);
+    }
+
+    private Bitmap loadBitmap(int resource) {
+        final BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        return BitmapFactory.decodeResource(getResources(), resource, options);
+    }
+}
diff --git a/tests/renderscript/src/main/res/drawable/data.jpg b/tests/renderscript/src/main/res/drawable/data.jpg
new file mode 100644 (file)
index 0000000..81a87b1
Binary files /dev/null and b/tests/renderscript/src/main/res/drawable/data.jpg differ
diff --git a/tests/renderscript/src/main/res/layout/main.xml b/tests/renderscript/src/main/res/layout/main.xml
new file mode 100644 (file)
index 0000000..3f7de43
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/displayin"
+        android:layout_width="320dip"
+        android:layout_height="266dip" />
+
+    <ImageView
+        android:id="@+id/displayout"
+        android:layout_width="320dip"
+        android:layout_height="266dip" />
+
+</LinearLayout>
diff --git a/tests/renderscript/src/main/rs/com/example/android/rs/hellocompute/mono.rs b/tests/renderscript/src/main/rs/com/example/android/rs/hellocompute/mono.rs
new file mode 100644 (file)
index 0000000..08592f5
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.hellocompute)
+
+const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
+
+void root(const uchar4 *v_in, uchar4 *v_out) {
+    float4 f4 = rsUnpackColor8888(*v_in);
+
+    float3 mono = dot(f4.rgb, gMonoMult);
+    *v_out = rsPackColorTo8888(mono);
+}
+
diff --git a/tests/renderscriptInLib/app/build.gradle b/tests/renderscriptInLib/app/build.gradle
new file mode 100644 (file)
index 0000000..f04e302
--- /dev/null
@@ -0,0 +1,13 @@
+apply plugin: 'android'
+
+android {
+    target "android-17"
+
+    defaultConfig {
+        renderscriptTargetApi = 11
+    }
+}
+
+dependencies {
+    compile project(':lib')
+}
diff --git a/tests/renderscriptInLib/app/src/main/AndroidManifest.xml b/tests/renderscriptInLib/app/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..c0ae2ff
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.balls">
+    <uses-sdk android:minSdkVersion="11" />
+    <application 
+        android:label="RsBalls"
+        android:icon="@drawable/test_pattern">
+        <activity android:name="Balls"
+                  android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/renderscriptInLib/app/src/main/java/com/example/android/rs/balls/Balls.java b/tests/renderscriptInLib/app/src/main/java/com/example/android/rs/balls/Balls.java
new file mode 100644 (file)
index 0000000..d3b900a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.balls;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+public class Balls extends Activity implements SensorEventListener {
+    //EventListener mListener = new EventListener();
+
+    private static final String LOG_TAG = "libRS_jni";
+    private static final boolean DEBUG  = false;
+    private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+    private BallsView mView;
+    private SensorManager mSensorManager;
+
+    // get the current looper (from your Activity UI thread for instance
+
+
+    public void onSensorChanged(SensorEvent event) {
+        //android.util.Log.d("rs", "sensor: " + event.sensor + ", x: " + event.values[0] + ", y: " + event.values[1] + ", z: " + event.values[2]);
+        synchronized (this) {
+            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+                if(mView != null) {
+                    mView.setAccel(event.values[0], event.values[1], event.values[2]);
+                }
+            }
+        }
+    }
+
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new BallsView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        mSensorManager.registerListener(this,
+                                        mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+                                        SensorManager.SENSOR_DELAY_FASTEST);
+
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mView.pause();
+        Runtime.getRuntime().exit(0);
+    }
+
+    @Override
+    protected void onStop() {
+        mSensorManager.unregisterListener(this);
+        super.onStop();
+    }
+
+    static void log(String message) {
+        if (LOG_ENABLED) {
+            Log.v(LOG_TAG, message);
+        }
+    }
+
+
+}
+
diff --git a/tests/renderscriptInLib/app/src/main/java/com/example/android/rs/balls/BallsRS.java b/tests/renderscriptInLib/app/src/main/java/com/example/android/rs/balls/BallsRS.java
new file mode 100644 (file)
index 0000000..8cab9b8
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.balls;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+public class BallsRS {
+    public static final int PART_COUNT = 900;
+
+    public BallsRS() {
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private ScriptC_balls mScript;
+    private ScriptC_ball_physics mPhysicsScript;
+    private ProgramFragment mPFLines;
+    private ProgramFragment mPFPoints;
+    private ProgramVertex mPV;
+    private ScriptField_Point mPoints;
+    private ScriptField_VpConsts mVpConsts;
+
+    void updateProjectionMatrices() {
+        mVpConsts = new ScriptField_VpConsts(mRS, 1,
+                                             Allocation.USAGE_SCRIPT |
+                                             Allocation.USAGE_GRAPHICS_CONSTANTS);
+        ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
+        Matrix4f mvp = new Matrix4f();
+        mvp.loadOrtho(0, mRS.getWidth(), mRS.getHeight(), 0, -1, 1);
+        i.MVP = mvp;
+        mVpConsts.set(i, 0, true);
+    }
+
+    private void createProgramVertex() {
+        updateProjectionMatrices();
+
+        ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS);
+        String t =  "varying vec4 varColor;\n" +
+                    "void main() {\n" +
+                    "  vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n" +
+                    "  pos.xy = ATTRIB_position;\n" +
+                    "  gl_Position = UNI_MVP * pos;\n" +
+                    "  varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
+                    "  gl_PointSize = ATTRIB_size;\n" +
+                    "}\n";
+        sb.setShader(t);
+        sb.addConstant(mVpConsts.getType());
+        sb.addInput(mPoints.getElement());
+        ProgramVertex pvs = sb.create();
+        pvs.bindConstants(mVpConsts.getAllocation(), 0);
+        mRS.bindProgramVertex(pvs);
+    }
+
+    private Allocation loadTexture(int id) {
+        final Allocation allocation =
+            Allocation.createFromBitmapResource(mRS, mRes,
+                id, Allocation.MipmapControl.MIPMAP_NONE,
+                Allocation.USAGE_GRAPHICS_TEXTURE);
+        return allocation;
+    }
+
+    ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+        ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
+        builder.setDitherEnabled(false);
+        builder.setDepthMaskEnabled(false);
+        return builder.create();
+    }
+
+    public void init(RenderScriptGL rs, Resources res, int width, int height) {
+        mRS = rs;
+        mRes = res;
+
+        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+        pfb.setPointSpriteTexCoordinateReplacement(true);
+        pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
+                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+        pfb.setVaryingColor(true);
+        mPFPoints = pfb.create();
+
+        pfb = new ProgramFragmentFixedFunction.Builder(rs);
+        pfb.setVaryingColor(true);
+        mPFLines = pfb.create();
+
+        android.util.Log.e("rs", "Load texture");
+        mPFPoints.bindTexture(loadTexture(R.drawable.flares), 0);
+
+        mPoints = new ScriptField_Point(mRS, PART_COUNT, Allocation.USAGE_SCRIPT);
+
+        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+        smb.addVertexAllocation(mPoints.getAllocation());
+        smb.addIndexSetType(Mesh.Primitive.POINT);
+        Mesh smP = smb.create();
+
+        mPhysicsScript = new ScriptC_ball_physics(mRS, mRes, R.raw.ball_physics);
+
+        mScript = new ScriptC_balls(mRS, mRes, R.raw.balls);
+        mScript.set_partMesh(smP);
+        mScript.set_physics_script(mPhysicsScript);
+        mScript.bind_point(mPoints);
+        mScript.bind_balls1(new ScriptField_Ball(mRS, PART_COUNT, Allocation.USAGE_SCRIPT));
+        mScript.bind_balls2(new ScriptField_Ball(mRS, PART_COUNT, Allocation.USAGE_SCRIPT));
+
+        mScript.set_gPFLines(mPFLines);
+        mScript.set_gPFPoints(mPFPoints);
+        createProgramVertex();
+
+        mRS.bindProgramStore(BLEND_ADD_DEPTH_NONE(mRS));
+
+        mPhysicsScript.set_gMinPos(new Float2(5, 5));
+        mPhysicsScript.set_gMaxPos(new Float2(width - 5, height - 5));
+
+        mScript.invoke_initParts(width, height);
+
+        mRS.bindRootScript(mScript);
+    }
+
+    public void newTouchPosition(float x, float y, float pressure, int id) {
+        mPhysicsScript.invoke_touch(x, y, pressure, id);
+    }
+
+    public void setAccel(float x, float y) {
+        mPhysicsScript.set_gGravityVector(new Float2(x, y));
+    }
+
+}
diff --git a/tests/renderscriptInLib/app/src/main/java/com/example/android/rs/balls/BallsView.java b/tests/renderscriptInLib/app/src/main/java/com/example/android/rs/balls/BallsView.java
new file mode 100644 (file)
index 0000000..b3b3756
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.balls;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class BallsView extends RSSurfaceView {
+
+    public BallsView(Context context) {
+        super(context);
+        //setFocusable(true);
+    }
+
+    private RenderScriptGL mRS;
+    private BallsRS mRender;
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            mRS = createRenderScriptGL(sc);
+            mRS.setSurface(holder, w, h);
+            mRender = new BallsRS();
+            mRender.init(mRS, getResources(), w, h);
+        }
+        mRender.updateProjectionMatrices();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if(mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev)
+    {
+        int act = ev.getActionMasked();
+        if (act == ev.ACTION_UP) {
+            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+            return false;
+        } else if (act == MotionEvent.ACTION_POINTER_UP) {
+            // only one pointer going up, we can get the index like this
+            int pointerIndex = ev.getActionIndex();
+            int pointerId = ev.getPointerId(pointerIndex);
+            mRender.newTouchPosition(0, 0, 0, pointerId);
+            return false;
+        }
+        int count = ev.getHistorySize();
+        int pcount = ev.getPointerCount();
+
+        for (int p=0; p < pcount; p++) {
+            int id = ev.getPointerId(p);
+            mRender.newTouchPosition(ev.getX(p),
+                                     ev.getY(p),
+                                     ev.getPressure(p),
+                                     id);
+
+            for (int i=0; i < count; i++) {
+                mRender.newTouchPosition(ev.getHistoricalX(p, i),
+                                         ev.getHistoricalY(p, i),
+                                         ev.getHistoricalPressure(p, i),
+                                         id);
+            }
+        }
+        return true;
+    }
+
+    void setAccel(float x, float y, float z) {
+        if (mRender == null) {
+            return;
+        }
+        mRender.setAccel(x, -y);
+    }
+
+}
+
+
diff --git a/tests/renderscriptInLib/app/src/main/res/drawable/flares.png b/tests/renderscriptInLib/app/src/main/res/drawable/flares.png
new file mode 100644 (file)
index 0000000..3a5c970
Binary files /dev/null and b/tests/renderscriptInLib/app/src/main/res/drawable/flares.png differ
diff --git a/tests/renderscriptInLib/app/src/main/res/drawable/test_pattern.png b/tests/renderscriptInLib/app/src/main/res/drawable/test_pattern.png
new file mode 100644 (file)
index 0000000..e7d1455
Binary files /dev/null and b/tests/renderscriptInLib/app/src/main/res/drawable/test_pattern.png differ
diff --git a/tests/renderscriptInLib/app/src/main/rs/com/example/android/rs/balls/ball_physics.rs b/tests/renderscriptInLib/app/src/main/rs/com/example/android/rs/balls/ball_physics.rs
new file mode 100644 (file)
index 0000000..ee6ab1d
--- /dev/null
@@ -0,0 +1,146 @@
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.balls)
+
+#include "balls.rsh"
+
+float2 gGravityVector = {0.f, 9.8f};
+
+float2 gMinPos = {0.f, 0.f};
+float2 gMaxPos = {1280.f, 700.f};
+
+static float2 touchPos[10];
+static float touchPressure[10];
+
+void touch(float x, float y, float pressure, int id) {
+    if (id >= 10) {
+        return;
+    }
+
+    touchPos[id].x = x;
+    touchPos[id].y = y;
+    touchPressure[id] = pressure;
+}
+
+void root(const Ball_t *ballIn, Ball_t *ballOut, const BallControl_t *ctl, uint32_t x) {
+    float2 fv = {0, 0};
+    float2 pos = ballIn->position;
+
+    int arcID = -1;
+    float arcInvStr = 100000;
+
+    const Ball_t * bPtr = rsGetElementAt(ctl->ain, 0);
+    for (uint32_t xin = 0; xin < ctl->dimX; xin++) {
+        float2 vec = bPtr[xin].position - pos;
+        float2 vec2 = vec * vec;
+        float len2 = vec2.x + vec2.y;
+
+        if (len2 < 10000) {
+            //float minDist = ballIn->size + bPtr[xin].size;
+            float forceScale = ballIn->size * bPtr[xin].size;
+            forceScale *= forceScale;
+
+            if (len2 > 16 /* (minDist*minDist)*/)  {
+                // Repulsion
+                float len = sqrt(len2);
+                fv -= (vec / (len * len * len)) * 20000.f * forceScale;
+            } else {
+                if (len2 < 1) {
+                    if (xin == x) {
+                        continue;
+                    }
+                    ballOut->delta = 0.f;
+                    ballOut->position = ballIn->position;
+                    if (xin > x) {
+                        ballOut->position.x += 1.f;
+                    } else {
+                        ballOut->position.x -= 1.f;
+                    }
+                    //ballOut->color.rgb = 1.f;
+                    //ballOut->arcID = -1;
+                    //ballOut->arcStr = 0;
+                    return;
+                }
+                // Collision
+                float2 axis = normalize(vec);
+                float e1 = dot(axis, ballIn->delta);
+                float e2 = dot(axis, bPtr[xin].delta);
+                float e = (e1 - e2) * 0.45f;
+                if (e1 > 0) {
+                    fv -= axis * e;
+                } else {
+                    fv += axis * e;
+                }
+            }
+        }
+    }
+
+    fv /= ballIn->size * ballIn->size * ballIn->size;
+    fv -= gGravityVector * 4.f;
+    fv *= ctl->dt;
+
+    for (int i=0; i < 10; i++) {
+        if (touchPressure[i] > 0.1f) {
+            float2 vec = touchPos[i] - ballIn->position;
+            float2 vec2 = vec * vec;
+            float len2 = max(2.f, vec2.x + vec2.y);
+            fv -= (vec / len2) * touchPressure[i] * 300.f;
+        }
+    }
+
+    ballOut->delta = (ballIn->delta * (1.f - 0.004f)) + fv;
+    ballOut->position = ballIn->position + (ballOut->delta * ctl->dt);
+
+    const float wallForce = 400.f;
+    if (ballOut->position.x > (gMaxPos.x - 20.f)) {
+        float d = gMaxPos.x - ballOut->position.x;
+        if (d < 0.f) {
+            if (ballOut->delta.x > 0) {
+                ballOut->delta.x *= -0.7;
+            }
+            ballOut->position.x = gMaxPos.x;
+        } else {
+            ballOut->delta.x -= min(wallForce / (d * d), 10.f);
+        }
+    }
+
+    if (ballOut->position.x < (gMinPos.x + 20.f)) {
+        float d = ballOut->position.x - gMinPos.x;
+        if (d < 0.f) {
+            if (ballOut->delta.x < 0) {
+                ballOut->delta.x *= -0.7;
+            }
+            ballOut->position.x = gMinPos.x + 1.f;
+        } else {
+            ballOut->delta.x += min(wallForce / (d * d), 10.f);
+        }
+    }
+
+    if (ballOut->position.y > (gMaxPos.y - 20.f)) {
+        float d = gMaxPos.y - ballOut->position.y;
+        if (d < 0.f) {
+            if (ballOut->delta.y > 0) {
+                ballOut->delta.y *= -0.7;
+            }
+            ballOut->position.y = gMaxPos.y;
+        } else {
+            ballOut->delta.y -= min(wallForce / (d * d), 10.f);
+        }
+    }
+
+    if (ballOut->position.y < (gMinPos.y + 20.f)) {
+        float d = ballOut->position.y - gMinPos.y;
+        if (d < 0.f) {
+            if (ballOut->delta.y < 0) {
+                ballOut->delta.y *= -0.7;
+            }
+            ballOut->position.y = gMinPos.y + 1.f;
+        } else {
+            ballOut->delta.y += min(wallForce / (d * d * d), 10.f);
+        }
+    }
+
+    ballOut->size = ballIn->size;
+
+    //rsDebug("physics pos out", ballOut->position);
+}
+
diff --git a/tests/renderscriptInLib/app/src/main/rs/com/example/android/rs/balls/balls.rs b/tests/renderscriptInLib/app/src/main/rs/com/example/android/rs/balls/balls.rs
new file mode 100644 (file)
index 0000000..d86b804
--- /dev/null
@@ -0,0 +1,85 @@
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.balls)
+#include "rs_graphics.rsh"
+
+#include "balls.rsh"
+
+#pragma stateVertex(parent)
+#pragma stateStore(parent)
+
+rs_program_fragment gPFPoints;
+rs_program_fragment gPFLines;
+rs_mesh partMesh;
+
+typedef struct __attribute__((packed, aligned(4))) Point {
+    float2 position;
+    float size;
+} Point_t;
+Point_t *point;
+
+typedef struct VpConsts {
+    rs_matrix4x4 MVP;
+} VpConsts_t;
+VpConsts_t *vpConstants;
+
+rs_script physics_script;
+
+Ball_t *balls1;
+Ball_t *balls2;
+
+static int frame = 0;
+
+void initParts(int w, int h)
+{
+    uint32_t dimX = rsAllocationGetDimX(rsGetAllocation(balls1));
+
+    for (uint32_t ct=0; ct < dimX; ct++) {
+        balls1[ct].position.x = rsRand(0.f, (float)w);
+        balls1[ct].position.y = rsRand(0.f, (float)h);
+        balls1[ct].delta.x = 0.f;
+        balls1[ct].delta.y = 0.f;
+        balls1[ct].size = 1.f;
+
+        float r = rsRand(100.f);
+        if (r > 90.f) {
+            balls1[ct].size += pow(10.f, rsRand(0.f, 2.f)) * 0.07;
+        }
+    }
+}
+
+
+
+int root() {
+    rsgClearColor(0.f, 0.f, 0.f, 1.f);
+
+    BallControl_t bc;
+    Ball_t *bout;
+
+    if (frame & 1) {
+        rsSetObject(&bc.ain, rsGetAllocation(balls2));
+        rsSetObject(&bc.aout, rsGetAllocation(balls1));
+        bout = balls2;
+    } else {
+        rsSetObject(&bc.ain, rsGetAllocation(balls1));
+        rsSetObject(&bc.aout, rsGetAllocation(balls2));
+        bout = balls1;
+    }
+
+    bc.dimX = rsAllocationGetDimX(bc.ain);
+    bc.dt = 1.f / 30.f;
+
+    rsForEach(physics_script, bc.ain, bc.aout, &bc);
+
+    for (uint32_t ct=0; ct < bc.dimX; ct++) {
+        point[ct].position = bout[ct].position;
+        point[ct].size = 6.f /*+ bout[ct].color.g * 6.f*/ * bout[ct].size;
+    }
+
+    frame++;
+    rsgBindProgramFragment(gPFPoints);
+    rsgDrawMesh(partMesh);
+    rsClearObject(&bc.ain);
+    rsClearObject(&bc.aout);
+    return 1;
+}
+
diff --git a/tests/renderscriptInLib/build.gradle b/tests/renderscriptInLib/build.gradle
new file mode 100644 (file)
index 0000000..a0832c6
--- /dev/null
@@ -0,0 +1,8 @@
+buildscript {
+    repositories {
+        maven { url '../../repo' }
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.3-SNAPSHOT'
+    }
+}
diff --git a/tests/renderscriptInLib/lib/build.gradle b/tests/renderscriptInLib/lib/build.gradle
new file mode 100644 (file)
index 0000000..b7ce7ab
--- /dev/null
@@ -0,0 +1,5 @@
+apply plugin: 'android-library'
+
+android {
+    target 'android-15'
+}
diff --git a/tests/renderscriptInLib/lib/src/main/AndroidManifest.xml b/tests/renderscriptInLib/lib/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..469aac1
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.balls.lib">
+    <uses-sdk android:minSdkVersion="11" />
+</manifest>
diff --git a/tests/renderscriptInLib/lib/src/main/rs/com/example/android/rs/balls/balls.rsh b/tests/renderscriptInLib/lib/src/main/rs/com/example/android/rs/balls/balls.rsh
new file mode 100644 (file)
index 0000000..fc886f9
--- /dev/null
@@ -0,0 +1,18 @@
+
+typedef struct __attribute__((packed, aligned(4))) Ball {
+    float2 delta;
+    float2 position;
+    //float3 color;
+    float size;
+    //int arcID;
+    //float arcStr;
+} Ball_t;
+Ball_t *balls;
+
+
+typedef struct BallControl {
+    uint32_t dimX;
+    rs_allocation ain;
+    rs_allocation aout;
+    float dt;
+} BallControl_t;
diff --git a/tests/renderscriptInLib/settings.gradle b/tests/renderscriptInLib/settings.gradle
new file mode 100644 (file)
index 0000000..5ed7972
--- /dev/null
@@ -0,0 +1,2 @@
+include 'app'
+include 'lib'
\ No newline at end of file
diff --git a/tests/renderscriptMultiSrc/build.gradle b/tests/renderscriptMultiSrc/build.gradle
new file mode 100644 (file)
index 0000000..13825b4
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// A basic Android application that follows all the conventions
+//
+buildscript {
+    repositories {
+        maven { url '../../repo' }
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.3-SNAPSHOT'
+    }
+}
+apply plugin: 'android'
+
+android {
+    target "android-17"
+
+    defaultConfig {
+        renderscriptTargetApi = 11
+    }
+}
\ No newline at end of file
diff --git a/tests/renderscriptMultiSrc/src/debug/rs/com/example/android/rs/balls/balls.rsh b/tests/renderscriptMultiSrc/src/debug/rs/com/example/android/rs/balls/balls.rsh
new file mode 100644 (file)
index 0000000..fc886f9
--- /dev/null
@@ -0,0 +1,18 @@
+
+typedef struct __attribute__((packed, aligned(4))) Ball {
+    float2 delta;
+    float2 position;
+    //float3 color;
+    float size;
+    //int arcID;
+    //float arcStr;
+} Ball_t;
+Ball_t *balls;
+
+
+typedef struct BallControl {
+    uint32_t dimX;
+    rs_allocation ain;
+    rs_allocation aout;
+    float dt;
+} BallControl_t;
diff --git a/tests/renderscriptMultiSrc/src/main/AndroidManifest.xml b/tests/renderscriptMultiSrc/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..c0ae2ff
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.balls">
+    <uses-sdk android:minSdkVersion="11" />
+    <application 
+        android:label="RsBalls"
+        android:icon="@drawable/test_pattern">
+        <activity android:name="Balls"
+                  android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/renderscriptMultiSrc/src/main/java/com/example/android/rs/balls/Balls.java b/tests/renderscriptMultiSrc/src/main/java/com/example/android/rs/balls/Balls.java
new file mode 100644 (file)
index 0000000..d3b900a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.balls;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+public class Balls extends Activity implements SensorEventListener {
+    //EventListener mListener = new EventListener();
+
+    private static final String LOG_TAG = "libRS_jni";
+    private static final boolean DEBUG  = false;
+    private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+    private BallsView mView;
+    private SensorManager mSensorManager;
+
+    // get the current looper (from your Activity UI thread for instance
+
+
+    public void onSensorChanged(SensorEvent event) {
+        //android.util.Log.d("rs", "sensor: " + event.sensor + ", x: " + event.values[0] + ", y: " + event.values[1] + ", z: " + event.values[2]);
+        synchronized (this) {
+            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+                if(mView != null) {
+                    mView.setAccel(event.values[0], event.values[1], event.values[2]);
+                }
+            }
+        }
+    }
+
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new BallsView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        mSensorManager.registerListener(this,
+                                        mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+                                        SensorManager.SENSOR_DELAY_FASTEST);
+
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mView.pause();
+        Runtime.getRuntime().exit(0);
+    }
+
+    @Override
+    protected void onStop() {
+        mSensorManager.unregisterListener(this);
+        super.onStop();
+    }
+
+    static void log(String message) {
+        if (LOG_ENABLED) {
+            Log.v(LOG_TAG, message);
+        }
+    }
+
+
+}
+
diff --git a/tests/renderscriptMultiSrc/src/main/java/com/example/android/rs/balls/BallsRS.java b/tests/renderscriptMultiSrc/src/main/java/com/example/android/rs/balls/BallsRS.java
new file mode 100644 (file)
index 0000000..8cab9b8
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.balls;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+public class BallsRS {
+    public static final int PART_COUNT = 900;
+
+    public BallsRS() {
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private ScriptC_balls mScript;
+    private ScriptC_ball_physics mPhysicsScript;
+    private ProgramFragment mPFLines;
+    private ProgramFragment mPFPoints;
+    private ProgramVertex mPV;
+    private ScriptField_Point mPoints;
+    private ScriptField_VpConsts mVpConsts;
+
+    void updateProjectionMatrices() {
+        mVpConsts = new ScriptField_VpConsts(mRS, 1,
+                                             Allocation.USAGE_SCRIPT |
+                                             Allocation.USAGE_GRAPHICS_CONSTANTS);
+        ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
+        Matrix4f mvp = new Matrix4f();
+        mvp.loadOrtho(0, mRS.getWidth(), mRS.getHeight(), 0, -1, 1);
+        i.MVP = mvp;
+        mVpConsts.set(i, 0, true);
+    }
+
+    private void createProgramVertex() {
+        updateProjectionMatrices();
+
+        ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS);
+        String t =  "varying vec4 varColor;\n" +
+                    "void main() {\n" +
+                    "  vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n" +
+                    "  pos.xy = ATTRIB_position;\n" +
+                    "  gl_Position = UNI_MVP * pos;\n" +
+                    "  varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
+                    "  gl_PointSize = ATTRIB_size;\n" +
+                    "}\n";
+        sb.setShader(t);
+        sb.addConstant(mVpConsts.getType());
+        sb.addInput(mPoints.getElement());
+        ProgramVertex pvs = sb.create();
+        pvs.bindConstants(mVpConsts.getAllocation(), 0);
+        mRS.bindProgramVertex(pvs);
+    }
+
+    private Allocation loadTexture(int id) {
+        final Allocation allocation =
+            Allocation.createFromBitmapResource(mRS, mRes,
+                id, Allocation.MipmapControl.MIPMAP_NONE,
+                Allocation.USAGE_GRAPHICS_TEXTURE);
+        return allocation;
+    }
+
+    ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+        ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
+        builder.setDitherEnabled(false);
+        builder.setDepthMaskEnabled(false);
+        return builder.create();
+    }
+
+    public void init(RenderScriptGL rs, Resources res, int width, int height) {
+        mRS = rs;
+        mRes = res;
+
+        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+        pfb.setPointSpriteTexCoordinateReplacement(true);
+        pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
+                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+        pfb.setVaryingColor(true);
+        mPFPoints = pfb.create();
+
+        pfb = new ProgramFragmentFixedFunction.Builder(rs);
+        pfb.setVaryingColor(true);
+        mPFLines = pfb.create();
+
+        android.util.Log.e("rs", "Load texture");
+        mPFPoints.bindTexture(loadTexture(R.drawable.flares), 0);
+
+        mPoints = new ScriptField_Point(mRS, PART_COUNT, Allocation.USAGE_SCRIPT);
+
+        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+        smb.addVertexAllocation(mPoints.getAllocation());
+        smb.addIndexSetType(Mesh.Primitive.POINT);
+        Mesh smP = smb.create();
+
+        mPhysicsScript = new ScriptC_ball_physics(mRS, mRes, R.raw.ball_physics);
+
+        mScript = new ScriptC_balls(mRS, mRes, R.raw.balls);
+        mScript.set_partMesh(smP);
+        mScript.set_physics_script(mPhysicsScript);
+        mScript.bind_point(mPoints);
+        mScript.bind_balls1(new ScriptField_Ball(mRS, PART_COUNT, Allocation.USAGE_SCRIPT));
+        mScript.bind_balls2(new ScriptField_Ball(mRS, PART_COUNT, Allocation.USAGE_SCRIPT));
+
+        mScript.set_gPFLines(mPFLines);
+        mScript.set_gPFPoints(mPFPoints);
+        createProgramVertex();
+
+        mRS.bindProgramStore(BLEND_ADD_DEPTH_NONE(mRS));
+
+        mPhysicsScript.set_gMinPos(new Float2(5, 5));
+        mPhysicsScript.set_gMaxPos(new Float2(width - 5, height - 5));
+
+        mScript.invoke_initParts(width, height);
+
+        mRS.bindRootScript(mScript);
+    }
+
+    public void newTouchPosition(float x, float y, float pressure, int id) {
+        mPhysicsScript.invoke_touch(x, y, pressure, id);
+    }
+
+    public void setAccel(float x, float y) {
+        mPhysicsScript.set_gGravityVector(new Float2(x, y));
+    }
+
+}
diff --git a/tests/renderscriptMultiSrc/src/main/java/com/example/android/rs/balls/BallsView.java b/tests/renderscriptMultiSrc/src/main/java/com/example/android/rs/balls/BallsView.java
new file mode 100644 (file)
index 0000000..b3b3756
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 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.example.android.rs.balls;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class BallsView extends RSSurfaceView {
+
+    public BallsView(Context context) {
+        super(context);
+        //setFocusable(true);
+    }
+
+    private RenderScriptGL mRS;
+    private BallsRS mRender;
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            mRS = createRenderScriptGL(sc);
+            mRS.setSurface(holder, w, h);
+            mRender = new BallsRS();
+            mRender.init(mRS, getResources(), w, h);
+        }
+        mRender.updateProjectionMatrices();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if(mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev)
+    {
+        int act = ev.getActionMasked();
+        if (act == ev.ACTION_UP) {
+            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+            return false;
+        } else if (act == MotionEvent.ACTION_POINTER_UP) {
+            // only one pointer going up, we can get the index like this
+            int pointerIndex = ev.getActionIndex();
+            int pointerId = ev.getPointerId(pointerIndex);
+            mRender.newTouchPosition(0, 0, 0, pointerId);
+            return false;
+        }
+        int count = ev.getHistorySize();
+        int pcount = ev.getPointerCount();
+
+        for (int p=0; p < pcount; p++) {
+            int id = ev.getPointerId(p);
+            mRender.newTouchPosition(ev.getX(p),
+                                     ev.getY(p),
+                                     ev.getPressure(p),
+                                     id);
+
+            for (int i=0; i < count; i++) {
+                mRender.newTouchPosition(ev.getHistoricalX(p, i),
+                                         ev.getHistoricalY(p, i),
+                                         ev.getHistoricalPressure(p, i),
+                                         id);
+            }
+        }
+        return true;
+    }
+
+    void setAccel(float x, float y, float z) {
+        if (mRender == null) {
+            return;
+        }
+        mRender.setAccel(x, -y);
+    }
+
+}
+
+
diff --git a/tests/renderscriptMultiSrc/src/main/res/drawable/flares.png b/tests/renderscriptMultiSrc/src/main/res/drawable/flares.png
new file mode 100644 (file)
index 0000000..3a5c970
Binary files /dev/null and b/tests/renderscriptMultiSrc/src/main/res/drawable/flares.png differ
diff --git a/tests/renderscriptMultiSrc/src/main/res/drawable/test_pattern.png b/tests/renderscriptMultiSrc/src/main/res/drawable/test_pattern.png
new file mode 100644 (file)
index 0000000..e7d1455
Binary files /dev/null and b/tests/renderscriptMultiSrc/src/main/res/drawable/test_pattern.png differ
diff --git a/tests/renderscriptMultiSrc/src/main/rs/com/example/android/rs/balls/ball_physics.rs b/tests/renderscriptMultiSrc/src/main/rs/com/example/android/rs/balls/ball_physics.rs
new file mode 100644 (file)
index 0000000..ee6ab1d
--- /dev/null
@@ -0,0 +1,146 @@
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.balls)
+
+#include "balls.rsh"
+
+float2 gGravityVector = {0.f, 9.8f};
+
+float2 gMinPos = {0.f, 0.f};
+float2 gMaxPos = {1280.f, 700.f};
+
+static float2 touchPos[10];
+static float touchPressure[10];
+
+void touch(float x, float y, float pressure, int id) {
+    if (id >= 10) {
+        return;
+    }
+
+    touchPos[id].x = x;
+    touchPos[id].y = y;
+    touchPressure[id] = pressure;
+}
+
+void root(const Ball_t *ballIn, Ball_t *ballOut, const BallControl_t *ctl, uint32_t x) {
+    float2 fv = {0, 0};
+    float2 pos = ballIn->position;
+
+    int arcID = -1;
+    float arcInvStr = 100000;
+
+    const Ball_t * bPtr = rsGetElementAt(ctl->ain, 0);
+    for (uint32_t xin = 0; xin < ctl->dimX; xin++) {
+        float2 vec = bPtr[xin].position - pos;
+        float2 vec2 = vec * vec;
+        float len2 = vec2.x + vec2.y;
+
+        if (len2 < 10000) {
+            //float minDist = ballIn->size + bPtr[xin].size;
+            float forceScale = ballIn->size * bPtr[xin].size;
+            forceScale *= forceScale;
+
+            if (len2 > 16 /* (minDist*minDist)*/)  {
+                // Repulsion
+                float len = sqrt(len2);
+                fv -= (vec / (len * len * len)) * 20000.f * forceScale;
+            } else {
+                if (len2 < 1) {
+                    if (xin == x) {
+                        continue;
+                    }
+                    ballOut->delta = 0.f;
+                    ballOut->position = ballIn->position;
+                    if (xin > x) {
+                        ballOut->position.x += 1.f;
+                    } else {
+                        ballOut->position.x -= 1.f;
+                    }
+                    //ballOut->color.rgb = 1.f;
+                    //ballOut->arcID = -1;
+                    //ballOut->arcStr = 0;
+                    return;
+                }
+                // Collision
+                float2 axis = normalize(vec);
+                float e1 = dot(axis, ballIn->delta);
+                float e2 = dot(axis, bPtr[xin].delta);
+                float e = (e1 - e2) * 0.45f;
+                if (e1 > 0) {
+                    fv -= axis * e;
+                } else {
+                    fv += axis * e;
+                }
+            }
+        }
+    }
+
+    fv /= ballIn->size * ballIn->size * ballIn->size;
+    fv -= gGravityVector * 4.f;
+    fv *= ctl->dt;
+
+    for (int i=0; i < 10; i++) {
+        if (touchPressure[i] > 0.1f) {
+            float2 vec = touchPos[i] - ballIn->position;
+            float2 vec2 = vec * vec;
+            float len2 = max(2.f, vec2.x + vec2.y);
+            fv -= (vec / len2) * touchPressure[i] * 300.f;
+        }
+    }
+
+    ballOut->delta = (ballIn->delta * (1.f - 0.004f)) + fv;
+    ballOut->position = ballIn->position + (ballOut->delta * ctl->dt);
+
+    const float wallForce = 400.f;
+    if (ballOut->position.x > (gMaxPos.x - 20.f)) {
+        float d = gMaxPos.x - ballOut->position.x;
+        if (d < 0.f) {
+            if (ballOut->delta.x > 0) {
+                ballOut->delta.x *= -0.7;
+            }
+            ballOut->position.x = gMaxPos.x;
+        } else {
+            ballOut->delta.x -= min(wallForce / (d * d), 10.f);
+        }
+    }
+
+    if (ballOut->position.x < (gMinPos.x + 20.f)) {
+        float d = ballOut->position.x - gMinPos.x;
+        if (d < 0.f) {
+            if (ballOut->delta.x < 0) {
+                ballOut->delta.x *= -0.7;
+            }
+            ballOut->position.x = gMinPos.x + 1.f;
+        } else {
+            ballOut->delta.x += min(wallForce / (d * d), 10.f);
+        }
+    }
+
+    if (ballOut->position.y > (gMaxPos.y - 20.f)) {
+        float d = gMaxPos.y - ballOut->position.y;
+        if (d < 0.f) {
+            if (ballOut->delta.y > 0) {
+                ballOut->delta.y *= -0.7;
+            }
+            ballOut->position.y = gMaxPos.y;
+        } else {
+            ballOut->delta.y -= min(wallForce / (d * d), 10.f);
+        }
+    }
+
+    if (ballOut->position.y < (gMinPos.y + 20.f)) {
+        float d = ballOut->position.y - gMinPos.y;
+        if (d < 0.f) {
+            if (ballOut->delta.y < 0) {
+                ballOut->delta.y *= -0.7;
+            }
+            ballOut->position.y = gMinPos.y + 1.f;
+        } else {
+            ballOut->delta.y += min(wallForce / (d * d * d), 10.f);
+        }
+    }
+
+    ballOut->size = ballIn->size;
+
+    //rsDebug("physics pos out", ballOut->position);
+}
+
diff --git a/tests/renderscriptMultiSrc/src/main/rs/com/example/android/rs/balls/balls.rs b/tests/renderscriptMultiSrc/src/main/rs/com/example/android/rs/balls/balls.rs
new file mode 100644 (file)
index 0000000..d86b804
--- /dev/null
@@ -0,0 +1,85 @@
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.balls)
+#include "rs_graphics.rsh"
+
+#include "balls.rsh"
+
+#pragma stateVertex(parent)
+#pragma stateStore(parent)
+
+rs_program_fragment gPFPoints;
+rs_program_fragment gPFLines;
+rs_mesh partMesh;
+
+typedef struct __attribute__((packed, aligned(4))) Point {
+    float2 position;
+    float size;
+} Point_t;
+Point_t *point;
+
+typedef struct VpConsts {
+    rs_matrix4x4 MVP;
+} VpConsts_t;
+VpConsts_t *vpConstants;
+
+rs_script physics_script;
+
+Ball_t *balls1;
+Ball_t *balls2;
+
+static int frame = 0;
+
+void initParts(int w, int h)
+{
+    uint32_t dimX = rsAllocationGetDimX(rsGetAllocation(balls1));
+
+    for (uint32_t ct=0; ct < dimX; ct++) {
+        balls1[ct].position.x = rsRand(0.f, (float)w);
+        balls1[ct].position.y = rsRand(0.f, (float)h);
+        balls1[ct].delta.x = 0.f;
+        balls1[ct].delta.y = 0.f;
+        balls1[ct].size = 1.f;
+
+        float r = rsRand(100.f);
+        if (r > 90.f) {
+            balls1[ct].size += pow(10.f, rsRand(0.f, 2.f)) * 0.07;
+        }
+    }
+}
+
+
+
+int root() {
+    rsgClearColor(0.f, 0.f, 0.f, 1.f);
+
+    BallControl_t bc;
+    Ball_t *bout;
+
+    if (frame & 1) {
+        rsSetObject(&bc.ain, rsGetAllocation(balls2));
+        rsSetObject(&bc.aout, rsGetAllocation(balls1));
+        bout = balls2;
+    } else {
+        rsSetObject(&bc.ain, rsGetAllocation(balls1));
+        rsSetObject(&bc.aout, rsGetAllocation(balls2));
+        bout = balls1;
+    }
+
+    bc.dimX = rsAllocationGetDimX(bc.ain);
+    bc.dt = 1.f / 30.f;
+
+    rsForEach(physics_script, bc.ain, bc.aout, &bc);
+
+    for (uint32_t ct=0; ct < bc.dimX; ct++) {
+        point[ct].position = bout[ct].position;
+        point[ct].size = 6.f /*+ bout[ct].color.g * 6.f*/ * bout[ct].size;
+    }
+
+    frame++;
+    rsgBindProgramFragment(gPFPoints);
+    rsgDrawMesh(partMesh);
+    rsClearObject(&bc.ain);
+    rsClearObject(&bc.aout);
+    return 1;
+}
+
diff --git a/tests/renderscriptMultiSrc/src/release/rs/com/example/android/rs/balls/balls.rsh b/tests/renderscriptMultiSrc/src/release/rs/com/example/android/rs/balls/balls.rsh
new file mode 100644 (file)
index 0000000..fc886f9
--- /dev/null
@@ -0,0 +1,18 @@
+
+typedef struct __attribute__((packed, aligned(4))) Ball {
+    float2 delta;
+    float2 position;
+    //float3 color;
+    float size;
+    //int arcID;
+    //float arcStr;
+} Ball_t;
+Ball_t *balls;
+
+
+typedef struct BallControl {
+    uint32_t dimX;
+    rs_allocation ain;
+    rs_allocation aout;
+    float dt;
+} BallControl_t;