Automatic sources dropoff on 2020-06-10 18:32:38.095721

The change is generated with prebuilt drop tool.

Change-Id: I24cbf6ba6db262a1ae1445db1427a08fee35b3b4
diff --git a/androidx/multidex/MultiDex.java b/androidx/multidex/MultiDex.java
new file mode 100644
index 0000000..c038709
--- /dev/null
+++ b/androidx/multidex/MultiDex.java
@@ -0,0 +1,783 @@
+/*
+ * 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 androidx.multidex;
+
+import android.app.Application;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.util.Log;
+
+import dalvik.system.DexFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.zip.ZipFile;
+
+/**
+ * MultiDex patches {@link Context#getClassLoader() the application context class
+ * loader} in order to load classes from more than one dex file. The primary
+ * {@code classes.dex} must contain the classes necessary for calling this
+ * class methods. Secondary dex files named classes2.dex, classes3.dex... found
+ * in the application apk will be added to the classloader after first call to
+ * {@link #install(Context)}.
+ *
+ * <p/>
+ * This library provides compatibility for platforms with API level 4 through 20. This library does
+ * nothing on newer versions of the platform which provide built-in support for secondary dex files.
+ */
+public final class MultiDex {
+
+    static final String TAG = "MultiDex";
+
+    private static final String OLD_SECONDARY_FOLDER_NAME = "secondary-dexes";
+
+    private static final String CODE_CACHE_NAME = "code_cache";
+
+    private static final String CODE_CACHE_SECONDARY_FOLDER_NAME = "secondary-dexes";
+
+    private static final int MAX_SUPPORTED_SDK_VERSION = 20;
+
+    private static final int MIN_SDK_VERSION = 4;
+
+    private static final int VM_WITH_MULTIDEX_VERSION_MAJOR = 2;
+
+    private static final int VM_WITH_MULTIDEX_VERSION_MINOR = 1;
+
+    private static final String NO_KEY_PREFIX = "";
+
+    private static final Set<File> installedApk = new HashSet<File>();
+
+    private static final boolean IS_VM_MULTIDEX_CAPABLE =
+            isVMMultidexCapable(System.getProperty("java.vm.version"));
+
+    private MultiDex() {}
+
+    /**
+     * Patches the application context class loader by appending extra dex files
+     * loaded from the application apk. This method should be called in the
+     * attachBaseContext of your {@link Application}, see
+     * {@link MultiDexApplication} for more explanation and an example.
+     *
+     * @param context application context.
+     * @throws RuntimeException if an error occurred preventing the classloader
+     *         extension.
+     */
+    public static void install(Context context) {
+        Log.i(TAG, "Installing application");
+        if (IS_VM_MULTIDEX_CAPABLE) {
+            Log.i(TAG, "VM has multidex support, MultiDex support library is disabled.");
+            return;
+        }
+
+        if (Build.VERSION.SDK_INT < MIN_SDK_VERSION) {
+            throw new RuntimeException("MultiDex installation failed. SDK " + Build.VERSION.SDK_INT
+                    + " is unsupported. Min SDK version is " + MIN_SDK_VERSION + ".");
+        }
+
+        try {
+            ApplicationInfo applicationInfo = getApplicationInfo(context);
+            if (applicationInfo == null) {
+              Log.i(TAG, "No ApplicationInfo available, i.e. running on a test Context:"
+                  + " MultiDex support library is disabled.");
+              return;
+            }
+
+            doInstallation(context,
+                    new File(applicationInfo.sourceDir),
+                    new File(applicationInfo.dataDir),
+                    CODE_CACHE_SECONDARY_FOLDER_NAME,
+                    NO_KEY_PREFIX,
+                    true);
+
+        } catch (Exception e) {
+            Log.e(TAG, "MultiDex installation failure", e);
+            throw new RuntimeException("MultiDex installation failed (" + e.getMessage() + ").");
+        }
+        Log.i(TAG, "install done");
+    }
+
+    /**
+     * Patches the instrumentation context class loader by appending extra dex files
+     * loaded from the instrumentation apk and the application apk. This method should be called in
+     * the onCreate of your {@link Instrumentation}, see
+     * {@link com.android.test.runner.MultiDexTestRunner} for an example.
+     *
+     * @param instrumentationContext instrumentation context.
+     * @param targetContext target application context.
+     * @throws RuntimeException if an error occurred preventing the classloader
+     *         extension.
+     */
+    public static void installInstrumentation(Context instrumentationContext,
+            Context targetContext) {
+        Log.i(TAG, "Installing instrumentation");
+
+        if (IS_VM_MULTIDEX_CAPABLE) {
+            Log.i(TAG, "VM has multidex support, MultiDex support library is disabled.");
+            return;
+        }
+
+        if (Build.VERSION.SDK_INT < MIN_SDK_VERSION) {
+            throw new RuntimeException("MultiDex installation failed. SDK " + Build.VERSION.SDK_INT
+                    + " is unsupported. Min SDK version is " + MIN_SDK_VERSION + ".");
+        }
+        try {
+
+            ApplicationInfo instrumentationInfo = getApplicationInfo(instrumentationContext);
+            if (instrumentationInfo == null) {
+                Log.i(TAG, "No ApplicationInfo available for instrumentation, i.e. running on a"
+                    + " test Context: MultiDex support library is disabled.");
+                return;
+            }
+
+            ApplicationInfo applicationInfo = getApplicationInfo(targetContext);
+            if (applicationInfo == null) {
+                Log.i(TAG, "No ApplicationInfo available, i.e. running on a test Context:"
+                    + " MultiDex support library is disabled.");
+                return;
+            }
+
+            String instrumentationPrefix = instrumentationContext.getPackageName() + ".";
+
+            File dataDir = new File(applicationInfo.dataDir);
+
+            doInstallation(targetContext,
+                    new File(instrumentationInfo.sourceDir),
+                    dataDir,
+                    instrumentationPrefix + CODE_CACHE_SECONDARY_FOLDER_NAME,
+                    instrumentationPrefix,
+                    false);
+
+            doInstallation(targetContext,
+                    new File(applicationInfo.sourceDir),
+                    dataDir,
+                    CODE_CACHE_SECONDARY_FOLDER_NAME,
+                    NO_KEY_PREFIX,
+                    false);
+        } catch (Exception e) {
+            Log.e(TAG, "MultiDex installation failure", e);
+            throw new RuntimeException("MultiDex installation failed (" + e.getMessage() + ").");
+        }
+        Log.i(TAG, "Installation done");
+    }
+
+    /**
+     * @param mainContext context used to get filesDir, to save preference and to get the
+     * classloader to patch.
+     * @param sourceApk Apk file.
+     * @param dataDir data directory to use for code cache simulation.
+     * @param secondaryFolderName name of the folder for storing extractions.
+     * @param prefsKeyPrefix prefix of all stored preference keys.
+     * @param reinstallOnPatchRecoverableException if set to true, will attempt a clean extraction
+     * if a possibly recoverable exception occurs during classloader patching.
+     */
+    private static void doInstallation(Context mainContext, File sourceApk, File dataDir,
+            String secondaryFolderName, String prefsKeyPrefix,
+            boolean reinstallOnPatchRecoverableException) throws IOException,
+                IllegalArgumentException, IllegalAccessException, NoSuchFieldException,
+                InvocationTargetException, NoSuchMethodException, SecurityException,
+                ClassNotFoundException, InstantiationException {
+        synchronized (installedApk) {
+            if (installedApk.contains(sourceApk)) {
+                return;
+            }
+            installedApk.add(sourceApk);
+
+            if (Build.VERSION.SDK_INT > MAX_SUPPORTED_SDK_VERSION) {
+                Log.w(TAG, "MultiDex is not guaranteed to work in SDK version "
+                        + Build.VERSION.SDK_INT + ": SDK version higher than "
+                        + MAX_SUPPORTED_SDK_VERSION + " should be backed by "
+                        + "runtime with built-in multidex capabilty but it's not the "
+                        + "case here: java.vm.version=\""
+                        + System.getProperty("java.vm.version") + "\"");
+            }
+
+            /* The patched class loader is expected to be a ClassLoader capable of loading DEX
+             * bytecode. We modify its pathList field to append additional DEX file entries.
+             */
+            ClassLoader loader = getDexClassloader(mainContext);
+            if (loader == null) {
+                return;
+            }
+
+            try {
+              clearOldDexDir(mainContext);
+            } catch (Throwable t) {
+              Log.w(TAG, "Something went wrong when trying to clear old MultiDex extraction, "
+                  + "continuing without cleaning.", t);
+            }
+
+            File dexDir = getDexDir(mainContext, dataDir, secondaryFolderName);
+            // MultiDexExtractor is taking the file lock and keeping it until it is closed.
+            // Keep it open during installSecondaryDexes and through forced extraction to ensure no
+            // extraction or optimizing dexopt is running in parallel.
+            MultiDexExtractor extractor = new MultiDexExtractor(sourceApk, dexDir);
+            IOException closeException = null;
+            try {
+                List<? extends File> files =
+                        extractor.load(mainContext, prefsKeyPrefix, false);
+                try {
+                    installSecondaryDexes(loader, dexDir, files);
+                // Some IOException causes may be fixed by a clean extraction.
+                } catch (IOException e) {
+                    if (!reinstallOnPatchRecoverableException) {
+                        throw e;
+                    }
+                    Log.w(TAG, "Failed to install extracted secondary dex files, retrying with "
+                            + "forced extraction", e);
+                    files = extractor.load(mainContext, prefsKeyPrefix, true);
+                    installSecondaryDexes(loader, dexDir, files);
+                }
+            } finally {
+                try {
+                    extractor.close();
+                } catch (IOException e) {
+                    // Delay throw of close exception to ensure we don't override some exception
+                    // thrown during the try block.
+                    closeException = e;
+                }
+            }
+            if (closeException != null) {
+                throw closeException;
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Classloader} from the {@link Context} that is capable of reading dex
+     * bytecode or null if the Classloader is not dex-capable e.g: when running on a JVM testing
+     * environment such as Robolectric.
+     */
+    private static ClassLoader getDexClassloader(Context context) {
+        ClassLoader loader;
+        try {
+            loader = context.getClassLoader();
+        } catch (RuntimeException e) {
+            /* Ignore those exceptions so that we don't break tests relying on Context like
+             * a android.test.mock.MockContext or a android.content.ContextWrapper with a
+             * null base Context.
+             */
+            Log.w(TAG, "Failure while trying to obtain Context class loader. "
+                    + "Must be running in test mode. Skip patching.", e);
+            return null;
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            if (loader instanceof dalvik.system.BaseDexClassLoader) {
+                return loader;
+            }
+        } else if (loader instanceof dalvik.system.DexClassLoader
+                    || loader instanceof dalvik.system.PathClassLoader) {
+            return loader;
+        }
+        Log.e(TAG, "Context class loader is null or not dex-capable. "
+                + "Must be running in test mode. Skip patching.");
+        return null;
+    }
+
+    private static ApplicationInfo getApplicationInfo(Context context) {
+        try {
+            /* Due to package install races it is possible for a process to be started from an old
+             * apk even though that apk has been replaced. Querying for ApplicationInfo by package
+             * name may return information for the new apk, leading to a runtime with the old main
+             * dex file and new secondary dex files. This leads to various problems like
+             * ClassNotFoundExceptions. Using context.getApplicationInfo() should result in the
+             * process having a consistent view of the world (even if it is of the old world). The
+             * package install races are eventually resolved and old processes are killed.
+             */
+            return context.getApplicationInfo();
+        } catch (RuntimeException e) {
+            /* Ignore those exceptions so that we don't break tests relying on Context like
+             * a android.test.mock.MockContext or a android.content.ContextWrapper with a null
+             * base Context.
+             */
+            Log.w(TAG, "Failure while trying to obtain ApplicationInfo from Context. " +
+                    "Must be running in test mode. Skip patching.", e);
+            return null;
+        }
+    }
+
+    /**
+     * Identifies if the current VM has a native support for multidex, meaning there is no need for
+     * additional installation by this library.
+     * @return true if the VM handles multidex
+     */
+    /* package visible for test */
+    static boolean isVMMultidexCapable(String versionString) {
+        boolean isMultidexCapable = false;
+        if (versionString != null) {
+            StringTokenizer tokenizer = new StringTokenizer(versionString, ".");
+            String majorToken = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+            String minorToken = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
+            if (majorToken != null && minorToken != null) {
+                try {
+                    int major = Integer.parseInt(majorToken);
+                    int minor = Integer.parseInt(minorToken);
+                    isMultidexCapable = (major > VM_WITH_MULTIDEX_VERSION_MAJOR)
+                            || ((major == VM_WITH_MULTIDEX_VERSION_MAJOR)
+                                    && (minor >= VM_WITH_MULTIDEX_VERSION_MINOR));
+                } catch (NumberFormatException e) {
+                    // let isMultidexCapable be false
+                }
+            }
+        }
+        Log.i(TAG, "VM with version " + versionString +
+                (isMultidexCapable ?
+                        " has multidex support" :
+                        " does not have multidex support"));
+        return isMultidexCapable;
+    }
+
+    private static void installSecondaryDexes(ClassLoader loader, File dexDir,
+        List<? extends File> files)
+            throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException,
+            InvocationTargetException, NoSuchMethodException, IOException, SecurityException,
+            ClassNotFoundException, InstantiationException {
+        if (!files.isEmpty()) {
+            if (Build.VERSION.SDK_INT >= 19) {
+                V19.install(loader, files, dexDir);
+            } else if (Build.VERSION.SDK_INT >= 14) {
+                V14.install(loader, files);
+            } else {
+                V4.install(loader, files);
+            }
+        }
+    }
+
+    /**
+     * Locates a given field anywhere in the class inheritance hierarchy.
+     *
+     * @param instance an object to search the field into.
+     * @param name field name
+     * @return a field object
+     * @throws NoSuchFieldException if the field cannot be located
+     */
+    private static Field findField(Object instance, String name) throws NoSuchFieldException {
+        for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
+            try {
+                Field field = clazz.getDeclaredField(name);
+
+
+                if (!field.isAccessible()) {
+                    field.setAccessible(true);
+                }
+
+                return field;
+            } catch (NoSuchFieldException e) {
+                // ignore and search next
+            }
+        }
+
+        throw new NoSuchFieldException("Field " + name + " not found in " + instance.getClass());
+    }
+
+    /**
+     * Locates a given method anywhere in the class inheritance hierarchy.
+     *
+     * @param instance an object to search the method into.
+     * @param name method name
+     * @param parameterTypes method parameter types
+     * @return a method object
+     * @throws NoSuchMethodException if the method cannot be located
+     */
+    private static Method findMethod(Object instance, String name, Class<?>... parameterTypes)
+            throws NoSuchMethodException {
+        for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
+            try {
+                Method method = clazz.getDeclaredMethod(name, parameterTypes);
+
+
+                if (!method.isAccessible()) {
+                    method.setAccessible(true);
+                }
+
+                return method;
+            } catch (NoSuchMethodException e) {
+                // ignore and search next
+            }
+        }
+
+        throw new NoSuchMethodException("Method " + name + " with parameters " +
+                Arrays.asList(parameterTypes) + " not found in " + instance.getClass());
+    }
+
+    /**
+     * Replace the value of a field containing a non null array, by a new array containing the
+     * elements of the original array plus the elements of extraElements.
+     * @param instance the instance whose field is to be modified.
+     * @param fieldName the field to modify.
+     * @param extraElements elements to append at the end of the array.
+     */
+    private static void expandFieldArray(Object instance, String fieldName,
+            Object[] extraElements) throws NoSuchFieldException, IllegalArgumentException,
+            IllegalAccessException {
+        Field jlrField = findField(instance, fieldName);
+        Object[] original = (Object[]) jlrField.get(instance);
+        Object[] combined = (Object[]) Array.newInstance(
+                original.getClass().getComponentType(), original.length + extraElements.length);
+        System.arraycopy(original, 0, combined, 0, original.length);
+        System.arraycopy(extraElements, 0, combined, original.length, extraElements.length);
+        jlrField.set(instance, combined);
+    }
+
+    private static void clearOldDexDir(Context context) throws Exception {
+        File dexDir = new File(context.getFilesDir(), OLD_SECONDARY_FOLDER_NAME);
+        if (dexDir.isDirectory()) {
+            Log.i(TAG, "Clearing old secondary dex dir (" + dexDir.getPath() + ").");
+            File[] files = dexDir.listFiles();
+            if (files == null) {
+                Log.w(TAG, "Failed to list secondary dex dir content (" + dexDir.getPath() + ").");
+                return;
+            }
+            for (File oldFile : files) {
+                Log.i(TAG, "Trying to delete old file " + oldFile.getPath() + " of size "
+                        + oldFile.length());
+                if (!oldFile.delete()) {
+                    Log.w(TAG, "Failed to delete old file " + oldFile.getPath());
+                } else {
+                    Log.i(TAG, "Deleted old file " + oldFile.getPath());
+                }
+            }
+            if (!dexDir.delete()) {
+                Log.w(TAG, "Failed to delete secondary dex dir " + dexDir.getPath());
+            } else {
+                Log.i(TAG, "Deleted old secondary dex dir " + dexDir.getPath());
+            }
+        }
+    }
+
+    private static File getDexDir(Context context, File dataDir, String secondaryFolderName)
+            throws IOException {
+        File cache = new File(dataDir, CODE_CACHE_NAME);
+        try {
+            mkdirChecked(cache);
+        } catch (IOException e) {
+            /* If we can't emulate code_cache, then store to filesDir. This means abandoning useless
+             * files on disk if the device ever updates to android 5+. But since this seems to
+             * happen only on some devices running android 2, this should cause no pollution.
+             */
+            cache = new File(context.getFilesDir(), CODE_CACHE_NAME);
+            mkdirChecked(cache);
+        }
+        File dexDir = new File(cache, secondaryFolderName);
+        mkdirChecked(dexDir);
+        return dexDir;
+    }
+
+    private static void mkdirChecked(File dir) throws IOException {
+        dir.mkdir();
+        if (!dir.isDirectory()) {
+            File parent = dir.getParentFile();
+            if (parent == null) {
+                Log.e(TAG, "Failed to create dir " + dir.getPath() + ". Parent file is null.");
+            } else {
+                Log.e(TAG, "Failed to create dir " + dir.getPath() +
+                        ". parent file is a dir " + parent.isDirectory() +
+                        ", a file " + parent.isFile() +
+                        ", exists " + parent.exists() +
+                        ", readable " + parent.canRead() +
+                        ", writable " + parent.canWrite());
+            }
+            throw new IOException("Failed to create directory " + dir.getPath());
+        }
+    }
+
+    /**
+     * Installer for platform versions 19.
+     */
+    private static final class V19 {
+
+        static void install(ClassLoader loader,
+                List<? extends File> additionalClassPathEntries,
+                File optimizedDirectory)
+                        throws IllegalArgumentException, IllegalAccessException,
+                        NoSuchFieldException, InvocationTargetException, NoSuchMethodException,
+                        IOException {
+            /* The patched class loader is expected to be a descendant of
+             * dalvik.system.BaseDexClassLoader. We modify its
+             * dalvik.system.DexPathList pathList field to append additional DEX
+             * file entries.
+             */
+            Field pathListField = findField(loader, "pathList");
+            Object dexPathList = pathListField.get(loader);
+            ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
+            expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList,
+                    new ArrayList<File>(additionalClassPathEntries), optimizedDirectory,
+                    suppressedExceptions));
+            if (suppressedExceptions.size() > 0) {
+                for (IOException e : suppressedExceptions) {
+                    Log.w(TAG, "Exception in makeDexElement", e);
+                }
+                Field suppressedExceptionsField =
+                        findField(dexPathList, "dexElementsSuppressedExceptions");
+                IOException[] dexElementsSuppressedExceptions =
+                        (IOException[]) suppressedExceptionsField.get(dexPathList);
+
+                if (dexElementsSuppressedExceptions == null) {
+                    dexElementsSuppressedExceptions =
+                            suppressedExceptions.toArray(
+                                    new IOException[suppressedExceptions.size()]);
+                } else {
+                    IOException[] combined =
+                            new IOException[suppressedExceptions.size() +
+                                            dexElementsSuppressedExceptions.length];
+                    suppressedExceptions.toArray(combined);
+                    System.arraycopy(dexElementsSuppressedExceptions, 0, combined,
+                            suppressedExceptions.size(), dexElementsSuppressedExceptions.length);
+                    dexElementsSuppressedExceptions = combined;
+                }
+
+                suppressedExceptionsField.set(dexPathList, dexElementsSuppressedExceptions);
+
+                IOException exception = new IOException("I/O exception during makeDexElement");
+                exception.initCause(suppressedExceptions.get(0));
+                throw exception;
+            }
+        }
+
+        /**
+         * A wrapper around
+         * {@code private static final dalvik.system.DexPathList#makeDexElements}.
+         */
+        private static Object[] makeDexElements(
+                Object dexPathList, ArrayList<File> files, File optimizedDirectory,
+                ArrayList<IOException> suppressedExceptions)
+                        throws IllegalAccessException, InvocationTargetException,
+                        NoSuchMethodException {
+            Method makeDexElements =
+                    findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class,
+                            ArrayList.class);
+
+            return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory,
+                    suppressedExceptions);
+        }
+    }
+
+    /**
+     * Installer for platform versions 14, 15, 16, 17 and 18.
+     */
+    private static final class V14 {
+
+        private interface ElementConstructor {
+            Object newInstance(File file, DexFile dex)
+                    throws IllegalArgumentException, InstantiationException,
+                    IllegalAccessException, InvocationTargetException, IOException;
+        }
+
+        /**
+         * Applies for ICS and early JB (initial release and MR1).
+         */
+        private static class ICSElementConstructor implements ElementConstructor {
+            private final Constructor<?> elementConstructor;
+
+            ICSElementConstructor(Class<?> elementClass)
+                    throws SecurityException, NoSuchMethodException {
+                elementConstructor =
+                        elementClass.getConstructor(File.class, ZipFile.class, DexFile.class);
+                elementConstructor.setAccessible(true);
+            }
+
+            @Override
+            public Object newInstance(File file, DexFile dex)
+                    throws IllegalArgumentException, InstantiationException,
+                    IllegalAccessException, InvocationTargetException, IOException {
+                return elementConstructor.newInstance(file, new ZipFile(file), dex);
+            }
+        }
+
+        /**
+         * Applies for some intermediate JB (MR1.1).
+         *
+         * See Change-Id: I1a5b5d03572601707e1fb1fd4424c1ae2fd2217d
+         */
+        private static class JBMR11ElementConstructor implements ElementConstructor {
+            private final Constructor<?> elementConstructor;
+
+            JBMR11ElementConstructor(Class<?> elementClass)
+                    throws SecurityException, NoSuchMethodException {
+                elementConstructor = elementClass
+                        .getConstructor(File.class, File.class, DexFile.class);
+                elementConstructor.setAccessible(true);
+            }
+
+            @Override
+            public Object newInstance(File file, DexFile dex)
+                    throws IllegalArgumentException, InstantiationException,
+                    IllegalAccessException, InvocationTargetException {
+                return elementConstructor.newInstance(file, file, dex);
+            }
+        }
+
+        /**
+         * Applies for latest JB (MR2).
+         *
+         * See Change-Id: Iec4dca2244db9c9c793ac157e258fd61557a7a5d
+         */
+        private static class JBMR2ElementConstructor implements ElementConstructor {
+            private final Constructor<?> elementConstructor;
+
+            JBMR2ElementConstructor(Class<?> elementClass)
+                    throws SecurityException, NoSuchMethodException {
+                elementConstructor = elementClass
+                        .getConstructor(File.class, Boolean.TYPE, File.class, DexFile.class);
+                elementConstructor.setAccessible(true);
+            }
+
+            @Override
+            public Object newInstance(File file, DexFile dex)
+                    throws IllegalArgumentException, InstantiationException,
+                    IllegalAccessException, InvocationTargetException {
+                return elementConstructor.newInstance(file, Boolean.FALSE, file, dex);
+            }
+        }
+
+        private static final int EXTRACTED_SUFFIX_LENGTH =
+                MultiDexExtractor.EXTRACTED_SUFFIX.length();
+
+        private final ElementConstructor elementConstructor;
+
+        static void install(ClassLoader loader,
+                List<? extends File> additionalClassPathEntries)
+                        throws  IOException, SecurityException, IllegalArgumentException,
+                        ClassNotFoundException, NoSuchMethodException, InstantiationException,
+                        IllegalAccessException, InvocationTargetException, NoSuchFieldException {
+            /* The patched class loader is expected to be a descendant of
+             * dalvik.system.BaseDexClassLoader. We modify its
+             * dalvik.system.DexPathList pathList field to append additional DEX
+             * file entries.
+             */
+            Field pathListField = findField(loader, "pathList");
+            Object dexPathList = pathListField.get(loader);
+            Object[] elements = new V14().makeDexElements(additionalClassPathEntries);
+            try {
+                expandFieldArray(dexPathList, "dexElements", elements);
+            } catch (NoSuchFieldException e) {
+                // dexElements was renamed pathElements for a short period during JB development,
+                // eventually it was renamed back shortly after.
+                Log.w(TAG, "Failed find field 'dexElements' attempting 'pathElements'", e);
+                expandFieldArray(dexPathList, "pathElements", elements);
+            }
+        }
+
+        private  V14() throws ClassNotFoundException, SecurityException, NoSuchMethodException {
+            ElementConstructor constructor;
+            Class<?> elementClass = Class.forName("dalvik.system.DexPathList$Element");
+            try {
+                constructor = new ICSElementConstructor(elementClass);
+            } catch (NoSuchMethodException e1) {
+                try {
+                    constructor = new JBMR11ElementConstructor(elementClass);
+                } catch (NoSuchMethodException e2) {
+                    constructor = new JBMR2ElementConstructor(elementClass);
+                }
+            }
+            this.elementConstructor = constructor;
+        }
+
+        /**
+         * An emulation of {@code private static final dalvik.system.DexPathList#makeDexElements}
+         * accepting only extracted secondary dex files.
+         * OS version is catching IOException and just logging some of them, this version is letting
+         * them through.
+         */
+        private Object[] makeDexElements(List<? extends File> files)
+                throws IOException, SecurityException, IllegalArgumentException,
+                InstantiationException, IllegalAccessException, InvocationTargetException {
+            Object[] elements = new Object[files.size()];
+            for (int i = 0; i < elements.length; i++) {
+                File file = files.get(i);
+                elements[i] = elementConstructor.newInstance(
+                        file,
+                        DexFile.loadDex(file.getPath(), optimizedPathFor(file), 0));
+            }
+            return elements;
+        }
+
+        /**
+         * Converts a zip file path of an extracted secondary dex to an output file path for an
+         * associated optimized dex file.
+         */
+        private static String optimizedPathFor(File path) {
+            // Any reproducible name ending with ".dex" should do but lets keep the same name
+            // as DexPathList.optimizedPathFor
+
+            File optimizedDirectory = path.getParentFile();
+            String fileName = path.getName();
+            String optimizedFileName =
+                    fileName.substring(0, fileName.length() - EXTRACTED_SUFFIX_LENGTH)
+                    + MultiDexExtractor.DEX_SUFFIX;
+            File result = new File(optimizedDirectory, optimizedFileName);
+            return result.getPath();
+        }
+    }
+
+    /**
+     * Installer for platform versions 4 to 13.
+     */
+    private static final class V4 {
+        static void install(ClassLoader loader,
+                List<? extends File> additionalClassPathEntries)
+                        throws IllegalArgumentException, IllegalAccessException,
+                        NoSuchFieldException, IOException {
+            /* The patched class loader is expected to be a descendant of
+             * dalvik.system.DexClassLoader. We modify its
+             * fields mPaths, mFiles, mZips and mDexs to append additional DEX
+             * file entries.
+             */
+            int extraSize = additionalClassPathEntries.size();
+
+            Field pathField = findField(loader, "path");
+
+            StringBuilder path = new StringBuilder((String) pathField.get(loader));
+            String[] extraPaths = new String[extraSize];
+            File[] extraFiles = new File[extraSize];
+            ZipFile[] extraZips = new ZipFile[extraSize];
+            DexFile[] extraDexs = new DexFile[extraSize];
+            for (ListIterator<? extends File> iterator = additionalClassPathEntries.listIterator();
+                    iterator.hasNext();) {
+                File additionalEntry = iterator.next();
+                String entryPath = additionalEntry.getAbsolutePath();
+                path.append(':').append(entryPath);
+                int index = iterator.previousIndex();
+                extraPaths[index] = entryPath;
+                extraFiles[index] = additionalEntry;
+                extraZips[index] = new ZipFile(additionalEntry);
+                extraDexs[index] = DexFile.loadDex(entryPath, entryPath + ".dex", 0);
+            }
+
+            pathField.set(loader, path.toString());
+            expandFieldArray(loader, "mPaths", extraPaths);
+            expandFieldArray(loader, "mFiles", extraFiles);
+            expandFieldArray(loader, "mZips", extraZips);
+            expandFieldArray(loader, "mDexs", extraDexs);
+        }
+    }
+
+}
diff --git a/androidx/multidex/MultiDexApplication.java b/androidx/multidex/MultiDexApplication.java
new file mode 100644
index 0000000..4c759e3
--- /dev/null
+++ b/androidx/multidex/MultiDexApplication.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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 androidx.multidex;
+
+import android.app.Application;
+import android.content.Context;
+
+/**
+ * Minimal MultiDex capable application. To use the legacy multidex library there is 3 possibility:
+ * <ul>
+ * <li>Declare this class as the application in your AndroidManifest.xml.</li>
+ * <li>Have your {@link Application} extends this class.</li>
+ * <li>Have your {@link Application} override attachBaseContext starting with<br>
+ * <code>
+  protected void attachBaseContext(Context base) {<br>
+    super.attachBaseContext(base);<br>
+    MultiDex.install(this);
+    </code></li>
+ *   <ul>
+ */
+public class MultiDexApplication extends Application {
+  @Override
+  protected void attachBaseContext(Context base) {
+    super.attachBaseContext(base);
+    MultiDex.install(this);
+  }
+}
diff --git a/androidx/multidex/MultiDexExtractor.java b/androidx/multidex/MultiDexExtractor.java
new file mode 100644
index 0000000..a63d724
--- /dev/null
+++ b/androidx/multidex/MultiDexExtractor.java
@@ -0,0 +1,432 @@
+/*
+ * 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 androidx.multidex;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Exposes application secondary dex files as files in the application data
+ * directory.
+ * {@link MultiDexExtractor} is taking the file lock in the dex dir on creation and release it
+ * during close.
+ */
+final class MultiDexExtractor implements Closeable {
+
+    /**
+     * Zip file containing one secondary dex file.
+     */
+    private static class ExtractedDex extends File {
+        public long crc = NO_VALUE;
+
+        public ExtractedDex(File dexDir, String fileName) {
+            super(dexDir, fileName);
+        }
+    }
+
+    private static final String TAG = MultiDex.TAG;
+
+    /**
+     * We look for additional dex files named {@code classes2.dex},
+     * {@code classes3.dex}, etc.
+     */
+    private static final String DEX_PREFIX = "classes";
+    static final String DEX_SUFFIX = ".dex";
+
+    private static final String EXTRACTED_NAME_EXT = ".classes";
+    static final String EXTRACTED_SUFFIX = ".zip";
+    private static final int MAX_EXTRACT_ATTEMPTS = 3;
+
+    private static final String PREFS_FILE = "multidex.version";
+    private static final String KEY_TIME_STAMP = "timestamp";
+    private static final String KEY_CRC = "crc";
+    private static final String KEY_DEX_NUMBER = "dex.number";
+    private static final String KEY_DEX_CRC = "dex.crc.";
+    private static final String KEY_DEX_TIME = "dex.time.";
+
+    /**
+     * Size of reading buffers.
+     */
+    private static final int BUFFER_SIZE = 0x4000;
+    /* Keep value away from 0 because it is a too probable time stamp value */
+    private static final long NO_VALUE = -1L;
+
+    private static final String LOCK_FILENAME = "MultiDex.lock";
+    private final File sourceApk;
+    private final long sourceCrc;
+    private final File dexDir;
+    private final RandomAccessFile lockRaf;
+    private final FileChannel lockChannel;
+    private final FileLock cacheLock;
+
+    MultiDexExtractor(File sourceApk, File dexDir) throws IOException {
+        Log.i(TAG, "MultiDexExtractor(" + sourceApk.getPath() + ", " + dexDir.getPath() + ")");
+        this.sourceApk = sourceApk;
+        this.dexDir = dexDir;
+        sourceCrc = getZipCrc(sourceApk);
+        File lockFile = new File(dexDir, LOCK_FILENAME);
+        lockRaf = new RandomAccessFile(lockFile, "rw");
+        try {
+            lockChannel = lockRaf.getChannel();
+            try {
+                Log.i(TAG, "Blocking on lock " + lockFile.getPath());
+                cacheLock = lockChannel.lock();
+            } catch (IOException | RuntimeException | Error e) {
+                closeQuietly(lockChannel);
+                throw e;
+            }
+            Log.i(TAG, lockFile.getPath() + " locked");
+        } catch (IOException | RuntimeException | Error e) {
+            closeQuietly(lockRaf);
+            throw e;
+        }
+    }
+
+    /**
+     * Extracts application secondary dexes into files in the application data
+     * directory.
+     *
+     * @return a list of files that were created. The list may be empty if there
+     *         are no secondary dex files. Never return null.
+     * @throws IOException if encounters a problem while reading or writing
+     *         secondary dex files
+     */
+    List<? extends File> load(Context context, String prefsKeyPrefix, boolean forceReload)
+            throws IOException {
+        Log.i(TAG, "MultiDexExtractor.load(" + sourceApk.getPath() + ", " + forceReload + ", " +
+                prefsKeyPrefix + ")");
+
+        if (!cacheLock.isValid()) {
+            throw new IllegalStateException("MultiDexExtractor was closed");
+        }
+
+        List<ExtractedDex> files;
+        if (!forceReload && !isModified(context, sourceApk, sourceCrc, prefsKeyPrefix)) {
+            try {
+                files = loadExistingExtractions(context, prefsKeyPrefix);
+            } catch (IOException ioe) {
+                Log.w(TAG, "Failed to reload existing extracted secondary dex files,"
+                        + " falling back to fresh extraction", ioe);
+                files = performExtractions();
+                putStoredApkInfo(context, prefsKeyPrefix, getTimeStamp(sourceApk), sourceCrc,
+                        files);
+            }
+        } else {
+            if (forceReload) {
+                Log.i(TAG, "Forced extraction must be performed.");
+            } else {
+                Log.i(TAG, "Detected that extraction must be performed.");
+            }
+            files = performExtractions();
+            putStoredApkInfo(context, prefsKeyPrefix, getTimeStamp(sourceApk), sourceCrc,
+                    files);
+        }
+
+        Log.i(TAG, "load found " + files.size() + " secondary dex files");
+        return files;
+    }
+
+    @Override
+    public void close() throws IOException {
+        cacheLock.release();
+        lockChannel.close();
+        lockRaf.close();
+    }
+
+    /**
+     * Load previously extracted secondary dex files. Should be called only while owning the lock on
+     * {@link #LOCK_FILENAME}.
+     */
+    private List<ExtractedDex> loadExistingExtractions(
+            Context context,
+            String prefsKeyPrefix)
+            throws IOException {
+        Log.i(TAG, "loading existing secondary dex files");
+
+        final String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT;
+        SharedPreferences multiDexPreferences = getMultiDexPreferences(context);
+        int totalDexNumber = multiDexPreferences.getInt(prefsKeyPrefix + KEY_DEX_NUMBER, 0);
+        if (totalDexNumber < 1) {
+            // Guard against SharedPreferences corruption
+            throw new IOException("Invalid dex number: " + totalDexNumber);
+        }
+        final List<ExtractedDex> files = new ArrayList<ExtractedDex>(totalDexNumber - 1);
+
+        for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) {
+            String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX;
+            ExtractedDex extractedFile = new ExtractedDex(dexDir, fileName);
+            if (extractedFile.isFile()) {
+                extractedFile.crc = getZipCrc(extractedFile);
+                long expectedCrc = multiDexPreferences.getLong(
+                        prefsKeyPrefix + KEY_DEX_CRC + secondaryNumber, NO_VALUE);
+                long expectedModTime = multiDexPreferences.getLong(
+                        prefsKeyPrefix + KEY_DEX_TIME + secondaryNumber, NO_VALUE);
+                long lastModified = extractedFile.lastModified();
+                if ((expectedModTime != lastModified)
+                        || (expectedCrc != extractedFile.crc)) {
+                    throw new IOException("Invalid extracted dex: " + extractedFile +
+                            " (key \"" + prefsKeyPrefix + "\"), expected modification time: "
+                            + expectedModTime + ", modification time: "
+                            + lastModified + ", expected crc: "
+                            + expectedCrc + ", file crc: " + extractedFile.crc);
+                }
+                files.add(extractedFile);
+            } else {
+                throw new IOException("Missing extracted secondary dex file '" +
+                        extractedFile.getPath() + "'");
+            }
+        }
+
+        return files;
+    }
+
+
+    /**
+     * Compare current archive and crc with values stored in {@link SharedPreferences}. Should be
+     * called only while owning the lock on {@link #LOCK_FILENAME}.
+     */
+    private static boolean isModified(Context context, File archive, long currentCrc,
+            String prefsKeyPrefix) {
+        SharedPreferences prefs = getMultiDexPreferences(context);
+        return (prefs.getLong(prefsKeyPrefix + KEY_TIME_STAMP, NO_VALUE) != getTimeStamp(archive))
+                || (prefs.getLong(prefsKeyPrefix + KEY_CRC, NO_VALUE) != currentCrc);
+    }
+
+    private static long getTimeStamp(File archive) {
+        long timeStamp = archive.lastModified();
+        if (timeStamp == NO_VALUE) {
+            // never return NO_VALUE
+            timeStamp--;
+        }
+        return timeStamp;
+    }
+
+
+    private static long getZipCrc(File archive) throws IOException {
+        long computedValue = ZipUtil.getZipCrc(archive);
+        if (computedValue == NO_VALUE) {
+            // never return NO_VALUE
+            computedValue--;
+        }
+        return computedValue;
+    }
+
+    private List<ExtractedDex> performExtractions() throws IOException {
+
+        final String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT;
+
+        // It is safe to fully clear the dex dir because we own the file lock so no other process is
+        // extracting or running optimizing dexopt. It may cause crash of already running
+        // applications if for whatever reason we end up extracting again over a valid extraction.
+        clearDexDir();
+
+        List<ExtractedDex> files = new ArrayList<ExtractedDex>();
+
+        final ZipFile apk = new ZipFile(sourceApk);
+        try {
+
+            int secondaryNumber = 2;
+
+            ZipEntry dexFile = apk.getEntry(DEX_PREFIX + secondaryNumber + DEX_SUFFIX);
+            while (dexFile != null) {
+                String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX;
+                ExtractedDex extractedFile = new ExtractedDex(dexDir, fileName);
+                files.add(extractedFile);
+
+                Log.i(TAG, "Extraction is needed for file " + extractedFile);
+                int numAttempts = 0;
+                boolean isExtractionSuccessful = false;
+                while (numAttempts < MAX_EXTRACT_ATTEMPTS && !isExtractionSuccessful) {
+                    numAttempts++;
+
+                    // Create a zip file (extractedFile) containing only the secondary dex file
+                    // (dexFile) from the apk.
+                    extract(apk, dexFile, extractedFile, extractedFilePrefix);
+
+                    // Read zip crc of extracted dex
+                    try {
+                        extractedFile.crc = getZipCrc(extractedFile);
+                        isExtractionSuccessful = true;
+                    } catch (IOException e) {
+                        isExtractionSuccessful = false;
+                        Log.w(TAG, "Failed to read crc from " + extractedFile.getAbsolutePath(), e);
+                    }
+
+                    // Log size and crc of the extracted zip file
+                    Log.i(TAG, "Extraction " + (isExtractionSuccessful ? "succeeded" : "failed")
+                            + " '" + extractedFile.getAbsolutePath() + "': length "
+                            + extractedFile.length() + " - crc: " + extractedFile.crc);
+                    if (!isExtractionSuccessful) {
+                        // Delete the extracted file
+                        extractedFile.delete();
+                        if (extractedFile.exists()) {
+                            Log.w(TAG, "Failed to delete corrupted secondary dex '" +
+                                    extractedFile.getPath() + "'");
+                        }
+                    }
+                }
+                if (!isExtractionSuccessful) {
+                    throw new IOException("Could not create zip file " +
+                            extractedFile.getAbsolutePath() + " for secondary dex (" +
+                            secondaryNumber + ")");
+                }
+                secondaryNumber++;
+                dexFile = apk.getEntry(DEX_PREFIX + secondaryNumber + DEX_SUFFIX);
+            }
+        } finally {
+            try {
+                apk.close();
+            } catch (IOException e) {
+                Log.w(TAG, "Failed to close resource", e);
+            }
+        }
+
+        return files;
+    }
+
+    /**
+     * Save {@link SharedPreferences}. Should be called only while owning the lock on
+     * {@link #LOCK_FILENAME}.
+     */
+    private static void putStoredApkInfo(Context context, String keyPrefix, long timeStamp,
+            long crc, List<ExtractedDex> extractedDexes) {
+        SharedPreferences prefs = getMultiDexPreferences(context);
+        SharedPreferences.Editor edit = prefs.edit();
+        edit.putLong(keyPrefix + KEY_TIME_STAMP, timeStamp);
+        edit.putLong(keyPrefix + KEY_CRC, crc);
+        edit.putInt(keyPrefix + KEY_DEX_NUMBER, extractedDexes.size() + 1);
+
+        int extractedDexId = 2;
+        for (ExtractedDex dex : extractedDexes) {
+            edit.putLong(keyPrefix + KEY_DEX_CRC + extractedDexId, dex.crc);
+            edit.putLong(keyPrefix + KEY_DEX_TIME + extractedDexId, dex.lastModified());
+            extractedDexId++;
+        }
+        /* Use commit() and not apply() as advised by the doc because we need synchronous writing of
+         * the editor content and apply is doing an "asynchronous commit to disk".
+         */
+        edit.commit();
+    }
+
+    /**
+     * Get the MuliDex {@link SharedPreferences} for the current application. Should be called only
+     * while owning the lock on {@link #LOCK_FILENAME}.
+     */
+    private static SharedPreferences getMultiDexPreferences(Context context) {
+        return context.getSharedPreferences(PREFS_FILE,
+                Build.VERSION.SDK_INT < 11 /* Build.VERSION_CODES.HONEYCOMB */
+                        ? Context.MODE_PRIVATE
+                        : Context.MODE_PRIVATE | 0x0004 /* Context.MODE_MULTI_PROCESS */);
+    }
+
+    /**
+     * Clear the dex dir from all files but the lock.
+     */
+    private void clearDexDir() {
+        File[] files = dexDir.listFiles(new FileFilter() {
+            @Override
+            public boolean accept(File pathname) {
+                return !pathname.getName().equals(LOCK_FILENAME);
+            }
+        });
+        if (files == null) {
+            Log.w(TAG, "Failed to list secondary dex dir content (" + dexDir.getPath() + ").");
+            return;
+        }
+        for (File oldFile : files) {
+            Log.i(TAG, "Trying to delete old file " + oldFile.getPath() + " of size " +
+                    oldFile.length());
+            if (!oldFile.delete()) {
+                Log.w(TAG, "Failed to delete old file " + oldFile.getPath());
+            } else {
+                Log.i(TAG, "Deleted old file " + oldFile.getPath());
+            }
+        }
+    }
+
+    private static void extract(ZipFile apk, ZipEntry dexFile, File extractTo,
+            String extractedFilePrefix) throws IOException, FileNotFoundException {
+
+        InputStream in = apk.getInputStream(dexFile);
+        ZipOutputStream out = null;
+        // Temp files must not start with extractedFilePrefix to get cleaned up in prepareDexDir()
+        File tmp = File.createTempFile("tmp-" + extractedFilePrefix, EXTRACTED_SUFFIX,
+                extractTo.getParentFile());
+        Log.i(TAG, "Extracting " + tmp.getPath());
+        try {
+            out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tmp)));
+            try {
+                ZipEntry classesDex = new ZipEntry("classes.dex");
+                // keep zip entry time since it is the criteria used by Dalvik
+                classesDex.setTime(dexFile.getTime());
+                out.putNextEntry(classesDex);
+
+                byte[] buffer = new byte[BUFFER_SIZE];
+                int length = in.read(buffer);
+                while (length != -1) {
+                    out.write(buffer, 0, length);
+                    length = in.read(buffer);
+                }
+                out.closeEntry();
+            } finally {
+                out.close();
+            }
+            if (!tmp.setReadOnly()) {
+                throw new IOException("Failed to mark readonly \"" + tmp.getAbsolutePath() +
+                        "\" (tmp of \"" + extractTo.getAbsolutePath() + "\")");
+            }
+            Log.i(TAG, "Renaming to " + extractTo.getPath());
+            if (!tmp.renameTo(extractTo)) {
+                throw new IOException("Failed to rename \"" + tmp.getAbsolutePath() +
+                        "\" to \"" + extractTo.getAbsolutePath() + "\"");
+            }
+        } finally {
+            closeQuietly(in);
+            tmp.delete(); // return status ignored
+        }
+    }
+
+    /**
+     * Closes the given {@code Closeable}. Suppresses any IO exceptions.
+     */
+    private static void closeQuietly(Closeable closeable) {
+        try {
+            closeable.close();
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to close resource", e);
+        }
+    }
+}
diff --git a/androidx/multidex/MultiDexTest.java b/androidx/multidex/MultiDexTest.java
new file mode 100644
index 0000000..656b12a
--- /dev/null
+++ b/androidx/multidex/MultiDexTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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 androidx.multidex;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test for {@link MultiDex} class.
+ */
+public class MultiDexTest {
+    @Test
+    public void testVersionCheck() {
+        Assert.assertFalse(MultiDex.isVMMultidexCapable(null));
+        Assert.assertFalse(MultiDex.isVMMultidexCapable("-1.32.54"));
+        Assert.assertFalse(MultiDex.isVMMultidexCapable("1.32.54"));
+        Assert.assertFalse(MultiDex.isVMMultidexCapable("1.32"));
+        Assert.assertFalse(MultiDex.isVMMultidexCapable("2.0"));
+        Assert.assertFalse(MultiDex.isVMMultidexCapable("2.000.1254"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("2.1.1254"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("2.1"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("2.2"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("2.1.0000"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("2.2.0000"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("002.0001.0010"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("3.0"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("3.0.0"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("3.0.1"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("3.1.0"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("03.1.132645"));
+        Assert.assertTrue(MultiDex.isVMMultidexCapable("03.2"));
+    }
+}
diff --git a/androidx/multidex/ZipEntryReader.java b/androidx/multidex/ZipEntryReader.java
new file mode 100644
index 0000000..a16e265
--- /dev/null
+++ b/androidx/multidex/ZipEntryReader.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+/* Apache Harmony HEADER because the code in this class comes mostly from ZipFile, ZipEntry and
+ * ZipConstants from android libcore.
+ */
+
+package androidx.multidex;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+
+class ZipEntryReader {
+    static final Charset UTF_8 = Charset.forName("UTF-8");
+   /**
+     * General Purpose Bit Flags, Bit 0.
+     * If set, indicates that the file is encrypted.
+     */
+    private static final int GPBF_ENCRYPTED_FLAG = 1 << 0;
+
+    /**
+     * Supported General Purpose Bit Flags Mask.
+     * Bit mask of bits not supported.
+     * Note: The only bit that we will enforce at this time
+     * is the encrypted bit. Although other bits are not supported,
+     * we must not enforce them as this could break some legitimate
+     * use cases (See http://b/8617715).
+     */
+    private static final int GPBF_UNSUPPORTED_MASK = GPBF_ENCRYPTED_FLAG;
+    private static final long CENSIG = 0x2014b50;
+
+    static ZipEntry readEntry(ByteBuffer in) throws IOException {
+
+        int sig = in.getInt();
+        if (sig != CENSIG) {
+             throw new ZipException("Central Directory Entry not found");
+        }
+
+        in.position(8);
+        int gpbf = in.getShort() & 0xffff;
+
+        if ((gpbf & GPBF_UNSUPPORTED_MASK) != 0) {
+            throw new ZipException("Invalid General Purpose Bit Flag: " + gpbf);
+        }
+
+        int compressionMethod = in.getShort() & 0xffff;
+        int time = in.getShort() & 0xffff;
+        int modDate = in.getShort() & 0xffff;
+
+        // These are 32-bit values in the file, but 64-bit fields in this object.
+        long crc = ((long) in.getInt()) & 0xffffffffL;
+        long compressedSize = ((long) in.getInt()) & 0xffffffffL;
+        long size = ((long) in.getInt()) & 0xffffffffL;
+
+        int nameLength = in.getShort() & 0xffff;
+        int extraLength = in.getShort() & 0xffff;
+        int commentByteCount = in.getShort() & 0xffff;
+
+        // This is a 32-bit value in the file, but a 64-bit field in this object.
+        in.position(42);
+        long localHeaderRelOffset = ((long) in.getInt()) & 0xffffffffL;
+
+        byte[] nameBytes = new byte[nameLength];
+        in.get(nameBytes, 0, nameBytes.length);
+        String name = new String(nameBytes, 0, nameBytes.length, UTF_8);
+
+        ZipEntry entry = new ZipEntry(name);
+        entry.setMethod(compressionMethod);
+        entry.setTime(getTime(time, modDate));
+
+        entry.setCrc(crc);
+        entry.setCompressedSize(compressedSize);
+        entry.setSize(size);
+
+        // The RI has always assumed UTF-8. (If GPBF_UTF8_FLAG isn't set, the encoding is
+        // actually IBM-437.)
+        if (commentByteCount > 0) {
+            byte[] commentBytes = new byte[commentByteCount];
+            in.get(commentBytes, 0, commentByteCount);
+            entry.setComment(new String(commentBytes, 0, commentBytes.length, UTF_8));
+        }
+
+        if (extraLength > 0) {
+            byte[] extra = new byte[extraLength];
+            in.get(extra, 0, extraLength);
+            entry.setExtra(extra);
+        }
+
+        return entry;
+
+    }
+
+    private static long getTime(int time, int modDate) {
+        GregorianCalendar cal = new GregorianCalendar();
+        cal.set(Calendar.MILLISECOND, 0);
+        cal.set(1980 + ((modDate >> 9) & 0x7f), ((modDate >> 5) & 0xf) - 1,
+                modDate & 0x1f, (time >> 11) & 0x1f, (time >> 5) & 0x3f,
+                (time & 0x1f) << 1);
+        return cal.getTime().getTime();
+    }
+
+}
diff --git a/androidx/multidex/ZipUtil.java b/androidx/multidex/ZipUtil.java
new file mode 100644
index 0000000..fc33623
--- /dev/null
+++ b/androidx/multidex/ZipUtil.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+/* Apache Harmony HEADER because the code in this class comes mostly from ZipFile, ZipEntry and
+ * ZipConstants from android libcore.
+ */
+
+package androidx.multidex;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.zip.CRC32;
+import java.util.zip.ZipException;
+
+/**
+ * Tools to build a quick partial crc of zip files.
+ */
+final class ZipUtil {
+    static class CentralDirectory {
+        long offset;
+        long size;
+    }
+
+    /* redefine those constant here because of bug 13721174 preventing to compile using the
+     * constants defined in ZipFile */
+    private static final int ENDHDR = 22;
+    private static final int ENDSIG = 0x6054b50;
+
+    /**
+     * Size of reading buffers.
+     */
+    private static final int BUFFER_SIZE = 0x4000;
+
+    /**
+     * Compute crc32 of the central directory of an apk. The central directory contains
+     * the crc32 of each entries in the zip so the computed result is considered valid for the whole
+     * zip file. Does not support zip64 nor multidisk but it should be OK for now since ZipFile does
+     * not either.
+     */
+    static long getZipCrc(File apk) throws IOException {
+        RandomAccessFile raf = new RandomAccessFile(apk, "r");
+        try {
+            CentralDirectory dir = findCentralDirectory(raf);
+
+            return computeCrcOfCentralDir(raf, dir);
+        } finally {
+            raf.close();
+        }
+    }
+
+    /* Package visible for testing */
+    static CentralDirectory findCentralDirectory(RandomAccessFile raf) throws IOException,
+            ZipException {
+        long scanOffset = raf.length() - ENDHDR;
+        if (scanOffset < 0) {
+            throw new ZipException("File too short to be a zip file: " + raf.length());
+        }
+
+        long stopOffset = scanOffset - 0x10000 /* ".ZIP file comment"'s max length */;
+        if (stopOffset < 0) {
+            stopOffset = 0;
+        }
+
+        int endSig = Integer.reverseBytes(ENDSIG);
+        while (true) {
+            raf.seek(scanOffset);
+            if (raf.readInt() == endSig) {
+                break;
+            }
+
+            scanOffset--;
+            if (scanOffset < stopOffset) {
+                throw new ZipException("End Of Central Directory signature not found");
+            }
+        }
+        // Read the End Of Central Directory. ENDHDR includes the signature
+        // bytes,
+        // which we've already read.
+
+        // Pull out the information we need.
+        raf.skipBytes(2); // diskNumber
+        raf.skipBytes(2); // diskWithCentralDir
+        raf.skipBytes(2); // numEntries
+        raf.skipBytes(2); // totalNumEntries
+        CentralDirectory dir = new CentralDirectory();
+        dir.size = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL;
+        dir.offset = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL;
+        return dir;
+    }
+
+    /* Package visible for testing */
+    static long computeCrcOfCentralDir(RandomAccessFile raf, CentralDirectory dir)
+            throws IOException {
+        CRC32 crc = new CRC32();
+        long stillToRead = dir.size;
+        raf.seek(dir.offset);
+        int length = (int) Math.min(BUFFER_SIZE, stillToRead);
+        byte[] buffer = new byte[BUFFER_SIZE];
+        length = raf.read(buffer, 0, length);
+        while (length != -1) {
+            crc.update(buffer, 0, length);
+            stillToRead -= length;
+            if (stillToRead == 0) {
+                break;
+            }
+            length = (int) Math.min(BUFFER_SIZE, stillToRead);
+            length = raf.read(buffer, 0, length);
+        }
+        return crc.getValue();
+    }
+}
diff --git a/androidx/multidex/ZipUtilTest.java b/androidx/multidex/ZipUtilTest.java
new file mode 100644
index 0000000..39a59ac
--- /dev/null
+++ b/androidx/multidex/ZipUtilTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2014 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 androidx.multidex;
+
+import androidx.multidex.ZipUtil.CentralDirectory;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+/**
+ * Tests of ZipUtil class.
+ *
+ * The test assumes that ANDROID_BUILD_TOP environment variable is defined and point to the top of a
+ * built android tree. This is the case when the console used for running the tests is setup for
+ * android tree compilation.
+ */
+public class ZipUtilTest {
+    private static final File zipFile = new File(System.getenv("ANDROID_BUILD_TOP"),
+        "out/target/common/obj/JAVA_LIBRARIES/android-support-multidex_intermediates/javalib.jar");
+    @BeforeClass
+    public static void setupClass() throws ZipException, IOException {
+        // just verify the zip is valid
+        new ZipFile(zipFile).close();
+    }
+
+    @Test
+    public void testCrcDoNotCrash() throws IOException {
+
+        long crc =
+                ZipUtil.getZipCrc(zipFile);
+        System.out.println("crc is " + crc);
+
+    }
+
+    @Test
+    public void testCrcRange() throws IOException {
+        RandomAccessFile raf = new RandomAccessFile(zipFile, "r");
+        CentralDirectory dir = ZipUtil.findCentralDirectory(raf);
+        byte[] dirData = new byte[(int) dir.size];
+        int length = dirData.length;
+        int off = 0;
+        raf.seek(dir.offset);
+        while (length > 0) {
+            int read = raf.read(dirData, off, length);
+            if (length == -1) {
+                throw new EOFException();
+            }
+            length -= read;
+            off += read;
+        }
+        raf.close();
+        ByteBuffer buffer = ByteBuffer.wrap(dirData);
+        Map<String, ZipEntry> toCheck = new HashMap<String, ZipEntry>();
+        while (buffer.hasRemaining()) {
+            buffer = buffer.slice();
+            buffer.order(ByteOrder.LITTLE_ENDIAN);
+            ZipEntry entry = ZipEntryReader.readEntry(buffer);
+            toCheck.put(entry.getName(), entry);
+        }
+
+        ZipFile zip = new ZipFile(zipFile);
+        Assert.assertEquals(zip.size(), toCheck.size());
+        Enumeration<? extends ZipEntry> ref = zip.entries();
+        while (ref.hasMoreElements()) {
+            ZipEntry refEntry = ref.nextElement();
+            ZipEntry checkEntry = toCheck.get(refEntry.getName());
+            Assert.assertNotNull(checkEntry);
+            Assert.assertEquals(refEntry.getName(), checkEntry.getName());
+            Assert.assertEquals(refEntry.getComment(), checkEntry.getComment());
+            Assert.assertEquals(refEntry.getTime(), checkEntry.getTime());
+            Assert.assertEquals(refEntry.getCrc(), checkEntry.getCrc());
+            Assert.assertEquals(refEntry.getCompressedSize(), checkEntry.getCompressedSize());
+            Assert.assertEquals(refEntry.getSize(), checkEntry.getSize());
+            Assert.assertEquals(refEntry.getMethod(), checkEntry.getMethod());
+            Assert.assertArrayEquals(refEntry.getExtra(), checkEntry.getExtra());
+        }
+        zip.close();
+    }
+
+    @Test
+    public void testCrcValue() throws IOException {
+        ZipFile zip = new ZipFile(zipFile);
+        Enumeration<? extends ZipEntry> ref = zip.entries();
+        byte[] buffer = new byte[0x2000];
+        while (ref.hasMoreElements()) {
+            ZipEntry refEntry = ref.nextElement();
+            if (refEntry.getSize() > 0) {
+                File tmp = File.createTempFile("ZipUtilTest", ".fakezip");
+                InputStream in = zip.getInputStream(refEntry);
+                OutputStream out = new FileOutputStream(tmp);
+                int read = in.read(buffer);
+                while (read != -1) {
+                    out.write(buffer, 0, read);
+                    read = in.read(buffer);
+                }
+                in.close();
+                out.close();
+                RandomAccessFile raf = new RandomAccessFile(tmp, "r");
+                CentralDirectory dir = new CentralDirectory();
+                dir.offset = 0;
+                dir.size = raf.length();
+                long crc = ZipUtil.computeCrcOfCentralDir(raf, dir);
+                Assert.assertEquals(refEntry.getCrc(), crc);
+                raf.close();
+                tmp.delete();
+            }
+        }
+        zip.close();
+    }
+    @Test
+    public void testInvalidCrcValue() throws IOException {
+        ZipFile zip = new ZipFile(zipFile);
+        Enumeration<? extends ZipEntry> ref = zip.entries();
+        byte[] buffer = new byte[0x2000];
+        while (ref.hasMoreElements()) {
+            ZipEntry refEntry = ref.nextElement();
+            if (refEntry.getSize() > 0) {
+                File tmp = File.createTempFile("ZipUtilTest", ".fakezip");
+                InputStream in = zip.getInputStream(refEntry);
+                OutputStream out = new FileOutputStream(tmp);
+                int read = in.read(buffer);
+                while (read != -1) {
+                    out.write(buffer, 0, read);
+                    read = in.read(buffer);
+                }
+                in.close();
+                out.close();
+                RandomAccessFile raf = new RandomAccessFile(tmp, "r");
+                CentralDirectory dir = new CentralDirectory();
+                dir.offset = 0;
+                dir.size = raf.length() - 1;
+                long crc = ZipUtil.computeCrcOfCentralDir(raf, dir);
+                Assert.assertNotEquals(refEntry.getCrc(), crc);
+                raf.close();
+                tmp.delete();
+            }
+        }
+        zip.close();
+    }
+
+}
diff --git a/androidx/renderscript/Allocation.java b/androidx/renderscript/Allocation.java
new file mode 100644
index 0000000..b6588c0
--- /dev/null
+++ b/androidx/renderscript/Allocation.java
@@ -0,0 +1,3032 @@
+/*
+ * Copyright (C) 2008-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 androidx.renderscript;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.util.Log;
+import android.view.Surface;
+
+/**
+ * <p> This class provides the primary method through which data is passed to
+ * and from RenderScript kernels.  An Allocation provides the backing store for
+ * a given {@link androidx.renderscript.Type}.  </p>
+ *
+ * <p>An Allocation also contains a set of usage flags that denote how the
+ * Allocation could be used. For example, an Allocation may have usage flags
+ * specifying that it can be used from a script as well as input to a {@link
+ * androidx.renderscript.Sampler}. A developer must synchronize
+ * across these different usages using
+ * {@link androidx.renderscript.Allocation#syncAll} in
+ * order to ensure that different users of the Allocation have a consistent view
+ * of memory. For example, in the case where an Allocation is used as the output
+ * of one kernel and as Sampler input in a later kernel, a developer must call
+ * {@link #syncAll syncAll(Allocation.USAGE_SCRIPT)} prior to launching the
+ * second kernel to ensure correctness.
+ *
+ * <p>An Allocation can be populated with the {@link #copyFrom} routines. For
+ * more complex Element types, the {@link #copyFromUnchecked} methods can be
+ * used to copy from byte arrays or similar constructs.</p>
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about creating an application that uses
+ * RenderScript, read the
+ * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
+ * developer guide.</p>
+ * </div>
+ **/
+public class Allocation extends BaseObj {
+    Type mType;
+    Bitmap mBitmap;
+    int mUsage;
+    int mSize;
+    Allocation mAdaptedAllocation;
+    ByteBuffer mByteBuffer = null;
+    long mByteBufferStride = 0;
+
+    boolean mConstrainedLOD;
+    boolean mConstrainedFace;
+    boolean mConstrainedY;
+    boolean mConstrainedZ;
+    boolean mReadAllowed = true;
+    boolean mWriteAllowed = true;
+    boolean mAutoPadding = false;
+    int mSelectedY;
+    int mSelectedZ;
+    int mSelectedLOD;
+    Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
+
+    int mCurrentDimX;
+    int mCurrentDimY;
+    int mCurrentDimZ;
+    int mCurrentCount;
+
+    private Element.DataType validateObjectIsPrimitiveArray(Object d, boolean checkType) {
+        final Class c = d.getClass();
+        if (!c.isArray()) {
+            throw new RSIllegalArgumentException("Object passed is not an array of primitives.");
+        }
+        final Class cmp = c.getComponentType();
+        if (!cmp.isPrimitive()) {
+            throw new RSIllegalArgumentException("Object passed is not an Array of primitives.");
+        }
+
+        if (cmp == Long.TYPE) {
+            if (checkType) {
+                validateIsInt64();
+                return mType.mElement.mType;
+            }
+            return Element.DataType.SIGNED_64;
+        }
+
+        if (cmp == Integer.TYPE) {
+            if (checkType) {
+                validateIsInt32();
+                return mType.mElement.mType;
+            }
+            return Element.DataType.SIGNED_32;
+        }
+
+        if (cmp == Short.TYPE) {
+            if (checkType) {
+                validateIsInt16();
+                return mType.mElement.mType;
+            }
+            return Element.DataType.SIGNED_16;
+        }
+
+        if (cmp == Byte.TYPE) {
+            if (checkType) {
+                validateIsInt8();
+                return mType.mElement.mType;
+            }
+            return Element.DataType.SIGNED_8;
+        }
+
+        if (cmp == Float.TYPE) {
+            if (checkType) {
+                validateIsFloat32();
+            }
+            return Element.DataType.FLOAT_32;
+        }
+
+        if (cmp == Double.TYPE) {
+            if (checkType) {
+                validateIsFloat64();
+            }
+            return Element.DataType.FLOAT_64;
+        }
+        return null;
+    }
+
+    /*
+     * Hold reference to the shared allocation in compat context
+     * for Incremental Support Lib.
+     */
+    long mIncCompatAllocation;
+    boolean mIncAllocDestroyed;
+    /**
+     * The usage of the Allocation.  These signal to RenderScript where to place
+     * the Allocation in memory.
+     *
+     */
+
+    /**
+     * The Allocation will be bound to and accessed by scripts.
+     */
+    public static final int USAGE_SCRIPT = 0x0001;
+
+    /**
+     * The Allocation will be used as a texture source by one or more graphics
+     * programs.
+     *
+     */
+    public static final int USAGE_GRAPHICS_TEXTURE = 0x0002;
+
+    /**
+     * The Allocation will be used as a {@link android.graphics.SurfaceTexture}
+     * consumer.  This usage will cause the Allocation to be created as
+     * read-only.
+     *
+     */
+    public static final int USAGE_IO_INPUT = 0x0020;
+
+    /**
+     * The Allocation will be used as a {@link android.graphics.SurfaceTexture}
+     * producer.  The dimensions and format of the {@link
+     * android.graphics.SurfaceTexture} will be forced to those of the
+     * Allocation.
+     *
+     */
+    public static final int USAGE_IO_OUTPUT = 0x0040;
+
+    /**
+     * The Allocation's backing store will be inherited from another object
+     * (usually a {@link android.graphics.Bitmap}); copying to or from the
+     * original source Bitmap will cause a synchronization rather than a full
+     * copy.  {@link #syncAll} may also be used to synchronize the Allocation
+     * and the source Bitmap.
+     *
+     * <p>This is set by default for allocations created with {@link
+     * #createFromBitmap} in API version 18 and higher.</p>
+     *
+     */
+    public static final int USAGE_SHARED = 0x0080;
+
+    /**
+     * Controls mipmap behavior when using the bitmap creation and update
+     * functions.
+     */
+    public enum MipmapControl {
+        /**
+         * No mipmaps will be generated and the type generated from the incoming
+         * bitmap will not contain additional LODs.
+         */
+        MIPMAP_NONE(0),
+
+        /**
+         * A full mipmap chain will be created in script memory.  The Type of
+         * the Allocation will contain a full mipmap chain.  On upload, the full
+         * chain will be transferred.
+         */
+        MIPMAP_FULL(1),
+
+        /**
+         * The Type of the Allocation will be the same as MIPMAP_NONE.  It will
+         * not contain mipmaps.  On upload, the allocation data will contain a
+         * full mipmap chain generated from the top level in script memory.
+         */
+        MIPMAP_ON_SYNC_TO_TEXTURE(2);
+
+        int mID;
+        MipmapControl(int id) {
+            mID = id;
+        }
+    }
+
+    /**
+     * Getter & Setter for the dummy allocation for Inc Support Lib.
+     *
+     */
+    public long getIncAllocID() {
+        return mIncCompatAllocation;
+    }
+    public void setIncAllocID(long id) {
+        mIncCompatAllocation = id;
+    }
+
+    private long getIDSafe() {
+        if (mAdaptedAllocation != null) {
+            return mAdaptedAllocation.getID(mRS);
+        }
+        return getID(mRS);
+    }
+
+
+   /**
+     * Get the {@link androidx.renderscript.Element} of the {@link
+     * androidx.renderscript.Type} of the Allocation.
+     *
+     * @return Element
+     *
+     */
+    public Element getElement() {
+        return mType.getElement();
+    }
+
+    /**
+     * Get the usage flags of the Allocation.
+     *
+     * @return usage this Allocation's set of the USAGE_* flags OR'd together
+     *
+     */
+    public int getUsage() {
+        return mUsage;
+    }
+
+    /**
+     * Specifies the mapping between the Allocation's cells and an array's elements
+     * when data is copied from the Allocation to the array, or vice-versa.
+     *
+     * Only applies to an Allocation whose Element is a vector of length 3 (such as
+     * {@link Element#U8_3} or {@link Element#RGB_888}). Enabling this feature may make
+     * copying data from the Allocation to an array or vice-versa less efficient.
+     *
+     * <p> Vec3 Element cells are stored in an Allocation as Vec4 Element cells with
+     * the same {@link androidx.renderscript.Element.DataType}, with the fourth vector
+     * component treated as padding. When this feature is enabled, only the data components,
+     * i.e. the first 3 vector components of each cell, will be mapped between the array
+     * and the Allocation. When disabled, explicit mapping of the padding components
+     * is required, as described in the following example.
+     *
+     * <p> For example, when copying an integer array to an Allocation of two {@link
+     * Element#I32_3} cells using {@link #copyFrom(int[])}:
+     * <p> When disabled:
+     *     The array must have at least 8 integers, with the first 4 integers copied
+     *     to the first cell of the Allocation, and the next 4 integers copied to
+     *     the second cell. The 4th and 8th integers are mapped as the padding components.
+     *
+     * <p> When enabled:
+     *     The array just needs to have at least 6 integers, with the first 3 integers
+     *     copied to the the first cell as data components, and the next 3 copied to
+     *     the second cell. There is no mapping for the padding components.
+     *
+     * <p> Similarly, when copying a byte array to an Allocation of two {@link
+     * Element#I32_3} cells, using {@link #copyFromUnchecked(int[])}:
+     * <p> When disabled:
+     *     The array must have at least 32 bytes, with the first 16 bytes copied
+     *     to the first cell of the Allocation, and the next 16 bytes copied to
+     *     the second cell. The 13th-16th and 29th-32nd bytes are mapped as padding
+     *     components.
+     *
+     * <p> When enabled:
+     *     The array just needs to have at least 24 bytes, with the first 12 bytes copied
+     *     to the first cell of the Allocation, and the next 12 bytes copied to
+     *     the second cell. There is no mapping for the padding components.
+     *
+     * <p> Similar to copying data to an Allocation from an array, when copying data from an
+     * Allocation to an array, the padding components for Vec3 Element cells will not be
+     * copied/mapped to the array if AutoPadding is enabled.
+     *
+     * <p> Default: Disabled.
+     *
+     * @param useAutoPadding True: enable AutoPadding; False: disable AutoPadding
+     *
+     */
+    public void setAutoPadding(boolean useAutoPadding) {
+        mAutoPadding = useAutoPadding;
+    }
+
+    /**
+     * Get the size of the Allocation in bytes.
+     *
+     * @return size of the Allocation in bytes.
+     *
+     */
+    public int getBytesSize() {
+        if (mType.mDimYuv != 0) {
+            return (int)Math.ceil(mType.getCount() * mType.getElement().getBytesSize() * 1.5);
+        }
+        return mType.getCount() * mType.getElement().getBytesSize();
+    }
+
+    private void updateCacheInfo(Type t) {
+        mCurrentDimX = t.getX();
+        mCurrentDimY = t.getY();
+        mCurrentDimZ = t.getZ();
+        mCurrentCount = mCurrentDimX;
+        if (mCurrentDimY > 1) {
+            mCurrentCount *= mCurrentDimY;
+        }
+        if (mCurrentDimZ > 1) {
+            mCurrentCount *= mCurrentDimZ;
+        }
+    }
+
+    private void setBitmap(Bitmap b) {
+        mBitmap = b;
+    }
+
+    Allocation(long id, RenderScript rs, Type t, int usage) {
+        super(id, rs);
+        if ((usage & ~(USAGE_SCRIPT |
+                       USAGE_GRAPHICS_TEXTURE |
+                       USAGE_IO_INPUT |
+                       USAGE_IO_OUTPUT |
+                       USAGE_SHARED)) != 0) {
+            throw new RSIllegalArgumentException("Unknown usage specified.");
+        }
+
+        if ((usage & USAGE_IO_INPUT) != 0) {
+            mWriteAllowed = false;
+
+            if ((usage & ~(USAGE_IO_INPUT |
+                           USAGE_GRAPHICS_TEXTURE |
+                           USAGE_SCRIPT)) != 0) {
+                throw new RSIllegalArgumentException("Invalid usage combination.");
+            }
+        }
+
+        mType = t;
+        mUsage = usage;
+        mIncCompatAllocation = 0;
+        mIncAllocDestroyed = false;
+
+        if (t != null) {
+            // TODO: A3D doesn't have Type info during creation, so we can't
+            // calculate the size ahead of time. We can possibly add a method
+            // to update the size in the future if it seems reasonable.
+            mSize = mType.getCount() * mType.getElement().getBytesSize();
+            updateCacheInfo(t);
+        }
+        if (RenderScript.sUseGCHooks == true) {
+            try {
+                RenderScript.registerNativeAllocation.invoke(RenderScript.sRuntime, mSize);
+            } catch (Exception e) {
+                Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
+                throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
+            }
+        }
+    }
+
+    protected void finalize() throws Throwable {
+        if (RenderScript.sUseGCHooks == true) {
+            RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
+        }
+        super.finalize();
+    }
+
+    private void validateIsInt64() {
+        if ((mType.mElement.mType == Element.DataType.SIGNED_64) ||
+            (mType.mElement.mType == Element.DataType.UNSIGNED_64)) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "64 bit integer source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsInt32() {
+        if ((mType.mElement.mType == Element.DataType.SIGNED_32) ||
+            (mType.mElement.mType == Element.DataType.UNSIGNED_32)) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "32 bit integer source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsInt16() {
+        if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
+            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "16 bit integer source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsInt8() {
+        if ((mType.mElement.mType == Element.DataType.SIGNED_8) ||
+            (mType.mElement.mType == Element.DataType.UNSIGNED_8)) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "8 bit integer source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsFloat32() {
+        if (mType.mElement.mType == Element.DataType.FLOAT_32) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "32 bit float source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsFloat64() {
+        if (mType.mElement.mType == Element.DataType.FLOAT_64) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "64 bit float source does not match allocation type " + mType.mElement.mType);
+    }
+
+    private void validateIsObject() {
+        if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) ||
+            (mType.mElement.mType == Element.DataType.RS_TYPE) ||
+            (mType.mElement.mType == Element.DataType.RS_ALLOCATION) ||
+            (mType.mElement.mType == Element.DataType.RS_SAMPLER) ||
+            (mType.mElement.mType == Element.DataType.RS_SCRIPT)) {
+            return;
+        }
+        throw new RSIllegalArgumentException(
+            "Object source does not match allocation type " + mType.mElement.mType);
+    }
+
+    /**
+     * Get the {@link androidx.renderscript.Type} of the Allocation.
+     *
+     * @return Type
+     *
+     */
+    public Type getType() {
+        return mType;
+    }
+
+    /**
+     * Propagate changes from one usage of the Allocation to the
+     * other usages of the Allocation.
+     *
+     */
+    public void syncAll(int srcLocation) {
+        switch (srcLocation) {
+        case USAGE_SCRIPT:
+        case USAGE_GRAPHICS_TEXTURE:
+            break;
+        default:
+            throw new RSIllegalArgumentException("Source must be exactly one usage type.");
+        }
+        mRS.validate();
+        mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
+    }
+
+    /**
+     * Send a buffer to the output stream.  The contents of the Allocation will
+     * be undefined after this operation. This operation is only valid if {@link
+     * #USAGE_IO_OUTPUT} is set on the Allocation.
+     *
+     *
+     */
+    public void ioSend() {
+        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
+            throw new RSIllegalArgumentException(
+                "Can only send buffer if IO_OUTPUT usage specified.");
+        }
+        mRS.validate();
+        mRS.nAllocationIoSend(getID(mRS));
+    }
+
+    /**
+     * Delete once code is updated.
+     */
+    public void ioSendOutput() {
+        ioSend();
+    }
+    /**
+     * Gets or creates a ByteBuffer that contains the raw data of the current Allocation.
+     * <p> If the Allocation is created with USAGE_IO_INPUT, the returned ByteBuffer
+     * would contain the up-to-date data as READ ONLY.
+     * For a 2D or 3D Allocation, the raw data maybe padded so that each row of
+     * the Allocation has certain alignment. The size of each row including padding,
+     * called stride, can be queried using the {@link #getStride()} method.
+     *
+     * Note: Operating on the ByteBuffer of a destroyed Allocation will triger errors.
+     *       The ByteBuffer will be Read-Only for devices before Lollopop (API 21).
+     *
+     * @return ByteBuffer The ByteBuffer associated with raw data pointer of the Allocation.
+     */
+    public ByteBuffer getByteBuffer() {
+        int xBytesSize = mType.getX() * mType.getElement().getBytesSize();
+        // When running on devices before L, we need to construct the ByteBuffer
+        // and explicitly copy the data from the allocation to it.
+        if (mRS.getDispatchAPILevel() < 21) {
+            byte[] data = null;
+            if (mType.getZ() > 0) {
+                // TODO: add support for 3D allocations.
+                return null;
+            } else if (mType.getY() > 0) {
+                // 2D Allocation
+                data = new byte[xBytesSize * mType.getY()];
+                copy2DRangeToUnchecked(0, 0, mType.getX(), mType.getY(), data,
+                                       Element.DataType.SIGNED_8, xBytesSize * mType.getY());
+            } else {
+                // 1D Allocation
+                data = new byte[xBytesSize];
+                copy1DRangeToUnchecked(0, mType.getX(), data);
+            }
+            ByteBuffer bBuffer = ByteBuffer.wrap(data).asReadOnlyBuffer();
+            mByteBufferStride = xBytesSize;
+            return bBuffer;
+        }
+        // Create a new ByteBuffer if it is not initialized or using IO_INPUT.
+        if (mByteBuffer == null || (mUsage & USAGE_IO_INPUT) != 0) {
+            mByteBuffer = mRS.nAllocationGetByteBuffer(getID(mRS), xBytesSize, mType.getY(), mType.getZ());
+        }
+        return mByteBuffer;
+    }
+
+    /**
+     * Gets the stride of the Allocation.
+     * For a 2D or 3D Allocation, the raw data maybe padded so that each row of
+     * the Allocation has certain alignment. The size of each row including such
+     * padding is called stride.
+     *
+     * @return the stride. For 1D Allocation, the stride will be the number of
+     *         bytes of this Allocation. For 2D and 3D Allocations, the stride
+     *         will be the stride in X dimension measuring in bytes.
+     */
+    public long getStride() {
+        if (mByteBufferStride ==0) {
+            if (mRS.getDispatchAPILevel() > 21) {
+                mByteBufferStride = mRS.nAllocationGetStride(getID(mRS));
+            } else {
+                mByteBufferStride = mType.getX() * mType.getElement().getBytesSize();
+            }
+        }
+        return mByteBufferStride;
+    }
+
+    /**
+     * Receive the latest input into the Allocation. This operation
+     * is only valid if {@link #USAGE_IO_INPUT} is set on the Allocation.
+     *
+     */
+    public void ioReceive() {
+        if ((mUsage & USAGE_IO_INPUT) == 0) {
+            throw new RSIllegalArgumentException(
+                "Can only receive if IO_INPUT usage specified.");
+        }
+        mRS.validate();
+        mRS.nAllocationIoReceive(getID(mRS));
+    }
+
+    /**
+     * Copy an array of RS objects to the Allocation.
+     *
+     * @param d Source array.
+     */
+    public void copyFrom(BaseObj[] d) {
+        mRS.validate();
+        validateIsObject();
+        if (d.length != mCurrentCount) {
+            throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
+                                                 mCurrentCount + ", array length = " + d.length);
+        }
+
+        if (RenderScript.sPointerSize == 8) {
+            long i[] = new long[d.length * 4];
+            for (int ct=0; ct < d.length; ct++) {
+                i[ct * 4] = d[ct].getID(mRS);
+            }
+            copy1DRangeFromUnchecked(0, mCurrentCount, i);
+        } else {
+            int i[] = new int[d.length];
+            for (int ct=0; ct < d.length; ct++) {
+                i[ct] = (int)d[ct].getID(mRS);
+            }
+            copy1DRangeFromUnchecked(0, mCurrentCount, i);
+        }
+    }
+
+    private void validateBitmapFormat(Bitmap b) {
+        Bitmap.Config bc = b.getConfig();
+        if (bc == null) {
+            throw new RSIllegalArgumentException("Bitmap has an unsupported format for this operation");
+        }
+        switch (bc) {
+        case ALPHA_8:
+            if (mType.getElement().mKind != Element.DataKind.PIXEL_A) {
+                throw new RSIllegalArgumentException("Allocation kind is " +
+                                                     mType.getElement().mKind + ", type " +
+                                                     mType.getElement().mType +
+                                                     " of " + mType.getElement().getBytesSize() +
+                                                     " bytes, passed bitmap was " + bc);
+            }
+            break;
+        case ARGB_8888:
+            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
+                (mType.getElement().getBytesSize() != 4)) {
+                throw new RSIllegalArgumentException("Allocation kind is " +
+                                                     mType.getElement().mKind + ", type " +
+                                                     mType.getElement().mType +
+                                                     " of " + mType.getElement().getBytesSize() +
+                                                     " bytes, passed bitmap was " + bc);
+            }
+            break;
+        case RGB_565:
+            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) ||
+                (mType.getElement().getBytesSize() != 2)) {
+                throw new RSIllegalArgumentException("Allocation kind is " +
+                                                     mType.getElement().mKind + ", type " +
+                                                     mType.getElement().mType +
+                                                     " of " + mType.getElement().getBytesSize() +
+                                                     " bytes, passed bitmap was " + bc);
+            }
+            break;
+        case ARGB_4444:
+            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
+                (mType.getElement().getBytesSize() != 2)) {
+                throw new RSIllegalArgumentException("Allocation kind is " +
+                                                     mType.getElement().mKind + ", type " +
+                                                     mType.getElement().mType +
+                                                     " of " + mType.getElement().getBytesSize() +
+                                                     " bytes, passed bitmap was " + bc);
+            }
+            break;
+
+        }
+    }
+
+    private void validateBitmapSize(Bitmap b) {
+        if((mCurrentDimX != b.getWidth()) || (mCurrentDimY != b.getHeight())) {
+            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
+        }
+    }
+
+    private void copyFromUnchecked(Object array, Element.DataType dt, int arrayLen) {
+        mRS.validate();
+        if (mCurrentDimZ > 0) {
+            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, array, dt, arrayLen);
+        } else if (mCurrentDimY > 0) {
+            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, array, dt, arrayLen);
+        } else {
+            copy1DRangeFromUnchecked(0, mCurrentCount, array, dt, arrayLen);
+        }
+    }
+
+    /**
+     * Copy into this Allocation from an array. This method does not guarantee
+     * that the Allocation is compatible with the input buffer; it copies memory
+     * without reinterpretation.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param array The source array
+     */
+    public void copyFromUnchecked(Object array) {
+        copyFromUnchecked(array, validateObjectIsPrimitiveArray(array, false),
+                          java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy into this Allocation from an array. This method does not guarantee
+     * that the Allocation is compatible with the input buffer; it copies memory
+     * without reinterpretation.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d the source array
+     */
+    public void copyFromUnchecked(int[] d) {
+        copyFromUnchecked(d, Element.DataType.SIGNED_32, d.length);
+    }
+
+    /**
+     * Copy into this Allocation from an array. This method does not guarantee
+     * that the Allocation is compatible with the input buffer; it copies memory
+     * without reinterpretation.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d the source array
+     */
+    public void copyFromUnchecked(short[] d) {
+        copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
+    }
+
+    /**
+     * Copy into this Allocation from an array. This method does not guarantee
+     * that the Allocation is compatible with the input buffer; it copies memory
+     * without reinterpretation.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d the source array
+     */
+    public void copyFromUnchecked(byte[] d) {
+        copyFromUnchecked(d, Element.DataType.SIGNED_8, d.length);
+    }
+
+    /**
+     * Copy into this Allocation from an array. This method does not guarantee
+     * that the Allocation is compatible with the input buffer; it copies memory
+     * without reinterpretation.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d the source array
+     */
+    public void copyFromUnchecked(float[] d) {
+        copyFromUnchecked(d, Element.DataType.FLOAT_32, d.length);
+    }
+
+
+    /**
+     * Copy into this Allocation from an array.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} does not match the array's
+     * primitive type.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param array The source array
+     */
+    public void copyFrom(Object array) {
+        copyFromUnchecked(array, validateObjectIsPrimitiveArray(array, true),
+                          java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy into this Allocation from an array.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not a 32 bit integer nor a vector of 32 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d the source array
+     */
+    public void copyFrom(int[] d) {
+        validateIsInt32();
+        copyFromUnchecked(d, Element.DataType.SIGNED_32, d.length);
+    }
+
+    /**
+     * Copy into this Allocation from an array.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not a 16 bit integer nor a vector of 16 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d the source array
+     */
+    public void copyFrom(short[] d) {
+        validateIsInt16();
+        copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
+    }
+
+    /**
+     * Copy into this Allocation from an array.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not an 8 bit integer nor a vector of 8 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d the source array
+     */
+    public void copyFrom(byte[] d) {
+        validateIsInt8();
+        copyFromUnchecked(d, Element.DataType.SIGNED_8, d.length);
+    }
+
+    /**
+     * Copy into this Allocation from an array.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is neither a 32 bit float nor a vector of
+     * 32 bit floats {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d the source array
+     */
+    public void copyFrom(float[] d) {
+        validateIsFloat32();
+        copyFromUnchecked(d, Element.DataType.FLOAT_32, d.length);
+    }
+
+    /**
+     * Copy into an Allocation from a {@link android.graphics.Bitmap}.  The
+     * height, width, and format of the bitmap must match the existing
+     * allocation.
+     *
+     * <p>If the {@link android.graphics.Bitmap} is the same as the {@link
+     * android.graphics.Bitmap} used to create the Allocation with {@link
+     * #createFromBitmap} and {@link #USAGE_SHARED} is set on the Allocation,
+     * this will synchronize the Allocation with the latest data from the {@link
+     * android.graphics.Bitmap}, potentially avoiding the actual copy.</p>
+     *
+     * @param b the source bitmap
+     */
+    public void copyFrom(Bitmap b) {
+        mRS.validate();
+        if (b.getConfig() == null) {
+            Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
+            Canvas c = new Canvas(newBitmap);
+            c.drawBitmap(b, 0, 0, null);
+            copyFrom(newBitmap);
+            return;
+        }
+        validateBitmapSize(b);
+        validateBitmapFormat(b);
+        mRS.nAllocationCopyFromBitmap(getID(mRS), b);
+    }
+
+    /**
+     * Copy an Allocation from an Allocation.  The types of both allocations
+     * must be identical.
+     *
+     * @param a the source allocation
+     */
+    public void copyFrom(Allocation a) {
+        mRS.validate();
+        if (!mType.equals(a.getType())) {
+            throw new RSIllegalArgumentException("Types of allocations must match.");
+        }
+        copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, a, 0, 0);
+    }
+
+
+    /**
+     * This is only intended to be used by auto-generated code reflected from
+     * the RenderScript script files and should not be used by developers.
+     *
+     * @param xoff
+     * @param fp
+     */
+    public void setFromFieldPacker(int xoff, FieldPacker fp) {
+        mRS.validate();
+        int eSize = mType.mElement.getBytesSize();
+        final byte[] data = fp.getData();
+        int data_length = fp.getPos();
+
+        int count = data_length / eSize;
+        if ((eSize * count) != data_length) {
+            throw new RSIllegalArgumentException("Field packer length " + data_length +
+                                               " not divisible by element size " + eSize + ".");
+        }
+        copy1DRangeFromUnchecked(xoff, count, data);
+    }
+
+    /**
+     * This is only intended to be used by auto-generated code reflected from
+     * the RenderScript script files.
+     *
+     * @param xoff
+     * @param component_number
+     * @param fp
+     */
+    public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
+        mRS.validate();
+        if (component_number >= mType.mElement.mElements.length) {
+            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
+        }
+        if(xoff < 0) {
+            throw new RSIllegalArgumentException("Offset must be >= 0.");
+        }
+
+        final byte[] data = fp.getData();
+        int data_length = fp.getPos();
+        int eSize = mType.mElement.mElements[component_number].getBytesSize();
+        eSize *= mType.mElement.mArraySizes[component_number];
+
+        if (data_length != eSize) {
+            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
+                                               " does not match component size " + eSize + ".");
+        }
+
+        mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
+                                     component_number, data, data_length);
+    }
+
+    /**
+     * @hide
+     * This is only intended to be used by auto-generated code reflected from
+     * the RenderScript script files.
+     *
+     * @param xoff
+     * @param yoff
+     * @param zoff
+     * @param component_number
+     * @param fp
+     */
+    /*
+    public void setFromFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
+        mRS.validate();
+        if (component_number >= mType.mElement.mElements.length) {
+            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
+        }
+        if(xoff < 0) {
+            throw new RSIllegalArgumentException("Offset x must be >= 0.");
+        }
+        if(yoff < 0) {
+            throw new RSIllegalArgumentException("Offset y must be >= 0.");
+        }
+        if(zoff < 0) {
+            throw new RSIllegalArgumentException("Offset z must be >= 0.");
+        }
+
+        final byte[] data = fp.getData();
+        int data_length = fp.getPos();
+        int eSize = mType.mElement.mElements[component_number].getBytesSize();
+        eSize *= mType.mElement.mArraySizes[component_number];
+
+        if (data_length != eSize) {
+            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
+                                               " does not match component size " + eSize + ".");
+        }
+
+        mRS.nAllocationElementData(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                                   component_number, data, data_length);
+    }
+    */
+
+    private void data1DChecks(int off, int count, int len, int dataSize, boolean usePadding) {
+        mRS.validate();
+        if(off < 0) {
+            throw new RSIllegalArgumentException("Offset must be >= 0.");
+        }
+        if(count < 1) {
+            throw new RSIllegalArgumentException("Count must be >= 1.");
+        }
+        if((off + count) > mCurrentCount) {
+            throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
+                                               ", got " + count + " at offset " + off + ".");
+        }
+        if(usePadding) {
+            if(len < dataSize / 4 * 3) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        } else {
+            if(len < dataSize) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
+    }
+
+    /**
+     * Generate a mipmap chain. This is only valid if the Type of the Allocation
+     * includes mipmaps.
+     *
+     * <p>This function will generate a complete set of mipmaps from the top
+     * level LOD and place them into the script memory space.</p>
+     *
+     * <p>If the Allocation is also using other memory spaces, a call to {@link
+     * #syncAll syncAll(Allocation.USAGE_SCRIPT)} is required.</p>
+     */
+    public void generateMipmaps() {
+        mRS.nAllocationGenerateMipmaps(getID(mRS));
+    }
+
+    private void copy1DRangeFromUnchecked(int off, int count, Object array,
+                                          Element.DataType dt, int arrayLen) {
+        final int dataSize = mType.mElement.getBytesSize() * count;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            usePadding = true;
+        }
+        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
+        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
+                              mType.mElement.mType.mSize, usePadding);
+    }
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param array The source array
+     */
+    public void copy1DRangeFromUnchecked(int off, int count, Object array) {
+        copy1DRangeFromUnchecked(off, count, array,
+                                 validateObjectIsPrimitiveArray(array, false),
+                                 java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
+        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
+    }
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
+        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
+    }
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
+        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
+    }
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
+        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
+    }
+
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} does not match the component type
+     * of the array passed in.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param array The source array.
+     */
+    public void copy1DRangeFrom(int off, int count, Object array) {
+        copy1DRangeFromUnchecked(off, count, array,
+                                 validateObjectIsPrimitiveArray(array, true),
+                                 java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not an 32 bit integer nor a vector of 32 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeFrom(int off, int count, int[] d) {
+        validateIsInt32();
+        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
+    }
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not an 16 bit integer nor a vector of 16 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeFrom(int off, int count, short[] d) {
+        validateIsInt16();
+        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
+    }
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not an 8 bit integer nor a vector of 8 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeFrom(int off, int count, byte[] d) {
+        validateIsInt8();
+        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
+    }
+
+    /**
+     * Copy an array into a 1D region of this Allocation.  This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is neither a 32 bit float nor a vector of
+     * 32 bit floats {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array.
+     */
+    public void copy1DRangeFrom(int off, int count, float[] d) {
+        validateIsFloat32();
+        copy1DRangeFromUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
+    }
+
+     /**
+     * Copy part of an Allocation into this Allocation.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param data the source data allocation.
+     * @param dataOff off The offset of the first element in data to
+     *          be copied.
+     */
+    public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
+        mRS.nAllocationData2D(getIDSafe(), off, 0,
+                              mSelectedLOD, mSelectedFace.mID,
+                              count, 1, data.getID(mRS), dataOff, 0,
+                              data.mSelectedLOD, data.mSelectedFace.mID);
+    }
+
+    private void validate2DRange(int xoff, int yoff, int w, int h) {
+        if (mAdaptedAllocation != null) {
+
+        } else {
+
+            if (xoff < 0 || yoff < 0) {
+                throw new RSIllegalArgumentException("Offset cannot be negative.");
+            }
+            if (h < 0 || w < 0) {
+                throw new RSIllegalArgumentException("Height or width cannot be negative.");
+            }
+            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
+                throw new RSIllegalArgumentException("Updated region larger than allocation.");
+            }
+        }
+    }
+
+    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, Object array,
+                                  Element.DataType dt, int arrayLen) {
+        mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
+        final int dataSize = mType.mElement.getBytesSize() * w * h;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
+        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
+                              array, sizeBytes, dt,
+                              mType.mElement.mType.mSize, usePadding);
+    }
+
+    /**
+     * Copy from an array into a rectangular region in this Allocation.  The
+     * array is assumed to be tightly packed. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} does not match the input data type.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to update in this Allocation
+     * @param yoff Y offset of the region to update in this Allocation
+     * @param w Width of the region to update
+     * @param h Height of the region to update
+     * @param array Data to be placed into the Allocation
+     */
+    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, Object array) {
+        copy2DRangeFromUnchecked(xoff, yoff, w, h, array,
+                                 validateObjectIsPrimitiveArray(array, true),
+                                 java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy from an array into a rectangular region in this Allocation.  The
+     * array is assumed to be tightly packed. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not an 8 bit integer nor a vector of 8 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to update in this Allocation
+     * @param yoff Y offset of the region to update in this Allocation
+     * @param w Width of the region to update
+     * @param h Height of the region to update
+     * @param data to be placed into the Allocation
+     */
+    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
+        validateIsInt8();
+        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
+                                 Element.DataType.SIGNED_8, data.length);
+    }
+
+    /**
+     * Copy from an array into a rectangular region in this Allocation.  The
+     * array is assumed to be tightly packed. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not a 16 bit integer nor a vector of 16 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to update in this Allocation
+     * @param yoff Y offset of the region to update in this Allocation
+     * @param w Width of the region to update
+     * @param h Height of the region to update
+     * @param data to be placed into the Allocation
+     */
+    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
+        validateIsInt16();
+        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
+                                 Element.DataType.SIGNED_16, data.length);
+    }
+
+    /**
+     * Copy from an array into a rectangular region in this Allocation.  The
+     * array is assumed to be tightly packed. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not a 32 bit integer nor a vector of 32 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to update in this Allocation
+     * @param yoff Y offset of the region to update in this Allocation
+     * @param w Width of the region to update
+     * @param h Height of the region to update
+     * @param data to be placed into the Allocation
+     */
+    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
+        validateIsInt32();
+        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
+                                 Element.DataType.SIGNED_32, data.length);
+    }
+
+    /**
+     * Copy from an array into a rectangular region in this Allocation.  The
+     * array is assumed to be tightly packed. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is neither a 32 bit float nor a vector of
+     * 32 bit floats {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to update in this Allocation
+     * @param yoff Y offset of the region to update in this Allocation
+     * @param w Width of the region to update
+     * @param h Height of the region to update
+     * @param data to be placed into the Allocation
+     */
+    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
+        validateIsFloat32();
+        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
+                                 Element.DataType.FLOAT_32, data.length);
+    }
+
+    /**
+     * Copy a rectangular region from an Allocation into a rectangular region in
+     * this Allocation.
+     *
+     * @param xoff X offset of the region in this Allocation
+     * @param yoff Y offset of the region in this Allocation
+     * @param w Width of the region to update.
+     * @param h Height of the region to update.
+     * @param data source Allocation.
+     * @param dataXoff X offset in source Allocation
+     * @param dataYoff Y offset in source Allocation
+     */
+    public void copy2DRangeFrom(int xoff, int yoff, int w, int h,
+                                Allocation data, int dataXoff, int dataYoff) {
+        mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
+        mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
+                              mSelectedLOD, mSelectedFace.mID,
+                              w, h, data.getID(mRS), dataXoff, dataYoff,
+                              data.mSelectedLOD, data.mSelectedFace.mID);
+    }
+
+    /**
+     * Copy a {@link android.graphics.Bitmap} into an Allocation.  The height
+     * and width of the update will use the height and width of the {@link
+     * android.graphics.Bitmap}.
+     *
+     * @param xoff X offset of the region to update in this Allocation
+     * @param yoff Y offset of the region to update in this Allocation
+     * @param data the Bitmap to be copied
+     */
+    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
+        mRS.validate();
+        if (data.getConfig() == null) {
+            Bitmap newBitmap = Bitmap.createBitmap(data.getWidth(), data.getHeight(), Bitmap.Config.ARGB_8888);
+            Canvas c = new Canvas(newBitmap);
+            c.drawBitmap(data, 0, 0, null);
+            copy2DRangeFrom(xoff, yoff, newBitmap);
+            return;
+        }
+        validateBitmapFormat(data);
+        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
+        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
+    }
+
+    private void validate3DRange(int xoff, int yoff, int zoff, int w, int h, int d) {
+        if (mAdaptedAllocation != null) {
+
+        } else {
+
+            if (xoff < 0 || yoff < 0 || zoff < 0) {
+                throw new RSIllegalArgumentException("Offset cannot be negative.");
+            }
+            if (h < 0 || w < 0 || d < 0) {
+                throw new RSIllegalArgumentException("Height or width cannot be negative.");
+            }
+            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
+                throw new RSIllegalArgumentException("Updated region larger than allocation.");
+            }
+        }
+    }
+
+    /**
+     * Copy a rectangular region from the array into the allocation.
+     * The array is assumed to be tightly packed.
+     *
+     * The data type of the array is not required to be the same as
+     * the element data type.
+     */
+    private void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
+                                          Object array, Element.DataType dt, int arrayLen) {
+        mRS.validate();
+        validate3DRange(xoff, yoff, zoff, w, h, d);
+        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
+        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
+                              array, sizeBytes, dt,
+                              mType.mElement.mType.mSize, usePadding);
+    }
+
+    /**
+     * Copy from an array into a 3D region in this Allocation.  The
+     * array is assumed to be tightly packed. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} does not match the input data type.
+     *
+     * <p> The size of the region is: w * h * d * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to update in this Allocation
+     * @param yoff Y offset of the region to update in this Allocation
+     * @param zoff Z offset of the region to update in this Allocation
+     * @param w Width of the region to update
+     * @param h Height of the region to update
+     * @param d Depth of the region to update
+     * @param array to be placed into the allocation
+     */
+    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
+        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, array,
+                                 validateObjectIsPrimitiveArray(array, true),
+                                 java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy a rectangular region into the allocation from another
+     * allocation.
+     *
+     * @param xoff X offset of the region to update in this Allocation
+     * @param yoff Y offset of the region to update in this Allocation
+     * @param zoff Z offset of the region to update in this Allocation
+     * @param w Width of the region to update.
+     * @param h Height of the region to update.
+     * @param d Depth of the region to update.
+     * @param data source allocation.
+     * @param dataXoff X offset of the region in the source Allocation
+     * @param dataYoff Y offset of the region in the source Allocation
+     * @param dataZoff Z offset of the region in the source Allocation
+     */
+    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d,
+                                Allocation data, int dataXoff, int dataYoff, int dataZoff) {
+        mRS.validate();
+        validate3DRange(xoff, yoff, zoff, w, h, d);
+        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                              w, h, d, data.getID(mRS), dataXoff, dataYoff, dataZoff,
+                              data.mSelectedLOD);
+    }
+
+
+    /**
+     * Copy from the Allocation into a {@link android.graphics.Bitmap}.  The
+     * bitmap must match the dimensions of the Allocation.
+     *
+     * @param b The bitmap to be set from the Allocation.
+     */
+    public void copyTo(Bitmap b) {
+        mRS.validate();
+        validateBitmapFormat(b);
+        validateBitmapSize(b);
+        mRS.nAllocationCopyToBitmap(getID(mRS), b);
+    }
+
+    private void copyTo(Object array, Element.DataType dt, int arrayLen) {
+        mRS.validate();
+        boolean usePadding = false;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            usePadding = true;
+        }
+        if (usePadding) {
+            if (dt.mSize * arrayLen < mSize / 4 * 3) {
+                throw new RSIllegalArgumentException(
+                    "Size of output array cannot be smaller than size of allocation.");
+            }
+        } else {
+            if (dt.mSize * arrayLen < mSize) {
+                throw new RSIllegalArgumentException(
+                    "Size of output array cannot be smaller than size of allocation.");
+            }
+        }
+        mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding);
+    }
+
+    /**
+     * Copy from the Allocation into an array. The method is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} does not match the input data type.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells will be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param array The array to be set from the Allocation.
+     */
+    public void copyTo(Object array) {
+        copyTo(array, validateObjectIsPrimitiveArray(array, true),
+               java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy from the Allocation into a byte array. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is neither an 8 bit integer nor a vector of 8 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells will be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d The array to be set from the Allocation.
+     */
+    public void copyTo(byte[] d) {
+        validateIsInt8();
+        copyTo(d, Element.DataType.SIGNED_8, d.length);
+    }
+
+    /**
+     * Copy from the Allocation into a short array. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not a 16 bit integer nor a vector of 16 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells will be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d The array to be set from the Allocation.
+     */
+    public void copyTo(short[] d) {
+        validateIsInt16();
+        copyTo(d, Element.DataType.SIGNED_16, d.length);
+    }
+
+    /**
+     * Copy from the Allocation into a int array. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is not a 32 bit integer nor a vector of 32 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells will be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d The array to be set from the Allocation.
+     */
+    public void copyTo(int[] d) {
+        validateIsInt32();
+        copyTo(d, Element.DataType.SIGNED_32, d.length);
+    }
+
+    /**
+     * Copy from the Allocation into a float array. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is neither a 32 bit float nor a vector of
+     * 32 bit floats {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the Allocation {@link
+     * #getBytesSize getBytesSize()}.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells will be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
+     * the cells must not be part of the array.
+     *
+     * @param d The array to be set from the Allocation.
+     */
+    public void copyTo(float[] d) {
+        validateIsFloat32();
+        copyTo(d, Element.DataType.FLOAT_32, d.length);
+    }
+
+    /**
+     * @hide
+     * This is only intended to be used by auto-generated code reflected from
+     * the RenderScript script files and should not be used by developers.
+     *
+     * @param xoff
+     * @param yoff
+     * @param zoff
+     * @param component_number
+     * @param fp
+     */
+    /*
+    public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
+        mRS.validate();
+        if (component_number >= mType.mElement.mElements.length) {
+            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
+        }
+        if(xoff < 0) {
+            throw new RSIllegalArgumentException("Offset x must be >= 0.");
+        }
+        if(yoff < 0) {
+            throw new RSIllegalArgumentException("Offset y must be >= 0.");
+        }
+        if(zoff < 0) {
+            throw new RSIllegalArgumentException("Offset z must be >= 0.");
+        }
+
+        final byte[] data = fp.getData();
+        int data_length = data.length;
+        int eSize = mType.mElement.mElements[component_number].getBytesSize();
+        eSize *= mType.mElement.mArraySizes[component_number];
+
+        if (data_length != eSize) {
+            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
+                                               " does not match component size " + eSize + ".");
+        }
+
+        mRS.nAllocationElementRead(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                                   component_number, data, data_length);
+    }
+    */
+
+    private void copy1DRangeToUnchecked(int off, int count, Object array,
+                                        Element.DataType dt, int arrayLen) {
+        final int dataSize = mType.mElement.getBytesSize() * count;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            usePadding = true;
+        }
+        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
+        mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
+                              mType.mElement.mType.mSize, usePadding);
+    }
+
+    /**
+     * Copy a 1D region of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param array The dest array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, Object array) {
+        copy1DRangeToUnchecked(off, count, array,
+                               validateObjectIsPrimitiveArray(array, false),
+                               java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy a 1D region of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, int[] d) {
+        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
+    }
+
+    /**
+     * Copy a 1D region of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, short[] d) {
+        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
+    }
+
+    /**
+     * Copy a 1D region of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, byte[] d) {
+        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
+    }
+
+    /**
+     * Copy a 1D region of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, float[] d) {
+        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
+    }
+
+
+    /**
+     * Copy a 1D region of this Allocation into an array.  This method is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} does not match the component type
+     * of the array passed in.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param array The source array.
+     */
+    public void copy1DRangeTo(int off, int count, Object array) {
+        copy1DRangeToUnchecked(off, count, array,
+                               validateObjectIsPrimitiveArray(array, true),
+                               java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy a 1D region of this Allocation into an array. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is neither a 32 bit integer nor a vector of 32 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeTo(int off, int count, int[] d) {
+        validateIsInt32();
+        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
+    }
+
+    /**
+     * Copy a 1D region of this Allocation into an array. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is neither a 16 bit integer nor a vector of 16 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeTo(int off, int count, short[] d) {
+        validateIsInt16();
+        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
+    }
+
+    /**
+     * Copy a 1D region of this Allocation into an array. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is neither an 8 bit integer nor a vector of 8 bit
+     * integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array
+     */
+    public void copy1DRangeTo(int off, int count, byte[] d) {
+        validateIsInt8();
+        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
+    }
+
+    /**
+     * Copy a 1D region of this Allocation into an array. This variant is type checked
+     * and will generate exceptions if the Allocation's {@link
+     * androidx.renderscript.Element} is neither a 32 bit float nor a vector of
+     * 32 bit floats {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: count * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source array.
+     */
+    public void copy1DRangeTo(int off, int count, float[] d) {
+        validateIsFloat32();
+        copy1DRangeToUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
+    }
+
+
+    void copy2DRangeToUnchecked(int xoff, int yoff, int w, int h, Object array,
+                                Element.DataType dt, int arrayLen) {
+        mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
+        final int dataSize = mType.mElement.getBytesSize() * w * h;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
+        mRS.nAllocationRead2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
+                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
+    }
+
+    /**
+     * Copy from a rectangular region in this Allocation into an array. This
+     * method is type checked and will generate exceptions if the Allocation's
+     * {@link androidx.renderscript.Element} does not match the component type
+     * of the array passed in.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param array Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, Object array) {
+        copy2DRangeToUnchecked(xoff, yoff, w, h, array,
+                               validateObjectIsPrimitiveArray(array, true),
+                               java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * Copy from a rectangular region in this Allocation into an array. This
+     * variant is type checked and will generate exceptions if the Allocation's
+     * {@link androidx.renderscript.Element} is neither an 8 bit integer nor a vector
+     * of 8 bit integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param data Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, byte[] data) {
+        validateIsInt8();
+        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
+                               Element.DataType.SIGNED_8, data.length);
+    }
+
+    /**
+     * Copy from a rectangular region in this Allocation into an array. This
+     * variant is type checked and will generate exceptions if the Allocation's
+     * {@link androidx.renderscript.Element} is neither a 16 bit integer nor a vector
+     * of 16 bit integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param data Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
+        validateIsInt16();
+        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
+                               Element.DataType.SIGNED_16, data.length);
+    }
+
+    /**
+     * Copy from a rectangular region in this Allocation into an array. This
+     * variant is type checked and will generate exceptions if the Allocation's
+     * {@link androidx.renderscript.Element} is neither a 32 bit integer nor a vector
+     * of 32 bit integers {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param data Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, int[] data) {
+        validateIsInt32();
+        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
+                               Element.DataType.SIGNED_32, data.length);
+    }
+
+    /**
+     * Copy from a rectangular region in this Allocation into an array. This
+     * variant is type checked and will generate exceptions if the Allocation's
+     * {@link androidx.renderscript.Element} is neither a 32 bit float nor a vector
+     * of 32 bit floats {@link androidx.renderscript.Element.DataType}.
+     *
+     * <p> The size of the region is: w * h * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param data Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, float[] data) {
+        validateIsFloat32();
+        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
+                               Element.DataType.FLOAT_32, data.length);
+    }
+
+
+    /**
+     * Copy from a 3D region in this Allocation into an array. This method does
+     * not guarantee that the Allocation is compatible with the input buffer.
+     * The array is assumed to be tightly packed.
+     *
+     * The data type of the array is not required to be the same as
+     * the element data type.
+     */
+    /*
+    private void copy3DRangeToUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
+                                        Object array, Element.DataType dt, int arrayLen) {
+        mRS.validate();
+        validate3DRange(xoff, yoff, zoff, w, h, d);
+        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
+        mRS.nAllocationRead3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
+                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
+    }
+    */
+
+    /**
+     * @hide
+     * Copy from a 3D region in this Allocation into an array. This
+     * method is type checked and will generate exceptions if the Allocation's
+     * {@link androidx.renderscript.Element} does not match the component type
+     * of the array passed in.
+     *
+     * <p> The size of the region is: w * h * d * {@link #getElement}.{@link
+     * Element#getBytesSize}.
+     *
+     * <p> If the Allocation does not have Vec3 Elements, then the size of the
+     * array in bytes must be at least the size of the region.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is disabled, then the size of the array in bytes must be at least the size
+     * of the region. The padding bytes for the cells must be part of the array.
+     *
+     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
+     * is enabled, then the size of the array in bytes must be at least 3/4 the size
+     * of the region. The padding bytes for the cells must not be part of the array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param zoff Z offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param d Depth of the region to copy
+     * @param array Dest Array to be copied into
+     */
+    /*
+    public void copy3DRangeTo(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
+        copy3DRangeToUnchecked(xoff, yoff, zoff, w, h, d, array,
+                                 validateObjectIsPrimitiveArray(array, true),
+                                 java.lang.reflect.Array.getLength(array));
+    }
+    */
+
+    // creation
+
+    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
+    static {
+        mBitmapOptions.inScaled = false;
+    }
+
+    /**
+     * Creates a new Allocation with the given {@link
+     * androidx.renderscript.Type}, mipmap flag, and usage flags.
+     *
+     * @param type RenderScript type describing data layout
+     * @param mips specifies desired mipmap behaviour for the
+     *             allocation
+     * @param usage bit field specifying how the Allocation is
+     *              utilized
+     */
+    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
+        rs.validate();
+        if (type.getID(rs) == 0) {
+            throw new RSInvalidStateException("Bad Type");
+        }
+
+        if(!rs.usingIO() && (usage & (USAGE_IO_INPUT | USAGE_IO_INPUT)) != 0) {
+            throw new RSRuntimeException("USAGE_IO not supported, Allocation creation failed.");
+        }
+
+        long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
+        if (id == 0) {
+            throw new RSRuntimeException("Allocation creation failed.");
+        }
+        return new Allocation(id, rs, type, usage);
+    }
+
+    /**
+     * Creates an Allocation with the size specified by the type and no mipmaps
+     * generated by default
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param type renderscript type describing data layout
+     * @param usage bit field specifying how the allocation is
+     *              utilized
+     *
+     * @return allocation
+     */
+    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
+        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
+    }
+
+    /**
+     * Creates an Allocation for use by scripts with a given {@link
+     * androidx.renderscript.Type} and no mipmaps
+     *
+     * @param rs Context to which the Allocation will belong.
+     * @param type RenderScript Type describing data layout
+     *
+     * @return allocation
+     */
+    static public Allocation createTyped(RenderScript rs, Type type) {
+        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
+    }
+
+    /**
+     * Creates an Allocation with a specified number of given elements
+     *
+     * @param rs Context to which the Allocation will belong.
+     * @param e Element to use in the Allocation
+     * @param count the number of Elements in the Allocation
+     * @param usage bit field specifying how the Allocation is
+     *              utilized
+     *
+     * @return allocation
+     */
+    static public Allocation createSized(RenderScript rs, Element e,
+                                         int count, int usage) {
+        rs.validate();
+        Type.Builder b = new Type.Builder(rs, e);
+        b.setX(count);
+        Type t = b.create();
+
+        long id = rs.nAllocationCreateTyped(t.getID(rs), MipmapControl.MIPMAP_NONE.mID, usage, 0);
+        if (id == 0) {
+            throw new RSRuntimeException("Allocation creation failed.");
+        }
+        return new Allocation(id, rs, t, usage);
+    }
+
+    /**
+     * Creates an Allocation with a specified number of given elements
+     *
+     * @param rs Context to which the Allocation will belong.
+     * @param e Element to use in the Allocation
+     * @param count the number of Elements in the Allocation
+     *
+     * @return allocation
+     */
+    static public Allocation createSized(RenderScript rs, Element e, int count) {
+        return createSized(rs, e, count, USAGE_SCRIPT);
+    }
+
+    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
+        final Bitmap.Config bc = b.getConfig();
+        if (bc == Bitmap.Config.ALPHA_8) {
+            return Element.A_8(rs);
+        }
+        if (bc == Bitmap.Config.ARGB_4444) {
+            return Element.RGBA_4444(rs);
+        }
+        if (bc == Bitmap.Config.ARGB_8888) {
+            return Element.RGBA_8888(rs);
+        }
+        if (bc == Bitmap.Config.RGB_565) {
+            return Element.RGB_565(rs);
+        }
+        throw new RSInvalidStateException("Bad bitmap type: " + bc);
+    }
+
+    static Type typeFromBitmap(RenderScript rs, Bitmap b,
+                                       MipmapControl mip) {
+        Element e = elementFromBitmap(rs, b);
+        Type.Builder tb = new Type.Builder(rs, e);
+        tb.setX(b.getWidth());
+        tb.setY(b.getHeight());
+        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
+        return tb.create();
+    }
+
+    /**
+     * Creates an Allocation from a {@link android.graphics.Bitmap}.
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param b Bitmap source for the allocation data
+     * @param mips specifies desired mipmap behaviour for the
+     *             allocation
+     * @param usage bit field specifying how the allocation is
+     *              utilized
+     *
+     * @return Allocation containing bitmap data
+     *
+     */
+    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
+                                              MipmapControl mips,
+                                              int usage) {
+        rs.validate();
+
+        // WAR undocumented color formats
+        if (b.getConfig() == null) {
+            if ((usage & USAGE_SHARED) != 0) {
+                throw new RSIllegalArgumentException("USAGE_SHARED cannot be used with a Bitmap that has a null config.");
+            }
+            Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
+            Canvas c = new Canvas(newBitmap);
+            c.drawBitmap(b, 0, 0, null);
+            return createFromBitmap(rs, newBitmap, mips, usage);
+        }
+
+        Type t = typeFromBitmap(rs, b, mips);
+
+        // enable optimized bitmap path only with no mipmap and script-only usage
+        if (mips == MipmapControl.MIPMAP_NONE &&
+            t.getElement().isCompatible(Element.RGBA_8888(rs)) &&
+            usage == (USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE)) {
+            long id = rs.nAllocationCreateBitmapBackedAllocation(t.getID(rs), mips.mID, b, usage);
+            if (id == 0) {
+                throw new RSRuntimeException("Load failed.");
+            }
+
+            // keep a reference to the Bitmap around to prevent GC
+            Allocation alloc = new Allocation(id, rs, t, usage);
+            alloc.setBitmap(b);
+            return alloc;
+        }
+
+
+        long id = rs.nAllocationCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
+        if (id == 0) {
+            throw new RSRuntimeException("Load failed.");
+        }
+        return new Allocation(id, rs, t, usage);
+    }
+
+    /**
+     * Associate a {@link android.view.Surface} with this Allocation. This
+     * operation is only valid for Allocations with {@link #USAGE_IO_OUTPUT}.
+     *
+     * @param sur Surface to associate with allocation
+     */
+    public void setSurface(Surface sur) {
+        mRS.validate();
+        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
+            throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
+        }
+
+        mRS.nAllocationSetSurface(getID(mRS), sur);
+    }
+
+    /**
+     * Creates an Allocation from a {@link android.graphics.Bitmap}.
+     *
+     * <p>This Allocation will be created with {@link #USAGE_SHARED}, and
+     * {@link #USAGE_SCRIPT}.</p>
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param b bitmap source for the allocation data
+     *
+     * @return Allocation containing bitmap data
+     *
+     */
+    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
+        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
+                                USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
+    }
+
+    /**
+     * Creates a cubemap Allocation from a {@link android.graphics.Bitmap}
+     * containing the horizontal list of cube faces. Each face must be a square,
+     * have the same size as all other faces, and have a width that is a power
+     * of 2.
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param b Bitmap with cubemap faces layed out in the following
+     *          format: right, left, top, bottom, front, back
+     * @param mips specifies desired mipmap behaviour for the cubemap
+     * @param usage bit field specifying how the cubemap is utilized
+     *
+     * @return allocation containing cubemap data
+     *
+     */
+    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
+                                                     MipmapControl mips,
+                                                     int usage) {
+        rs.validate();
+
+        int height = b.getHeight();
+        int width = b.getWidth();
+
+        if (width % 6 != 0) {
+            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
+        }
+        if (width / 6 != height) {
+            throw new RSIllegalArgumentException("Only square cube map faces supported");
+        }
+        boolean isPow2 = (height & (height - 1)) == 0;
+        if (!isPow2) {
+            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
+        }
+
+        Element e = elementFromBitmap(rs, b);
+        Type.Builder tb = new Type.Builder(rs, e);
+        tb.setX(height);
+        tb.setY(height);
+        tb.setFaces(true);
+        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
+        Type t = tb.create();
+
+        long id = rs.nAllocationCubeCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
+        if(id == 0) {
+            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
+        }
+        return new Allocation(id, rs, t, usage);
+    }
+
+    /**
+     * Creates a non-mipmapped cubemap Allocation for use as a graphics texture
+     * from a {@link android.graphics.Bitmap} containing the horizontal list of
+     * cube faces. Each face must be a square, have the same size as all other
+     * faces, and have a width that is a power of 2.
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param b bitmap with cubemap faces layed out in the following
+     *          format: right, left, top, bottom, front, back
+     *
+     * @return allocation containing cubemap data
+     *
+     */
+    static public Allocation createCubemapFromBitmap(RenderScript rs,
+                                                     Bitmap b) {
+        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
+                                       USAGE_GRAPHICS_TEXTURE);
+    }
+
+    /**
+     * Creates a cubemap Allocation from 6 {@link android.graphics.Bitmap}
+     * objects containing the cube faces. Each face must be a square, have the
+     * same size as all other faces, and have a width that is a power of 2.
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param xpos cubemap face in the positive x direction
+     * @param xneg cubemap face in the negative x direction
+     * @param ypos cubemap face in the positive y direction
+     * @param yneg cubemap face in the negative y direction
+     * @param zpos cubemap face in the positive z direction
+     * @param zneg cubemap face in the negative z direction
+     * @param mips specifies desired mipmap behaviour for the cubemap
+     * @param usage bit field specifying how the cubemap is utilized
+     *
+     * @return allocation containing cubemap data
+     *
+     */
+    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
+                                                        Bitmap xpos,
+                                                        Bitmap xneg,
+                                                        Bitmap ypos,
+                                                        Bitmap yneg,
+                                                        Bitmap zpos,
+                                                        Bitmap zneg,
+                                                        MipmapControl mips,
+                                                        int usage) {
+        /*
+        int height = xpos.getHeight();
+        if (xpos.getWidth() != height ||
+            xneg.getWidth() != height || xneg.getHeight() != height ||
+            ypos.getWidth() != height || ypos.getHeight() != height ||
+            yneg.getWidth() != height || yneg.getHeight() != height ||
+            zpos.getWidth() != height || zpos.getHeight() != height ||
+            zneg.getWidth() != height || zneg.getHeight() != height) {
+            throw new RSIllegalArgumentException("Only square cube map faces supported");
+        }
+        boolean isPow2 = (height & (height - 1)) == 0;
+        if (!isPow2) {
+            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
+        }
+
+        Element e = elementFromBitmap(rs, xpos);
+        Type.Builder tb = new Type.Builder(rs, e);
+        tb.setX(height);
+        tb.setY(height);
+        tb.setFaces(true);
+        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
+        Type t = tb.create();
+        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
+
+        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
+        adapter.setFace(Type.CubemapFace.POSITIVE_X);
+        adapter.copyFrom(xpos);
+        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
+        adapter.copyFrom(xneg);
+        adapter.setFace(Type.CubemapFace.POSITIVE_Y);
+        adapter.copyFrom(ypos);
+        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
+        adapter.copyFrom(yneg);
+        adapter.setFace(Type.CubemapFace.POSITIVE_Z);
+        adapter.copyFrom(zpos);
+        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
+        adapter.copyFrom(zneg);
+
+        return cubemap;
+        */
+        return null;
+    }
+
+    /**
+     * Creates a non-mipmapped cubemap Allocation for use as a sampler input
+     * from 6 {@link android.graphics.Bitmap} objects containing the cube
+     * faces. Each face must be a square, have the same size as all other faces,
+     * and have a width that is a power of 2.
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param xpos cubemap face in the positive x direction
+     * @param xneg cubemap face in the negative x direction
+     * @param ypos cubemap face in the positive y direction
+     * @param yneg cubemap face in the negative y direction
+     * @param zpos cubemap face in the positive z direction
+     * @param zneg cubemap face in the negative z direction
+     *
+     * @return allocation containing cubemap data
+     *
+     */
+    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
+                                                        Bitmap xpos,
+                                                        Bitmap xneg,
+                                                        Bitmap ypos,
+                                                        Bitmap yneg,
+                                                        Bitmap zpos,
+                                                        Bitmap zneg) {
+        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
+                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
+                                          USAGE_GRAPHICS_TEXTURE);
+    }
+
+    /**
+     * Creates an Allocation from the Bitmap referenced
+     * by resource ID.
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param res application resources
+     * @param id resource id to load the data from
+     * @param mips specifies desired mipmap behaviour for the
+     *             allocation
+     * @param usage bit field specifying how the allocation is
+     *              utilized
+     *
+     * @return Allocation containing resource data
+     *
+     */
+    static public Allocation createFromBitmapResource(RenderScript rs,
+                                                      Resources res,
+                                                      int id,
+                                                      MipmapControl mips,
+                                                      int usage) {
+
+        rs.validate();
+        if ((usage & (USAGE_SHARED | USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
+            throw new RSIllegalArgumentException("Unsupported usage specified.");
+        }
+        Bitmap b = BitmapFactory.decodeResource(res, id);
+        Allocation alloc = createFromBitmap(rs, b, mips, usage);
+        b.recycle();
+        return alloc;
+    }
+
+    /**
+     * Creates a non-mipmapped Allocation to use as a graphics texture from the
+     * {@link android.graphics.Bitmap} referenced by resource ID.
+     *
+     * <p>This allocation will be created with {@link #USAGE_SCRIPT} and
+     * {@link #USAGE_GRAPHICS_TEXTURE}.</p>
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param res application resources
+     * @param id resource id to load the data from
+     *
+     * @return Allocation containing resource data
+     *
+     */
+    static public Allocation createFromBitmapResource(RenderScript rs,
+                                                      Resources res,
+                                                      int id) {
+        return createFromBitmapResource(rs, res, id,
+                                        MipmapControl.MIPMAP_NONE,
+                                        USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
+    }
+
+    /**
+     * Creates an Allocation containing string data encoded in UTF-8 format.
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param str string to create the allocation from
+     * @param usage bit field specifying how the allocaiton is
+     *              utilized
+     *
+     */
+    static public Allocation createFromString(RenderScript rs,
+                                              String str,
+                                              int usage) {
+        rs.validate();
+        byte[] allocArray = null;
+        try {
+            allocArray = str.getBytes("UTF-8");
+            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
+            alloc.copyFrom(allocArray);
+            return alloc;
+        }
+        catch (Exception e) {
+            throw new RSRuntimeException("Could not convert string to utf-8.");
+        }
+    }
+
+    /**
+     * Frees any native resources associated with this object.  The
+     * primary use is to force immediate cleanup of resources when it is
+     * believed the GC will not respond quickly enough.
+     * For USAGE_IO_OUTPUT, destroy() implies setSurface(null).
+     */
+    @Override
+    public void destroy() {
+        if (mIncCompatAllocation != 0) {
+            boolean shouldDestroy = false;
+            synchronized(this) {
+                if (!mIncAllocDestroyed) {
+                    shouldDestroy = true;
+                    mIncAllocDestroyed = true;
+                }
+            }
+
+            if (shouldDestroy) {
+                // must include nObjDestroy in the critical section
+                ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
+                rlock.lock();
+                if(mRS.isAlive()) {
+                    mRS.nIncObjDestroy(mIncCompatAllocation);
+                }
+                rlock.unlock();
+                mIncCompatAllocation = 0;
+            }
+        }
+        if ((mUsage & (USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
+            setSurface(null);
+        }
+        super.destroy();
+    }
+
+}
diff --git a/androidx/renderscript/BaseObj.java b/androidx/renderscript/BaseObj.java
new file mode 100644
index 0000000..eda0066
--- /dev/null
+++ b/androidx/renderscript/BaseObj.java
@@ -0,0 +1,155 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.util.Log;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * BaseObj is the base class for all RenderScript objects owned by a RS context.
+ * It is responsible for lifetime management and resource tracking. This class
+ * should not be used by a user application.
+ *
+ **/
+public class BaseObj {
+    BaseObj(long id, RenderScript rs) {
+        rs.validate();
+        mRS = rs;
+        mID = id;
+        mDestroyed = false;
+    }
+
+    void setID(long id) {
+        if (mID != 0) {
+            throw new RSRuntimeException("Internal Error, reset of object ID.");
+        }
+        mID = id;
+    }
+
+    /**
+     * Lookup the native object ID for this object.  Primarily used by the
+     * generated reflected code.
+     *
+     * @param rs Context to verify against internal context for
+     *           match.
+     *
+     * @return long
+     */
+    long getID(RenderScript rs) {
+        mRS.validate();
+        if (mDestroyed) {
+            throw new RSInvalidStateException("using a destroyed object.");
+        }
+        if (mID == 0) {
+            throw new RSRuntimeException("Internal error: Object id 0.");
+        }
+        if ((rs != null) && (rs != mRS)) {
+            throw new RSInvalidStateException("using object with mismatched context.");
+        }
+        return mID;
+    }
+
+    android.renderscript.BaseObj getNObj() {
+        return null;
+    }
+
+    void checkValid() {
+        if ((mID == 0) && (getNObj() == null)) {
+            throw new RSIllegalArgumentException("Invalid object.");
+        }
+    }
+
+    private long mID;
+    private boolean mDestroyed;
+    RenderScript mRS;
+
+    private void helpDestroy() {
+        boolean shouldDestroy = false;
+        synchronized(this) {
+            if (!mDestroyed) {
+                shouldDestroy = true;
+                mDestroyed = true;
+            }
+        }
+
+        if (shouldDestroy) {
+            // must include nObjDestroy in the critical section
+            ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
+            rlock.lock();
+            if(mRS.isAlive()) {
+                mRS.nObjDestroy(mID);
+            }
+            rlock.unlock();
+            mRS = null;
+            mID = 0;
+        }
+    }
+
+
+    protected void finalize() throws Throwable {
+        helpDestroy();
+        super.finalize();
+    }
+
+    /**
+     * Frees any native resources associated with this object.  The
+     * primary use is to force immediate cleanup of resources when it is
+     * believed the GC will not respond quickly enough.
+     */
+    public void destroy() {
+        if(mDestroyed) {
+            throw new RSInvalidStateException("Object already destroyed.");
+        }
+        helpDestroy();
+    }
+
+    /**
+     * Calculates the hash code value for a BaseObj.
+     *
+     * @return int
+     */
+    @Override
+    public int hashCode() {
+        return (int)((mID & 0xfffffff) ^ (mID >> 32));
+    }
+
+    /**
+     * Compare the current BaseObj with another BaseObj for equality.
+     *
+     * @param obj The object to check equality with.
+     *
+     * @return boolean
+     */
+    @Override
+    public boolean equals(Object obj) {
+        // Early-out check to see if both BaseObjs are actually the same
+        if (this == obj)
+            return true;
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        BaseObj b = (BaseObj) obj;
+        return mID == b.mID;
+    }
+}
+
diff --git a/androidx/renderscript/Byte2.java b/androidx/renderscript/Byte2.java
new file mode 100644
index 0000000..cf738f4
--- /dev/null
+++ b/androidx/renderscript/Byte2.java
@@ -0,0 +1,42 @@
+/*
+ * 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript byte2 type back to the Android system.
+ *
+ **/
+public class Byte2 {
+    public Byte2() {
+    }
+
+    public Byte2(byte initX, byte initY) {
+        x = initX;
+        y = initY;
+    }
+
+    public byte x;
+    public byte y;
+}
+
+
+
+
diff --git a/androidx/renderscript/Byte3.java b/androidx/renderscript/Byte3.java
new file mode 100644
index 0000000..559e34a
--- /dev/null
+++ b/androidx/renderscript/Byte3.java
@@ -0,0 +1,44 @@
+/*
+ * 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript byte3 type back to the Android system.
+ *
+ **/
+public class Byte3 {
+    public Byte3() {
+    }
+
+    public Byte3(byte initX, byte initY, byte initZ) {
+        x = initX;
+        y = initY;
+        z = initZ;
+    }
+
+    public byte x;
+    public byte y;
+    public byte z;
+}
+
+
+
+
diff --git a/androidx/renderscript/Byte4.java b/androidx/renderscript/Byte4.java
new file mode 100644
index 0000000..0a71e63
--- /dev/null
+++ b/androidx/renderscript/Byte4.java
@@ -0,0 +1,45 @@
+/*
+ * 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript byte4 type back to the Android system.
+ *
+ **/
+public class Byte4 {
+    public Byte4() {
+    }
+
+    public Byte4(byte initX, byte initY, byte initZ, byte initW) {
+        x = initX;
+        y = initY;
+        z = initZ;
+        w = initW;
+    }
+
+    public byte x;
+    public byte y;
+    public byte z;
+    public byte w;
+}
+
+
+
diff --git a/androidx/renderscript/Double2.java b/androidx/renderscript/Double2.java
new file mode 100644
index 0000000..9abcd01
--- /dev/null
+++ b/androidx/renderscript/Double2.java
@@ -0,0 +1,43 @@
+/*
+ * 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript double2 type back
+ * to the Android system.
+ *
+ **/
+public class Double2 {
+    public Double2() {
+    }
+
+    public Double2(double initX, double initY) {
+        x = initX;
+        y = initY;
+    }
+
+    public double x;
+    public double y;
+}
+
+
+
+
diff --git a/androidx/renderscript/Double3.java b/androidx/renderscript/Double3.java
new file mode 100644
index 0000000..0d07a50
--- /dev/null
+++ b/androidx/renderscript/Double3.java
@@ -0,0 +1,45 @@
+/*
+ * 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript double3 type back
+ * to the Android system.
+ *
+ **/
+public class Double3 {
+    public Double3() {
+    }
+
+    public Double3(double initX, double initY, double initZ) {
+        x = initX;
+        y = initY;
+        z = initZ;
+    }
+
+    public double x;
+    public double y;
+    public double z;
+}
+
+
+
+
diff --git a/androidx/renderscript/Double4.java b/androidx/renderscript/Double4.java
new file mode 100644
index 0000000..3350abf
--- /dev/null
+++ b/androidx/renderscript/Double4.java
@@ -0,0 +1,46 @@
+/*
+ * 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript double4 type back
+ * to the Android system.
+ *
+ **/
+public class Double4 {
+    public Double4() {
+    }
+
+    public Double4(double initX, double initY, double initZ, double initW) {
+        x = initX;
+        y = initY;
+        z = initZ;
+        w = initW;
+    }
+
+    public double x;
+    public double y;
+    public double z;
+    public double w;
+}
+
+
+
diff --git a/androidx/renderscript/Element.java b/androidx/renderscript/Element.java
new file mode 100644
index 0000000..44dbc61
--- /dev/null
+++ b/androidx/renderscript/Element.java
@@ -0,0 +1,1020 @@
+/*
+ * 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 androidx.renderscript;
+
+import java.lang.reflect.Field;
+
+import android.util.Log;
+
+/**
+ * <p>An Element represents one item within an {@link
+ * androidx.renderscript.Allocation}.  An Element is roughly
+ * equivalent to a C type in a RenderScript kernel. Elements may be basic or
+ * complex. Some basic elements are</p> <ul> <li>A single float value
+ * (equivalent to a float in a kernel)</li> <li>A four-element float vector
+ * (equivalent to a float4 in a kernel)</li> <li>An unsigned 32-bit integer
+ * (equivalent to an unsigned int in a kernel)</li> <li>A single signed 8-bit
+ * integer (equivalent to a char in a kernel)</li> </ul> <p>A complex element is
+ * roughly equivalent to a C struct and contains a number of basic or complex
+ * Elements. From Java code, a complex element contains a list of sub-elements
+ * and names that represents a particular data structure. Structs used in RS
+ * scripts are available to Java code by using the
+ * {@code ScriptField_structname} class that is reflected from a particular
+ * script.</p>
+ *
+ * <p>Basic Elements are comprised of a {@link
+ * androidx.renderscript.Element.DataType} and a {@link
+ * androidx.renderscript.Element.DataKind}. The DataType encodes C
+ * type information of an Element, while the DataKind encodes how that Element
+ * should be interpreted by a {@link androidx.renderscript.Sampler}.
+ * Note that {@link androidx.renderscript.Allocation} objects with
+ * DataKind {@link androidx.renderscript.Element.DataKind#USER} cannot
+ * be used as input for a {@link androidx.renderscript.Sampler}. In
+ * general, {@link androidx.renderscript.Allocation} objects that are
+ * intended for use with a {@link androidx.renderscript.Sampler}
+ * should use bitmap-derived Elements such as
+ * {@link androidx.renderscript.Element#RGBA_8888} or {@link
+ * androidx.renderscript#Element.A_8}.</p>
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about creating an application that uses RenderScript,
+ * read the
+ * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
+ * developer guide.</p>
+ * </div>
+ **/
+public class Element extends BaseObj {
+    int mSize;
+    Element[] mElements;
+    String[] mElementNames;
+    int[] mArraySizes;
+    int[] mOffsetInBytes;
+    int[] mVisibleElementMap;
+
+    DataType mType;
+    DataKind mKind;
+    boolean mNormalized;
+    int mVectorSize;
+
+    private void updateVisibleSubElements() {
+        if (mElements == null) {
+            return;
+        }
+
+        int noPaddingFieldCount = 0;
+        int fieldCount = mElementNames.length;
+        // Find out how many elements are not padding
+        for (int ct = 0; ct < fieldCount; ct ++) {
+            if (mElementNames[ct].charAt(0) != '#') {
+                noPaddingFieldCount ++;
+            }
+        }
+        mVisibleElementMap = new int[noPaddingFieldCount];
+
+        // Make a map that points us at non-padding elements
+        for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
+            if (mElementNames[ct].charAt(0) != '#') {
+                mVisibleElementMap[ctNoPadding ++] = ct;
+            }
+        }
+    }
+
+    /**
+    * @return element size in bytes
+    */
+    public int getBytesSize() {
+        return mSize;
+    }
+
+    /**
+    * Returns the number of vector components. 2 for float2, 4 for
+    * float4, etc.
+    * @return element vector size
+    */
+    public int getVectorSize() {
+        return mVectorSize;
+    }
+
+
+    /**
+     * DataType represents the basic type information for a basic element.  The
+     * naming convention follows.  For numeric types it is FLOAT,
+     * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+     * size of the data.  BOOLEAN is a true / false (1,0)
+     * represented in an 8 bit container.  The UNSIGNED variants
+     * with multiple bit definitions are for packed graphical data
+     * formats and represent vectors with per vector member sizes
+     * which are treated as a single unit for packing and alignment
+     * purposes.
+     *
+     * MATRIX the three matrix types contain FLOAT_32 elements and are treated
+     * as 32 bits for alignment purposes.
+     *
+     * RS_* objects.  32 bit opaque handles.
+     */
+    public enum DataType {
+        NONE (0, 0),
+        //FLOAT_16 (1, 2),
+        FLOAT_32 (2, 4),
+        FLOAT_64 (3, 8),
+        SIGNED_8 (4, 1),
+        SIGNED_16 (5, 2),
+        SIGNED_32 (6, 4),
+        SIGNED_64 (7, 8),
+        UNSIGNED_8 (8, 1),
+        UNSIGNED_16 (9, 2),
+        UNSIGNED_32 (10, 4),
+        UNSIGNED_64 (11, 8),
+
+        BOOLEAN(12, 1),
+
+        UNSIGNED_5_6_5 (13, 2),
+        UNSIGNED_5_5_5_1 (14, 2),
+        UNSIGNED_4_4_4_4 (15, 2),
+
+        MATRIX_4X4 (16, 64),
+        MATRIX_3X3 (17, 36),
+        MATRIX_2X2 (18, 16),
+
+        RS_ELEMENT (1000),
+        RS_TYPE (1001),
+        RS_ALLOCATION (1002),
+        RS_SAMPLER (1003),
+        RS_SCRIPT (1004);
+
+        int mID;
+        int mSize;
+        DataType(int id, int size) {
+            mID = id;
+            mSize = size;
+        }
+
+        DataType(int id) {
+            mID = id;
+            mSize = 4;
+            if (RenderScript.sPointerSize == 8) {
+                mSize = 32;
+            }
+        }
+    }
+
+    /**
+     * The special interpretation of the data if required.  This is primarly
+     * useful for graphical data.  USER indicates no special interpretation is
+     * expected.  PIXEL is used in conjunction with the standard data types for
+     * representing texture formats.
+     */
+    public enum DataKind {
+        USER (0),
+
+        PIXEL_L (7),
+        PIXEL_A (8),
+        PIXEL_LA (9),
+        PIXEL_RGB (10),
+        PIXEL_RGBA (11),
+        PIXEL_DEPTH (12),
+        PIXEL_YUV(13);
+
+        int mID;
+        DataKind(int id) {
+            mID = id;
+        }
+    }
+
+    /**
+     * Return if a element is too complex for use as a data source for a Mesh or
+     * a Program.
+     *
+     * @return boolean
+     */
+    public boolean isComplex() {
+        if (mElements == null) {
+            return false;
+        }
+        for (int ct=0; ct < mElements.length; ct++) {
+            if (mElements[ct].mElements != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+    * Elements could be simple, such as an int or a float, or a
+    * structure with multiple sub elements, such as a collection of
+    * floats, float2, float4. This function returns zero for simple
+    * elements or the number of sub-elements otherwise.
+    * @return number of sub-elements in this element
+    */
+    public int getSubElementCount() {
+        if (mVisibleElementMap == null) {
+            return 0;
+        }
+        return mVisibleElementMap.length;
+    }
+
+    /**
+    * For complex elements, this function will return the
+    * sub-element at index
+    * @param index index of the sub-element to return
+    * @return sub-element in this element at given index
+    */
+    public Element getSubElement(int index) {
+        if (mVisibleElementMap == null) {
+            throw new RSIllegalArgumentException("Element contains no sub-elements");
+        }
+        if (index < 0 || index >= mVisibleElementMap.length) {
+            throw new RSIllegalArgumentException("Illegal sub-element index");
+        }
+        return mElements[mVisibleElementMap[index]];
+    }
+
+    /**
+    * For complex elements, this function will return the
+    * sub-element name at index
+    * @param index index of the sub-element
+    * @return sub-element in this element at given index
+    */
+    public String getSubElementName(int index) {
+        if (mVisibleElementMap == null) {
+            throw new RSIllegalArgumentException("Element contains no sub-elements");
+        }
+        if (index < 0 || index >= mVisibleElementMap.length) {
+            throw new RSIllegalArgumentException("Illegal sub-element index");
+        }
+        return mElementNames[mVisibleElementMap[index]];
+    }
+
+    /**
+    * For complex elements, some sub-elements could be statically
+    * sized arrays. This function will return the array size for
+    * sub-element at index
+    * @param index index of the sub-element
+    * @return array size of sub-element in this element at given index
+    */
+    public int getSubElementArraySize(int index) {
+        if (mVisibleElementMap == null) {
+            throw new RSIllegalArgumentException("Element contains no sub-elements");
+        }
+        if (index < 0 || index >= mVisibleElementMap.length) {
+            throw new RSIllegalArgumentException("Illegal sub-element index");
+        }
+        return mArraySizes[mVisibleElementMap[index]];
+    }
+
+    /**
+    * This function specifies the location of a sub-element within
+    * the element
+    * @param index index of the sub-element
+    * @return offset in bytes of sub-element in this element at given index
+    */
+    public int getSubElementOffsetBytes(int index) {
+        if (mVisibleElementMap == null) {
+            throw new RSIllegalArgumentException("Element contains no sub-elements");
+        }
+        if (index < 0 || index >= mVisibleElementMap.length) {
+            throw new RSIllegalArgumentException("Illegal sub-element index");
+        }
+        return mOffsetInBytes[mVisibleElementMap[index]];
+    }
+
+    /**
+    * @return element data type
+    */
+    public DataType getDataType() {
+        return mType;
+    }
+
+    /**
+    * @return element data kind
+    */
+    public DataKind getDataKind() {
+        return mKind;
+    }
+
+    /**
+     * Utility function for returning an Element containing a single Boolean.
+     *
+     * @param rs Context to which the element will belong.
+     *
+     * @return Element
+     */
+    public static Element BOOLEAN(RenderScript rs) {
+        if(rs.mElement_BOOLEAN == null) {
+            rs.mElement_BOOLEAN = createUser(rs, DataType.BOOLEAN);
+        }
+        return rs.mElement_BOOLEAN;
+    }
+
+    /**
+     * Utility function for returning an Element containing a single UNSIGNED_8.
+     *
+     * @param rs Context to which the element will belong.
+     *
+     * @return Element
+     */
+    public static Element U8(RenderScript rs) {
+        if(rs.mElement_U8 == null) {
+            rs.mElement_U8 = createUser(rs, DataType.UNSIGNED_8);
+        }
+        return rs.mElement_U8;
+    }
+
+    /**
+     * Utility function for returning an Element containing a single SIGNED_8.
+     *
+     * @param rs Context to which the element will belong.
+     *
+     * @return Element
+     */
+    public static Element I8(RenderScript rs) {
+        if(rs.mElement_I8 == null) {
+            rs.mElement_I8 = createUser(rs, DataType.SIGNED_8);
+        }
+        return rs.mElement_I8;
+    }
+
+    public static Element U16(RenderScript rs) {
+        if(rs.mElement_U16 == null) {
+            rs.mElement_U16 = createUser(rs, DataType.UNSIGNED_16);
+        }
+        return rs.mElement_U16;
+    }
+
+    public static Element I16(RenderScript rs) {
+        if(rs.mElement_I16 == null) {
+            rs.mElement_I16 = createUser(rs, DataType.SIGNED_16);
+        }
+        return rs.mElement_I16;
+    }
+
+    public static Element U32(RenderScript rs) {
+        if(rs.mElement_U32 == null) {
+            rs.mElement_U32 = createUser(rs, DataType.UNSIGNED_32);
+        }
+        return rs.mElement_U32;
+    }
+
+    public static Element I32(RenderScript rs) {
+        if(rs.mElement_I32 == null) {
+            rs.mElement_I32 = createUser(rs, DataType.SIGNED_32);
+        }
+        return rs.mElement_I32;
+    }
+
+    public static Element U64(RenderScript rs) {
+        if(rs.mElement_U64 == null) {
+            rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64);
+        }
+        return rs.mElement_U64;
+    }
+
+    public static Element I64(RenderScript rs) {
+        if(rs.mElement_I64 == null) {
+            rs.mElement_I64 = createUser(rs, DataType.SIGNED_64);
+        }
+        return rs.mElement_I64;
+    }
+
+    public static Element F32(RenderScript rs) {
+        if(rs.mElement_F32 == null) {
+            rs.mElement_F32 = createUser(rs, DataType.FLOAT_32);
+        }
+        return rs.mElement_F32;
+    }
+
+    public static Element F64(RenderScript rs) {
+        if(rs.mElement_F64 == null) {
+            rs.mElement_F64 = createUser(rs, DataType.FLOAT_64);
+        }
+        return rs.mElement_F64;
+    }
+
+    public static Element ELEMENT(RenderScript rs) {
+        if(rs.mElement_ELEMENT == null) {
+            rs.mElement_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
+        }
+        return rs.mElement_ELEMENT;
+    }
+
+    public static Element TYPE(RenderScript rs) {
+        if(rs.mElement_TYPE == null) {
+            rs.mElement_TYPE = createUser(rs, DataType.RS_TYPE);
+        }
+        return rs.mElement_TYPE;
+    }
+
+    public static Element ALLOCATION(RenderScript rs) {
+        if(rs.mElement_ALLOCATION == null) {
+            rs.mElement_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
+        }
+        return rs.mElement_ALLOCATION;
+    }
+
+    public static Element SAMPLER(RenderScript rs) {
+        if(rs.mElement_SAMPLER == null) {
+            rs.mElement_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
+        }
+        return rs.mElement_SAMPLER;
+    }
+
+    public static Element SCRIPT(RenderScript rs) {
+        if(rs.mElement_SCRIPT == null) {
+            rs.mElement_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
+        }
+        return rs.mElement_SCRIPT;
+    }
+
+
+    public static Element A_8(RenderScript rs) {
+        if(rs.mElement_A_8 == null) {
+            rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A);
+        }
+        return rs.mElement_A_8;
+    }
+
+    public static Element RGB_565(RenderScript rs) {
+        if(rs.mElement_RGB_565 == null) {
+            rs.mElement_RGB_565 = createPixel(rs, DataType.UNSIGNED_5_6_5, DataKind.PIXEL_RGB);
+        }
+        return rs.mElement_RGB_565;
+    }
+
+    public static Element RGB_888(RenderScript rs) {
+        if(rs.mElement_RGB_888 == null) {
+            rs.mElement_RGB_888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGB);
+        }
+        return rs.mElement_RGB_888;
+    }
+
+    public static Element RGBA_5551(RenderScript rs) {
+        if(rs.mElement_RGBA_5551 == null) {
+            rs.mElement_RGBA_5551 = createPixel(rs, DataType.UNSIGNED_5_5_5_1, DataKind.PIXEL_RGBA);
+        }
+        return rs.mElement_RGBA_5551;
+    }
+
+    public static Element RGBA_4444(RenderScript rs) {
+        if(rs.mElement_RGBA_4444 == null) {
+            rs.mElement_RGBA_4444 = createPixel(rs, DataType.UNSIGNED_4_4_4_4, DataKind.PIXEL_RGBA);
+        }
+        return rs.mElement_RGBA_4444;
+    }
+
+    public static Element RGBA_8888(RenderScript rs) {
+        if(rs.mElement_RGBA_8888 == null) {
+            rs.mElement_RGBA_8888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGBA);
+        }
+        return rs.mElement_RGBA_8888;
+    }
+
+    public static Element F32_2(RenderScript rs) {
+        if(rs.mElement_FLOAT_2 == null) {
+            rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2);
+        }
+        return rs.mElement_FLOAT_2;
+    }
+
+    public static Element F32_3(RenderScript rs) {
+        if(rs.mElement_FLOAT_3 == null) {
+            rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_32, 3);
+        }
+        return rs.mElement_FLOAT_3;
+    }
+
+    public static Element F32_4(RenderScript rs) {
+        if(rs.mElement_FLOAT_4 == null) {
+            rs.mElement_FLOAT_4 = createVector(rs, DataType.FLOAT_32, 4);
+        }
+        return rs.mElement_FLOAT_4;
+    }
+
+    public static Element F64_2(RenderScript rs) {
+        if(rs.mElement_DOUBLE_2 == null) {
+            rs.mElement_DOUBLE_2 = createVector(rs, DataType.FLOAT_64, 2);
+        }
+        return rs.mElement_DOUBLE_2;
+    }
+
+    public static Element F64_3(RenderScript rs) {
+        if(rs.mElement_DOUBLE_3 == null) {
+            rs.mElement_DOUBLE_3 = createVector(rs, DataType.FLOAT_64, 3);
+        }
+        return rs.mElement_DOUBLE_3;
+    }
+
+    public static Element F64_4(RenderScript rs) {
+        if(rs.mElement_DOUBLE_4 == null) {
+            rs.mElement_DOUBLE_4 = createVector(rs, DataType.FLOAT_64, 4);
+        }
+        return rs.mElement_DOUBLE_4;
+    }
+
+    public static Element U8_2(RenderScript rs) {
+        if(rs.mElement_UCHAR_2 == null) {
+            rs.mElement_UCHAR_2 = createVector(rs, DataType.UNSIGNED_8, 2);
+        }
+        return rs.mElement_UCHAR_2;
+    }
+
+    public static Element U8_3(RenderScript rs) {
+        if(rs.mElement_UCHAR_3 == null) {
+            rs.mElement_UCHAR_3 = createVector(rs, DataType.UNSIGNED_8, 3);
+        }
+        return rs.mElement_UCHAR_3;
+    }
+
+    public static Element U8_4(RenderScript rs) {
+        if(rs.mElement_UCHAR_4 == null) {
+            rs.mElement_UCHAR_4 = createVector(rs, DataType.UNSIGNED_8, 4);
+        }
+        return rs.mElement_UCHAR_4;
+    }
+
+    public static Element I8_2(RenderScript rs) {
+        if(rs.mElement_CHAR_2 == null) {
+            rs.mElement_CHAR_2 = createVector(rs, DataType.SIGNED_8, 2);
+        }
+        return rs.mElement_CHAR_2;
+    }
+
+    public static Element I8_3(RenderScript rs) {
+        if(rs.mElement_CHAR_3 == null) {
+            rs.mElement_CHAR_3 = createVector(rs, DataType.SIGNED_8, 3);
+        }
+        return rs.mElement_CHAR_3;
+    }
+
+    public static Element I8_4(RenderScript rs) {
+        if(rs.mElement_CHAR_4 == null) {
+            rs.mElement_CHAR_4 = createVector(rs, DataType.SIGNED_8, 4);
+        }
+        return rs.mElement_CHAR_4;
+    }
+
+    public static Element U16_2(RenderScript rs) {
+        if(rs.mElement_USHORT_2 == null) {
+            rs.mElement_USHORT_2 = createVector(rs, DataType.UNSIGNED_16, 2);
+        }
+        return rs.mElement_USHORT_2;
+    }
+
+    public static Element U16_3(RenderScript rs) {
+        if(rs.mElement_USHORT_3 == null) {
+            rs.mElement_USHORT_3 = createVector(rs, DataType.UNSIGNED_16, 3);
+        }
+        return rs.mElement_USHORT_3;
+    }
+
+    public static Element U16_4(RenderScript rs) {
+        if(rs.mElement_USHORT_4 == null) {
+            rs.mElement_USHORT_4 = createVector(rs, DataType.UNSIGNED_16, 4);
+        }
+        return rs.mElement_USHORT_4;
+    }
+
+    public static Element I16_2(RenderScript rs) {
+        if(rs.mElement_SHORT_2 == null) {
+            rs.mElement_SHORT_2 = createVector(rs, DataType.SIGNED_16, 2);
+        }
+        return rs.mElement_SHORT_2;
+    }
+
+    public static Element I16_3(RenderScript rs) {
+        if(rs.mElement_SHORT_3 == null) {
+            rs.mElement_SHORT_3 = createVector(rs, DataType.SIGNED_16, 3);
+        }
+        return rs.mElement_SHORT_3;
+    }
+
+    public static Element I16_4(RenderScript rs) {
+        if(rs.mElement_SHORT_4 == null) {
+            rs.mElement_SHORT_4 = createVector(rs, DataType.SIGNED_16, 4);
+        }
+        return rs.mElement_SHORT_4;
+    }
+
+    public static Element U32_2(RenderScript rs) {
+        if(rs.mElement_UINT_2 == null) {
+            rs.mElement_UINT_2 = createVector(rs, DataType.UNSIGNED_32, 2);
+        }
+        return rs.mElement_UINT_2;
+    }
+
+    public static Element U32_3(RenderScript rs) {
+        if(rs.mElement_UINT_3 == null) {
+            rs.mElement_UINT_3 = createVector(rs, DataType.UNSIGNED_32, 3);
+        }
+        return rs.mElement_UINT_3;
+    }
+
+    public static Element U32_4(RenderScript rs) {
+        if(rs.mElement_UINT_4 == null) {
+            rs.mElement_UINT_4 = createVector(rs, DataType.UNSIGNED_32, 4);
+        }
+        return rs.mElement_UINT_4;
+    }
+
+    public static Element I32_2(RenderScript rs) {
+        if(rs.mElement_INT_2 == null) {
+            rs.mElement_INT_2 = createVector(rs, DataType.SIGNED_32, 2);
+        }
+        return rs.mElement_INT_2;
+    }
+
+    public static Element I32_3(RenderScript rs) {
+        if(rs.mElement_INT_3 == null) {
+            rs.mElement_INT_3 = createVector(rs, DataType.SIGNED_32, 3);
+        }
+        return rs.mElement_INT_3;
+    }
+
+    public static Element I32_4(RenderScript rs) {
+        if(rs.mElement_INT_4 == null) {
+            rs.mElement_INT_4 = createVector(rs, DataType.SIGNED_32, 4);
+        }
+        return rs.mElement_INT_4;
+    }
+
+    public static Element U64_2(RenderScript rs) {
+        if(rs.mElement_ULONG_2 == null) {
+            rs.mElement_ULONG_2 = createVector(rs, DataType.UNSIGNED_64, 2);
+        }
+        return rs.mElement_ULONG_2;
+    }
+
+    public static Element U64_3(RenderScript rs) {
+        if(rs.mElement_ULONG_3 == null) {
+            rs.mElement_ULONG_3 = createVector(rs, DataType.UNSIGNED_64, 3);
+        }
+        return rs.mElement_ULONG_3;
+    }
+
+    public static Element U64_4(RenderScript rs) {
+        if(rs.mElement_ULONG_4 == null) {
+            rs.mElement_ULONG_4 = createVector(rs, DataType.UNSIGNED_64, 4);
+        }
+        return rs.mElement_ULONG_4;
+    }
+
+    public static Element I64_2(RenderScript rs) {
+        if(rs.mElement_LONG_2 == null) {
+            rs.mElement_LONG_2 = createVector(rs, DataType.SIGNED_64, 2);
+        }
+        return rs.mElement_LONG_2;
+    }
+
+    public static Element I64_3(RenderScript rs) {
+        if(rs.mElement_LONG_3 == null) {
+            rs.mElement_LONG_3 = createVector(rs, DataType.SIGNED_64, 3);
+        }
+        return rs.mElement_LONG_3;
+    }
+
+    public static Element I64_4(RenderScript rs) {
+        if(rs.mElement_LONG_4 == null) {
+            rs.mElement_LONG_4 = createVector(rs, DataType.SIGNED_64, 4);
+        }
+        return rs.mElement_LONG_4;
+    }
+
+    public static Element MATRIX_4X4(RenderScript rs) {
+        if(rs.mElement_MATRIX_4X4 == null) {
+            rs.mElement_MATRIX_4X4 = createUser(rs, DataType.MATRIX_4X4);
+        }
+        return rs.mElement_MATRIX_4X4;
+    }
+
+    public static Element MATRIX_3X3(RenderScript rs) {
+        if(rs.mElement_MATRIX_3X3 == null) {
+            rs.mElement_MATRIX_3X3 = createUser(rs, DataType.MATRIX_3X3);
+        }
+        return rs.mElement_MATRIX_3X3;
+    }
+
+    public static Element MATRIX_2X2(RenderScript rs) {
+        if(rs.mElement_MATRIX_2X2 == null) {
+            rs.mElement_MATRIX_2X2 = createUser(rs, DataType.MATRIX_2X2);
+        }
+        return rs.mElement_MATRIX_2X2;
+    }
+
+    Element(long id, RenderScript rs, Element[] e, String[] n, int[] as) {
+        super(id, rs);
+        mSize = 0;
+        mVectorSize = 1;
+        mElements = e;
+        mElementNames = n;
+        mArraySizes = as;
+        mType = DataType.NONE;
+        mKind = DataKind.USER;
+        mOffsetInBytes = new int[mElements.length];
+        for (int ct = 0; ct < mElements.length; ct++ ) {
+            mOffsetInBytes[ct] = mSize;
+            mSize += mElements[ct].mSize * mArraySizes[ct];
+        }
+        updateVisibleSubElements();
+    }
+
+    Element(long id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
+        super(id, rs);
+        if ((dt != DataType.UNSIGNED_5_6_5) &&
+            (dt != DataType.UNSIGNED_4_4_4_4) &&
+            (dt != DataType.UNSIGNED_5_5_5_1)) {
+            if (size == 3) {
+                mSize = dt.mSize * 4;
+            } else {
+                mSize = dt.mSize * size;
+            }
+        } else {
+            mSize = dt.mSize;
+        }
+        mType = dt;
+        mKind = dk;
+        mNormalized = norm;
+        mVectorSize = size;
+    }
+
+    Element(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /*
+     * Get an identical dummy Element for Compat Context
+     *
+     */
+    public long getDummyElement(RenderScript mRS) {
+        return mRS.nIncElementCreate(mType.mID, mKind.mID, mNormalized, mVectorSize);
+    }
+    /**
+     * Create a custom Element of the specified DataType.  The DataKind will be
+     * set to USER and the vector size to 1 indicating non-vector.
+     *
+     * @param rs The context associated with the new Element.
+     * @param dt The DataType for the new element.
+     * @return Element
+     */
+    static Element createUser(RenderScript rs, DataType dt) {
+        DataKind dk = DataKind.USER;
+        boolean norm = false;
+        int vecSize = 1;
+        long id = rs.nElementCreate(dt.mID, dk.mID, norm, vecSize);
+        return new Element(id, rs, dt, dk, norm, vecSize);
+    }
+
+    /**
+     * Create a custom vector element of the specified DataType and vector size.
+     * DataKind will be set to USER. Only primitive types (FLOAT_32, FLOAT_64,
+     * SIGNED_8, SIGNED_16, SIGNED_32, SIGNED_64, UNSIGNED_8, UNSIGNED_16,
+     * UNSIGNED_32, UNSIGNED_64, BOOLEAN) are supported.
+     *
+     * @param rs The context associated with the new Element.
+     * @param dt The DataType for the new Element.
+     * @param size Vector size for the new Element.  Range 2-4 inclusive
+     *             supported.
+     *
+     * @return Element
+     */
+    public static Element createVector(RenderScript rs, DataType dt, int size) {
+        if (size < 2 || size > 4) {
+            throw new RSIllegalArgumentException("Vector size out of range 2-4.");
+        }
+
+        switch (dt) {
+        // Support only primitive integer/float/boolean types as vectors.
+        case FLOAT_32:
+        case FLOAT_64:
+        case SIGNED_8:
+        case SIGNED_16:
+        case SIGNED_32:
+        case SIGNED_64:
+        case UNSIGNED_8:
+        case UNSIGNED_16:
+        case UNSIGNED_32:
+        case UNSIGNED_64:
+        case BOOLEAN: {
+            DataKind dk = DataKind.USER;
+            boolean norm = false;
+            long id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
+            return new Element(id, rs, dt, dk, norm, size);
+        }
+
+        default: {
+            throw new RSIllegalArgumentException("Cannot create vector of " +
+                "non-primitive type.");
+        }
+        }
+    }
+
+    /**
+     * Create a new pixel Element type.  A matching DataType and DataKind must
+     * be provided.  The DataType and DataKind must contain the same number of
+     * components.  Vector size will be set to 1.
+     *
+     * @param rs The context associated with the new Element.
+     * @param dt The DataType for the new element.
+     * @param dk The DataKind to specify the mapping of each component in the
+     *           DataType.
+     *
+     * @return Element
+     */
+    public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) {
+        if (!(dk == DataKind.PIXEL_L ||
+              dk == DataKind.PIXEL_A ||
+              dk == DataKind.PIXEL_LA ||
+              dk == DataKind.PIXEL_RGB ||
+              dk == DataKind.PIXEL_RGBA ||
+              dk == DataKind.PIXEL_DEPTH ||
+              dk == DataKind.PIXEL_YUV)) {
+            throw new RSIllegalArgumentException("Unsupported DataKind");
+        }
+        if (!(dt == DataType.UNSIGNED_8 ||
+              dt == DataType.UNSIGNED_16 ||
+              dt == DataType.UNSIGNED_5_6_5 ||
+              dt == DataType.UNSIGNED_4_4_4_4 ||
+              dt == DataType.UNSIGNED_5_5_5_1)) {
+            throw new RSIllegalArgumentException("Unsupported DataType");
+        }
+        if (dt == DataType.UNSIGNED_5_6_5 && dk != DataKind.PIXEL_RGB) {
+            throw new RSIllegalArgumentException("Bad kind and type combo");
+        }
+        if (dt == DataType.UNSIGNED_5_5_5_1 && dk != DataKind.PIXEL_RGBA) {
+            throw new RSIllegalArgumentException("Bad kind and type combo");
+        }
+        if (dt == DataType.UNSIGNED_4_4_4_4 && dk != DataKind.PIXEL_RGBA) {
+            throw new RSIllegalArgumentException("Bad kind and type combo");
+        }
+        if (dt == DataType.UNSIGNED_16 &&
+            dk != DataKind.PIXEL_DEPTH) {
+            throw new RSIllegalArgumentException("Bad kind and type combo");
+        }
+
+        int size = 1;
+        switch (dk) {
+        case PIXEL_LA:
+            size = 2;
+            break;
+        case PIXEL_RGB:
+            size = 3;
+            break;
+        case PIXEL_RGBA:
+            size = 4;
+            break;
+        }
+
+        boolean norm = true;
+        long id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
+        return new Element(id, rs, dt, dk, norm, size);
+    }
+
+    /**
+     * Check if the current Element is compatible with another Element.
+     * Primitive Elements are compatible if they share the same underlying
+     * size and type (i.e. U8 is compatible with A_8). User-defined Elements
+     * must be equal in order to be compatible. This requires strict name
+     * equivalence for all sub-Elements (in addition to structural equivalence).
+     *
+     * @param e The Element to check compatibility with.
+     *
+     * @return boolean true if the Elements are compatible, otherwise false.
+     */
+    public boolean isCompatible(Element e) {
+        // Try strict BaseObj equality to start with.
+        if (this.equals(e)) {
+            return true;
+        }
+
+        // Ignore mKind because it is allowed to be different (user vs. pixel).
+        // We also ignore mNormalized because it can be different. The mType
+        // field must not be NONE since we require name equivalence for
+        // all user-created Elements.
+        return ((mSize == e.mSize) &&
+                (mType != DataType.NONE) &&
+                (mType == e.mType) &&
+                (mVectorSize == e.mVectorSize));
+    }
+
+    /**
+     * Builder class for producing complex elements with matching field and name
+     * pairs.  The builder starts empty.  The order in which elements are added
+     * is retained for the layout in memory.
+     *
+     */
+    public static class Builder {
+
+        RenderScript mRS;
+        Element[] mElements;
+        String[] mElementNames;
+        int[] mArraySizes;
+        int mCount;
+        int mSkipPadding;
+
+        /**
+         * Create a builder object.
+         *
+         * @param rs
+         */
+        public Builder(RenderScript rs) {
+            mRS = rs;
+            mCount = 0;
+            mElements = new Element[8];
+            mElementNames = new String[8];
+            mArraySizes = new int[8];
+        }
+
+        /**
+         * Add an array of elements to this element.
+         *
+         * @param element
+         * @param name
+         * @param arraySize
+         */
+        public Builder add(Element element, String name, int arraySize) {
+            if (arraySize < 1) {
+                throw new RSIllegalArgumentException("Array size cannot be less than 1.");
+            }
+
+            // Skip padding fields after a vector 3 type.
+            if (mSkipPadding != 0) {
+                if (name.startsWith("#padding_")) {
+                    mSkipPadding = 0;
+                    return this;
+                }
+            }
+
+            if (element.mVectorSize == 3) {
+                mSkipPadding = 1;
+            } else {
+                mSkipPadding = 0;
+            }
+
+            if(mCount == mElements.length) {
+                Element[] e = new Element[mCount + 8];
+                String[] s = new String[mCount + 8];
+                int[] as = new int[mCount + 8];
+                System.arraycopy(mElements, 0, e, 0, mCount);
+                System.arraycopy(mElementNames, 0, s, 0, mCount);
+                System.arraycopy(mArraySizes, 0, as, 0, mCount);
+                mElements = e;
+                mElementNames = s;
+                mArraySizes = as;
+            }
+            mElements[mCount] = element;
+            mElementNames[mCount] = name;
+            mArraySizes[mCount] = arraySize;
+            mCount++;
+
+            return this;
+        }
+
+        /**
+         * Add a single element to this Element.
+         *
+         * @param element
+         * @param name
+         */
+        public Builder add(Element element, String name) {
+            return add(element, name, 1);
+        }
+
+        /**
+         * Create the element from this builder.
+         *
+         *
+         * @return Element
+         */
+        public Element create() {
+            mRS.validate();
+            Element[] ein = new Element[mCount];
+            String[] sin = new String[mCount];
+            int[] asin = new int[mCount];
+            java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
+            java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
+            java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
+
+            long[] ids = new long[ein.length];
+            for (int ct = 0; ct < ein.length; ct++ ) {
+                ids[ct] = ein[ct].getID(mRS);
+            }
+
+            long id = mRS.nElementCreate2(ids, sin, asin);
+            return new Element(id, mRS, ein, sin, asin);
+        }
+    }
+}
+
diff --git a/androidx/renderscript/FieldPacker.java b/androidx/renderscript/FieldPacker.java
new file mode 100644
index 0000000..34e9ae6
--- /dev/null
+++ b/androidx/renderscript/FieldPacker.java
@@ -0,0 +1,946 @@
+/*
+ * 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 androidx.renderscript;
+
+import androidx.renderscript.RenderScript;
+import java.util.BitSet;
+
+/**
+ * Utility class for packing arguments and structures from Android system objects to
+ * RenderScript objects.
+ *
+ * This class is only intended to be used to support the
+ * reflected code generated by the RS tool chain.  It should not
+ * be called directly.
+ *
+ **/
+public class FieldPacker {
+    public FieldPacker(int len) {
+        mPos = 0;
+        mLen = len;
+        mData = new byte[len];
+        mAlignment = new BitSet();
+    }
+
+    public FieldPacker(byte[] data) {
+        // Advance mPos to the end of the buffer, since we are copying in the
+        // full data input.
+        mPos = data.length;
+        mLen = data.length;
+        mData = data;
+        mAlignment = new BitSet();
+        // TODO: We should either have an actual FieldPacker copy constructor
+        // or drop support for computing alignment like this. As it stands,
+        // subAlign() can never work correctly for copied FieldPacker objects.
+    }
+
+    static FieldPacker createFromArray(Object[] args) {
+        FieldPacker fp = new FieldPacker(RenderScript.sPointerSize * 8);
+        for (Object arg : args) {
+            fp.addSafely(arg);
+        }
+        fp.resize(fp.mPos);
+        return fp;
+    }
+
+    public void align(int v) {
+        if ((v <= 0) || ((v & (v - 1)) != 0)) {
+            throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
+        }
+
+        while ((mPos & (v - 1)) != 0) {
+            mAlignment.flip(mPos);
+            mData[mPos++] = 0;
+        }
+    }
+
+    public void subalign(int v) {
+        if ((v & (v - 1)) != 0) {
+            throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
+        }
+
+        while ((mPos & (v - 1)) != 0) {
+            mPos--;
+        }
+
+        if (mPos > 0) {
+            while (mAlignment.get(mPos - 1) == true) {
+                mPos--;
+                mAlignment.flip(mPos);
+            }
+        }
+
+    }
+
+    public void reset() {
+        mPos = 0;
+    }
+    public void reset(int i) {
+        if ((i < 0) || (i > mLen)) {
+            throw new RSIllegalArgumentException("out of range argument: " + i);
+        }
+        mPos = i;
+    }
+
+    public void skip(int i) {
+        int res = mPos + i;
+        if ((res < 0) || (res > mLen)) {
+            throw new RSIllegalArgumentException("out of range argument: " + i);
+        }
+        mPos = res;
+    }
+
+    public void addI8(byte v) {
+        mData[mPos++] = v;
+    }
+
+    public byte subI8() {
+        subalign(1);
+        return mData[--mPos];
+    }
+
+    public void addI16(short v) {
+        align(2);
+        mData[mPos++] = (byte)(v & 0xff);
+        mData[mPos++] = (byte)(v >> 8);
+    }
+
+    public short subI16() {
+        subalign(2);
+        short v = 0;
+        v = (short)((mData[--mPos] & 0xff) << 8);
+        v = (short)(v | (short)(mData[--mPos] & 0xff));
+        return v;
+    }
+
+
+    public void addI32(int v) {
+        align(4);
+        mData[mPos++] = (byte)(v & 0xff);
+        mData[mPos++] = (byte)((v >> 8) & 0xff);
+        mData[mPos++] = (byte)((v >> 16) & 0xff);
+        mData[mPos++] = (byte)((v >> 24) & 0xff);
+    }
+
+    public int subI32() {
+        subalign(4);
+        int v = 0;
+        v = ((mData[--mPos] & 0xff) << 24);
+        v = v | ((mData[--mPos] & 0xff) << 16);
+        v = v | ((mData[--mPos] & 0xff) << 8);
+        v = v | ((mData[--mPos] & 0xff));
+        return v;
+    }
+
+
+    public void addI64(long v) {
+        align(8);
+        mData[mPos++] = (byte)(v & 0xff);
+        mData[mPos++] = (byte)((v >> 8) & 0xff);
+        mData[mPos++] = (byte)((v >> 16) & 0xff);
+        mData[mPos++] = (byte)((v >> 24) & 0xff);
+        mData[mPos++] = (byte)((v >> 32) & 0xff);
+        mData[mPos++] = (byte)((v >> 40) & 0xff);
+        mData[mPos++] = (byte)((v >> 48) & 0xff);
+        mData[mPos++] = (byte)((v >> 56) & 0xff);
+    }
+
+    public long subI64() {
+        subalign(8);
+        long v = 0;
+        byte x = 0;
+        x = ((mData[--mPos]));
+        v = (long)(v | (((long)x) & 0xff) << 56l);
+        x = ((mData[--mPos]));
+        v = (long)(v | (((long)x) & 0xff) << 48l);
+        x = ((mData[--mPos]));
+        v = (long)(v | (((long)x) & 0xff) << 40l);
+        x = ((mData[--mPos]));
+        v = (long)(v | (((long)x) & 0xff) << 32l);
+        x = ((mData[--mPos]));
+        v = (long)(v | (((long)x) & 0xff) << 24l);
+        x = ((mData[--mPos]));
+        v = (long)(v | (((long)x) & 0xff) << 16l);
+        x = ((mData[--mPos]));
+        v = (long)(v | (((long)x) & 0xff) << 8l);
+        x = ((mData[--mPos]));
+        v = (long)(v | (((long)x) & 0xff));
+        return v;
+    }
+
+    public void addU8(short v) {
+        if ((v < 0) || (v > 0xff)) {
+            android.util.Log.e("rs", "FieldPacker.addU8( " + v + " )");
+            throw new IllegalArgumentException("Saving value out of range for type");
+        }
+        mData[mPos++] = (byte)v;
+    }
+
+    public void addU16(int v) {
+        if ((v < 0) || (v > 0xffff)) {
+            android.util.Log.e("rs", "FieldPacker.addU16( " + v + " )");
+            throw new IllegalArgumentException("Saving value out of range for type");
+        }
+        align(2);
+        mData[mPos++] = (byte)(v & 0xff);
+        mData[mPos++] = (byte)(v >> 8);
+    }
+
+    public void addU32(long v) {
+        if ((v < 0) || (v > 0xffffffffL)) {
+            android.util.Log.e("rs", "FieldPacker.addU32( " + v + " )");
+            throw new IllegalArgumentException("Saving value out of range for type");
+        }
+        align(4);
+        mData[mPos++] = (byte)(v & 0xff);
+        mData[mPos++] = (byte)((v >> 8) & 0xff);
+        mData[mPos++] = (byte)((v >> 16) & 0xff);
+        mData[mPos++] = (byte)((v >> 24) & 0xff);
+    }
+
+    public void addU64(long v) {
+        if (v < 0) {
+            android.util.Log.e("rs", "FieldPacker.addU64( " + v + " )");
+            throw new IllegalArgumentException("Saving value out of range for type");
+        }
+        align(8);
+        mData[mPos++] = (byte)(v & 0xff);
+        mData[mPos++] = (byte)((v >> 8) & 0xff);
+        mData[mPos++] = (byte)((v >> 16) & 0xff);
+        mData[mPos++] = (byte)((v >> 24) & 0xff);
+        mData[mPos++] = (byte)((v >> 32) & 0xff);
+        mData[mPos++] = (byte)((v >> 40) & 0xff);
+        mData[mPos++] = (byte)((v >> 48) & 0xff);
+        mData[mPos++] = (byte)((v >> 56) & 0xff);
+    }
+
+    public void addF32(float v) {
+        addI32(Float.floatToRawIntBits(v));
+    }
+
+    public float subF32() {
+        return Float.intBitsToFloat(subI32());
+    }
+
+    public void addF64(double v) {
+        addI64(Double.doubleToRawLongBits(v));
+    }
+
+    public double subF64() {
+        return Double.longBitsToDouble(subI64());
+    }
+
+    public void addObj(BaseObj obj) {
+        if (obj != null) {
+            if (RenderScript.sPointerSize == 8) {
+                addI64(obj.getID(null));
+                addI64(0);
+                addI64(0);
+                addI64(0);
+            } else {
+                addI32((int)obj.getID(null));
+            }
+        } else {
+            if (RenderScript.sPointerSize == 8) {
+                addI64(0);
+                addI64(0);
+                addI64(0);
+                addI64(0);
+            } else {
+                addI32(0);
+            }
+        }
+    }
+
+    public void addF32(Float2 v) {
+        addF32(v.x);
+        addF32(v.y);
+    }
+    public void addF32(Float3 v) {
+        addF32(v.x);
+        addF32(v.y);
+        addF32(v.z);
+    }
+    public void addF32(Float4 v) {
+        addF32(v.x);
+        addF32(v.y);
+        addF32(v.z);
+        addF32(v.w);
+    }
+
+    public void addF64(Double2 v) {
+        addF64(v.x);
+        addF64(v.y);
+    }
+    public void addF64(Double3 v) {
+        addF64(v.x);
+        addF64(v.y);
+        addF64(v.z);
+    }
+    public void addF64(Double4 v) {
+        addF64(v.x);
+        addF64(v.y);
+        addF64(v.z);
+        addF64(v.w);
+    }
+
+    public void addI8(Byte2 v) {
+        addI8(v.x);
+        addI8(v.y);
+    }
+    public void addI8(Byte3 v) {
+        addI8(v.x);
+        addI8(v.y);
+        addI8(v.z);
+    }
+    public void addI8(Byte4 v) {
+        addI8(v.x);
+        addI8(v.y);
+        addI8(v.z);
+        addI8(v.w);
+    }
+
+    public void addU8(Short2 v) {
+        addU8(v.x);
+        addU8(v.y);
+    }
+    public void addU8(Short3 v) {
+        addU8(v.x);
+        addU8(v.y);
+        addU8(v.z);
+    }
+    public void addU8(Short4 v) {
+        addU8(v.x);
+        addU8(v.y);
+        addU8(v.z);
+        addU8(v.w);
+    }
+
+    public void addI16(Short2 v) {
+        addI16(v.x);
+        addI16(v.y);
+    }
+    public void addI16(Short3 v) {
+        addI16(v.x);
+        addI16(v.y);
+        addI16(v.z);
+    }
+    public void addI16(Short4 v) {
+        addI16(v.x);
+        addI16(v.y);
+        addI16(v.z);
+        addI16(v.w);
+    }
+
+    public void addU16(Int2 v) {
+        addU16(v.x);
+        addU16(v.y);
+    }
+    public void addU16(Int3 v) {
+        addU16(v.x);
+        addU16(v.y);
+        addU16(v.z);
+    }
+    public void addU16(Int4 v) {
+        addU16(v.x);
+        addU16(v.y);
+        addU16(v.z);
+        addU16(v.w);
+    }
+
+    public void addI32(Int2 v) {
+        addI32(v.x);
+        addI32(v.y);
+    }
+    public void addI32(Int3 v) {
+        addI32(v.x);
+        addI32(v.y);
+        addI32(v.z);
+    }
+    public void addI32(Int4 v) {
+        addI32(v.x);
+        addI32(v.y);
+        addI32(v.z);
+        addI32(v.w);
+    }
+
+    public void addU32(Long2 v) {
+        addU32(v.x);
+        addU32(v.y);
+    }
+    public void addU32(Long3 v) {
+        addU32(v.x);
+        addU32(v.y);
+        addU32(v.z);
+    }
+    public void addU32(Long4 v) {
+        addU32(v.x);
+        addU32(v.y);
+        addU32(v.z);
+        addU32(v.w);
+    }
+
+    public void addI64(Long2 v) {
+        addI64(v.x);
+        addI64(v.y);
+    }
+    public void addI64(Long3 v) {
+        addI64(v.x);
+        addI64(v.y);
+        addI64(v.z);
+    }
+    public void addI64(Long4 v) {
+        addI64(v.x);
+        addI64(v.y);
+        addI64(v.z);
+        addI64(v.w);
+    }
+
+    public void addU64(Long2 v) {
+        addU64(v.x);
+        addU64(v.y);
+    }
+    public void addU64(Long3 v) {
+        addU64(v.x);
+        addU64(v.y);
+        addU64(v.z);
+    }
+    public void addU64(Long4 v) {
+        addU64(v.x);
+        addU64(v.y);
+        addU64(v.z);
+        addU64(v.w);
+    }
+
+
+    public Float2 subFloat2() {
+        Float2 v = new Float2();
+        v.y = subF32();
+        v.x = subF32();
+        return v;
+    }
+    public Float3 subFloat3() {
+        Float3 v = new Float3();
+        v.z = subF32();
+        v.y = subF32();
+        v.x = subF32();
+        return v;
+    }
+    public Float4 subFloat4() {
+        Float4 v = new Float4();
+        v.w = subF32();
+        v.z = subF32();
+        v.y = subF32();
+        v.x = subF32();
+        return v;
+    }
+
+    public Double2 subDouble2() {
+        Double2 v = new Double2();
+        v.y = subF64();
+        v.x = subF64();
+        return v;
+    }
+    public Double3 subDouble3() {
+        Double3 v = new Double3();
+        v.z = subF64();
+        v.y = subF64();
+        v.x = subF64();
+        return v;
+    }
+    public Double4 subDouble4() {
+        Double4 v = new Double4();
+        v.w = subF64();
+        v.z = subF64();
+        v.y = subF64();
+        v.x = subF64();
+        return v;
+    }
+
+    public Byte2 subByte2() {
+        Byte2 v = new Byte2();
+        v.y = subI8();
+        v.x = subI8();
+        return v;
+    }
+    public Byte3 subByte3() {
+        Byte3 v = new Byte3();
+        v.z = subI8();
+        v.y = subI8();
+        v.x = subI8();
+        return v;
+    }
+    public Byte4 subByte4() {
+        Byte4 v = new Byte4();
+        v.w = subI8();
+        v.z = subI8();
+        v.y = subI8();
+        v.x = subI8();
+        return v;
+    }
+
+    public Short2 subShort2() {
+        Short2 v = new Short2();
+        v.y = subI16();
+        v.x = subI16();
+        return v;
+    }
+    public Short3 subShort3() {
+        Short3 v = new Short3();
+        v.z = subI16();
+        v.y = subI16();
+        v.x = subI16();
+        return v;
+    }
+    public Short4 subShort4() {
+        Short4 v = new Short4();
+        v.w = subI16();
+        v.z = subI16();
+        v.y = subI16();
+        v.x = subI16();
+        return v;
+    }
+
+    public Int2 subInt2() {
+        Int2 v = new Int2();
+        v.y = subI32();
+        v.x = subI32();
+        return v;
+    }
+    public Int3 subInt3() {
+        Int3 v = new Int3();
+        v.z = subI32();
+        v.y = subI32();
+        v.x = subI32();
+        return v;
+    }
+    public Int4 subInt4() {
+        Int4 v = new Int4();
+        v.w = subI32();
+        v.z = subI32();
+        v.y = subI32();
+        v.x = subI32();
+        return v;
+    }
+
+    public Long2 subLong2() {
+        Long2 v = new Long2();
+        v.y = subI64();
+        v.x = subI64();
+        return v;
+    }
+    public Long3 subLong3() {
+        Long3 v = new Long3();
+        v.z = subI64();
+        v.y = subI64();
+        v.x = subI64();
+        return v;
+    }
+    public Long4 subLong4() {
+        Long4 v = new Long4();
+        v.w = subI64();
+        v.z = subI64();
+        v.y = subI64();
+        v.x = subI64();
+        return v;
+    }
+
+
+
+    public void addMatrix(Matrix4f v) {
+        for (int i=0; i < v.mMat.length; i++) {
+            addF32(v.mMat[i]);
+        }
+    }
+
+    public Matrix4f subMatrix4f() {
+        Matrix4f v = new Matrix4f();
+        for (int i = v.mMat.length - 1; i >= 0; i--) {
+            v.mMat[i] = subF32();
+        }
+        return v;
+    }
+
+    public void addMatrix(Matrix3f v) {
+        for (int i=0; i < v.mMat.length; i++) {
+            addF32(v.mMat[i]);
+        }
+    }
+
+    public Matrix3f subMatrix3f() {
+        Matrix3f v = new Matrix3f();
+        for (int i = v.mMat.length - 1; i >= 0; i--) {
+            v.mMat[i] = subF32();
+        }
+        return v;
+    }
+
+    public void addMatrix(Matrix2f v) {
+        for (int i=0; i < v.mMat.length; i++) {
+            addF32(v.mMat[i]);
+        }
+    }
+
+    public Matrix2f subMatrix2f() {
+        Matrix2f v = new Matrix2f();
+        for (int i = v.mMat.length - 1; i >= 0; i--) {
+            v.mMat[i] = subF32();
+        }
+        return v;
+    }
+
+    public void addBoolean(boolean v) {
+        addI8((byte)(v ? 1 : 0));
+    }
+
+    public boolean subBoolean() {
+        byte v = subI8();
+        if (v == 1) {
+            return true;
+        }
+        return false;
+    }
+
+    public final byte[] getData() {
+        return mData;
+    }
+
+    /**
+     * Get the actual length used for the FieldPacker.
+     *
+     * @hide
+     */
+    public int getPos() {
+        return mPos;
+    }
+
+    private static void addToPack(FieldPacker fp, Object obj) {
+        if (obj instanceof Boolean) {
+            fp.addBoolean(((Boolean)obj).booleanValue());
+            return;
+        }
+
+        if (obj instanceof Byte) {
+            fp.addI8(((Byte)obj).byteValue());
+            return;
+        }
+
+        if (obj instanceof Short) {
+            fp.addI16(((Short)obj).shortValue());
+            return;
+        }
+
+        if (obj instanceof Integer) {
+            fp.addI32(((Integer)obj).intValue());
+            return;
+        }
+
+        if (obj instanceof Long) {
+            fp.addI64(((Long)obj).longValue());
+            return;
+        }
+
+        if (obj instanceof Float) {
+            fp.addF32(((Float)obj).floatValue());
+            return;
+        }
+
+        if (obj instanceof Double) {
+            fp.addF64(((Double)obj).doubleValue());
+            return;
+        }
+
+        if (obj instanceof Byte2) {
+            fp.addI8((Byte2)obj);
+            return;
+        }
+
+        if (obj instanceof Byte3) {
+            fp.addI8((Byte3)obj);
+            return;
+        }
+
+        if (obj instanceof Byte4) {
+            fp.addI8((Byte4)obj);
+            return;
+        }
+
+        if (obj instanceof Short2) {
+            fp.addI16((Short2)obj);
+            return;
+        }
+
+        if (obj instanceof Short3) {
+            fp.addI16((Short3)obj);
+            return;
+        }
+
+        if (obj instanceof Short4) {
+            fp.addI16((Short4)obj);
+            return;
+        }
+
+        if (obj instanceof Int2) {
+            fp.addI32((Int2)obj);
+            return;
+        }
+
+        if (obj instanceof Int3) {
+            fp.addI32((Int3)obj);
+            return;
+        }
+
+        if (obj instanceof Int4) {
+            fp.addI32((Int4)obj);
+            return;
+        }
+
+        if (obj instanceof Long2) {
+            fp.addI64((Long2)obj);
+            return;
+        }
+
+        if (obj instanceof Long3) {
+            fp.addI64((Long3)obj);
+            return;
+        }
+
+        if (obj instanceof Long4) {
+            fp.addI64((Long4)obj);
+            return;
+        }
+
+        if (obj instanceof Float2) {
+            fp.addF32((Float2)obj);
+            return;
+        }
+
+        if (obj instanceof Float3) {
+            fp.addF32((Float3)obj);
+            return;
+        }
+
+        if (obj instanceof Float4) {
+            fp.addF32((Float4)obj);
+            return;
+        }
+
+        if (obj instanceof Double2) {
+            fp.addF64((Double2)obj);
+            return;
+        }
+
+        if (obj instanceof Double3) {
+            fp.addF64((Double3)obj);
+            return;
+        }
+
+        if (obj instanceof Double4) {
+            fp.addF64((Double4)obj);
+            return;
+        }
+
+        if (obj instanceof Matrix2f) {
+            fp.addMatrix((Matrix2f)obj);
+            return;
+        }
+
+        if (obj instanceof Matrix3f) {
+            fp.addMatrix((Matrix3f)obj);
+            return;
+        }
+
+        if (obj instanceof Matrix4f) {
+            fp.addMatrix((Matrix4f)obj);
+            return;
+        }
+
+        if (obj instanceof BaseObj) {
+            fp.addObj((BaseObj)obj);
+            return;
+        }
+    }
+
+    private static int getPackedSize(Object obj) {
+        if (obj instanceof Boolean) {
+            return 1;
+        }
+
+        if (obj instanceof Byte) {
+            return 1;
+        }
+
+        if (obj instanceof Short) {
+            return 2;
+        }
+
+        if (obj instanceof Integer) {
+            return 4;
+        }
+
+        if (obj instanceof Long) {
+            return 8;
+        }
+
+        if (obj instanceof Float) {
+            return 4;
+        }
+
+        if (obj instanceof Double) {
+            return 8;
+        }
+
+        if (obj instanceof Byte2) {
+            return 2;
+        }
+
+        if (obj instanceof Byte3) {
+            return 3;
+        }
+
+        if (obj instanceof Byte4) {
+            return 4;
+        }
+
+        if (obj instanceof Short2) {
+            return 4;
+        }
+
+        if (obj instanceof Short3) {
+            return 6;
+        }
+
+        if (obj instanceof Short4) {
+            return 8;
+        }
+
+        if (obj instanceof Int2) {
+            return 8;
+        }
+
+        if (obj instanceof Int3) {
+            return 12;
+        }
+
+        if (obj instanceof Int4) {
+            return 16;
+        }
+
+        if (obj instanceof Long2) {
+            return 16;
+        }
+
+        if (obj instanceof Long3) {
+            return 24;
+        }
+
+        if (obj instanceof Long4) {
+            return 32;
+        }
+
+        if (obj instanceof Float2) {
+            return 8;
+        }
+
+        if (obj instanceof Float3) {
+            return 12;
+        }
+
+        if (obj instanceof Float4) {
+            return 16;
+        }
+
+        if (obj instanceof Double2) {
+            return 16;
+        }
+
+        if (obj instanceof Double3) {
+            return 24;
+        }
+
+        if (obj instanceof Double4) {
+            return 32;
+        }
+
+        if (obj instanceof Matrix2f) {
+            return 16;
+        }
+
+        if (obj instanceof Matrix3f) {
+            return 36;
+        }
+
+        if (obj instanceof Matrix4f) {
+            return 64;
+        }
+
+        if (obj instanceof BaseObj) {
+            if (RenderScript.sPointerSize == 8) {
+                return 32;
+            } else {
+                return 4;
+            }
+        }
+
+        return 0;
+    }
+
+    static FieldPacker createFieldPack(Object[] args) {
+        int len = 0;
+        for (Object arg : args) {
+            len += getPackedSize(arg);
+        }
+        FieldPacker fp = new FieldPacker(len);
+        for (Object arg : args) {
+            addToPack(fp, arg);
+        }
+        return fp;
+    }
+
+
+    private boolean resize(int newSize) {
+        if (newSize == mLen) {
+            return false;
+        }
+
+        byte[] newData = new byte[newSize];
+        System.arraycopy(mData, 0, newData, 0, mPos);
+        mData = newData;
+        mLen = newSize;
+        return true;
+    }
+
+    private void addSafely(Object obj) {
+        boolean retry;
+        final int oldPos = mPos;
+        do {
+            retry = false;
+            try {
+                addToPack(this, obj);
+            } catch (ArrayIndexOutOfBoundsException e) {
+                mPos = oldPos;
+                resize(mLen * 2);
+                retry = true;
+            }
+        } while (retry);
+    }
+
+    private byte mData[];
+    private int mPos;
+    private int mLen;
+    private BitSet mAlignment;
+}
diff --git a/androidx/renderscript/Float2.java b/androidx/renderscript/Float2.java
new file mode 100644
index 0000000..01a166b
--- /dev/null
+++ b/androidx/renderscript/Float2.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript float2 type back to the Android system.
+ *
+ **/
+public class Float2 {
+    public Float2() {
+    }
+
+    public Float2(float initX, float initY) {
+        x = initX;
+        y = initY;
+    }
+
+    public float x;
+    public float y;
+}
+
+
+
+
diff --git a/androidx/renderscript/Float3.java b/androidx/renderscript/Float3.java
new file mode 100644
index 0000000..bb7932a
--- /dev/null
+++ b/androidx/renderscript/Float3.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript float2 type back to the Android system.
+ *
+ **/
+public class Float3 {
+    public Float3() {
+    }
+    public Float3(float initX, float initY, float initZ) {
+        x = initX;
+        y = initY;
+        z = initZ;
+    }
+
+    public float x;
+    public float y;
+    public float z;
+}
+
+
+
+
diff --git a/androidx/renderscript/Float4.java b/androidx/renderscript/Float4.java
new file mode 100644
index 0000000..8336d9e
--- /dev/null
+++ b/androidx/renderscript/Float4.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript float2 type back to the Android system.
+ *
+ **/
+public class Float4 {
+    public Float4() {
+    }
+
+    public Float4(float initX, float initY, float initZ, float initW) {
+        x = initX;
+        y = initY;
+        z = initZ;
+        w = initW;
+    }
+
+    public float x;
+    public float y;
+    public float z;
+    public float w;
+}
+
+
+
diff --git a/androidx/renderscript/Int2.java b/androidx/renderscript/Int2.java
new file mode 100644
index 0000000..fe86fe3
--- /dev/null
+++ b/androidx/renderscript/Int2.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript int2 type back to the Android system.
+ *
+ **/
+public class Int2 {
+    public Int2() {
+    }
+
+    public Int2(int initX, int initY) {
+        x = initX;
+        y = initY;
+    }
+
+    public int x;
+    public int y;
+}
+
+
+
+
diff --git a/androidx/renderscript/Int3.java b/androidx/renderscript/Int3.java
new file mode 100644
index 0000000..bd6fbc7
--- /dev/null
+++ b/androidx/renderscript/Int3.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript int3 type back to the Android system.
+ *
+ **/
+public class Int3 {
+    public Int3() {
+    }
+
+    public Int3(int initX, int initY, int initZ) {
+        x = initX;
+        y = initY;
+        z = initZ;
+    }
+
+    public int x;
+    public int y;
+    public int z;
+}
+
+
+
+
diff --git a/androidx/renderscript/Int4.java b/androidx/renderscript/Int4.java
new file mode 100644
index 0000000..91e0b9f
--- /dev/null
+++ b/androidx/renderscript/Int4.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript int4 type back to the Android system.
+ *
+ **/
+public class Int4 {
+    public Int4() {
+    }
+
+    public Int4(int initX, int initY, int initZ, int initW) {
+        x = initX;
+        y = initY;
+        z = initZ;
+        w = initW;
+    }
+
+    public int x;
+    public int y;
+    public int z;
+    public int w;
+}
+
+
+
diff --git a/androidx/renderscript/Long2.java b/androidx/renderscript/Long2.java
new file mode 100644
index 0000000..0871706
--- /dev/null
+++ b/androidx/renderscript/Long2.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript long2 type back to the Android system.
+ **/
+public class Long2 {
+    public Long2() {
+    }
+
+    public Long2(long initX, long initY) {
+        x = initX;
+        y = initY;
+    }
+
+    public long x;
+    public long y;
+}
+
+
+
+
diff --git a/androidx/renderscript/Long3.java b/androidx/renderscript/Long3.java
new file mode 100644
index 0000000..250b50f
--- /dev/null
+++ b/androidx/renderscript/Long3.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript long3 type back to the Android system.
+ **/
+public class Long3 {
+    public Long3() {
+    }
+
+    public Long3(long initX, long initY, long initZ) {
+        x = initX;
+        y = initY;
+        z = initZ;
+    }
+
+    public long x;
+    public long y;
+    public long z;
+}
+
+
+
+
diff --git a/androidx/renderscript/Long4.java b/androidx/renderscript/Long4.java
new file mode 100644
index 0000000..438d34e
--- /dev/null
+++ b/androidx/renderscript/Long4.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript long4 type back to the Android system.
+ **/
+public class Long4 {
+    public Long4() {
+    }
+
+    public Long4(long initX, long initY, long initZ, long initW) {
+        x = initX;
+        y = initY;
+        z = initZ;
+        w = initW;
+    }
+
+    public long x;
+    public long y;
+    public long z;
+    public long w;
+}
+
+
+
diff --git a/androidx/renderscript/Matrix2f.java b/androidx/renderscript/Matrix2f.java
new file mode 100644
index 0000000..b5c5a08
--- /dev/null
+++ b/androidx/renderscript/Matrix2f.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2009-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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript rs_matrix2x2 type back to the Android system.
+ *
+ **/
+public class Matrix2f {
+
+    /**
+    * Creates a new identity 2x2 matrix
+    */
+    public Matrix2f() {
+        mMat = new float[4];
+        loadIdentity();
+    }
+
+    /**
+    * Creates a new matrix and sets its values from the given
+    * parameter
+    *
+    * @param dataArray values to set the matrix to, must be 4
+    *                  floats long
+    */
+    public Matrix2f(float[] dataArray) {
+        mMat = new float[4];
+        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
+    }
+
+    /**
+    * Return a reference to the internal array representing matrix
+    * values. Modifying this array will also change the matrix
+    *
+    * @return internal array representing the matrix
+    */
+    public float[] getArray() {
+        return mMat;
+    }
+
+    /**
+    * Returns the value for a given row and column
+    *
+    * @param x column of the value to return
+    * @param y row of the value to return
+    *
+    * @return value in the yth row and xth column
+    */
+    public float get(int x, int y) {
+        return mMat[x*2 + y];
+    }
+
+    /**
+    * Sets the value for a given row and column
+    *
+    * @param x column of the value to set
+    * @param y row of the value to set
+    */
+    public void set(int x, int y, float v) {
+        mMat[x*2 + y] = v;
+    }
+
+    /**
+    * Sets the matrix values to identity
+    */
+    public void loadIdentity() {
+        mMat[0] = 1;
+        mMat[1] = 0;
+
+        mMat[2] = 0;
+        mMat[3] = 1;
+    }
+
+    /**
+    * Sets the values of the matrix to those of the parameter
+    *
+    * @param src matrix to load the values from
+    */
+    public void load(Matrix2f src) {
+        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
+    }
+
+    /**
+    * Sets current values to be a rotation matrix of given angle
+    *
+    * @param rot rotation angle
+    */
+    public void loadRotate(float rot) {
+        float c, s;
+        rot *= (float)(java.lang.Math.PI / 180.0f);
+        c = (float)java.lang.Math.cos(rot);
+        s = (float)java.lang.Math.sin(rot);
+        mMat[0] = c;
+        mMat[1] = -s;
+        mMat[2] = s;
+        mMat[3] = c;
+    }
+
+    /**
+    * Sets current values to be a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    */
+    public void loadScale(float x, float y) {
+        loadIdentity();
+        mMat[0] = x;
+        mMat[3] = y;
+    }
+
+    /**
+    * Sets current values to be the result of multiplying two given
+    * matrices
+    *
+    * @param lhs left hand side matrix
+    * @param rhs right hand side matrix
+    */
+    public void loadMultiply(Matrix2f lhs, Matrix2f rhs) {
+        for (int i=0 ; i<2 ; i++) {
+            float ri0 = 0;
+            float ri1 = 0;
+            for (int j=0 ; j<2 ; j++) {
+                float rhs_ij = rhs.get(i,j);
+                ri0 += lhs.get(j,0) * rhs_ij;
+                ri1 += lhs.get(j,1) * rhs_ij;
+            }
+            set(i,0, ri0);
+            set(i,1, ri1);
+        }
+    }
+
+    /**
+    * Post-multiplies the current matrix by a given parameter
+    *
+    * @param rhs right hand side to multiply by
+    */
+    public void multiply(Matrix2f rhs) {
+        Matrix2f tmp = new Matrix2f();
+        tmp.loadMultiply(this, rhs);
+        load(tmp);
+    }
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * rotation matrix of given angle
+    *
+    * @param rot angle of rotation
+    */
+    public void rotate(float rot) {
+        Matrix2f tmp = new Matrix2f();
+        tmp.loadRotate(rot);
+        multiply(tmp);
+    }
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    */
+    public void scale(float x, float y) {
+        Matrix2f tmp = new Matrix2f();
+        tmp.loadScale(x, y);
+        multiply(tmp);
+    }
+    /**
+    * Sets the current matrix to its transpose
+    */
+    public void transpose() {
+        float temp = mMat[1];
+        mMat[1] = mMat[2];
+        mMat[2] = temp;
+    }
+
+    final float[] mMat;
+}
+
+
+
diff --git a/androidx/renderscript/Matrix3f.java b/androidx/renderscript/Matrix3f.java
new file mode 100644
index 0000000..699c42b
--- /dev/null
+++ b/androidx/renderscript/Matrix3f.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2009-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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript rs_matrix3x3 type back to the Android system.
+ *
+ **/
+public class Matrix3f {
+
+    /**
+    * Creates a new identity 3x3 matrix
+    */
+    public Matrix3f() {
+        mMat = new float[9];
+        loadIdentity();
+    }
+
+    /**
+    * Creates a new matrix and sets its values from the given
+    * parameter
+    *
+    * @param dataArray values to set the matrix to, must be 9
+    *                  floats long
+    */
+    public Matrix3f(float[] dataArray) {
+        mMat = new float[9];
+        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
+    }
+
+    /**
+    * Return a reference to the internal array representing matrix
+    * values. Modifying this array will also change the matrix
+    *
+    * @return internal array representing the matrix
+    */
+    public float[] getArray() {
+        return mMat;
+    }
+
+    /**
+    * Returns the value for a given row and column
+    *
+    * @param x column of the value to return
+    * @param y row of the value to return
+    *
+    * @return value in the yth row and xth column
+    */
+    public float get(int x, int y) {
+        return mMat[x*3 + y];
+    }
+
+    /**
+    * Sets the value for a given row and column
+    *
+    * @param x column of the value to set
+    * @param y row of the value to set
+    */
+    public void set(int x, int y, float v) {
+        mMat[x*3 + y] = v;
+    }
+
+    /**
+    * Sets the matrix values to identity
+    */
+    public void loadIdentity() {
+        mMat[0] = 1;
+        mMat[1] = 0;
+        mMat[2] = 0;
+
+        mMat[3] = 0;
+        mMat[4] = 1;
+        mMat[5] = 0;
+
+        mMat[6] = 0;
+        mMat[7] = 0;
+        mMat[8] = 1;
+    }
+
+    /**
+    * Sets the values of the matrix to those of the parameter
+    *
+    * @param src matrix to load the values from
+    */
+    public void load(Matrix3f src) {
+        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
+    }
+
+    /**
+    * Sets current values to be a rotation matrix of certain angle
+    * about a given axis
+    *
+    * @param rot angle of rotation
+    * @param x rotation axis x
+    * @param y rotation axis y
+    * @param z rotation axis z
+    */
+    public void loadRotate(float rot, float x, float y, float z) {
+        float c, s;
+        rot *= (float)(java.lang.Math.PI / 180.0f);
+        c = (float)java.lang.Math.cos(rot);
+        s = (float)java.lang.Math.sin(rot);
+
+        float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z);
+        if (!(len != 1)) {
+            float recipLen = 1.f / len;
+            x *= recipLen;
+            y *= recipLen;
+            z *= recipLen;
+        }
+        float nc = 1.0f - c;
+        float xy = x * y;
+        float yz = y * z;
+        float zx = z * x;
+        float xs = x * s;
+        float ys = y * s;
+        float zs = z * s;
+        mMat[0] = x*x*nc +  c;
+        mMat[3] =  xy*nc - zs;
+        mMat[6] =  zx*nc + ys;
+        mMat[1] =  xy*nc + zs;
+        mMat[4] = y*y*nc +  c;
+        mMat[7] =  yz*nc - xs;
+        mMat[2] =  zx*nc - ys;
+        mMat[5] =  yz*nc + xs;
+        mMat[8] = z*z*nc +  c;
+    }
+
+    /**
+    * Makes the upper 2x2 a rotation matrix of the given angle
+    *
+    * @param rot rotation angle
+    */
+    public void loadRotate(float rot) {
+        loadIdentity();
+        float c, s;
+        rot *= (float)(java.lang.Math.PI / 180.0f);
+        c = (float)java.lang.Math.cos(rot);
+        s = (float)java.lang.Math.sin(rot);
+        mMat[0] = c;
+        mMat[1] = -s;
+        mMat[3] = s;
+        mMat[4] = c;
+    }
+
+    /**
+    * Makes the upper 2x2 a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    */
+    public void loadScale(float x, float y) {
+        loadIdentity();
+        mMat[0] = x;
+        mMat[4] = y;
+    }
+
+    /**
+    * Sets current values to be a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    * @param z scale component z
+    */
+    public void loadScale(float x, float y, float z) {
+        loadIdentity();
+        mMat[0] = x;
+        mMat[4] = y;
+        mMat[8] = z;
+    }
+
+    /**
+    * Sets current values to be a translation matrix of given
+    * dimensions
+    *
+    * @param x translation component x
+    * @param y translation component y
+    */
+    public void loadTranslate(float x, float y) {
+        loadIdentity();
+        mMat[6] = x;
+        mMat[7] = y;
+    }
+
+    /**
+    * Sets current values to be the result of multiplying two given
+    * matrices
+    *
+    * @param lhs left hand side matrix
+    * @param rhs right hand side matrix
+    */
+    public void loadMultiply(Matrix3f lhs, Matrix3f rhs) {
+        for (int i=0 ; i<3 ; i++) {
+            float ri0 = 0;
+            float ri1 = 0;
+            float ri2 = 0;
+            for (int j=0 ; j<3 ; j++) {
+                float rhs_ij = rhs.get(i,j);
+                ri0 += lhs.get(j,0) * rhs_ij;
+                ri1 += lhs.get(j,1) * rhs_ij;
+                ri2 += lhs.get(j,2) * rhs_ij;
+            }
+            set(i,0, ri0);
+            set(i,1, ri1);
+            set(i,2, ri2);
+        }
+    }
+
+    /**
+    * Post-multiplies the current matrix by a given parameter
+    *
+    * @param rhs right hand side to multiply by
+    */
+    public void multiply(Matrix3f rhs) {
+        Matrix3f tmp = new Matrix3f();
+        tmp.loadMultiply(this, rhs);
+        load(tmp);
+    }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * rotation matrix of certain angle about a given axis
+    *
+    * @param rot angle of rotation
+    * @param x rotation axis x
+    * @param y rotation axis y
+    * @param z rotation axis z
+    */
+    public void rotate(float rot, float x, float y, float z) {
+        Matrix3f tmp = new Matrix3f();
+        tmp.loadRotate(rot, x, y, z);
+        multiply(tmp);
+    }
+
+    /**
+    * Modifies the upper 2x2 of the current matrix by
+    * post-multiplying it with a rotation matrix of given angle
+    *
+    * @param rot angle of rotation
+    */
+    public void rotate(float rot) {
+        Matrix3f tmp = new Matrix3f();
+        tmp.loadRotate(rot);
+        multiply(tmp);
+    }
+
+    /**
+    * Modifies the upper 2x2 of the current matrix by
+    * post-multiplying it with a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    */
+    public void scale(float x, float y) {
+        Matrix3f tmp = new Matrix3f();
+        tmp.loadScale(x, y);
+        multiply(tmp);
+    }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    * @param z scale component z
+    */
+    public void scale(float x, float y, float z) {
+        Matrix3f tmp = new Matrix3f();
+        tmp.loadScale(x, y, z);
+        multiply(tmp);
+    }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * translation matrix of given dimensions
+    *
+    * @param x translation component x
+    * @param y translation component y
+    */
+    public void translate(float x, float y) {
+        Matrix3f tmp = new Matrix3f();
+        tmp.loadTranslate(x, y);
+        multiply(tmp);
+    }
+
+    /**
+    * Sets the current matrix to its transpose
+    */
+    public void transpose() {
+        for(int i = 0; i < 2; ++i) {
+            for(int j = i + 1; j < 3; ++j) {
+                float temp = mMat[i*3 + j];
+                mMat[i*3 + j] = mMat[j*3 + i];
+                mMat[j*3 + i] = temp;
+            }
+        }
+    }
+
+    final float[] mMat;
+}
+
+
diff --git a/androidx/renderscript/Matrix4f.java b/androidx/renderscript/Matrix4f.java
new file mode 100644
index 0000000..6a38af8
--- /dev/null
+++ b/androidx/renderscript/Matrix4f.java
@@ -0,0 +1,494 @@
+/*
+ * Copyright (C) 2009-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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript rs_matrix4x4 type back to the Android system.
+ *
+ **/
+public class Matrix4f {
+
+    /**
+    * Creates a new identity 4x4 matrix
+    */
+    public Matrix4f() {
+        mMat = new float[16];
+        loadIdentity();
+    }
+
+    /**
+    * Creates a new matrix and sets its values from the given
+    * parameter
+    *
+    * @param dataArray values to set the matrix to, must be 16
+    *                  floats long
+    */
+    public Matrix4f(float[] dataArray) {
+        mMat = new float[16];
+        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
+    }
+
+    /**
+    * Return a reference to the internal array representing matrix
+    * values. Modifying this array will also change the matrix
+    *
+    * @return internal array representing the matrix
+    */
+    public float[] getArray() {
+        return mMat;
+    }
+
+    /**
+    * Returns the value for a given row and column
+    *
+    * @param x column of the value to return
+    * @param y row of the value to return
+    *
+    * @return value in the yth row and xth column
+    */
+    public float get(int x, int y) {
+        return mMat[x*4 + y];
+    }
+
+    /**
+    * Sets the value for a given row and column
+    *
+    * @param x column of the value to set
+    * @param y row of the value to set
+    */
+    public void set(int x, int y, float v) {
+        mMat[x*4 + y] = v;
+    }
+
+    /**
+    * Sets the matrix values to identity
+    */
+    public void loadIdentity() {
+        mMat[0] = 1;
+        mMat[1] = 0;
+        mMat[2] = 0;
+        mMat[3] = 0;
+
+        mMat[4] = 0;
+        mMat[5] = 1;
+        mMat[6] = 0;
+        mMat[7] = 0;
+
+        mMat[8] = 0;
+        mMat[9] = 0;
+        mMat[10] = 1;
+        mMat[11] = 0;
+
+        mMat[12] = 0;
+        mMat[13] = 0;
+        mMat[14] = 0;
+        mMat[15] = 1;
+    }
+
+    /**
+    * Sets the values of the matrix to those of the parameter
+    *
+    * @param src matrix to load the values from
+    */
+    public void load(Matrix4f src) {
+        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
+    }
+
+    /**
+    * Sets the values of the matrix to those of the parameter
+    *
+    * @param src matrix to load the values from
+    * @hide
+    */
+    public void load(Matrix3f src) {
+        mMat[0] = src.mMat[0];
+        mMat[1] = src.mMat[1];
+        mMat[2] = src.mMat[2];
+        mMat[3] = 0;
+
+        mMat[4] = src.mMat[3];
+        mMat[5] = src.mMat[4];
+        mMat[6] = src.mMat[5];
+        mMat[7] = 0;
+
+        mMat[8] = src.mMat[6];
+        mMat[9] = src.mMat[7];
+        mMat[10] = src.mMat[8];
+        mMat[11] = 0;
+
+        mMat[12] = 0;
+        mMat[13] = 0;
+        mMat[14] = 0;
+        mMat[15] = 1;
+    }
+
+    /**
+    * Sets current values to be a rotation matrix of certain angle
+    * about a given axis
+    *
+    * @param rot angle of rotation
+    * @param x rotation axis x
+    * @param y rotation axis y
+    * @param z rotation axis z
+    */
+    public void loadRotate(float rot, float x, float y, float z) {
+        float c, s;
+        mMat[3] = 0;
+        mMat[7] = 0;
+        mMat[11]= 0;
+        mMat[12]= 0;
+        mMat[13]= 0;
+        mMat[14]= 0;
+        mMat[15]= 1;
+        rot *= (float)(java.lang.Math.PI / 180.0f);
+        c = (float)java.lang.Math.cos(rot);
+        s = (float)java.lang.Math.sin(rot);
+
+        float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z);
+        if (!(len != 1)) {
+            float recipLen = 1.f / len;
+            x *= recipLen;
+            y *= recipLen;
+            z *= recipLen;
+        }
+        float nc = 1.0f - c;
+        float xy = x * y;
+        float yz = y * z;
+        float zx = z * x;
+        float xs = x * s;
+        float ys = y * s;
+        float zs = z * s;
+        mMat[ 0] = x*x*nc +  c;
+        mMat[ 4] =  xy*nc - zs;
+        mMat[ 8] =  zx*nc + ys;
+        mMat[ 1] =  xy*nc + zs;
+        mMat[ 5] = y*y*nc +  c;
+        mMat[ 9] =  yz*nc - xs;
+        mMat[ 2] =  zx*nc - ys;
+        mMat[ 6] =  yz*nc + xs;
+        mMat[10] = z*z*nc +  c;
+    }
+
+    /**
+    * Sets current values to be a scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    * @param z scale component z
+    */
+    public void loadScale(float x, float y, float z) {
+        loadIdentity();
+        mMat[0] = x;
+        mMat[5] = y;
+        mMat[10] = z;
+    }
+
+    /**
+    * Sets current values to be a translation matrix of given
+    * dimensions
+    *
+    * @param x translation component x
+    * @param y translation component y
+    * @param z translation component z
+    */
+    public void loadTranslate(float x, float y, float z) {
+        loadIdentity();
+        mMat[12] = x;
+        mMat[13] = y;
+        mMat[14] = z;
+    }
+
+    /**
+    * Sets current values to be the result of multiplying two given
+    * matrices
+    *
+    * @param lhs left hand side matrix
+    * @param rhs right hand side matrix
+    */
+    public void loadMultiply(Matrix4f lhs, Matrix4f rhs) {
+        for (int i=0 ; i<4 ; i++) {
+            float ri0 = 0;
+            float ri1 = 0;
+            float ri2 = 0;
+            float ri3 = 0;
+            for (int j=0 ; j<4 ; j++) {
+                float rhs_ij = rhs.get(i,j);
+                ri0 += lhs.get(j,0) * rhs_ij;
+                ri1 += lhs.get(j,1) * rhs_ij;
+                ri2 += lhs.get(j,2) * rhs_ij;
+                ri3 += lhs.get(j,3) * rhs_ij;
+            }
+            set(i,0, ri0);
+            set(i,1, ri1);
+            set(i,2, ri2);
+            set(i,3, ri3);
+        }
+    }
+
+    /**
+    * Set current values to be an orthographic projection matrix
+    *
+    * @param l location of the left vertical clipping plane
+    * @param r location of the right vertical clipping plane
+    * @param b location of the bottom horizontal clipping plane
+    * @param t location of the top horizontal clipping plane
+    * @param n location of the near clipping plane
+    * @param f location of the far clipping plane
+    */
+    public void loadOrtho(float l, float r, float b, float t, float n, float f) {
+        loadIdentity();
+        mMat[0] = 2 / (r - l);
+        mMat[5] = 2 / (t - b);
+        mMat[10]= -2 / (f - n);
+        mMat[12]= -(r + l) / (r - l);
+        mMat[13]= -(t + b) / (t - b);
+        mMat[14]= -(f + n) / (f - n);
+    }
+
+    /**
+    * Set current values to be an orthographic projection matrix
+    * with the right and bottom clipping planes set to the given
+    * values. Left and top clipping planes are set to 0. Near and
+    * far are set to -1, 1 respectively
+    *
+    * @param w location of the right vertical clipping plane
+    * @param h location of the bottom horizontal clipping plane
+    *
+    */
+    public void loadOrthoWindow(int w, int h) {
+        loadOrtho(0,w, h,0, -1,1);
+    }
+
+    /**
+    * Sets current values to be a perspective projection matrix
+    *
+    * @param l location of the left vertical clipping plane
+    * @param r location of the right vertical clipping plane
+    * @param b location of the bottom horizontal clipping plane
+    * @param t location of the top horizontal clipping plane
+    * @param n location of the near clipping plane, must be positive
+    * @param f location of the far clipping plane, must be positive
+    *
+    */
+    public void loadFrustum(float l, float r, float b, float t, float n, float f) {
+        loadIdentity();
+        mMat[0] = 2 * n / (r - l);
+        mMat[5] = 2 * n / (t - b);
+        mMat[8] = (r + l) / (r - l);
+        mMat[9] = (t + b) / (t - b);
+        mMat[10]= -(f + n) / (f - n);
+        mMat[11]= -1;
+        mMat[14]= -2*f*n / (f - n);
+        mMat[15]= 0;
+    }
+
+    /**
+    * Sets current values to be a perspective projection matrix
+    *
+    * @param fovy vertical field of view angle in degrees
+    * @param aspect aspect ratio of the screen
+    * @param near near cliping plane, must be positive
+    * @param far far clipping plane, must be positive
+    */
+    public void loadPerspective(float fovy, float aspect, float near, float far) {
+        float top = near * (float)Math.tan((float) (fovy * Math.PI / 360.0f));
+        float bottom = -top;
+        float left = bottom * aspect;
+        float right = top * aspect;
+        loadFrustum(left, right, bottom, top, near, far);
+    }
+
+    /**
+    * Helper function to set the current values to a perspective
+    * projection matrix with aspect ratio defined by the parameters
+    * and (near, far), (bottom, top) mapping to (-1, 1) at z = 0
+    *
+    * @param w screen width
+    * @param h screen height
+    */
+    public void loadProjectionNormalized(int w, int h) {
+        // range -1,1 in the narrow axis at z = 0.
+        Matrix4f m1 = new Matrix4f();
+        Matrix4f m2 = new Matrix4f();
+
+        if(w > h) {
+            float aspect = ((float)w) / h;
+            m1.loadFrustum(-aspect,aspect,  -1,1,  1,100);
+        } else {
+            float aspect = ((float)h) / w;
+            m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
+        }
+
+        m2.loadRotate(180, 0, 1, 0);
+        m1.loadMultiply(m1, m2);
+
+        m2.loadScale(-2, 2, 1);
+        m1.loadMultiply(m1, m2);
+
+        m2.loadTranslate(0, 0, 2);
+        m1.loadMultiply(m1, m2);
+
+        load(m1);
+    }
+
+    /**
+    * Post-multiplies the current matrix by a given parameter
+    *
+    * @param rhs right hand side to multiply by
+    */
+    public void multiply(Matrix4f rhs) {
+        Matrix4f tmp = new Matrix4f();
+        tmp.loadMultiply(this, rhs);
+        load(tmp);
+    }
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * rotation matrix of certain angle about a given axis
+    *
+    * @param rot angle of rotation
+    * @param x rotation axis x
+    * @param y rotation axis y
+    * @param z rotation axis z
+    */
+    public void rotate(float rot, float x, float y, float z) {
+        Matrix4f tmp = new Matrix4f();
+        tmp.loadRotate(rot, x, y, z);
+        multiply(tmp);
+    }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * scale matrix of given dimensions
+    *
+    * @param x scale component x
+    * @param y scale component y
+    * @param z scale component z
+    */
+    public void scale(float x, float y, float z) {
+        Matrix4f tmp = new Matrix4f();
+        tmp.loadScale(x, y, z);
+        multiply(tmp);
+    }
+
+    /**
+    * Modifies the current matrix by post-multiplying it with a
+    * translation matrix of given dimensions
+    *
+    * @param x translation component x
+    * @param y translation component y
+    * @param z translation component z
+    */
+    public void translate(float x, float y, float z) {
+        Matrix4f tmp = new Matrix4f();
+        tmp.loadTranslate(x, y, z);
+        multiply(tmp);
+    }
+    private float computeCofactor(int i, int j) {
+        int c0 = (i+1) % 4;
+        int c1 = (i+2) % 4;
+        int c2 = (i+3) % 4;
+        int r0 = (j+1) % 4;
+        int r1 = (j+2) % 4;
+        int r2 = (j+3) % 4;
+
+        float minor = (mMat[c0 + 4*r0] * (mMat[c1 + 4*r1] * mMat[c2 + 4*r2] -
+                                            mMat[c1 + 4*r2] * mMat[c2 + 4*r1]))
+                     - (mMat[c0 + 4*r1] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r2] -
+                                            mMat[c1 + 4*r2] * mMat[c2 + 4*r0]))
+                     + (mMat[c0 + 4*r2] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r1] -
+                                            mMat[c1 + 4*r1] * mMat[c2 + 4*r0]));
+
+        float cofactor = ((i+j) & 1) != 0 ? -minor : minor;
+        return cofactor;
+    }
+
+    /**
+    * Sets the current matrix to its inverse
+    */
+    public boolean inverse() {
+
+        Matrix4f result = new Matrix4f();
+
+        for (int i = 0; i < 4; ++i) {
+            for (int j = 0; j < 4; ++j) {
+                result.mMat[4*i + j] = computeCofactor(i, j);
+            }
+        }
+
+        // Dot product of 0th column of source and 0th row of result
+        float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[1] +
+                     mMat[8]*result.mMat[2] + mMat[12]*result.mMat[3];
+
+        if (Math.abs(det) < 1e-6) {
+            return false;
+        }
+
+        det = 1.0f / det;
+        for (int i = 0; i < 16; ++i) {
+            mMat[i] = result.mMat[i] * det;
+        }
+
+        return true;
+    }
+
+    /**
+    * Sets the current matrix to its inverse transpose
+    */
+    public boolean inverseTranspose() {
+
+        Matrix4f result = new Matrix4f();
+
+        for (int i = 0; i < 4; ++i) {
+            for (int j = 0; j < 4; ++j) {
+                result.mMat[4*j + i] = computeCofactor(i, j);
+            }
+        }
+
+        float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[4] +
+                     mMat[8]*result.mMat[8] + mMat[12]*result.mMat[12];
+
+        if (Math.abs(det) < 1e-6) {
+            return false;
+        }
+
+        det = 1.0f / det;
+        for (int i = 0; i < 16; ++i) {
+            mMat[i] = result.mMat[i] * det;
+        }
+
+        return true;
+    }
+
+    /**
+    * Sets the current matrix to its transpose
+    */
+    public void transpose() {
+        for(int i = 0; i < 3; ++i) {
+            for(int j = i + 1; j < 4; ++j) {
+                float temp = mMat[i*4 + j];
+                mMat[i*4 + j] = mMat[j*4 + i];
+                mMat[j*4 + i] = temp;
+            }
+        }
+    }
+
+    final float[] mMat;
+}
diff --git a/androidx/renderscript/RSDriverException.java b/androidx/renderscript/RSDriverException.java
new file mode 100644
index 0000000..11b5be2
--- /dev/null
+++ b/androidx/renderscript/RSDriverException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 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 androidx.renderscript;
+
+
+/**
+ * Base class for all exceptions thrown by the Android
+ * RenderScript
+ */
+public class RSDriverException extends RSRuntimeException {
+    public RSDriverException(String string) {
+        super(string);
+    }
+}
+
+
+
diff --git a/androidx/renderscript/RSIllegalArgumentException.java b/androidx/renderscript/RSIllegalArgumentException.java
new file mode 100644
index 0000000..6e7c0e9
--- /dev/null
+++ b/androidx/renderscript/RSIllegalArgumentException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 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 androidx.renderscript;
+
+
+/**
+ * Base class for all exceptions thrown by the Android
+ * RenderScript
+ */
+public class RSIllegalArgumentException extends RSRuntimeException {
+    public RSIllegalArgumentException(String string) {
+        super(string);
+    }
+}
+
+
diff --git a/androidx/renderscript/RSInvalidStateException.java b/androidx/renderscript/RSInvalidStateException.java
new file mode 100644
index 0000000..82cc7c9
--- /dev/null
+++ b/androidx/renderscript/RSInvalidStateException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 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 androidx.renderscript;
+
+
+/**
+ * Base class for all exceptions thrown by the Android
+ * RenderScript
+ */
+public class RSInvalidStateException extends RSRuntimeException {
+    public RSInvalidStateException(String string) {
+        super(string);
+    }
+}
+
+
+
diff --git a/androidx/renderscript/RSRuntimeException.java b/androidx/renderscript/RSRuntimeException.java
new file mode 100644
index 0000000..886cd14
--- /dev/null
+++ b/androidx/renderscript/RSRuntimeException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 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 androidx.renderscript;
+
+
+/**
+ * Base class for all exceptions thrown by the Android
+ * RenderScript
+ */
+public class RSRuntimeException
+  extends java.lang.RuntimeException {
+    public RSRuntimeException(String string) {
+        super(string);
+    }
+}
+
diff --git a/androidx/renderscript/RenderScript.java b/androidx/renderscript/RenderScript.java
new file mode 100644
index 0000000..cf80342
--- /dev/null
+++ b/androidx/renderscript/RenderScript.java
@@ -0,0 +1,1748 @@
+/*
+ * 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 androidx.renderscript;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.ArrayList;
+import java.nio.ByteBuffer;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Process;
+import android.util.Log;
+import android.view.Surface;
+
+/**
+ * This class provides access to a RenderScript context, which controls RenderScript
+ * initialization, resource management, and teardown. An instance of the RenderScript
+ * class must be created before any other RS objects can be created.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about creating an application that uses RenderScript, read the
+ * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
+ * </div>
+ **/
+public class RenderScript {
+    static final String LOG_TAG = "RenderScript_jni";
+    static final boolean DEBUG  = false;
+    @SuppressWarnings({"UnusedDeclaration", "deprecation"})
+    static final boolean LOG_ENABLED = false;
+    static final int SUPPORT_LIB_API = 23;
+    static final int SUPPORT_LIB_VERSION = 2301;
+
+    static private ArrayList<RenderScript> mProcessContextList = new ArrayList<RenderScript>();
+    private boolean mIsProcessContext = false;
+    private boolean mEnableMultiInput = false;
+    private int mDispatchAPILevel = 0;
+
+    private int mContextFlags = 0;
+    private int mContextSdkVersion = 0;
+
+    private Context mApplicationContext;
+    private String mNativeLibDir;
+
+    static private String mBlackList = "";
+     /**
+     * Sets the blackList of Models to only use support lib runtime.
+     * Should be used before context create.
+     *
+     * @param blackList User provided black list string.
+     *
+     * Format: "(MANUFACTURER1:PRODUCT1:MODEL1), (MANUFACTURER2:PRODUCT2:MODEL2)..."
+     * e.g. : To Blacklist Nexus 7(2013) and Nexus 5.
+     *        mBlackList = "(asus:razor:Nexus 7), (LGE:hammerhead:Nexus 5)";
+     */
+    static public void setBlackList(String blackList) {
+        if (blackList != null) {
+            mBlackList = blackList;
+        }
+    }
+     /**
+     * Force using support lib runtime.
+     * Should be used before context create.
+     *
+     */
+    static public void forceCompat() {
+        sNative = 0;
+    }
+    /*
+     * We use a class initializer to allow the native code to cache some
+     * field offsets.
+     */
+    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
+    static boolean sInitialized;
+    static boolean sUseGCHooks;
+    static Object sRuntime;
+    static Method registerNativeAllocation;
+    static Method registerNativeFree;
+
+    static Object lock = new Object();
+
+    // Non-threadsafe functions.
+    native boolean nLoadSO(boolean useNative, int deviceApi, String libPath);
+    native boolean nLoadIOSO();
+    native long nDeviceCreate();
+    native void nDeviceDestroy(long dev);
+    native void nDeviceSetConfig(long dev, int param, int value);
+    native int nContextGetUserMessage(long con, int[] data);
+    native String nContextGetErrorMessage(long con);
+    native int  nContextPeekMessage(long con, int[] subID);
+    native void nContextInitToClient(long con);
+    native void nContextDeinitToClient(long con);
+
+    static private int sNative = -1;
+    static private int sSdkVersion = -1;
+    static private boolean useIOlib = false;
+    static private boolean useNative;
+
+    /*
+     * Context creation flag that specifies a normal context.
+     * RenderScript Support lib only support normal context.
+     */
+    public static final int CREATE_FLAG_NONE = 0x0000;
+
+    int getDispatchAPILevel() {
+        return mDispatchAPILevel;
+    }
+
+    boolean isUseNative() {
+        return useNative;
+    }
+    /*
+     * Detect the bitness of the VM to allow FieldPacker and generated code to do the right thing.
+     */
+    static native int rsnSystemGetPointerSize();
+    static int sPointerSize;
+    static public int getPointerSize() {
+        // We provide an accessor rather than making the data item public for two reasons.
+        // 1) Prevents anyone outside this class from writing the data item.
+        // 2) Prevents anyone outside this class from reading the data item unless a class
+        //    instance has been created (ensuring the data item has been initialized).
+        // DISCLAIMER: Reflection can circumvent these preventive measures.
+        synchronized(lock) {
+            if (!sInitialized)
+                throw new RSInvalidStateException("Calling getPointerSize() before any RenderScript instantiated");
+        }
+        return sPointerSize;
+    }
+
+    /**
+     * Determines whether or not we should be thunking into the native
+     * RenderScript layer or actually using the compatibility library.
+     */
+    static private boolean setupNative(int sdkVersion, Context ctx) {
+        // if targetSdkVersion is higher than the device api version, always use compat mode.
+        // Workaround for KK
+        if (android.os.Build.VERSION.SDK_INT < sdkVersion &&
+            android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
+            sNative = 0;
+        }
+
+        if (sNative == -1) {
+
+            // get the value of the debug.rs.forcecompat property
+            int forcecompat = 0;
+            try {
+                Class<?> sysprop = Class.forName("android.os.SystemProperties");
+                Class[] signature = {String.class, Integer.TYPE};
+                Method getint = sysprop.getDeclaredMethod("getInt", signature);
+                Object[] args = {"debug.rs.forcecompat", new Integer(0)};
+                forcecompat = ((java.lang.Integer)getint.invoke(null, args)).intValue();
+            } catch (Exception e) {
+
+            }
+
+            if ((android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
+                     && forcecompat == 0) {
+                sNative = 1;
+            } else {
+                sNative = 0;
+            }
+
+
+            if (sNative == 1) {
+                // Workarounds that may disable thunking go here
+                ApplicationInfo info;
+                try {
+                    info = ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(),
+                                                                      PackageManager.GET_META_DATA);
+                } catch (PackageManager.NameNotFoundException e) {
+                    // assume no workarounds needed
+                    return true;
+                }
+                long minorVersion = 0;
+
+                // load minorID from reflection
+                try {
+                    Class<?> javaRS = Class.forName("android.renderscript.RenderScript");
+                    Method getMinorID = javaRS.getDeclaredMethod("getMinorID");
+                    minorVersion = ((java.lang.Long)getMinorID.invoke(null)).longValue();
+                } catch (Exception e) {
+                    // minor version remains 0 on devices with no possible WARs
+                }
+
+                if (info.metaData != null) {
+                    // asynchronous teardown: minor version 1+
+                    if (info.metaData.getBoolean("androidx.renderscript.EnableAsyncTeardown") == true) {
+                        if (minorVersion == 0) {
+                            sNative = 0;
+                        }
+                    }
+
+                    // blur issues on some drivers with 4.4
+                    if (info.metaData.getBoolean("androidx.renderscript.EnableBlurWorkaround") == true) {
+                        if (android.os.Build.VERSION.SDK_INT <= 19) {
+                            //android.util.Log.e("rs", "war on");
+                            sNative = 0;
+                        }
+                    }
+                }
+                // end of workarounds
+            }
+        }
+
+        if (sNative == 1) {
+            // check against the blacklist
+            if (mBlackList.length() > 0) {
+                String deviceInfo = '(' +
+                                    android.os.Build.MANUFACTURER +
+                                    ':' +
+                                    android.os.Build.PRODUCT +
+                                    ':' +
+                                    android.os.Build.MODEL +
+                                    ')';
+                if (mBlackList.contains(deviceInfo)) {
+                    sNative = 0;
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Name of the file that holds the object cache.
+     */
+    private static final String CACHE_PATH = "com.android.renderscript.cache";
+    static String mCachePath;
+
+     /**
+     * Sets the directory to use as a persistent storage for the
+     * renderscript object file cache.
+     *
+     * @hide
+     * @param cacheDir A directory the current process can write to
+     */
+    public static void setupDiskCache(File cacheDir) {
+        File f = new File(cacheDir, CACHE_PATH);
+        mCachePath = f.getAbsolutePath();
+        f.mkdirs();
+    }
+
+    /**
+     * ContextType specifies the specific type of context to be created.
+     *
+     */
+    public enum ContextType {
+        /**
+         * NORMAL context, this is the default and what shipping apps should
+         * use.
+         */
+        NORMAL (0),
+
+        /**
+         * DEBUG context, perform extra runtime checks to validate the
+         * kernels and APIs are being used as intended.  Get and SetElementAt
+         * will be bounds checked in this mode.
+         */
+        DEBUG (1),
+
+        /**
+         * PROFILE context, Intended to be used once the first time an
+         * application is run on a new device.  This mode allows the runtime to
+         * do additional testing and performance tuning.
+         */
+        PROFILE (2);
+
+        int mID;
+        ContextType(int id) {
+            mID = id;
+        }
+    }
+
+    ContextType mContextType;
+    // Methods below are wrapped to protect the non-threadsafe
+    // lockless fifo.
+
+    native long  rsnContextCreate(long dev, int ver, int sdkVer, int contextType, String nativeLibDir);
+    synchronized long nContextCreate(long dev, int ver, int sdkVer, int contextType, String nativeLibDir) {
+        return rsnContextCreate(dev, ver, sdkVer, contextType, nativeLibDir);
+    }
+    native void rsnContextDestroy(long con);
+    synchronized void nContextDestroy() {
+        validate();
+
+        // take teardown lock
+        // teardown lock can only be taken when no objects are being destroyed
+        ReentrantReadWriteLock.WriteLock wlock = mRWLock.writeLock();
+        wlock.lock();
+
+        long curCon = mContext;
+        // context is considered dead as of this point
+        mContext = 0;
+
+        wlock.unlock();
+        rsnContextDestroy(curCon);
+    }
+    native void rsnContextSetPriority(long con, int p);
+    synchronized void nContextSetPriority(int p) {
+        validate();
+        rsnContextSetPriority(mContext, p);
+    }
+    native void rsnContextDump(long con, int bits);
+    synchronized void nContextDump(int bits) {
+        validate();
+        rsnContextDump(mContext, bits);
+    }
+    native void rsnContextFinish(long con);
+    synchronized void nContextFinish() {
+        validate();
+        rsnContextFinish(mContext);
+    }
+
+    native void rsnContextSendMessage(long con, int id, int[] data);
+    synchronized void nContextSendMessage(int id, int[] data) {
+        validate();
+        rsnContextSendMessage(mContext, id, data);
+    }
+
+    // nObjDestroy is explicitly _not_ synchronous to prevent crashes in finalizers
+    native void rsnObjDestroy(long con, long id);
+    void nObjDestroy(long id) {
+        // There is a race condition here.  The calling code may be run
+        // by the gc while teardown is occuring.  This protects againts
+        // deleting dead objects.
+        if (mContext != 0) {
+            rsnObjDestroy(mContext, id);
+        }
+    }
+
+    native long  rsnElementCreate(long con, long type, int kind, boolean norm, int vecSize);
+    synchronized long nElementCreate(long type, int kind, boolean norm, int vecSize) {
+        validate();
+        return rsnElementCreate(mContext, type, kind, norm, vecSize);
+    }
+    native long  rsnElementCreate2(long con, long[] elements, String[] names, int[] arraySizes);
+    synchronized long nElementCreate2(long[] elements, String[] names, int[] arraySizes) {
+        validate();
+        return rsnElementCreate2(mContext, elements, names, arraySizes);
+    }
+    native void rsnElementGetNativeData(long con, long id, int[] elementData);
+    synchronized void nElementGetNativeData(long id, int[] elementData) {
+        validate();
+        rsnElementGetNativeData(mContext, id, elementData);
+    }
+    native void rsnElementGetSubElements(long con, long id,
+                                         long[] IDs, String[] names, int[] arraySizes);
+    synchronized void nElementGetSubElements(long id, long[] IDs, String[] names, int[] arraySizes) {
+        validate();
+        rsnElementGetSubElements(mContext, id, IDs, names, arraySizes);
+    }
+
+    native long rsnTypeCreate(long con, long eid, int x, int y, int z, boolean mips, boolean faces, int yuv);
+    synchronized long nTypeCreate(long eid, int x, int y, int z, boolean mips, boolean faces, int yuv) {
+        validate();
+        return rsnTypeCreate(mContext, eid, x, y, z, mips, faces, yuv);
+    }
+
+    native void rsnTypeGetNativeData(long con, long id, long[] typeData);
+    synchronized void nTypeGetNativeData(long id, long[] typeData) {
+        validate();
+        rsnTypeGetNativeData(mContext, id, typeData);
+    }
+
+    native long  rsnAllocationCreateTyped(long con, long type, int mip, int usage, long pointer);
+    synchronized long nAllocationCreateTyped(long type, int mip, int usage, long pointer) {
+        validate();
+        return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
+    }
+    native long  rsnAllocationCreateFromBitmap(long con, long type, int mip, Bitmap bmp, int usage);
+    synchronized long nAllocationCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
+        validate();
+        return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
+    }
+
+    native long  rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, Bitmap bmp, int usage);
+    synchronized long nAllocationCreateBitmapBackedAllocation(long type, int mip, Bitmap bmp, int usage) {
+        validate();
+        return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp, usage);
+    }
+
+
+    native long  rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, Bitmap bmp, int usage);
+    synchronized long nAllocationCubeCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
+        validate();
+        return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
+    }
+    native long  rsnAllocationCreateBitmapRef(long con, long type, Bitmap bmp);
+    synchronized long nAllocationCreateBitmapRef(long type, Bitmap bmp) {
+        validate();
+        return rsnAllocationCreateBitmapRef(mContext, type, bmp);
+    }
+    native long  rsnAllocationCreateFromAssetStream(long con, int mips, int assetStream, int usage);
+    synchronized long nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
+        validate();
+        return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
+    }
+
+    native void  rsnAllocationCopyToBitmap(long con, long alloc, Bitmap bmp);
+    synchronized void nAllocationCopyToBitmap(long alloc, Bitmap bmp) {
+        validate();
+        rsnAllocationCopyToBitmap(mContext, alloc, bmp);
+    }
+
+
+    native void rsnAllocationSyncAll(long con, long alloc, int src);
+    synchronized void nAllocationSyncAll(long alloc, int src) {
+        validate();
+        rsnAllocationSyncAll(mContext, alloc, src);
+    }
+
+    native void rsnAllocationSetSurface(long con, long alloc, Surface sur);
+    synchronized void nAllocationSetSurface(long alloc, Surface sur) {
+        validate();
+        rsnAllocationSetSurface(mContext, alloc, sur);
+    }
+
+    native void rsnAllocationIoSend(long con, long alloc);
+    synchronized void nAllocationIoSend(long alloc) {
+        validate();
+        rsnAllocationIoSend(mContext, alloc);
+    }
+    native void rsnAllocationIoReceive(long con, long alloc);
+    synchronized void nAllocationIoReceive(long alloc) {
+        validate();
+        rsnAllocationIoReceive(mContext, alloc);
+    }
+    native ByteBuffer rsnAllocationGetByteBuffer(long con, long alloc, int xBytesSize, int dimY, int dimZ);
+    synchronized ByteBuffer nAllocationGetByteBuffer(long alloc, int xBytesSize, int dimY, int dimZ) {
+        validate();
+        return rsnAllocationGetByteBuffer(mContext, alloc, xBytesSize, dimY, dimZ);
+    }
+    native long rsnAllocationGetStride(long con, long alloc);
+    synchronized long nAllocationGetStride(long alloc) {
+        validate();
+        return rsnAllocationGetStride(mContext, alloc);
+    }
+
+    native void rsnAllocationGenerateMipmaps(long con, long alloc);
+    synchronized void nAllocationGenerateMipmaps(long alloc) {
+        validate();
+        rsnAllocationGenerateMipmaps(mContext, alloc);
+    }
+    native void  rsnAllocationCopyFromBitmap(long con, long alloc, Bitmap bmp);
+    synchronized void nAllocationCopyFromBitmap(long alloc, Bitmap bmp) {
+        validate();
+        rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
+    }
+
+
+    native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
+    synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
+        validate();
+        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
+    }
+
+    native void rsnAllocationElementData1D(long con,long id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes);
+    synchronized void nAllocationElementData1D(long id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes) {
+        validate();
+        rsnAllocationElementData1D(mContext, id, xoff, mip, compIdx, d, sizeBytes);
+    }
+    /*
+    native void rsnAllocationElementData(long con,long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes);
+    synchronized void nAllocationElementData(long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes) {
+        validate();
+        rsnAllocationElementData(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
+    }
+    */
+
+    native void rsnAllocationData2D(long con,
+                                    long dstAlloc, int dstXoff, int dstYoff,
+                                    int dstMip, int dstFace,
+                                    int width, int height,
+                                    long srcAlloc, int srcXoff, int srcYoff,
+                                    int srcMip, int srcFace);
+    synchronized void nAllocationData2D(long dstAlloc, int dstXoff, int dstYoff,
+                                        int dstMip, int dstFace,
+                                        int width, int height,
+                                        long srcAlloc, int srcXoff, int srcYoff,
+                                        int srcMip, int srcFace) {
+        validate();
+        rsnAllocationData2D(mContext,
+                            dstAlloc, dstXoff, dstYoff,
+                            dstMip, dstFace,
+                            width, height,
+                            srcAlloc, srcXoff, srcYoff,
+                            srcMip, srcFace);
+    }
+
+    native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face,
+                                    int w, int h, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
+    synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face,
+                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
+        validate();
+        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
+    }
+
+    native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face, Bitmap b);
+    synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face, Bitmap b) {
+        validate();
+        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, b);
+    }
+
+    native void rsnAllocationData3D(long con,
+                                    long dstAlloc, int dstXoff, int dstYoff, int dstZoff,
+                                    int dstMip,
+                                    int width, int height, int depth,
+                                    long srcAlloc, int srcXoff, int srcYoff, int srcZoff,
+                                    int srcMip);
+    synchronized void nAllocationData3D(long dstAlloc, int dstXoff, int dstYoff, int dstZoff,
+                                        int dstMip,
+                                        int width, int height, int depth,
+                                        long srcAlloc, int srcXoff, int srcYoff, int srcZoff,
+                                        int srcMip) {
+        validate();
+        rsnAllocationData3D(mContext,
+                            dstAlloc, dstXoff, dstYoff, dstZoff,
+                            dstMip, width, height, depth,
+                            srcAlloc, srcXoff, srcYoff, srcZoff, srcMip);
+    }
+
+
+    native void rsnAllocationData3D(long con, long id, int xoff, int yoff, int zoff, int mip,
+                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
+    synchronized void nAllocationData3D(long id, int xoff, int yoff, int zoff, int mip,
+                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
+        validate();
+        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes,
+                            dt.mID, mSize, usePadding);
+    }
+
+    native void rsnAllocationRead(long con, long id, Object d, int dt, int mSize, boolean usePadding);
+    synchronized void nAllocationRead(long id, Object d, Element.DataType dt, int mSize, boolean usePadding) {
+        validate();
+        rsnAllocationRead(mContext, id, d, dt.mID, mSize, usePadding);
+    }
+
+    native void rsnAllocationRead1D(long con, long id, int off, int mip, int count, Object d,
+                                    int sizeBytes, int dt, int mSize, boolean usePadding);
+    synchronized void nAllocationRead1D(long id, int off, int mip, int count, Object d,
+                                        int sizeBytes, Element.DataType dt, int mSize, boolean usePadding) {
+        validate();
+        rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
+    }
+
+    /*
+    native void rsnAllocationElementRead(long con,long id, int xoff, int yoff, int zoff,
+                                         int mip, int compIdx, byte[] d, int sizeBytes);
+    synchronized void nAllocationElementRead(long id, int xoff, int yoff, int zoff,
+                                             int mip, int compIdx, byte[] d, int sizeBytes) {
+        validate();
+        rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
+    }
+    */
+
+    native void rsnAllocationRead2D(long con, long id, int xoff, int yoff, int mip, int face,
+                                    int w, int h, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
+    synchronized void nAllocationRead2D(long id, int xoff, int yoff, int mip, int face,
+                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
+        validate();
+        rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
+    }
+
+    /*
+    native void rsnAllocationRead3D(long con, long id, int xoff, int yoff, int zoff, int mip,
+                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
+    synchronized void nAllocationRead3D(long id, int xoff, int yoff, int zoff, int mip,
+                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
+        validate();
+        rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID, mSize, usePadding);
+    }
+    */
+
+    native long  rsnAllocationGetType(long con, long id);
+    synchronized long nAllocationGetType(long id) {
+        validate();
+        return rsnAllocationGetType(mContext, id);
+    }
+
+    native void rsnAllocationResize1D(long con, long id, int dimX);
+    synchronized void nAllocationResize1D(long id, int dimX) {
+        validate();
+        rsnAllocationResize1D(mContext, id, dimX);
+    }
+    native void rsnAllocationResize2D(long con, long id, int dimX, int dimY);
+    synchronized void nAllocationResize2D(long id, int dimX, int dimY) {
+        validate();
+        rsnAllocationResize2D(mContext, id, dimX, dimY);
+    }
+
+    native void rsnScriptBindAllocation(long con, long script, long alloc, int slot, boolean mUseInc);
+    synchronized void nScriptBindAllocation(long script, long alloc, int slot, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptBindAllocation(curCon, script, alloc, slot, mUseInc);
+    }
+    native void rsnScriptSetTimeZone(long con, long script, byte[] timeZone, boolean mUseInc);
+    synchronized void nScriptSetTimeZone(long script, byte[] timeZone, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptSetTimeZone(curCon, script, timeZone, mUseInc);
+    }
+    native void rsnScriptInvoke(long con, long id, int slot, boolean mUseInc);
+    synchronized void nScriptInvoke(long id, int slot, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptInvoke(curCon, id, slot, mUseInc);
+    }
+    native void rsnScriptForEach(long con, long incCon, long id, int slot, long ain, long aout, byte[] params, boolean mUseInc);
+    native void rsnScriptForEach(long con, long incCon, long id, int slot, long ain, long aout, boolean mUseInc);
+    native void rsnScriptForEachClipped(long con, long incCon, long id, int slot, long ain, long aout, byte[] params,
+                                        int xstart, int xend, int ystart, int yend, int zstart, int zend, boolean mUseInc);
+    native void rsnScriptForEachClipped(long con, long incCon, long id, int slot, long ain, long aout,
+                                        int xstart, int xend, int ystart, int yend, int zstart, int zend, boolean mUseInc);
+    synchronized void nScriptForEach(long id, int slot, long ain, long aout, byte[] params, boolean mUseInc) {
+        validate();
+        if (params == null) {
+            rsnScriptForEach(mContext, mIncCon, id, slot, ain, aout, mUseInc);
+        } else {
+            rsnScriptForEach(mContext, mIncCon, id, slot, ain, aout, params, mUseInc);
+        }
+    }
+
+    synchronized void nScriptForEachClipped(long id, int slot, long ain, long aout, byte[] params,
+                                            int xstart, int xend, int ystart, int yend, int zstart, int zend, boolean mUseInc) {
+        validate();
+        if (params == null) {
+            rsnScriptForEachClipped(mContext, mIncCon, id, slot, ain, aout, xstart, xend, ystart, yend, zstart, zend, mUseInc);
+        } else {
+            rsnScriptForEachClipped(mContext, mIncCon, id, slot, ain, aout, params, xstart, xend, ystart, yend, zstart, zend, mUseInc);
+        }
+    }
+
+    native void rsnScriptForEach(long con, long id, int slot, long[] ains,
+                                 long aout, byte[] params, int[] limits);
+
+    synchronized void nScriptForEach(long id, int slot, long[] ains, long aout,
+                                     byte[] params, int[] limits) {
+        if (!mEnableMultiInput) {
+            Log.e(LOG_TAG, "Multi-input kernels are not supported, please change targetSdkVersion to >= 23");
+            throw new RSRuntimeException("Multi-input kernels are not supported before API 23)");
+        }
+        validate();
+        rsnScriptForEach(mContext, id, slot, ains, aout, params, limits);
+    }
+
+    native void rsnScriptReduce(long con, long id, int slot, long[] ains,
+                                long aout, int[] limits);
+    synchronized void nScriptReduce(long id, int slot, long ains[], long aout,
+                                    int[] limits) {
+        validate();
+        rsnScriptReduce(mContext, id, slot, ains, aout, limits);
+    }
+
+    native void rsnScriptInvokeV(long con, long id, int slot, byte[] params, boolean mUseInc);
+    synchronized void nScriptInvokeV(long id, int slot, byte[] params, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptInvokeV(curCon, id, slot, params, mUseInc);
+    }
+    native void rsnScriptSetVarI(long con, long id, int slot, int val, boolean mUseInc);
+    synchronized void nScriptSetVarI(long id, int slot, int val, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptSetVarI(curCon, id, slot, val, mUseInc);
+    }
+    native void rsnScriptSetVarJ(long con, long id, int slot, long val, boolean mUseInc);
+    synchronized void nScriptSetVarJ(long id, int slot, long val, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptSetVarJ(curCon, id, slot, val, mUseInc);
+    }
+    native void rsnScriptSetVarF(long con, long id, int slot, float val, boolean mUseInc);
+    synchronized void nScriptSetVarF(long id, int slot, float val, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptSetVarF(curCon, id, slot, val, mUseInc);
+    }
+    native void rsnScriptSetVarD(long con, long id, int slot, double val, boolean mUseInc);
+    synchronized void nScriptSetVarD(long id, int slot, double val, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptSetVarD(curCon, id, slot, val, mUseInc);
+    }
+    native void rsnScriptSetVarV(long con, long id, int slot, byte[] val, boolean mUseInc);
+    synchronized void nScriptSetVarV(long id, int slot, byte[] val, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptSetVarV(curCon, id, slot, val, mUseInc);
+    }
+    native void rsnScriptSetVarVE(long con, long id, int slot, byte[] val,
+                                  long e, int[] dims, boolean mUseInc);
+    synchronized void nScriptSetVarVE(long id, int slot, byte[] val,
+                                      long e, int[] dims, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptSetVarVE(curCon, id, slot, val, e, dims, mUseInc);
+    }
+    native void rsnScriptSetVarObj(long con, long id, int slot, long val, boolean mUseInc);
+    synchronized void nScriptSetVarObj(long id, int slot, long val, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        rsnScriptSetVarObj(curCon, id, slot, val, mUseInc);
+    }
+
+    native long  rsnScriptCCreate(long con, String resName, String cacheDir,
+                                 byte[] script, int length);
+    synchronized long nScriptCCreate(String resName, String cacheDir, byte[] script, int length) {
+        validate();
+        return rsnScriptCCreate(mContext, resName, cacheDir, script, length);
+    }
+
+    native long  rsnScriptIntrinsicCreate(long con, int id, long eid, boolean mUseInc);
+    synchronized long nScriptIntrinsicCreate(int id, long eid, boolean mUseInc) {
+        validate();
+        if (mUseInc) {
+            if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
+                Log.e(LOG_TAG, "Incremental Intrinsics are not supported, please change targetSdkVersion to >= 21");
+                throw new RSRuntimeException("Incremental Intrinsics are not supported before Lollipop (API 21)");
+            }
+
+            if (!mIncLoaded) {
+                try {
+                    System.loadLibrary("RSSupport");
+                } catch (UnsatisfiedLinkError e) {
+                    Log.e(LOG_TAG, "Error loading RS Compat library for Incremental Intrinsic Support: " + e);
+                    throw new RSRuntimeException("Error loading RS Compat library for Incremental Intrinsic Support: " + e);
+                }
+                if (!nIncLoadSO(SUPPORT_LIB_API, mNativeLibDir + "/libRSSupport.so")) {
+                    throw new RSRuntimeException("Error loading libRSSupport library for Incremental Intrinsic Support");
+                }
+                mIncLoaded = true;
+            }
+            if (mIncCon == 0) {
+                //Create a dummy compat context (synchronous).
+                long device = nIncDeviceCreate();
+                mIncCon = nIncContextCreate(device, 0, 0, 0);
+            }
+            return rsnScriptIntrinsicCreate(mIncCon, id, eid, mUseInc);
+        } else {
+            return rsnScriptIntrinsicCreate(mContext, id, eid, mUseInc);
+        }
+    }
+
+    native long  rsnScriptKernelIDCreate(long con, long sid, int slot, int sig, boolean mUseInc);
+    synchronized long nScriptKernelIDCreate(long sid, int slot, int sig, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        return rsnScriptKernelIDCreate(curCon, sid, slot, sig, mUseInc);
+    }
+
+    native long  rsnScriptInvokeIDCreate(long con, long sid, int slot);
+    synchronized long nScriptInvokeIDCreate(long sid, int slot) {
+        validate();
+        return rsnScriptInvokeIDCreate(mContext, sid, slot);
+    }
+
+    native long  rsnScriptFieldIDCreate(long con, long sid, int slot, boolean mUseInc);
+    synchronized long nScriptFieldIDCreate(long sid, int slot, boolean mUseInc) {
+        validate();
+        long curCon = mContext;
+        if (mUseInc) {
+            curCon = mIncCon;
+        }
+        return rsnScriptFieldIDCreate(curCon, sid, slot, mUseInc);
+    }
+
+    native long  rsnScriptGroupCreate(long con, long[] kernels, long[] src, long[] dstk, long[] dstf, long[] types);
+    synchronized long nScriptGroupCreate(long[] kernels, long[] src, long[] dstk, long[] dstf, long[] types) {
+        validate();
+        return rsnScriptGroupCreate(mContext, kernels, src, dstk, dstf, types);
+    }
+
+    native void rsnScriptGroupSetInput(long con, long group, long kernel, long alloc);
+    synchronized void nScriptGroupSetInput(long group, long kernel, long alloc) {
+        validate();
+        rsnScriptGroupSetInput(mContext, group, kernel, alloc);
+    }
+
+    native void rsnScriptGroupSetOutput(long con, long group, long kernel, long alloc);
+    synchronized void nScriptGroupSetOutput(long group, long kernel, long alloc) {
+        validate();
+        rsnScriptGroupSetOutput(mContext, group, kernel, alloc);
+    }
+
+    native void rsnScriptGroupExecute(long con, long group);
+    synchronized void nScriptGroupExecute(long group) {
+        validate();
+        rsnScriptGroupExecute(mContext, group);
+    }
+
+    native long  rsnSamplerCreate(long con, int magFilter, int minFilter,
+                                 int wrapS, int wrapT, int wrapR, float aniso);
+    synchronized long nSamplerCreate(int magFilter, int minFilter,
+                                 int wrapS, int wrapT, int wrapR, float aniso) {
+        validate();
+        return rsnSamplerCreate(mContext, magFilter, minFilter, wrapS, wrapT, wrapR, aniso);
+    }
+
+// entry points for ScriptGroup2
+    native long rsnClosureCreate(long con, long kernelID, long returnValue,
+        long[] fieldIDs, long[] values, int[] sizes, long[] depClosures,
+        long[] depFieldIDs);
+    synchronized long nClosureCreate(long kernelID, long returnValue,
+        long[] fieldIDs, long[] values, int[] sizes, long[] depClosures,
+        long[] depFieldIDs) {
+      validate();
+      long c = rsnClosureCreate(mContext, kernelID, returnValue, fieldIDs, values,
+          sizes, depClosures, depFieldIDs);
+      if (c == 0) {
+          throw new RSRuntimeException("Failed creating closure.");
+      }
+      return c;
+    }
+
+    native long rsnInvokeClosureCreate(long con, long invokeID, byte[] params,
+        long[] fieldIDs, long[] values, int[] sizes);
+    synchronized long nInvokeClosureCreate(long invokeID, byte[] params,
+        long[] fieldIDs, long[] values, int[] sizes) {
+      validate();
+      long c = rsnInvokeClosureCreate(mContext, invokeID, params, fieldIDs,
+          values, sizes);
+      if (c == 0) {
+          throw new RSRuntimeException("Failed creating closure.");
+      }
+      return c;
+    }
+
+    native void rsnClosureSetArg(long con, long closureID, int index,
+      long value, int size);
+    synchronized void nClosureSetArg(long closureID, int index, long value,
+        int size) {
+      validate();
+      rsnClosureSetArg(mContext, closureID, index, value, size);
+    }
+
+    native void rsnClosureSetGlobal(long con, long closureID, long fieldID,
+        long value, int size);
+    // Does this have to be synchronized?
+    synchronized void nClosureSetGlobal(long closureID, long fieldID,
+        long value, int size) {
+      validate(); // TODO: is this necessary?
+      rsnClosureSetGlobal(mContext, closureID, fieldID, value, size);
+    }
+
+    native long rsnScriptGroup2Create(long con, String name, String cachePath,
+                                      long[] closures);
+    synchronized long nScriptGroup2Create(String name, String cachePath,
+                                          long[] closures) {
+      validate();
+      return rsnScriptGroup2Create(mContext, name, cachePath, closures);
+    }
+
+    native void rsnScriptGroup2Execute(long con, long groupID);
+    synchronized void nScriptGroup2Execute(long groupID) {
+      validate();
+      rsnScriptGroup2Execute(mContext, groupID);
+    }
+
+    native void rsnScriptIntrinsicBLAS_Single(long con, long incCon, long id, int func, int TransA,
+                                              int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                              float alpha, long A, long B, float beta, long C, int incX, int incY,
+                                              int KL, int KU, boolean mUseInc);
+    synchronized void nScriptIntrinsicBLAS_Single(long id, int func, int TransA,
+                                                  int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                                  float alpha, long A, long B, float beta, long C, int incX, int incY,
+                                                  int KL, int KU, boolean mUseInc) {
+        validate();
+        rsnScriptIntrinsicBLAS_Single(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alpha, A, B, beta, C, incX, incY, KL, KU, mUseInc);
+    }
+
+    native void rsnScriptIntrinsicBLAS_Double(long con, long incCon, long id, int func, int TransA,
+                                              int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                              double alpha, long A, long B, double beta, long C, int incX, int incY,
+                                              int KL, int KU, boolean mUseInc);
+    synchronized void nScriptIntrinsicBLAS_Double(long id, int func, int TransA,
+                                                  int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                                  double alpha, long A, long B, double beta, long C, int incX, int incY,
+                                                  int KL, int KU, boolean mUseInc) {
+        validate();
+        rsnScriptIntrinsicBLAS_Double(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alpha, A, B, beta, C, incX, incY, KL, KU, mUseInc);
+    }
+
+    native void rsnScriptIntrinsicBLAS_Complex(long con, long incCon, long id, int func, int TransA,
+                                               int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                               float alphaX, float alphaY, long A, long B, float betaX, float betaY, long C, int incX, int incY,
+                                               int KL, int KU, boolean mUseInc);
+    synchronized void nScriptIntrinsicBLAS_Complex(long id, int func, int TransA,
+                                                   int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                                   float alphaX, float alphaY, long A, long B, float betaX, float betaY, long C, int incX, int incY,
+                                                   int KL, int KU, boolean mUseInc) {
+        validate();
+        rsnScriptIntrinsicBLAS_Complex(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alphaX, alphaY, A, B, betaX, betaY, C, incX, incY, KL, KU, mUseInc);
+    }
+
+    native void rsnScriptIntrinsicBLAS_Z(long con, long incCon, long id, int func, int TransA,
+                                         int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                         double alphaX, double alphaY, long A, long B, double betaX, double betaY, long C, int incX, int incY,
+                                         int KL, int KU, boolean mUseInc);
+    synchronized void nScriptIntrinsicBLAS_Z(long id, int func, int TransA,
+                                             int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                             double alphaX, double alphaY, long A, long B, double betaX, double betaY, long C, int incX, int incY,
+                                             int KL, int KU, boolean mUseInc) {
+        validate();
+        rsnScriptIntrinsicBLAS_Z(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alphaX, alphaY, A, B, betaX, betaY, C, incX, incY, KL, KU, mUseInc);
+    }
+
+    native void rsnScriptIntrinsicBLAS_BNNM(long con, long incCon, long id, int M, int N, int K,
+                                             long A, int a_offset, long B, int b_offset, long C, int c_offset,
+                                             int c_mult_int, boolean mUseInc);
+    synchronized void nScriptIntrinsicBLAS_BNNM(long id, int M, int N, int K,
+                                             long A, int a_offset, long B, int b_offset, long C, int c_offset,
+                                             int c_mult_int, boolean mUseInc) {
+        validate();
+        rsnScriptIntrinsicBLAS_BNNM(mContext, mIncCon, id, M, N, K, A, a_offset, B, b_offset, C, c_offset, c_mult_int, mUseInc);
+    }
+
+// Additional Entry points For inc libRSSupport
+
+    native boolean nIncLoadSO(int deviceApi, String libPath);
+    native long nIncDeviceCreate();
+    native void nIncDeviceDestroy(long dev);
+    // Methods below are wrapped to protect the non-threadsafe
+    // lockless fifo.
+    native long  rsnIncContextCreate(long dev, int ver, int sdkVer, int contextType);
+    synchronized long nIncContextCreate(long dev, int ver, int sdkVer, int contextType) {
+        return rsnIncContextCreate(dev, ver, sdkVer, contextType);
+    }
+    native void rsnIncContextDestroy(long con);
+    synchronized void nIncContextDestroy() {
+        validate();
+
+        // take teardown lock
+        // teardown lock can only be taken when no objects are being destroyed
+        ReentrantReadWriteLock.WriteLock wlock = mRWLock.writeLock();
+        wlock.lock();
+
+        long curCon = mIncCon;
+        // context is considered dead as of this point
+        mIncCon = 0;
+
+        wlock.unlock();
+        rsnIncContextDestroy(curCon);
+    }
+
+    native void rsnIncContextFinish(long con);
+    synchronized void nIncContextFinish() {
+        validate();
+        rsnIncContextFinish(mIncCon);
+    }
+
+    native void rsnIncObjDestroy(long con, long id);
+    void nIncObjDestroy(long id) {
+        // There is a race condition here.  The calling code may be run
+        // by the gc while teardown is occuring.  This protects againts
+        // deleting dead objects.
+        if (mIncCon != 0) {
+            rsnIncObjDestroy(mIncCon, id);
+        }
+    }
+    native long  rsnIncElementCreate(long con, long type, int kind, boolean norm, int vecSize);
+    synchronized long nIncElementCreate(long type, int kind, boolean norm, int vecSize) {
+        validate();
+        return rsnIncElementCreate(mIncCon, type, kind, norm, vecSize);
+    }
+    native long rsnIncTypeCreate(long con, long eid, int x, int y, int z, boolean mips, boolean faces, int yuv);
+    synchronized long nIncTypeCreate(long eid, int x, int y, int z, boolean mips, boolean faces, int yuv) {
+        validate();
+        return rsnIncTypeCreate(mIncCon, eid, x, y, z, mips, faces, yuv);
+    }
+    native long  rsnIncAllocationCreateTyped(long con, long incCon, long alloc, long type, int xBytesSize);
+    synchronized long nIncAllocationCreateTyped(long alloc, long type, int xBytesSize) {
+        validate();
+        return rsnIncAllocationCreateTyped(mContext, mIncCon, alloc, type, xBytesSize);
+    }
+
+    long     mContext;
+    private boolean mDestroyed = false;
+    //Dummy device & context for Inc Support Lib
+    long     mIncCon;
+    //indicator of whether inc support lib has been loaded or not.
+    boolean  mIncLoaded;
+    ReentrantReadWriteLock mRWLock;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    MessageThread mMessageThread;
+
+    Element mElement_U8;
+    Element mElement_I8;
+    Element mElement_U16;
+    Element mElement_I16;
+    Element mElement_U32;
+    Element mElement_I32;
+    Element mElement_U64;
+    Element mElement_I64;
+    Element mElement_F32;
+    Element mElement_F64;
+    Element mElement_BOOLEAN;
+
+    Element mElement_ELEMENT;
+    Element mElement_TYPE;
+    Element mElement_ALLOCATION;
+    Element mElement_SAMPLER;
+    Element mElement_SCRIPT;
+
+    Element mElement_A_8;
+    Element mElement_RGB_565;
+    Element mElement_RGB_888;
+    Element mElement_RGBA_5551;
+    Element mElement_RGBA_4444;
+    Element mElement_RGBA_8888;
+
+    Element mElement_FLOAT_2;
+    Element mElement_FLOAT_3;
+    Element mElement_FLOAT_4;
+
+    Element mElement_DOUBLE_2;
+    Element mElement_DOUBLE_3;
+    Element mElement_DOUBLE_4;
+
+    Element mElement_UCHAR_2;
+    Element mElement_UCHAR_3;
+    Element mElement_UCHAR_4;
+
+    Element mElement_CHAR_2;
+    Element mElement_CHAR_3;
+    Element mElement_CHAR_4;
+
+    Element mElement_USHORT_2;
+    Element mElement_USHORT_3;
+    Element mElement_USHORT_4;
+
+    Element mElement_SHORT_2;
+    Element mElement_SHORT_3;
+    Element mElement_SHORT_4;
+
+    Element mElement_UINT_2;
+    Element mElement_UINT_3;
+    Element mElement_UINT_4;
+
+    Element mElement_INT_2;
+    Element mElement_INT_3;
+    Element mElement_INT_4;
+
+    Element mElement_ULONG_2;
+    Element mElement_ULONG_3;
+    Element mElement_ULONG_4;
+
+    Element mElement_LONG_2;
+    Element mElement_LONG_3;
+    Element mElement_LONG_4;
+
+    Element mElement_MATRIX_4X4;
+    Element mElement_MATRIX_3X3;
+    Element mElement_MATRIX_2X2;
+
+    Sampler mSampler_CLAMP_NEAREST;
+    Sampler mSampler_CLAMP_LINEAR;
+    Sampler mSampler_CLAMP_LINEAR_MIP_LINEAR;
+    Sampler mSampler_WRAP_NEAREST;
+    Sampler mSampler_WRAP_LINEAR;
+    Sampler mSampler_WRAP_LINEAR_MIP_LINEAR;
+    Sampler mSampler_MIRRORED_REPEAT_NEAREST;
+    Sampler mSampler_MIRRORED_REPEAT_LINEAR;
+    Sampler mSampler_MIRRORED_REPEAT_LINEAR_MIP_LINEAR;
+
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+
+    /**
+     * The base class from which an application should derive in order
+     * to receive RS messages from scripts. When a script calls {@code
+     * rsSendToClient}, the data fields will be filled, and the run
+     * method will be called on a separate thread.  This will occur
+     * some time after {@code rsSendToClient} completes in the script,
+     * as {@code rsSendToClient} is asynchronous. Message handlers are
+     * not guaranteed to have completed when {@link
+     * androidx.renderscript.RenderScript#finish} returns.
+     *
+     */
+    public static class RSMessageHandler implements Runnable {
+        protected int[] mData;
+        protected int mID;
+        protected int mLength;
+        public void run() {
+        }
+    }
+    /**
+     * If an application is expecting messages, it should set this
+     * field to an instance of {@link RSMessageHandler}.  This
+     * instance will receive all the user messages sent from {@code
+     * sendToClient} by scripts from this context.
+     *
+     */
+    RSMessageHandler mMessageCallback = null;
+
+    public void setMessageHandler(RSMessageHandler msg) {
+        mMessageCallback = msg;
+    }
+    public RSMessageHandler getMessageHandler() {
+        return mMessageCallback;
+    }
+
+    /**
+     * Place a message into the message queue to be sent back to the message
+     * handler once all previous commands have been executed.
+     *
+     * @param id
+     * @param data
+     */
+    public void sendMessage(int id, int[] data) {
+        nContextSendMessage(id, data);
+    }
+
+    /**
+     * The runtime error handler base class.  An application should derive from this class
+     * if it wishes to install an error handler.  When errors occur at runtime,
+     * the fields in this class will be filled, and the run method will be called.
+     *
+     */
+    public static class RSErrorHandler implements Runnable {
+        protected String mErrorMessage;
+        protected int mErrorNum;
+        public void run() {
+        }
+    }
+
+    /**
+     * Application Error handler.  All runtime errors will be dispatched to the
+     * instance of RSAsyncError set here.  If this field is null a
+     * {@link RSRuntimeException} will instead be thrown with details about the error.
+     * This will cause program termaination.
+     *
+     */
+    RSErrorHandler mErrorCallback = null;
+
+    public void setErrorHandler(RSErrorHandler msg) {
+        mErrorCallback = msg;
+    }
+    public RSErrorHandler getErrorHandler() {
+        return mErrorCallback;
+    }
+
+    /**
+     * RenderScript worker thread priority enumeration.  The default value is
+     * NORMAL.  Applications wishing to do background processing should set
+     * their priority to LOW to avoid starving forground processes.
+     */
+    public enum Priority {
+        LOW (Process.THREAD_PRIORITY_BACKGROUND + (5 * Process.THREAD_PRIORITY_LESS_FAVORABLE)),
+        NORMAL (Process.THREAD_PRIORITY_DISPLAY);
+
+        int mID;
+        Priority(int id) {
+            mID = id;
+        }
+    }
+
+    void validateObject(BaseObj o) {
+        if (o != null) {
+            if (o.mRS != this) {
+                throw new RSIllegalArgumentException("Attempting to use an object across contexts.");
+            }
+        }
+    }
+
+    void validate() {
+        if (mContext == 0) {
+            throw new RSInvalidStateException("Calling RS with no Context active.");
+        }
+    }
+
+    /**
+     * check if IO support lib is available.
+     */
+    boolean usingIO() {
+        return useIOlib;
+    }
+    /**
+     * Change the priority of the worker threads for this context.
+     *
+     * @param p New priority to be set.
+     */
+    public void setPriority(Priority p) {
+        validate();
+        nContextSetPriority(p.mID);
+    }
+
+    static class MessageThread extends Thread {
+        RenderScript mRS;
+        boolean mRun = true;
+        int[] mAuxData = new int[2];
+
+        static final int RS_MESSAGE_TO_CLIENT_NONE = 0;
+        static final int RS_MESSAGE_TO_CLIENT_EXCEPTION = 1;
+        static final int RS_MESSAGE_TO_CLIENT_RESIZE = 2;
+        static final int RS_MESSAGE_TO_CLIENT_ERROR = 3;
+
+        static final int RS_MESSAGE_TO_CLIENT_USER = 4;
+        static final int RS_ERROR_FATAL_DEBUG = 0x800;
+        static final int RS_ERROR_FATAL_UNKNOWN = 0x1000;
+
+        MessageThread(RenderScript rs) {
+            super("RSMessageThread");
+            mRS = rs;
+
+        }
+
+        public void run() {
+            // This function is a temporary solution.  The final solution will
+            // used typed allocations where the message id is the type indicator.
+            int[] rbuf = new int[16];
+            mRS.nContextInitToClient(mRS.mContext);
+            while(mRun) {
+                rbuf[0] = 0;
+                int msg = mRS.nContextPeekMessage(mRS.mContext, mAuxData);
+                int size = mAuxData[1];
+                int subID = mAuxData[0];
+
+                if (msg == RS_MESSAGE_TO_CLIENT_USER) {
+                    if ((size>>2) >= rbuf.length) {
+                        rbuf = new int[(size + 3) >> 2];
+                    }
+                    if (mRS.nContextGetUserMessage(mRS.mContext, rbuf) !=
+                        RS_MESSAGE_TO_CLIENT_USER) {
+                        throw new RSDriverException("Error processing message from RenderScript.");
+                    }
+
+                    if(mRS.mMessageCallback != null) {
+                        mRS.mMessageCallback.mData = rbuf;
+                        mRS.mMessageCallback.mID = subID;
+                        mRS.mMessageCallback.mLength = size;
+                        mRS.mMessageCallback.run();
+                    } else {
+                        throw new RSInvalidStateException("Received a message from the script with no message handler installed.");
+                    }
+                    continue;
+                }
+
+                if (msg == RS_MESSAGE_TO_CLIENT_ERROR) {
+                    String e = mRS.nContextGetErrorMessage(mRS.mContext);
+
+                    // Copied from java/android/renderscript/RenderScript.java
+                    // Throw RSRuntimeException under the following conditions:
+                    //
+                    // 1) It is an unknown fatal error.
+                    // 2) It is a debug fatal error, and we are not in a
+                    //    debug context.
+                    // 3) It is a debug fatal error, and we do not have an
+                    //    error callback.
+                    if (subID >= RS_ERROR_FATAL_UNKNOWN ||
+                        (subID >= RS_ERROR_FATAL_DEBUG &&
+                         (mRS.mContextType != ContextType.DEBUG ||
+                          mRS.mErrorCallback == null))) {
+                        android.util.Log.e(LOG_TAG, "fatal RS error, " + e);
+                        throw new RSRuntimeException("Fatal error " + subID + ", details: " + e);
+                    }
+
+                    if(mRS.mErrorCallback != null) {
+                        mRS.mErrorCallback.mErrorMessage = e;
+                        mRS.mErrorCallback.mErrorNum = subID;
+                        mRS.mErrorCallback.run();
+                    } else {
+                        android.util.Log.e(LOG_TAG, "non fatal RS error, " + e);
+                        // Do not throw here. In these cases, we do not have
+                        // a fatal error.
+                    }
+                    continue;
+                }
+
+                // 2: teardown.
+                // But we want to avoid starving other threads during
+                // teardown by yielding until the next line in the destructor
+                // can execute to set mRun = false
+                try {
+                    sleep(1, 0);
+                } catch(InterruptedException e) {
+                }
+            }
+            //Log.d(LOG_TAG, "MessageThread exiting.");
+        }
+    }
+
+    RenderScript(Context ctx) {
+        mContextType = ContextType.NORMAL;
+        if (ctx != null) {
+            mApplicationContext = ctx.getApplicationContext();
+            // Only set mNativeLibDir for API 9+.
+            mNativeLibDir = mApplicationContext.getApplicationInfo().nativeLibraryDir;
+        }
+        mIncCon = 0;
+        mIncLoaded = false;
+        mRWLock = new ReentrantReadWriteLock();
+    }
+
+    /**
+     * Gets the application context associated with the RenderScript context.
+     *
+     * @return The application context.
+     */
+    public final Context getApplicationContext() {
+        return mApplicationContext;
+    }
+
+    /**
+     * Create a RenderScript context.
+     *
+     * @param ctx The context.
+     * @return RenderScript
+     */
+    private static RenderScript internalCreate(Context ctx, int sdkVersion, ContextType ct, int flags) {
+        RenderScript rs = new RenderScript(ctx);
+
+        if (sSdkVersion == -1) {
+            sSdkVersion = sdkVersion;
+        } else if (sSdkVersion != sdkVersion) {
+            throw new RSRuntimeException("Can't have two contexts with different SDK versions in support lib");
+        }
+        useNative = setupNative(sSdkVersion, ctx);
+        synchronized(lock) {
+            if (sInitialized == false) {
+                try {
+                    Class<?> vm_runtime = Class.forName("dalvik.system.VMRuntime");
+                    Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime");
+                    sRuntime = get_runtime.invoke(null);
+                    Class<?> argClass = android.os.Build.VERSION.SDK_INT >= 29 ? Long.TYPE : Integer.TYPE;
+                    // The int version is (so far) always defined, but deprecated for APIs >= 29.
+                    registerNativeAllocation = vm_runtime.getDeclaredMethod("registerNativeAllocation", argClass);
+                    registerNativeFree = vm_runtime.getDeclaredMethod("registerNativeFree", argClass);
+                    sUseGCHooks = true;
+                } catch (Exception e) {
+                    Log.e(LOG_TAG, "No GC methods");
+                    sUseGCHooks = false;
+                }
+                try {
+                    // For API 9 - 22, always use the absolute path of librsjni.so
+                    // http://b/25226912
+                    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M &&
+                        rs.mNativeLibDir != null) {
+                        System.load(rs.mNativeLibDir + "/librsjni.so");
+                    } else {
+                        System.loadLibrary("rsjni");
+                    }
+                    sInitialized = true;
+                    sPointerSize = rsnSystemGetPointerSize();
+                } catch (UnsatisfiedLinkError e) {
+                    Log.e(LOG_TAG, "Error loading RS jni library: " + e);
+                    throw new RSRuntimeException("Error loading RS jni library: " + e + " Support lib API: " + SUPPORT_LIB_VERSION);
+                }
+            }
+        }
+
+        if (useNative) {
+            android.util.Log.v(LOG_TAG, "RS native mode");
+        } else {
+            android.util.Log.v(LOG_TAG, "RS compat mode");
+        }
+
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            useIOlib = true;
+        }
+
+        // The target API level used to init dispatchTable.
+        int dispatchAPI = sdkVersion;
+        if (sdkVersion < android.os.Build.VERSION.SDK_INT) {
+            // If the device API is higher than target API level, init dispatch table based on device API.
+            dispatchAPI = android.os.Build.VERSION.SDK_INT;
+        }
+
+        String rssupportPath = null;
+        // For API 9 - 22, always use the absolute path of libRSSupport.so
+        // http://b/25226912
+        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M &&
+            rs.mNativeLibDir != null) {
+            rssupportPath = rs.mNativeLibDir + "/libRSSupport.so";
+        }
+        if (!rs.nLoadSO(useNative, dispatchAPI, rssupportPath)) {
+            if (useNative) {
+                android.util.Log.v(LOG_TAG, "Unable to load libRS.so, falling back to compat mode");
+                useNative = false;
+            }
+            try {
+                if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M &&
+                    rs.mNativeLibDir != null) {
+                    System.load(rssupportPath);
+                } else {
+                    System.loadLibrary("RSSupport");
+                }
+            } catch (UnsatisfiedLinkError e) {
+                Log.e(LOG_TAG, "Error loading RS Compat library: " + e + " Support lib version: " + SUPPORT_LIB_VERSION);
+                throw new RSRuntimeException("Error loading RS Compat library: " + e + " Support lib version: " + SUPPORT_LIB_VERSION);
+            }
+            if (!rs.nLoadSO(false, dispatchAPI, rssupportPath)) {
+                Log.e(LOG_TAG, "Error loading RS Compat library: nLoadSO() failed; Support lib version: " + SUPPORT_LIB_VERSION);
+                throw new RSRuntimeException("Error loading libRSSupport library, Support lib version: " + SUPPORT_LIB_VERSION);
+            }
+        }
+
+        if (useIOlib) {
+            try {
+                System.loadLibrary("RSSupportIO");
+            } catch (UnsatisfiedLinkError e) {
+                useIOlib = false;
+            }
+            if (!useIOlib || !rs.nLoadIOSO()) {
+                android.util.Log.v(LOG_TAG, "Unable to load libRSSupportIO.so, USAGE_IO not supported");
+                useIOlib = false;
+            }
+        }
+
+        // For old APIs with dlopen bug, need to load blas lib in Java first.
+        // Only try load to blasV8 when the desired API level includes IntrinsicBLAS.
+        if (dispatchAPI >= 23) {
+            // Enable multi-input kernels only when diapatchAPI is M+.
+            rs.mEnableMultiInput = true;
+            try {
+                System.loadLibrary("blasV8");
+            } catch (UnsatisfiedLinkError e) {
+                Log.v(LOG_TAG, "Unable to load BLAS lib, ONLY BNNM will be supported: " + e);
+            }
+        }
+
+        long device = rs.nDeviceCreate();
+        rs.mContext = rs.nContextCreate(device, 0, sdkVersion, ct.mID, rs.mNativeLibDir);
+        rs.mContextType = ct;
+        rs.mContextFlags = flags;
+        rs.mContextSdkVersion = sdkVersion;
+        rs.mDispatchAPILevel = dispatchAPI;
+        if (rs.mContext == 0) {
+            throw new RSDriverException("Failed to create RS context.");
+        }
+        rs.mMessageThread = new MessageThread(rs);
+        rs.mMessageThread.start();
+        return rs;
+    }
+
+    /**
+     * Create a RenderScript context.
+     *
+     * See documentation for @create for details
+     *
+     * @param ctx The context.
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx) {
+        return create(ctx, ContextType.NORMAL);
+    }
+
+    /**
+     * calls create(ctx, ct, CREATE_FLAG_NONE)
+     *
+     * See documentation for @create for details
+     *
+     * @param ctx The context.
+     * @param ct The type of context to be created.
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx, ContextType ct) {
+        return create(ctx, ct, CREATE_FLAG_NONE);
+    }
+
+    /**
+     * Gets or creates a RenderScript context of the specified type.
+     *
+     * The returned context will be cached for future reuse within
+     * the process. When an application is finished using
+     * RenderScript it should call releaseAllContexts()
+     *
+     * A process context is a context designed for easy creation and
+     * lifecycle management.  Multiple calls to this function will
+     * return the same object provided they are called with the same
+     * options.  This allows it to be used any time a RenderScript
+     * context is needed.
+     *
+     *
+     * @param ctx The context.
+     * @param ct The type of context to be created.
+     * @param flags The OR of the CREATE_FLAG_* options desired
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx, ContextType ct, int flags) {
+        int v = ctx.getApplicationInfo().targetSdkVersion;
+        return create(ctx, v, ct, flags);
+    }
+
+    /**
+     * calls create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE)
+     *
+     * Used by the RenderScriptThunker to maintain backward compatibility.
+     *
+     * @hide
+     * @param ctx The context.
+     * @param sdkVersion The target SDK Version.
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx, int sdkVersion) {
+        return create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE);
+    }
+
+
+    /**
+     * calls create(ctx, sdkVersion, ct, CREATE_FLAG_NONE)
+     * Create a RenderScript context.
+     *
+     * @hide
+     * @param ctx The context.
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct) {
+        return create(ctx, sdkVersion, ct, CREATE_FLAG_NONE);
+    }
+
+     /**
+     * Gets or creates a RenderScript context of the specified type.
+     *
+     * @param ctx The context.
+     * @param ct The type of context to be created.
+     * @param sdkVersion The target SDK Version.
+     * @param flags The OR of the CREATE_FLAG_* options desired
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, int flags) {
+        synchronized (mProcessContextList) {
+            for (RenderScript prs : mProcessContextList) {
+                if ((prs.mContextType == ct) &&
+                    (prs.mContextFlags == flags) &&
+                    (prs.mContextSdkVersion == sdkVersion)) {
+
+                    return prs;
+                }
+            }
+
+            RenderScript prs = internalCreate(ctx, sdkVersion, ct, flags);
+            prs.mIsProcessContext = true;
+            mProcessContextList.add(prs);
+            return prs;
+        }
+    }
+
+    /**
+     *
+     * Releases all the process contexts.  This is the same as
+     * calling .destroy() on each unique context retreived with
+     * create(...). If no contexts have been created this
+     * function does nothing.
+     *
+     * Typically you call this when your application is losing focus
+     * and will not be using a context for some time.
+     *
+     * This has no effect on a context created with
+     * createMultiContext()
+     */
+    public static void releaseAllContexts() {
+        ArrayList<RenderScript> oldList;
+        synchronized (mProcessContextList) {
+            oldList = mProcessContextList;
+            mProcessContextList = new ArrayList<RenderScript>();
+        }
+
+        for (RenderScript prs : oldList) {
+            prs.mIsProcessContext = false;
+            prs.destroy();
+        }
+        oldList.clear();
+    }
+
+
+
+    /**
+     * Create a RenderScript context.
+     *
+     * This is an advanced function intended for applications which
+     * need to create more than one RenderScript context to be used
+     * at the same time.
+     *
+     * If you need a single context please use create()
+     *
+     * @param ctx The context.
+     * @return RenderScript
+     */
+    public static RenderScript createMultiContext(Context ctx, ContextType ct, int flags, int API_number) {
+        return internalCreate(ctx, API_number, ct, flags);
+    }
+
+    /**
+     * Print the currently available debugging information about the state of
+     * the RS context to the log.
+     *
+     */
+    public void contextDump() {
+        validate();
+        nContextDump(0);
+    }
+
+    /**
+     * Wait for any pending asynchronous opeations (such as copies to a RS
+     * allocation or RS script executions) to complete.
+     *
+     */
+    public void finish() {
+        nContextFinish();
+    }
+
+    private void helpDestroy() {
+        boolean shouldDestroy = false;
+        synchronized(this) {
+            if (!mDestroyed) {
+                shouldDestroy = true;
+                mDestroyed = true;
+            }
+        }
+
+        if (shouldDestroy) {
+            nContextFinish();
+            if (mIncCon != 0) {
+                nIncContextFinish();
+                nIncContextDestroy();
+                mIncCon = 0;
+            }
+            nContextDeinitToClient(mContext);
+            mMessageThread.mRun = false;
+            // Interrupt mMessageThread so it gets to see immediately that mRun is false
+            // and exit rightaway.
+            mMessageThread.interrupt();
+
+            // Wait for mMessageThread to join.  Try in a loop, in case this thread gets interrupted
+            // during the wait.  If interrupted, set the "interrupted" status of the current thread.
+            boolean hasJoined = false, interrupted = false;
+            while (!hasJoined) {
+                try {
+                    mMessageThread.join();
+                    hasJoined = true;
+                } catch (InterruptedException e) {
+                    interrupted = true;
+                }
+            }
+            if (interrupted) {
+                Log.v(LOG_TAG, "Interrupted during wait for MessageThread to join");
+                Thread.currentThread().interrupt();
+            }
+
+            nContextDestroy();
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        helpDestroy();
+        super.finalize();
+    }
+
+    /**
+     * Destroys this RenderScript context.  Once this function is called,
+     * using this context or any objects belonging to this context is
+     * illegal.
+     *
+     * This function is a NOP if the context was created
+     * with create().  Please use releaseAllContexts() to clean up
+     * contexts created with the create function.
+     */
+    public void destroy() {
+        if (mIsProcessContext) {
+            // users cannot destroy a process context
+            return;
+        }
+        validate();
+        helpDestroy();
+    }
+
+    boolean isAlive() {
+        return mContext != 0;
+    }
+
+    long safeID(BaseObj o) {
+        if(o != null) {
+            return o.getID(this);
+        }
+        return 0;
+    }
+}
diff --git a/androidx/renderscript/Sampler.java b/androidx/renderscript/Sampler.java
new file mode 100644
index 0000000..57b94d5
--- /dev/null
+++ b/androidx/renderscript/Sampler.java
@@ -0,0 +1,346 @@
+/*
+ * 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 androidx.renderscript;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.Log;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+/**
+ * Sampler object that defines how Allocations can be read as textures within a
+ * kernel. Samplers are used in conjunction with the {@code rsSample} runtime
+ * function to return values from normalized coordinates.
+ *
+ * Any Allocation used with a Sampler must have been created with {@link
+ * androidx.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE}; using a
+ * Sampler on an {@link androidx.renderscript.Allocation} that was not
+ * created with
+ * {@link androidx.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE} is
+ * undefined.
+ **/
+public class Sampler extends BaseObj {
+    public enum Value {
+        NEAREST (0),
+        LINEAR (1),
+        LINEAR_MIP_LINEAR (2),
+        LINEAR_MIP_NEAREST (5),
+        WRAP (3),
+        CLAMP (4),
+        MIRRORED_REPEAT (6);
+
+        int mID;
+        Value(int id) {
+            mID = id;
+        }
+    }
+
+    Value mMin;
+    Value mMag;
+    Value mWrapS;
+    Value mWrapT;
+    Value mWrapR;
+    float mAniso;
+
+    Sampler(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * @return minification setting for the sampler
+     */
+    public Value getMinification() {
+        return mMin;
+    }
+
+    /**
+     * @return magnification setting for the sampler
+     */
+    public Value getMagnification() {
+        return mMag;
+    }
+
+    /**
+     * @return S wrapping mode for the sampler
+     */
+    public Value getWrapS() {
+        return mWrapS;
+    }
+
+    /**
+     * @return T wrapping mode for the sampler
+     */
+    public Value getWrapT() {
+        return mWrapT;
+    }
+
+    /**
+     * @return anisotropy setting for the sampler
+     */
+    public float getAnisotropy() {
+        return mAniso;
+    }
+
+    /**
+     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
+     * clamp.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler CLAMP_NEAREST(RenderScript rs) {
+        if(rs.mSampler_CLAMP_NEAREST == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.NEAREST);
+            b.setMagnification(Value.NEAREST);
+            b.setWrapS(Value.CLAMP);
+            b.setWrapT(Value.CLAMP);
+            rs.mSampler_CLAMP_NEAREST = b.create();
+        }
+        return rs.mSampler_CLAMP_NEAREST;
+    }
+
+    /**
+     * Retrieve a sampler with min and mag set to linear and wrap modes set to
+     * clamp.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler CLAMP_LINEAR(RenderScript rs) {
+        if(rs.mSampler_CLAMP_LINEAR == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.LINEAR);
+            b.setMagnification(Value.LINEAR);
+            b.setWrapS(Value.CLAMP);
+            b.setWrapT(Value.CLAMP);
+            rs.mSampler_CLAMP_LINEAR = b.create();
+        }
+        return rs.mSampler_CLAMP_LINEAR;
+    }
+
+    /**
+     * Retrieve a sampler with mag set to linear, min linear mipmap linear, and
+     * wrap modes set to clamp.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler CLAMP_LINEAR_MIP_LINEAR(RenderScript rs) {
+        if(rs.mSampler_CLAMP_LINEAR_MIP_LINEAR == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.LINEAR_MIP_LINEAR);
+            b.setMagnification(Value.LINEAR);
+            b.setWrapS(Value.CLAMP);
+            b.setWrapT(Value.CLAMP);
+            rs.mSampler_CLAMP_LINEAR_MIP_LINEAR = b.create();
+        }
+        return rs.mSampler_CLAMP_LINEAR_MIP_LINEAR;
+    }
+
+    /**
+     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
+     * wrap.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler WRAP_NEAREST(RenderScript rs) {
+        if(rs.mSampler_WRAP_NEAREST == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.NEAREST);
+            b.setMagnification(Value.NEAREST);
+            b.setWrapS(Value.WRAP);
+            b.setWrapT(Value.WRAP);
+            rs.mSampler_WRAP_NEAREST = b.create();
+        }
+        return rs.mSampler_WRAP_NEAREST;
+    }
+
+    /**
+     * Retrieve a sampler with min and mag set to linear and wrap modes set to
+     * wrap.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler WRAP_LINEAR(RenderScript rs) {
+        if(rs.mSampler_WRAP_LINEAR == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.LINEAR);
+            b.setMagnification(Value.LINEAR);
+            b.setWrapS(Value.WRAP);
+            b.setWrapT(Value.WRAP);
+            rs.mSampler_WRAP_LINEAR = b.create();
+        }
+        return rs.mSampler_WRAP_LINEAR;
+    }
+
+    /**
+     * Retrieve a sampler with mag set to linear, min linear mipmap linear, and
+     * wrap modes set to wrap.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler WRAP_LINEAR_MIP_LINEAR(RenderScript rs) {
+        if(rs.mSampler_WRAP_LINEAR_MIP_LINEAR == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.LINEAR_MIP_LINEAR);
+            b.setMagnification(Value.LINEAR);
+            b.setWrapS(Value.WRAP);
+            b.setWrapT(Value.WRAP);
+            rs.mSampler_WRAP_LINEAR_MIP_LINEAR = b.create();
+        }
+        return rs.mSampler_WRAP_LINEAR_MIP_LINEAR;
+    }
+
+    /**
+     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
+     * mirrored repeat.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler MIRRORED_REPEAT_NEAREST(RenderScript rs) {
+        if(rs.mSampler_MIRRORED_REPEAT_NEAREST == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.NEAREST);
+            b.setMagnification(Value.NEAREST);
+            b.setWrapS(Value.MIRRORED_REPEAT);
+            b.setWrapT(Value.MIRRORED_REPEAT);
+            rs.mSampler_MIRRORED_REPEAT_NEAREST = b.create();
+        }
+        return rs.mSampler_MIRRORED_REPEAT_NEAREST;
+    }
+
+    /**
+     * Retrieve a sampler with min and mag set to linear and wrap modes set to
+     * mirrored repeat.
+     *
+     * @param rs Context to which the sampler will belong.
+     *
+     * @return Sampler
+     */
+    public static Sampler MIRRORED_REPEAT_LINEAR(RenderScript rs) {
+        if(rs.mSampler_MIRRORED_REPEAT_LINEAR == null) {
+            Builder b = new Builder(rs);
+            b.setMinification(Value.LINEAR);
+            b.setMagnification(Value.LINEAR);
+            b.setWrapS(Value.MIRRORED_REPEAT);
+            b.setWrapT(Value.MIRRORED_REPEAT);
+            rs.mSampler_MIRRORED_REPEAT_LINEAR = b.create();
+        }
+        return rs.mSampler_MIRRORED_REPEAT_LINEAR;
+    }
+
+    /**
+     * Builder for creating non-standard samplers.  This is only necessary if
+     * a Sampler with different min and mag modes is desired.
+     */
+    public static class Builder {
+        RenderScript mRS;
+        Value mMin;
+        Value mMag;
+        Value mWrapS;
+        Value mWrapT;
+        Value mWrapR;
+        float mAniso;
+
+        public Builder(RenderScript rs) {
+            mRS = rs;
+            mMin = Value.NEAREST;
+            mMag = Value.NEAREST;
+            mWrapS = Value.WRAP;
+            mWrapT = Value.WRAP;
+            mWrapR = Value.WRAP;
+            mAniso = 1.0f;
+        }
+
+        public void setMinification(Value v) {
+            if (v == Value.NEAREST ||
+                v == Value.LINEAR ||
+                v == Value.LINEAR_MIP_LINEAR ||
+                v == Value.LINEAR_MIP_NEAREST) {
+                mMin = v;
+            } else {
+                throw new IllegalArgumentException("Invalid value");
+            }
+        }
+
+        public void setMagnification(Value v) {
+            if (v == Value.NEAREST || v == Value.LINEAR) {
+                mMag = v;
+            } else {
+                throw new IllegalArgumentException("Invalid value");
+            }
+        }
+
+        public void setWrapS(Value v) {
+            if (v == Value.WRAP || v == Value.CLAMP || v == Value.MIRRORED_REPEAT) {
+                mWrapS = v;
+            } else {
+                throw new IllegalArgumentException("Invalid value");
+            }
+        }
+
+        public void setWrapT(Value v) {
+            if (v == Value.WRAP || v == Value.CLAMP || v == Value.MIRRORED_REPEAT) {
+                mWrapT = v;
+            } else {
+                throw new IllegalArgumentException("Invalid value");
+            }
+        }
+
+        public void setAnisotropy(float v) {
+            if(v >= 0.0f) {
+                mAniso = v;
+            } else {
+                throw new IllegalArgumentException("Invalid value");
+            }
+        }
+
+        public Sampler create() {
+            mRS.validate();
+            long id = mRS.nSamplerCreate(mMag.mID, mMin.mID,
+                                        mWrapS.mID, mWrapT.mID, mWrapR.mID, mAniso);
+            Sampler sampler = new Sampler(id, mRS);
+            sampler.mMin = mMin;
+            sampler.mMag = mMag;
+            sampler.mWrapS = mWrapS;
+            sampler.mWrapT = mWrapT;
+            sampler.mWrapR = mWrapR;
+            sampler.mAniso = mAniso;
+            return sampler;
+        }
+    }
+
+}
+
diff --git a/androidx/renderscript/Script.java b/androidx/renderscript/Script.java
new file mode 100644
index 0000000..49c0039
--- /dev/null
+++ b/androidx/renderscript/Script.java
@@ -0,0 +1,701 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.util.SparseArray;
+
+/**
+ * The parent class for all executable scripts. This should not be used by
+ * applications.
+ **/
+public class Script extends BaseObj {
+    /**
+     * Determine if Incremental Intrinsic Support is needed
+     *
+     */
+    private boolean mUseIncSupp;
+    protected void setIncSupp(boolean useInc) {
+        mUseIncSupp = useInc;
+    }
+    protected boolean isIncSupp() {
+        return mUseIncSupp;
+    }
+    /**
+     * An allocation for the compat context will be created when needed
+     * e.g. foreach(ain, aout), setVar(ain);
+     *
+     */
+    long getDummyAlloc(Allocation ain) {
+        long dInElement = 0;
+        long dInType = 0;
+        long dummyAlloc = 0;
+        if (ain != null) {
+            Type inType = ain.getType();
+            dInElement = inType.getElement().getDummyElement(mRS);
+            dInType = inType.getDummyType(mRS, dInElement);
+            int xBytesSize = inType.getX() * inType.getElement().getBytesSize();
+            dummyAlloc = mRS.nIncAllocationCreateTyped(ain.getID(mRS), dInType, xBytesSize);
+            ain.setIncAllocID(dummyAlloc);
+        }
+
+        return dummyAlloc;
+    }
+    /**
+     * KernelID is an identifier for a Script + root function pair. It is used
+     * as an identifier for ScriptGroup creation.
+     *
+     * This class should not be directly created. Instead use the method in the
+     * reflected or intrinsic code "getKernelID_funcname()".
+     *
+     */
+    public static final class KernelID extends BaseObj {
+        android.renderscript.Script.KernelID mN;
+        Script mScript;
+        int mSlot;
+        int mSig;
+        KernelID(long id, RenderScript rs, Script s, int slot, int sig) {
+            super(id, rs);
+            mScript = s;
+            mSlot = slot;
+            mSig = sig;
+        }
+    }
+
+    private final SparseArray<KernelID> mKIDs = new SparseArray<KernelID>();
+    /**
+     * Only to be used by generated reflected classes.
+     *
+     *
+     * @param slot
+     * @param sig
+     * @param ein
+     * @param eout
+     *
+     * @return KernelID
+     */
+    protected KernelID createKernelID(int slot, int sig, Element ein, Element eout) {
+        KernelID k = mKIDs.get(slot);
+        if (k != null) {
+            return k;
+        }
+
+        long id = mRS.nScriptKernelIDCreate(getID(mRS), slot, sig, mUseIncSupp);
+        if (id == 0) {
+            throw new RSDriverException("Failed to create KernelID");
+        }
+
+        k = new KernelID(id, mRS, this, slot, sig);
+
+        mKIDs.put(slot, k);
+        return k;
+    }
+
+    /**
+     * InvokeID is an identifier for a invoke function. It is used
+     * as an identifier for ScriptGroup creation.
+     *
+     * This class should not be directly created. Instead use the method in the
+     * reflected or intrinsic code "getInvokeID_funcname()".
+     *
+     */
+    public static final class InvokeID extends BaseObj {
+        Script mScript;
+        int mSlot;
+        InvokeID(long id, RenderScript rs, Script s, int slot) {
+            super(id, rs);
+            mScript = s;
+            mSlot = slot;
+        }
+    }
+
+    private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>();
+    /**
+     * Only to be used by generated reflected classes.
+     */
+    protected InvokeID createInvokeID(int slot) {
+        InvokeID i = mIIDs.get(slot);
+        if (i != null) {
+            return i;
+        }
+
+        long id = mRS.nScriptInvokeIDCreate(getID(mRS), slot);
+        if (id == 0) {
+            throw new RSDriverException("Failed to create KernelID");
+        }
+
+        i = new InvokeID(id, mRS, this, slot);
+        mIIDs.put(slot, i);
+        return i;
+    }
+
+    /**
+     * FieldID is an identifier for a Script + exported field pair. It is used
+     * as an identifier for ScriptGroup creation.
+     *
+     * This class should not be directly created. Instead use the method in the
+     * reflected or intrinsic code "getFieldID_funcname()".
+     *
+     */
+    public static final class FieldID extends BaseObj {
+        android.renderscript.Script.FieldID mN;
+        Script mScript;
+        int mSlot;
+        FieldID(long id, RenderScript rs, Script s, int slot) {
+            super(id, rs);
+            mScript = s;
+            mSlot = slot;
+        }
+    }
+
+    private final SparseArray<FieldID> mFIDs = new SparseArray();
+    /**
+     * Only to be used by generated reflected classes.
+     *
+     * @param slot
+     * @param e
+     *
+     * @return FieldID
+     */
+    protected FieldID createFieldID(int slot, Element e) {
+        FieldID f = mFIDs.get(slot);
+        if (f != null) {
+            return f;
+        }
+
+        long id = mRS.nScriptFieldIDCreate(getID(mRS), slot, mUseIncSupp);
+        if (id == 0) {
+            throw new RSDriverException("Failed to create FieldID");
+        }
+
+        f = new FieldID(id, mRS, this, slot);
+        mFIDs.put(slot, f);
+        return f;
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param slot
+     */
+    protected void invoke(int slot) {
+        mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param slot
+     * @param v
+     */
+    protected void invoke(int slot, FieldPacker v) {
+        if (v != null) {
+            mRS.nScriptInvokeV(getID(mRS), slot, v.getData(), mUseIncSupp);
+        } else {
+            mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
+        }
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param va
+     * @param slot
+     */
+    public void bindAllocation(Allocation va, int slot) {
+        mRS.validate();
+        if (va != null) {
+            mRS.nScriptBindAllocation(getID(mRS), va.getID(mRS), slot, mUseIncSupp);
+        } else {
+            mRS.nScriptBindAllocation(getID(mRS), 0, slot, mUseIncSupp);
+        }
+    }
+
+    public void setTimeZone(String timeZone) {
+        mRS.validate();
+        try {
+            mRS.nScriptSetTimeZone(getID(mRS), timeZone.getBytes("UTF-8"), mUseIncSupp);
+        } catch (java.io.UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param slot
+     * @param ain
+     * @param aout
+     * @param v
+     */
+    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v) {
+        if (ain == null && aout == null) {
+            throw new RSIllegalArgumentException(
+                "At least one of ain or aout is required to be non-null.");
+        }
+        long in_id = 0;
+        long out_id = 0;
+        if (ain != null) {
+            in_id = ain.getID(mRS);
+        }
+        if (aout != null) {
+            out_id = aout.getID(mRS);
+        }
+
+        byte[] params = null;
+        if (v != null) {
+            params = v.getData();
+        }
+
+        if (mUseIncSupp) {
+            long ainInc = getDummyAlloc(ain);
+            long aoutInc = getDummyAlloc(aout);
+            mRS.nScriptForEach(getID(mRS), slot, ainInc, aoutInc, params, mUseIncSupp);
+        } else {
+            mRS.nScriptForEach(getID(mRS), slot, in_id, out_id, params, mUseIncSupp);
+        }
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param slot
+     * @param ain
+     * @param aout
+     * @param v
+     * @param sc
+     */
+    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc) {
+        if (ain == null && aout == null) {
+            throw new RSIllegalArgumentException(
+                "At least one of ain or aout is required to be non-null.");
+        }
+
+        if (sc == null) {
+            forEach(slot, ain, aout, v);
+            return;
+        }
+        long in_id = 0;
+        long out_id = 0;
+        if (ain != null) {
+            in_id = ain.getID(mRS);
+        }
+        if (aout != null) {
+            out_id = aout.getID(mRS);
+        }
+
+        byte[] params = null;
+        if (v != null) {
+            params = v.getData();
+        }
+        if (mUseIncSupp) {
+            long ainInc = getDummyAlloc(ain);
+            long aoutInc = getDummyAlloc(aout);
+            mRS.nScriptForEachClipped(getID(mRS), slot, ainInc, aoutInc, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);        
+        } else {
+            mRS.nScriptForEachClipped(getID(mRS), slot, in_id, out_id, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);
+        }
+    }
+
+    Script(long id, RenderScript rs) {
+        super(id, rs);
+        mUseIncSupp = false;
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @hide
+     */
+    protected void forEach(int slot, Allocation[] ains, Allocation aout,
+                           FieldPacker v) {
+        forEach(slot, ains, aout, v, null);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @hide
+     */
+    protected void forEach(int slot, Allocation[] ains, Allocation aout,
+                           FieldPacker v, LaunchOptions sc) {
+        // TODO: Is this necessary if nScriptForEach calls validate as well?
+        mRS.validate();
+        if (ains != null) {
+            for (Allocation ain : ains) {
+                mRS.validateObject(ain);
+            }
+        }
+        mRS.validateObject(aout);
+
+        if (ains == null && aout == null) {
+            throw new RSIllegalArgumentException(
+                "At least one of ain or aout is required to be non-null.");
+        }
+
+        long[] in_ids;
+        if (ains != null) {
+            in_ids = new long[ains.length];
+            for (int index = 0; index < ains.length; ++index) {
+                in_ids[index] = ains[index].getID(mRS);
+            }
+        } else {
+            in_ids = null;
+        }
+
+        long out_id = 0;
+        if (aout != null) {
+            out_id = aout.getID(mRS);
+        }
+
+        byte[] params = null;
+        if (v != null) {
+            params = v.getData();
+        }
+
+        int[] limits = null;
+        if (sc != null) {
+            limits = new int[6];
+
+            limits[0] = sc.xstart;
+            limits[1] = sc.xend;
+            limits[2] = sc.ystart;
+            limits[3] = sc.yend;
+            limits[4] = sc.zstart;
+            limits[5] = sc.zend;
+        }
+
+        mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.  (General reduction)
+     *
+     * @hide
+     */
+    protected void reduce(int slot, Allocation[] ains, Allocation aout, LaunchOptions sc) {
+        mRS.validate();
+        if (ains == null || ains.length < 1) {
+            throw new RSIllegalArgumentException(
+                "At least one input is required.");
+        }
+        if (aout == null) {
+            throw new RSIllegalArgumentException(
+                "aout is required to be non-null.");
+        }
+        for (Allocation ain : ains) {
+            mRS.validateObject(ain);
+        }
+
+        long[] in_ids = new long[ains.length];
+        for (int index = 0; index < ains.length; ++index) {
+            in_ids[index] = ains[index].getID(mRS);
+        }
+        long out_id = aout.getID(mRS);
+
+        int[] limits = null;
+        if (sc != null) {
+            limits = new int[6];
+
+            limits[0] = sc.xstart;
+            limits[1] = sc.xend;
+            limits[2] = sc.ystart;
+            limits[3] = sc.yend;
+            limits[4] = sc.zstart;
+            limits[5] = sc.zend;
+        }
+
+        mRS.nScriptReduce(getID(mRS), slot, in_ids, out_id, limits);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param index
+     * @param v
+     */
+    public void setVar(int index, float v) {
+        mRS.nScriptSetVarF(getID(mRS), index, v, mUseIncSupp);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param index
+     * @param v
+     */
+    public void setVar(int index, double v) {
+        mRS.nScriptSetVarD(getID(mRS), index, v, mUseIncSupp);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param index
+     * @param v
+     */
+    public void setVar(int index, int v) {
+        mRS.nScriptSetVarI(getID(mRS), index, v, mUseIncSupp);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param index
+     * @param v
+     */
+    public void setVar(int index, long v) {
+        mRS.nScriptSetVarJ(getID(mRS), index, v, mUseIncSupp);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param index
+     * @param v
+     */
+    public void setVar(int index, boolean v) {
+        mRS.nScriptSetVarI(getID(mRS), index, v ? 1 : 0, mUseIncSupp);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param index
+     * @param o
+     */
+    public void setVar(int index, BaseObj o) {
+        if (mUseIncSupp) {
+            long oInc = getDummyAlloc((Allocation)o);
+            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : oInc, mUseIncSupp);            
+        } else {
+            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : o.getID(mRS), mUseIncSupp);
+        }
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param index
+     * @param v
+     */
+    public void setVar(int index, FieldPacker v) {
+        mRS.nScriptSetVarV(getID(mRS), index, v.getData(), mUseIncSupp);
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param index
+     * @param v
+     * @param e
+     * @param dims
+     */
+    public void setVar(int index, FieldPacker v, Element e, int[] dims) {
+        if (mUseIncSupp) {
+            long dElement = e.getDummyElement(mRS);
+            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), dElement, dims, mUseIncSupp);
+        } else {
+            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), e.getID(mRS), dims, mUseIncSupp);
+        }
+    }
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     */
+    public static class Builder {
+        RenderScript mRS;
+
+        Builder(RenderScript rs) {
+            mRS = rs;
+        }
+    }
+
+
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     */
+    public static class FieldBase {
+        protected Element mElement;
+        protected Allocation mAllocation;
+
+        protected void init(RenderScript rs, int dimx) {
+            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT);
+        }
+
+        protected void init(RenderScript rs, int dimx, int usages) {
+            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT | usages);
+        }
+
+        protected FieldBase() {
+        }
+
+        public Element getElement() {
+            return mElement;
+        }
+
+        public Type getType() {
+            return mAllocation.getType();
+        }
+
+        public Allocation getAllocation() {
+            return mAllocation;
+        }
+
+        //@Override
+        public void updateAllocation() {
+        }
+    }
+
+
+    /**
+     * Class for specifying the specifics about how a kernel will be
+     * launched.
+     *
+     * This class can specify a potential range of cells on which to
+     * run a kernel.  If no set is called for a dimension then this
+     * class will have no impact on that dimension when the kernel
+     * is executed.
+     *
+     * The forEach kernel launch will operate over the intersection of
+     * the dimensions.
+     *
+     * Example:
+     * LaunchOptions with setX(5, 15)
+     * Allocation with dimension X=10, Y=10
+     * The resulting forEach run would execute over:
+     * x = 5 to 9 (inclusive) and
+     * y = 0 to 9 (inclusive).
+     *
+     */
+    public static final class LaunchOptions {
+        private int xstart = 0;
+        private int ystart = 0;
+        private int xend = 0;
+        private int yend = 0;
+        private int zstart = 0;
+        private int zend = 0;
+        private int strategy;
+
+        /**
+         * Set the X range. xstartArg is the lowest coordinate of the range,
+         * and xendArg-1 is the highest coordinate of the range.
+         *
+         * @param xstartArg Must be >= 0
+         * @param xendArg Must be > xstartArg
+         *
+         * @return LaunchOptions
+         */
+        public LaunchOptions setX(int xstartArg, int xendArg) {
+            if (xstartArg < 0 || xendArg <= xstartArg) {
+                throw new RSIllegalArgumentException("Invalid dimensions");
+            }
+            xstart = xstartArg;
+            xend = xendArg;
+            return this;
+        }
+
+        /**
+         * Set the Y range. ystartArg is the lowest coordinate of the range,
+         * and yendArg-1 is the highest coordinate of the range.
+         *
+         * @param ystartArg Must be >= 0
+         * @param yendArg Must be > ystartArg
+         *
+         * @return LaunchOptions
+         */
+        public LaunchOptions setY(int ystartArg, int yendArg) {
+            if (ystartArg < 0 || yendArg <= ystartArg) {
+                throw new RSIllegalArgumentException("Invalid dimensions");
+            }
+            ystart = ystartArg;
+            yend = yendArg;
+            return this;
+        }
+
+        /**
+         * Set the Z range. zstartArg is the lowest coordinate of the range,
+         * and zendArg-1 is the highest coordinate of the range.
+         *
+         * @param zstartArg Must be >= 0
+         * @param zendArg Must be > zstartArg
+         *
+         * @return LaunchOptions
+         */
+        public LaunchOptions setZ(int zstartArg, int zendArg) {
+            if (zstartArg < 0 || zendArg <= zstartArg) {
+                throw new RSIllegalArgumentException("Invalid dimensions");
+            }
+            zstart = zstartArg;
+            zend = zendArg;
+            return this;
+        }
+
+
+        /**
+         * Returns the current X start
+         *
+         * @return int current value
+         */
+        public int getXStart() {
+            return xstart;
+        }
+        /**
+         * Returns the current X end
+         *
+         * @return int current value
+         */
+        public int getXEnd() {
+            return xend;
+        }
+        /**
+         * Returns the current Y start
+         *
+         * @return int current value
+         */
+        public int getYStart() {
+            return ystart;
+        }
+        /**
+         * Returns the current Y end
+         *
+         * @return int current value
+         */
+        public int getYEnd() {
+            return yend;
+        }
+        /**
+         * Returns the current Z start
+         *
+         * @return int current value
+         */
+        public int getZStart() {
+            return zstart;
+        }
+        /**
+         * Returns the current Z end
+         *
+         * @return int current value
+         */
+        public int getZEnd() {
+            return zend;
+        }
+
+    }
+}
diff --git a/androidx/renderscript/ScriptC.java b/androidx/renderscript/ScriptC.java
new file mode 100644
index 0000000..31201b1
--- /dev/null
+++ b/androidx/renderscript/ScriptC.java
@@ -0,0 +1,131 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map.Entry;
+import java.util.HashMap;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * The superclass for all user-defined scripts. This is only
+ * intended to be used by the generated derived classes.
+ **/
+public class ScriptC extends Script {
+    private static final String TAG = "ScriptC";
+
+    /**
+     * Only intended for use by the generated derived classes.
+     *
+     * @param id
+     * @param rs
+     */
+    protected ScriptC(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Only intended for use by the generated derived classes.
+     *
+     *
+     * @param rs
+     * @param resources
+     * @param resourceID
+     */
+    protected ScriptC(RenderScript rs, Resources resources, int resourceID) {
+        super(0, rs);
+        long id = internalCreate(rs, resources, resourceID);
+        if (id == 0) {
+            throw new RSRuntimeException("Loading of ScriptC script failed.");
+        }
+        setID(id);
+    }
+
+    /**
+     * Only intended for use by the generated derived classes.
+     *
+     * @param rs
+     * @param resName
+     * @param bitcode32
+     * @param bitcode64
+     */
+    protected ScriptC(RenderScript rs, String resName, byte[] bitcode32, byte[] bitcode64) {
+        super(0, rs);
+        long id = 0;
+        if (RenderScript.sPointerSize == 4) {
+            id = internalStringCreate(rs, resName, bitcode32);
+        } else {
+            id = internalStringCreate(rs, resName, bitcode64);
+        }
+        if (id == 0) {
+            throw new RSRuntimeException("Loading of ScriptC script failed.");
+        }
+        setID(id);
+    }
+
+    private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) {
+        byte[] pgm;
+        int pgmLength;
+        InputStream is = resources.openRawResource(resourceID);
+        try {
+            try {
+                pgm = new byte[1024];
+                pgmLength = 0;
+                while(true) {
+                    int bytesLeft = pgm.length - pgmLength;
+                    if (bytesLeft == 0) {
+                        byte[] buf2 = new byte[pgm.length * 2];
+                        System.arraycopy(pgm, 0, buf2, 0, pgm.length);
+                        pgm = buf2;
+                        bytesLeft = pgm.length - pgmLength;
+                    }
+                    int bytesRead = is.read(pgm, pgmLength, bytesLeft);
+                    if (bytesRead <= 0) {
+                        break;
+                    }
+                    pgmLength += bytesRead;
+                }
+            } finally {
+                is.close();
+            }
+        } catch(IOException e) {
+            throw new Resources.NotFoundException();
+        }
+
+        String resName = resources.getResourceEntryName(resourceID);
+        String cachePath = rs.getApplicationContext().getCacheDir().toString();
+
+        //        Log.v(TAG, "Create script for resource = " + resName + ", " + pgmLength + ", " + pgm);
+        //Log.v(TAG, " path = " + cachePath);
+        return rs.nScriptCCreate(resName, cachePath, pgm, pgmLength);
+    }
+
+    private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) {
+        //        Log.v(TAG, "Create script for resource = " + resName);
+        String cachePath = rs.getApplicationContext().getCacheDir().toString();
+        return rs.nScriptCCreate(resName, cachePath, bitcode, bitcode.length);
+    }
+
+}
diff --git a/androidx/renderscript/ScriptGroup.java b/androidx/renderscript/ScriptGroup.java
new file mode 100644
index 0000000..ba8cf4b
--- /dev/null
+++ b/androidx/renderscript/ScriptGroup.java
@@ -0,0 +1,1180 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.util.Log;
+import android.util.Pair;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A group of kernels that are executed
+ * together with one execution call as if they were a single kernel
+ * <p>
+ * In addition to kernels, a script group may contain invocable functions as well.
+ * A script group may take inputs and generate outputs, which are consumed and
+ * produced by its member kernels.
+ * Inside a script group, outputs from one kernel can be passed to another kernel as inputs.
+ * The API disallows cyclic dependencies among kernels in a script group,
+ * effectively making it a directed acyclic graph (DAG) of kernels.
+ * <p>
+ * Grouping kernels together allows for more efficient execution. For example,
+ * runtime and compiler optimization can be applied to reduce computation and
+ * communication overhead, and to make better use of the CPU and the GPU.
+ **/
+public final class ScriptGroup extends BaseObj {
+    //FIXME: Change 23 to the codename when that is decided.
+    private static final int MIN_API_VERSION = 23;
+    private static final String TAG = "ScriptGroup";
+    IO mOutputs[];
+    IO mInputs[];
+    private boolean mUseIncSupp = false;
+    private ArrayList<Node> mNodes = new ArrayList<Node>();
+
+    static class IO {
+        Script.KernelID mKID;
+        Allocation mAllocation;
+
+        IO(Script.KernelID s) {
+            mKID = s;
+        }
+    }
+
+    static class ConnectLine {
+        ConnectLine(Type t, Script.KernelID from, Script.KernelID to) {
+            mFrom = from;
+            mToK = to;
+            mAllocationType = t;
+        }
+
+        ConnectLine(Type t, Script.KernelID from, Script.FieldID to) {
+            mFrom = from;
+            mToF = to;
+            mAllocationType = t;
+        }
+
+        Script.FieldID mToF;
+        Script.KernelID mToK;
+        Script.KernelID mFrom;
+        Type mAllocationType;
+        Allocation mAllocation;
+    }
+
+    static class Node {
+        Script mScript;
+        ArrayList<Script.KernelID> mKernels = new ArrayList<Script.KernelID>();
+        ArrayList<ConnectLine> mInputs = new ArrayList<ConnectLine>();
+        ArrayList<ConnectLine> mOutputs = new ArrayList<ConnectLine>();
+        int dagNumber;
+        boolean mSeen;
+        int mOrder;
+
+        Node mNext;
+
+        Node(Script s) {
+            mScript = s;
+        }
+    }
+
+    /**
+     * An opaque class for closures
+     * <p>
+     * A closure represents a function call to a kernel or invocable function,
+     * combined with arguments and values for global variables. A closure is
+     * created using the {@link Builder2#addKernel} or
+     * {@link Builder2#addInvoke}
+     * method.
+     */
+
+    public static final class Closure extends BaseObj {
+        private Object[] mArgs;
+        private Allocation mReturnValue;
+        private Map<Script.FieldID, Object> mBindings;
+
+        private Future mReturnFuture;
+        private Map<Script.FieldID, Future> mGlobalFuture;
+
+        private FieldPacker mFP;
+
+        private static final String TAG = "Closure";
+
+        Closure(long id, RenderScript rs) {
+            super(id, rs);
+        }
+
+        Closure(RenderScript rs, Script.KernelID kernelID, Type returnType,
+                       Object[] args, Map<Script.FieldID, Object> globals) {
+            super(0, rs);
+
+            if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
+                throw new RSRuntimeException("ScriptGroup2 not supported in this API level");
+            }
+
+            mArgs = args;
+            mReturnValue = Allocation.createTyped(rs, returnType);
+            mBindings = globals;
+            mGlobalFuture = new HashMap<Script.FieldID, Future>();
+
+            int numValues = args.length + globals.size();
+
+            long[] fieldIDs = new long[numValues];
+            long[] values = new long[numValues];
+            int[] sizes = new int[numValues];
+            long[] depClosures = new long[numValues];
+            long[] depFieldIDs = new long[numValues];
+
+            int i;
+            for (i = 0; i < args.length; i++) {
+                fieldIDs[i] = 0;
+                retrieveValueAndDependenceInfo(rs, i, null, args[i],
+                                               values, sizes, depClosures, depFieldIDs);
+            }
+            for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
+                Object obj = entry.getValue();
+                Script.FieldID fieldID = entry.getKey();
+                fieldIDs[i] = fieldID.getID(rs);
+                retrieveValueAndDependenceInfo(rs, i, fieldID, obj,
+                                               values, sizes, depClosures, depFieldIDs);
+                i++;
+            }
+
+            long id = rs.nClosureCreate(kernelID.getID(rs), mReturnValue.getID(rs),
+                                        fieldIDs, values, sizes, depClosures, depFieldIDs);
+
+            setID(id);
+        }
+
+        Closure(RenderScript rs, Script.InvokeID invokeID,
+                Object[] args, Map<Script.FieldID, Object> globals) {
+            super(0, rs);
+
+            if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
+                throw new RSRuntimeException("ScriptGroup2 not supported in this API level");
+            }
+
+            mFP = FieldPacker.createFromArray(args);
+
+            mArgs = args;
+            mBindings = globals;
+            mGlobalFuture = new HashMap<Script.FieldID, Future>();
+
+            int numValues = globals.size();
+
+            long[] fieldIDs = new long[numValues];
+            long[] values = new long[numValues];
+            int[] sizes = new int[numValues];
+            long[] depClosures = new long[numValues];
+            long[] depFieldIDs = new long[numValues];
+
+            int i = 0;
+            for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
+                Object obj = entry.getValue();
+                Script.FieldID fieldID = entry.getKey();
+                fieldIDs[i] = fieldID.getID(rs);
+                retrieveValueAndDependenceInfo(rs, i, fieldID, obj, values,
+                                               sizes, depClosures, depFieldIDs);
+                i++;
+            }
+
+            long id = rs.nInvokeClosureCreate(invokeID.getID(rs), mFP.getData(), fieldIDs,
+                                              values, sizes);
+
+            setID(id);
+        }
+
+        private void retrieveValueAndDependenceInfo(RenderScript rs,
+                                                    int index, Script.FieldID fid, Object obj,
+                                                    long[] values, int[] sizes,
+                                                    long[] depClosures,
+                                                    long[] depFieldIDs) {
+
+            if (obj instanceof Future) {
+                Future f = (Future)obj;
+                obj = f.getValue();
+                depClosures[index] = f.getClosure().getID(rs);
+                Script.FieldID fieldID = f.getFieldID();
+                depFieldIDs[index] = fieldID != null ? fieldID.getID(rs) : 0;
+            } else {
+                depClosures[index] = 0;
+                depFieldIDs[index] = 0;
+            }
+
+            if (obj instanceof Input) {
+                Input unbound = (Input)obj;
+                if (index < mArgs.length) {
+                    unbound.addReference(this, index);
+                } else {
+                    unbound.addReference(this, fid);
+                }
+                values[index] = 0;
+                sizes[index] = 0;
+            } else {
+                ValueAndSize vs = new ValueAndSize(rs, obj);
+                values[index] = vs.value;
+                sizes[index] = vs.size;
+            }
+        }
+
+        /**
+         * Returns the future for the return value
+         *
+         * @return a future
+         */
+
+        public Future getReturn() {
+            if (mReturnFuture == null) {
+                mReturnFuture = new Future(this, null, mReturnValue);
+            }
+
+            return mReturnFuture;
+        }
+
+        /**
+         * Returns the future for a global variable
+         *
+         * @param field the field ID for the global variable
+         * @return a future
+         */
+
+        public Future getGlobal(Script.FieldID field) {
+            Future f = mGlobalFuture.get(field);
+
+            if (f == null) {
+                // If the field is not bound to this closure, this will return a future
+                // without an associated value (reference). So this is not working for
+                // cross-module (cross-script) linking in this case where a field not
+                // explicitly bound.
+                Object obj = mBindings.get(field);
+                if (obj instanceof Future) {
+                    obj = ((Future)obj).getValue();
+                }
+                f = new Future(this, field, obj);
+                mGlobalFuture.put(field, f);
+            }
+
+            return f;
+        }
+
+        void setArg(int index, Object obj) {
+            if (obj instanceof Future) {
+                obj = ((Future)obj).getValue();
+            }
+            mArgs[index] = obj;
+            ValueAndSize vs = new ValueAndSize(mRS, obj);
+            mRS.nClosureSetArg(getID(mRS), index, vs.value, vs.size);
+        }
+
+        void setGlobal(Script.FieldID fieldID, Object obj) {
+            if (obj instanceof Future) {
+                obj = ((Future)obj).getValue();
+            }
+            mBindings.put(fieldID, obj);
+            ValueAndSize vs = new ValueAndSize(mRS, obj);
+            mRS.nClosureSetGlobal(getID(mRS), fieldID.getID(mRS), vs.value, vs.size);
+        }
+
+        private static final class ValueAndSize {
+            public ValueAndSize(RenderScript rs, Object obj) {
+                if (obj instanceof Allocation) {
+                    value = ((Allocation)obj).getID(rs);
+                    size = -1;
+                } else if (obj instanceof Boolean) {
+                    value = ((Boolean)obj).booleanValue() ? 1 : 0;
+                    size = 4;
+                } else if (obj instanceof Integer) {
+                    value = ((Integer)obj).longValue();
+                    size = 4;
+                } else if (obj instanceof Long) {
+                    value = ((Long)obj).longValue();
+                    size = 8;
+                } else if (obj instanceof Float) {
+                    value = Float.floatToRawIntBits(((Float)obj).floatValue());
+                    size = 4;
+                } else if (obj instanceof Double) {
+                    value = Double.doubleToRawLongBits(((Double)obj).doubleValue());
+                    size = 8;
+                }
+            }
+            public long value;
+            public int size;
+        }
+    }
+
+    /**
+     * An opaque class for futures
+     * <p>
+     * A future represents an output of a closure, either the return value of
+     * the function, or the value of a global variable written by the function.
+     * A future is created by calling the {@link Closure#getReturn}  or
+     * {@link Closure#getGlobal} method.
+     */
+
+    public static final class Future {
+        Closure mClosure;
+        Script.FieldID mFieldID;
+        Object mValue;
+
+        Future(Closure closure, Script.FieldID fieldID, Object value) {
+            mClosure = closure;
+            mFieldID = fieldID;
+            mValue = value;
+        }
+
+        Closure getClosure() { return mClosure; }
+        Script.FieldID getFieldID() { return mFieldID; }
+        Object getValue() { return mValue; }
+    }
+
+    /**
+     * An opaque class for unbound values (used for script group inputs)
+     * <p>
+     * Created by calling the {@link Builder2#addInput} method. The value
+     * is assigned in {@link ScriptGroup#execute(Object...)} method as
+     * one of its arguments. Arguments to the execute method should be in
+     * the same order as intputs are added using the addInput method.
+     */
+
+    public static final class Input {
+        // Either mFieldID or mArgIndex should be set but not both.
+        List<Pair<Closure, Script.FieldID>> mFieldID;
+        // -1 means unset. Legal values are 0 .. n-1, where n is the number of
+        // arguments for the referencing closure.
+        List<Pair<Closure, Integer>> mArgIndex;
+        Object mValue;
+
+        Input() {
+            mFieldID = new ArrayList<Pair<Closure, Script.FieldID>>();
+            mArgIndex = new ArrayList<Pair<Closure, Integer>>();
+        }
+
+        void addReference(Closure closure, int index) {
+            mArgIndex.add(Pair.create(closure, Integer.valueOf(index)));
+        }
+
+        void addReference(Closure closure, Script.FieldID fieldID) {
+            mFieldID.add(Pair.create(closure, fieldID));
+        }
+
+        void set(Object value) {
+            mValue = value;
+            for (Pair<Closure, Integer> p : mArgIndex) {
+                Closure closure = p.first;
+                int index = p.second.intValue();
+                closure.setArg(index, value);
+            }
+            for (Pair<Closure, Script.FieldID> p : mFieldID) {
+                Closure closure = p.first;
+                Script.FieldID fieldID = p.second;
+                closure.setGlobal(fieldID, value);
+            }
+        }
+
+        Object get() { return mValue; }
+    }
+
+    private String mName;
+    private List<Closure> mClosures;
+    private List<Input> mInputs2;
+    private Future[] mOutputs2;
+
+    ScriptGroup(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    ScriptGroup(RenderScript rs, String name, List<Closure> closures,
+                List<Input> inputs, Future[] outputs) {
+        super(0, rs);
+
+        if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
+            throw new RSRuntimeException("ScriptGroup2 not supported in this API level");
+        }
+        mName = name;
+        mClosures = closures;
+        mInputs2 = inputs;
+        mOutputs2 = outputs;
+
+        long[] closureIDs = new long[closures.size()];
+        for (int i = 0; i < closureIDs.length; i++) {
+            closureIDs[i] = closures.get(i).getID(rs);
+        }
+        String cachePath = rs.getApplicationContext().getCacheDir().toString();
+        long id = rs.nScriptGroup2Create(name, cachePath, closureIDs);
+        setID(id);
+    }
+
+    /**
+     * Executes a script group
+     *
+     * @param inputs inputs to the script group
+     * @return outputs of the script group as an array of objects
+     */
+
+    public Object[] execute(Object... inputs) {
+        if (inputs.length < mInputs2.size()) {
+            Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
+                  "less than expected " + mInputs2.size());
+            return null;
+        }
+
+        if (inputs.length > mInputs2.size()) {
+            Log.i(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
+                  "more than expected " + mInputs2.size());
+        }
+
+        for (int i = 0; i < mInputs2.size(); i++) {
+            Object obj = inputs[i];
+            if (obj instanceof Future || obj instanceof Input) {
+                Log.e(TAG, this.toString() + ": input " + i +
+                      " is a future or unbound value");
+                return null;
+            }
+            Input unbound = mInputs2.get(i);
+            unbound.set(obj);
+        }
+
+        mRS.nScriptGroup2Execute(getID(mRS));
+
+        Object[] outputObjs = new Object[mOutputs2.length];
+        int i = 0;
+        for (Future f : mOutputs2) {
+            Object output = f.getValue();
+            if (output instanceof Input) {
+                output = ((Input)output).get();
+            }
+            outputObjs[i++] = output;
+        }
+        return outputObjs;
+    }
+
+    /**
+     * Sets an input of the ScriptGroup. This specifies an
+     * Allocation to be used for kernels that require an input
+     * Allocation provided from outside of the ScriptGroup.
+     *
+     * @deprecated Set arguments to {@link #execute(Object...)} instead.
+     *
+     * @param s The ID of the kernel where the allocation should be
+     *          connected.
+     * @param a The allocation to connect.
+     */
+    @Deprecated
+    public void setInput(Script.KernelID s, Allocation a) {
+        for (int ct=0; ct < mInputs.length; ct++) {
+            if (mInputs[ct].mKID == s) {
+                mInputs[ct].mAllocation = a;
+                if (!mUseIncSupp) {
+                    mRS.nScriptGroupSetInput(getID(mRS), s.getID(mRS), mRS.safeID(a));
+                }
+                return;
+            }
+        }
+        throw new RSIllegalArgumentException("Script not found");
+    }
+
+    /**
+     * Sets an output of the ScriptGroup. This specifies an
+     * Allocation to be used for the kernels that require an output
+     * Allocation visible after the ScriptGroup is executed.
+     *
+     * @deprecated Use return value of {@link #execute(Object...)} instead.
+     *
+     * @param s The ID of the kernel where the allocation should be
+     *          connected.
+     * @param a The allocation to connect.
+     */
+    @Deprecated
+    public void setOutput(Script.KernelID s, Allocation a) {
+        for (int ct=0; ct < mOutputs.length; ct++) {
+            if (mOutputs[ct].mKID == s) {
+                mOutputs[ct].mAllocation = a;
+                if (!mUseIncSupp) {
+                    mRS.nScriptGroupSetOutput(getID(mRS), s.getID(mRS), mRS.safeID(a));
+                }
+                return;
+            }
+        }
+        throw new RSIllegalArgumentException("Script not found");
+    }
+
+    /**
+     * Execute the ScriptGroup.  This will run all the kernels in
+     * the ScriptGroup.  No internal connection results will be visible
+     * after execution of the ScriptGroup.
+     *
+     * If Incremental Support for intrinsics is needed, the execution
+     * will take the naive path: execute kernels one by one in the
+     * correct order.
+     *
+     * @deprecated Use {@link #execute} instead.
+     */
+    @Deprecated
+    public void execute() {
+        if (!mUseIncSupp) {
+            mRS.nScriptGroupExecute(getID(mRS));
+        } else {
+            // setup the allocations.
+            for (int ct=0; ct < mNodes.size(); ct++) {
+                Node n = mNodes.get(ct);
+                for (int ct2=0; ct2 < n.mOutputs.size(); ct2++) {
+                    ConnectLine l = n.mOutputs.get(ct2);
+                    if (l.mAllocation !=null) {
+                        continue;
+                    }
+
+                    //create allocation here
+                    Allocation alloc = Allocation.createTyped(mRS, l.mAllocationType,
+                                                              Allocation.MipmapControl.MIPMAP_NONE,
+                                                              Allocation.USAGE_SCRIPT);
+
+                    l.mAllocation = alloc;
+                    for (int ct3=ct2+1; ct3 < n.mOutputs.size(); ct3++) {
+                        if (n.mOutputs.get(ct3).mFrom == l.mFrom) {
+                            n.mOutputs.get(ct3).mAllocation = alloc;
+                        }
+                    }
+                }
+            }
+            for (Node node : mNodes) {
+                for (Script.KernelID kernel : node.mKernels) {
+                    Allocation ain  = null;
+                    Allocation aout = null;
+
+                    for (ConnectLine nodeInput : node.mInputs) {
+                        if (nodeInput.mToK == kernel) {
+                            ain = nodeInput.mAllocation;
+                        }
+                    }
+
+                    for (IO sgInput : mInputs) {
+                        if (sgInput.mKID == kernel) {
+                            ain = sgInput.mAllocation;
+                        }
+                    }
+
+                    for (ConnectLine nodeOutput : node.mOutputs) {
+                        if (nodeOutput.mFrom == kernel) {
+                            aout = nodeOutput.mAllocation;
+                        }
+                    }
+
+                    for (IO sgOutput : mOutputs) {
+                        if (sgOutput.mKID == kernel) {
+                            aout = sgOutput.mAllocation;
+                        }
+                    }
+
+                    kernel.mScript.forEach(kernel.mSlot, ain, aout, null);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Helper class to build a ScriptGroup. A ScriptGroup is
+     * created in two steps.
+     * <p>
+     * First, all kernels to be used by the ScriptGroup should be added.
+     * <p>
+     * Second, add connections between kernels. There are two types
+     * of connections: kernel to kernel and kernel to field.
+     * Kernel to kernel allows a kernel's output to be passed to
+     * another kernel as input. Kernel to field allows the output of
+     * one kernel to be bound as a script global. Kernel to kernel is
+     * higher performance and should be used where possible.
+     * <p>
+     * A ScriptGroup must contain a single directed acyclic graph (DAG); it
+     * cannot contain cycles. Currently, all kernels used in a ScriptGroup
+     * must come from different Script objects. Additionally, all kernels
+     * in a ScriptGroup must have at least one input, output, or internal
+     * connection.
+     * <p>
+     * Once all connections are made, a call to {@link #create} will
+     * return the ScriptGroup object.
+     *
+     * @deprecated Use {@link Builder2} instead.
+     *
+     */
+    @Deprecated
+    public static final class Builder {
+        private RenderScript mRS;
+        private ArrayList<Node> mNodes = new ArrayList<Node>();
+        private ArrayList<ConnectLine> mLines = new ArrayList<ConnectLine>();
+        private int mKernelCount;
+        private boolean mUseIncSupp = false;
+
+        /**
+         * Create a Builder for generating a ScriptGroup.
+         *
+         *
+         * @param rs The RenderScript context.
+         */
+        public Builder(RenderScript rs) {
+            mRS = rs;
+        }
+
+        // do a DFS from original node, looking for original node
+        // any cycle that could be created must contain original node
+        private void validateCycle(Node target, Node original) {
+            for (int ct = 0; ct < target.mOutputs.size(); ct++) {
+                final ConnectLine cl = target.mOutputs.get(ct);
+                if (cl.mToK != null) {
+                    Node tn = findNode(cl.mToK.mScript);
+                    if (tn.equals(original)) {
+                        throw new RSInvalidStateException("Loops in group not allowed.");
+                    }
+                    validateCycle(tn, original);
+                }
+                if (cl.mToF != null) {
+                    Node tn = findNode(cl.mToF.mScript);
+                    if (tn.equals(original)) {
+                        throw new RSInvalidStateException("Loops in group not allowed.");
+                    }
+                    validateCycle(tn, original);
+                }
+            }
+        }
+
+        private void mergeDAGs(int valueUsed, int valueKilled) {
+            for (int ct=0; ct < mNodes.size(); ct++) {
+                if (mNodes.get(ct).dagNumber == valueKilled)
+                    mNodes.get(ct).dagNumber = valueUsed;
+            }
+        }
+
+        private void validateDAGRecurse(Node n, int dagNumber) {
+            // combine DAGs if this node has been seen already
+            if (n.dagNumber != 0 && n.dagNumber != dagNumber) {
+                mergeDAGs(n.dagNumber, dagNumber);
+                return;
+            }
+
+            n.dagNumber = dagNumber;
+            for (int ct=0; ct < n.mOutputs.size(); ct++) {
+                final ConnectLine cl = n.mOutputs.get(ct);
+                if (cl.mToK != null) {
+                    Node tn = findNode(cl.mToK.mScript);
+                    validateDAGRecurse(tn, dagNumber);
+                }
+                if (cl.mToF != null) {
+                    Node tn = findNode(cl.mToF.mScript);
+                    validateDAGRecurse(tn, dagNumber);
+                }
+            }
+        }
+
+        private void validateDAG() {
+            for (int ct=0; ct < mNodes.size(); ct++) {
+                Node n = mNodes.get(ct);
+                if (n.mInputs.size() == 0) {
+                    if (n.mOutputs.size() == 0 && mNodes.size() > 1) {
+                        String msg = "Groups cannot contain unconnected scripts";
+                        throw new RSInvalidStateException(msg);
+                    }
+                    validateDAGRecurse(n, ct+1);
+                }
+            }
+            int dagNumber = mNodes.get(0).dagNumber;
+            for (int ct=0; ct < mNodes.size(); ct++) {
+                if (mNodes.get(ct).dagNumber != dagNumber) {
+                    throw new RSInvalidStateException("Multiple DAGs in group not allowed.");
+                }
+            }
+        }
+
+        private Node findNode(Script s) {
+            for (int ct=0; ct < mNodes.size(); ct++) {
+                if (s == mNodes.get(ct).mScript) {
+                    return mNodes.get(ct);
+                }
+            }
+            return null;
+        }
+
+        private Node findNode(Script.KernelID k) {
+            for (int ct=0; ct < mNodes.size(); ct++) {
+                Node n = mNodes.get(ct);
+                for (int ct2=0; ct2 < n.mKernels.size(); ct2++) {
+                    if (k == n.mKernels.get(ct2)) {
+                        return n;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Adds a Kernel to the group.
+         *
+         *
+         * @param k The kernel to add.
+         *
+         * @return Builder Returns this.
+         */
+        public Builder addKernel(Script.KernelID k) {
+            if (mLines.size() != 0) {
+                throw new RSInvalidStateException(
+                    "Kernels may not be added once connections exist.");
+            }
+            if (k.mScript.isIncSupp()) {
+                mUseIncSupp = true;
+            }
+            //android.util.Log.v("RSR", "addKernel 1 k=" + k);
+            if (findNode(k) != null) {
+                return this;
+            }
+            //android.util.Log.v("RSR", "addKernel 2 ");
+            mKernelCount++;
+            Node n = findNode(k.mScript);
+            if (n == null) {
+                //android.util.Log.v("RSR", "addKernel 3 ");
+                n = new Node(k.mScript);
+                mNodes.add(n);
+            }
+            n.mKernels.add(k);
+            return this;
+        }
+
+        /**
+         * Adds a connection to the group.
+         *
+         *
+         * @param t The type of the connection. This is used to
+         *          determine the kernel launch sizes on the source side
+         *          of this connection.
+         * @param from The source for the connection.
+         * @param to The destination of the connection.
+         *
+         * @return Builder Returns this
+         */
+        public Builder addConnection(Type t, Script.KernelID from, Script.FieldID to) {
+            //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to);
+            Node nf = findNode(from);
+            if (nf == null) {
+                throw new RSInvalidStateException("From script not found.");
+            }
+
+            Node nt = findNode(to.mScript);
+            if (nt == null) {
+                throw new RSInvalidStateException("To script not found.");
+            }
+
+            ConnectLine cl = new ConnectLine(t, from, to);
+            mLines.add(new ConnectLine(t, from, to));
+
+            nf.mOutputs.add(cl);
+            nt.mInputs.add(cl);
+
+            validateCycle(nf, nf);
+            return this;
+        }
+
+        /**
+         * Adds a connection to the group.
+         *
+         *
+         * @param t The type of the connection. This is used to
+         *          determine the kernel launch sizes for both sides of
+         *          this connection.
+         * @param from The source for the connection.
+         * @param to The destination of the connection.
+         *
+         * @return Builder Returns this
+         */
+        public Builder addConnection(Type t, Script.KernelID from, Script.KernelID to) {
+            //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to);
+            Node nf = findNode(from);
+            if (nf == null) {
+                throw new RSInvalidStateException("From script not found.");
+            }
+
+            Node nt = findNode(to);
+            if (nt == null) {
+                throw new RSInvalidStateException("To script not found.");
+            }
+
+            ConnectLine cl = new ConnectLine(t, from, to);
+            mLines.add(new ConnectLine(t, from, to));
+
+            nf.mOutputs.add(cl);
+            nt.mInputs.add(cl);
+
+            validateCycle(nf, nf);
+            return this;
+        }
+
+        /**
+         * Calculate the order of each node.
+         *
+         *
+         * @return Success or Fail
+         */
+        private boolean calcOrderRecurse(Node node0, int depth) {
+            node0.mSeen = true;
+            if (node0.mOrder < depth) {
+                node0.mOrder = depth;
+            }
+            boolean ret = true;
+
+            for (ConnectLine link : node0.mOutputs) {
+                Node node1 = null;
+                if (link.mToF != null) {
+                    node1 = findNode(link.mToF.mScript);
+                } else {
+                    node1 = findNode(link.mToK.mScript);
+                }
+                if (node1.mSeen) {
+                    return false;
+                }
+                ret &= calcOrderRecurse(node1, node0.mOrder + 1);
+            }
+
+            return ret;
+        }
+
+        private boolean calcOrder() {
+            boolean ret = true;
+            for (Node n0 : mNodes) {
+                if (n0.mInputs.size() == 0) {
+                    for (Node n1 : mNodes) {
+                        n1.mSeen = false;
+                    }
+                    ret &= calcOrderRecurse(n0, 1);
+                }
+            }
+
+            Collections.sort(mNodes, new Comparator<Node>() {
+                public int compare(Node n1, Node n2) {
+                    return n1.mOrder - n2.mOrder;
+                }
+            });
+
+            return ret;
+        }
+
+        /**
+         * Creates the Script group.
+         *
+         *
+         * @return ScriptGroup The new ScriptGroup
+         */
+        public ScriptGroup create() {
+
+            if (mNodes.size() == 0) {
+                throw new RSInvalidStateException("Empty script groups are not allowed");
+            }
+
+            // reset DAG numbers in case we're building a second group
+            for (int ct=0; ct < mNodes.size(); ct++) {
+                mNodes.get(ct).dagNumber = 0;
+            }
+            validateDAG();
+
+            ArrayList<IO> inputs = new ArrayList<IO>();
+            ArrayList<IO> outputs = new ArrayList<IO>();
+
+            long[] kernels = new long[mKernelCount];
+            int idx = 0;
+            for (int ct=0; ct < mNodes.size(); ct++) {
+                Node n = mNodes.get(ct);
+                for (int ct2=0; ct2 < n.mKernels.size(); ct2++) {
+                    final Script.KernelID kid = n.mKernels.get(ct2);
+                    kernels[idx++] = kid.getID(mRS);
+
+                    boolean hasInput = false;
+                    boolean hasOutput = false;
+                    for (int ct3=0; ct3 < n.mInputs.size(); ct3++) {
+                        if (n.mInputs.get(ct3).mToK == kid) {
+                            hasInput = true;
+                        }
+                    }
+                    for (int ct3=0; ct3 < n.mOutputs.size(); ct3++) {
+                        if (n.mOutputs.get(ct3).mFrom == kid) {
+                            hasOutput = true;
+                        }
+                    }
+                    if (!hasInput) {
+                        inputs.add(new IO(kid));
+                    }
+                    if (!hasOutput) {
+                        outputs.add(new IO(kid));
+                    }
+                }
+            }
+            if (idx != mKernelCount) {
+                throw new RSRuntimeException("Count mismatch, should not happen.");
+            }
+
+            long id = 0;
+            if (!mUseIncSupp) {
+                long[] src = new long[mLines.size()];
+                long[] dstk = new long[mLines.size()];
+                long[] dstf = new long[mLines.size()];
+                long[] types = new long[mLines.size()];
+
+                for (int ct=0; ct < mLines.size(); ct++) {
+                    ConnectLine cl = mLines.get(ct);
+                    src[ct] = cl.mFrom.getID(mRS);
+                    if (cl.mToK != null) {
+                        dstk[ct] = cl.mToK.getID(mRS);
+                    }
+                    if (cl.mToF != null) {
+                        dstf[ct] = cl.mToF.getID(mRS);
+                    }
+                    types[ct] = cl.mAllocationType.getID(mRS);
+                }
+                id = mRS.nScriptGroupCreate(kernels, src, dstk, dstf, types);
+                if (id == 0) {
+                    throw new RSRuntimeException("Object creation error, should not happen.");
+                }
+            } else {
+                //Calculate the order of the DAG so that script can run one after another.
+                calcOrder();
+            }
+
+            ScriptGroup sg = new ScriptGroup(id, mRS);
+            sg.mOutputs = new IO[outputs.size()];
+            for (int ct=0; ct < outputs.size(); ct++) {
+                sg.mOutputs[ct] = outputs.get(ct);
+            }
+
+            sg.mInputs = new IO[inputs.size()];
+            for (int ct=0; ct < inputs.size(); ct++) {
+                sg.mInputs[ct] = inputs.get(ct);
+            }
+            sg.mNodes = mNodes;
+            sg.mUseIncSupp = mUseIncSupp;
+            return sg;
+        }
+
+    }
+
+    /**
+     * Represents a binding of a value to a global variable in a
+     * kernel or invocable function. Used in closure creation.
+     */
+
+    public static final class Binding {
+        private final Script.FieldID mField;
+        private final Object mValue;
+
+        /**
+         * Returns a Binding object that binds value to field
+         *
+         * @param field the Script.FieldID of the global variable
+         * @param value the value
+         */
+
+        public Binding(Script.FieldID field, Object value) {
+            mField = field;
+            mValue = value;
+        }
+
+        /**
+         * Returns the field ID
+         */
+
+        public Script.FieldID getField() { return mField; }
+
+        /**
+         * Returns the value
+         */
+
+        public Object getValue() { return mValue; }
+    }
+
+    /**
+     * The builder class for creating script groups
+     * <p>
+     * A script group is created using closures (see class {@link Closure}).
+     * A closure is a function call to a kernel or
+     * invocable function. Each function argument or global variable accessed inside
+     * the function is bound to 1) a known value, 2) a script group input
+     * (see class {@link Input}), or 3) a
+     * future (see class {@link Future}).
+     * A future is the output of a closure, either the return value of the
+     * function or a global variable written by that function.
+     * <p>
+     * Closures are created using the {@link #addKernel} or {@link #addInvoke}
+     * methods.
+     * When a closure is created, futures from previously created closures
+     * can be used as its inputs.
+     * External script group inputs can be used as inputs to individual closures as well.
+     * An external script group input is created using the {@link #addInput} method.
+     * A script group is created by a call to the {@link #create} method, which
+     * accepts an array of futures as the outputs for the script group.
+     * <p>
+     * Closures in a script group can be evaluated in any order as long as the
+     * following conditions are met:
+     * 1) a closure must be evaluated before any other closures that take its
+     * futures as inputs;
+     * 2) all closures added before an invoke closure must be evaluated
+     * before it;
+     * and 3) all closures added after an invoke closure must be evaluated after
+     * it.
+     * As a special case, the order that the closures are added is a legal
+     * evaluation order. However, other evaluation orders are possible, including
+     * concurrently evaluating independent closures.
+     */
+
+    public static final class Builder2 {
+        RenderScript mRS;
+        List<Closure> mClosures;
+        List<Input> mInputs;
+        private static final String TAG = "ScriptGroup.Builder2";
+
+        /**
+         * Returns a Builder object
+         *
+         * @param rs the RenderScript context
+         */
+        public Builder2(RenderScript rs) {
+            mRS = rs;
+            mClosures = new ArrayList<Closure>();
+            mInputs = new ArrayList<Input>();
+        }
+
+        /**
+         * Adds a closure for a kernel
+         *
+         * @param k Kernel ID for the kernel function
+         * @param returnType Allocation type for the return value
+         * @param args arguments to the kernel function
+         * @param globalBindings bindings for global variables
+         * @return a closure
+         */
+
+        private Closure addKernelInternal(Script.KernelID k, Type returnType, Object[] args,
+                                          Map<Script.FieldID, Object> globalBindings) {
+            Closure c = new Closure(mRS, k, returnType, args, globalBindings);
+            mClosures.add(c);
+            return c;
+        }
+
+        /**
+         * Adds a closure for an invocable function
+         *
+         * @param invoke Invoke ID for the invocable function
+         * @param args arguments to the invocable function
+         * @param globalBindings bindings for global variables
+         * @return a closure
+         */
+
+        private Closure addInvokeInternal(Script.InvokeID invoke, Object[] args,
+                                          Map<Script.FieldID, Object> globalBindings) {
+            Closure c = new Closure(mRS, invoke, args, globalBindings);
+            mClosures.add(c);
+            return c;
+        }
+
+        /**
+         * Adds a script group input
+         *
+         * @return a script group input, which can be used as an argument or a value to
+         *     a global variable for creating closures
+         */
+
+        public Input addInput() {
+            Input unbound = new Input();
+            mInputs.add(unbound);
+            return unbound;
+        }
+
+        /**
+         * Adds a closure for a kernel
+         *
+         * @param k Kernel ID for the kernel function
+         * @param argsAndBindings arguments followed by bindings for global variables
+         * @return a closure
+         */
+
+        public Closure addKernel(Script.KernelID k, Type returnType, Object... argsAndBindings) {
+            ArrayList<Object> args = new ArrayList<Object>();
+            Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
+            if (!seperateArgsAndBindings(argsAndBindings, args, bindingMap)) {
+                return null;
+            }
+            return addKernelInternal(k, returnType, args.toArray(), bindingMap);
+        }
+
+        /**
+         * Adds a closure for an invocable function
+         *
+         * @param invoke Invoke ID for the invocable function
+         * @param argsAndBindings arguments followed by bindings for global variables
+         * @return a closure
+         */
+
+        public Closure addInvoke(Script.InvokeID invoke, Object... argsAndBindings) {
+            ArrayList<Object> args = new ArrayList<Object>();
+            Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
+            if (!seperateArgsAndBindings(argsAndBindings, args, bindingMap)) {
+                return null;
+            }
+            return addInvokeInternal(invoke, args.toArray(), bindingMap);
+        }
+
+        /**
+         * Creates a script group
+         *
+         * @param name name for the script group. Legal names can only contain letters, digits,
+         *        '-', or '_'. The name can be no longer than 100 characters.
+         * @param outputs futures intended as outputs of the script group
+         * @return a script group
+         */
+
+        public ScriptGroup create(String name, Future... outputs) {
+            if (name == null || name.isEmpty() || name.length() > 100 ||
+                !name.equals(name.replaceAll("[^a-zA-Z0-9-]", "_"))) {
+                throw new RSIllegalArgumentException("invalid script group name");
+            }
+            ScriptGroup ret = new ScriptGroup(mRS, name, mClosures, mInputs, outputs);
+            return ret;
+        }
+
+        private boolean seperateArgsAndBindings(Object[] argsAndBindings,
+                                                ArrayList<Object> args,
+                                                Map<Script.FieldID, Object> bindingMap) {
+            int i;
+            for (i = 0; i < argsAndBindings.length; i++) {
+                if (argsAndBindings[i] instanceof Binding) {
+                    break;
+                }
+                args.add(argsAndBindings[i]);
+            }
+
+            for (; i < argsAndBindings.length; i++) {
+                if (!(argsAndBindings[i] instanceof Binding)) {
+                    return false;
+                }
+                Binding b = (Binding)argsAndBindings[i];
+                bindingMap.put(b.getField(), b.getValue());
+            }
+
+            return true;
+        }
+
+    }
+
+}
+
+
diff --git a/androidx/renderscript/ScriptIntrinsic.java b/androidx/renderscript/ScriptIntrinsic.java
new file mode 100644
index 0000000..cf7b72e
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsic.java
@@ -0,0 +1,34 @@
+/*
+ * 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 androidx.renderscript;
+
+/**
+ * Base class for all Intrinsic scripts. An intrinsic a script
+ * which implements a pre-defined function. Intrinsics are
+ * provided to provide effecient implemtations of common
+ * operations.
+ *
+ * Not intended for direct use.
+ **/
+public abstract class ScriptIntrinsic extends Script {
+    ScriptIntrinsic(long id, RenderScript rs) {
+        super(id, rs);
+        if (id == 0) {
+            throw new RSRuntimeException("Loading of ScriptIntrinsic failed.");
+        }
+    }
+}
diff --git a/androidx/renderscript/ScriptIntrinsic3DLUT.java b/androidx/renderscript/ScriptIntrinsic3DLUT.java
new file mode 100644
index 0000000..e7b6a07
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsic3DLUT.java
@@ -0,0 +1,110 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.util.Log;
+
+/**
+ *
+ * Intrinsic for converting RGB to RGBA by using a 3D lookup table.  The
+ * incoming r,g,b values are use as normalized x,y,z coordinates into a 3D
+ * allocation.  The 8 nearest values are sampled and linearly interpolated.  The
+ * result is placed in the output.
+ *
+ **/
+public class ScriptIntrinsic3DLUT extends ScriptIntrinsic {
+    private Allocation mLUT;
+    private Element mElement;
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 19;
+
+    protected ScriptIntrinsic3DLUT(long id, RenderScript rs, Element e) {
+        super(id, rs);
+        mElement = e;
+    }
+
+    /**
+     * Supported elements types are {@link Element#U8_4}
+     *
+     * The defaults tables are identity.
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for intputs and outputs
+     *
+     * @return ScriptIntrinsic3DLUT
+     */
+    public static ScriptIntrinsic3DLUT create(RenderScript rs, Element e) {
+        if (!e.isCompatible(Element.U8_4(rs))) {
+            throw new RSIllegalArgumentException("Element must be compatible with uchar4.");
+        }
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(8, e.getID(rs), mUseIncSupp);
+
+        ScriptIntrinsic3DLUT si = new ScriptIntrinsic3DLUT(id, rs, e);
+        si.setIncSupp(mUseIncSupp);
+        return si;
+    }
+
+    /**
+     * Sets the {@link androidx.renderscript.Allocation} to be used as
+     * the lookup table.
+     *
+     * The lookup table must use the same
+     * {@link androidx.renderscript.Element} as the intrinsic.
+     *
+     */
+
+    public void setLUT(Allocation lut) {
+        final Type t = lut.getType();
+
+        if (t.getZ() == 0) {
+            throw new RSIllegalArgumentException("LUT must be 3d.");
+        }
+
+        if (!t.getElement().isCompatible(mElement)) {
+            throw new RSIllegalArgumentException("LUT element type must match.");
+        }
+
+        mLUT = lut;
+        setVar(0, mLUT);
+    }
+
+
+    /**
+     * Invoke the kernel and apply the lookup to each cell of ain
+     * and copy to aout.
+     *
+     * @param ain Input allocation
+     * @param aout Output allocation
+     */
+    public void forEach(Allocation ain, Allocation aout) {
+        forEach(0, ain, aout, null);
+    }
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID() {
+        return createKernelID(0, 3, null, null);
+    }
+}
+
diff --git a/androidx/renderscript/ScriptIntrinsicBLAS.java b/androidx/renderscript/ScriptIntrinsicBLAS.java
new file mode 100644
index 0000000..7d8e668
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicBLAS.java
@@ -0,0 +1,4190 @@
+/*
+ * Copyright (C) 2015 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 androidx.renderscript;
+
+import android.support.annotation.IntDef;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ *
+ * ScriptIntrinsicBLAS class provides high performance RenderScript APIs to BLAS.
+ *
+ * The BLAS (Basic Linear Algebra Subprograms) are routines that provide standard
+ * building blocks for performing basic vector and matrix operations.
+ *
+ * For detailed description of BLAS, please refer to http://www.netlib.org/blas/
+ *
+ **/
+public final class ScriptIntrinsicBLAS extends ScriptIntrinsic {
+    private Allocation mLUT;
+    private static final int INTRINSIC_API_LEVEL = 23;
+
+    private ScriptIntrinsicBLAS(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    private static final int RsBlas_sdsdot = 1;
+    private static final int RsBlas_dsdot = 2;
+    private static final int RsBlas_sdot = 3;
+    private static final int RsBlas_ddot = 4;
+    private static final int RsBlas_cdotu_sub = 5;
+    private static final int RsBlas_cdotc_sub = 6;
+    private static final int RsBlas_zdotu_sub = 7;
+    private static final int RsBlas_zdotc_sub = 8;
+    private static final int RsBlas_snrm2 = 9;
+    private static final int RsBlas_sasum = 10;
+    private static final int RsBlas_dnrm2 = 11;
+    private static final int RsBlas_dasum = 12;
+    private static final int RsBlas_scnrm2 = 13;
+    private static final int RsBlas_scasum = 14;
+    private static final int RsBlas_dznrm2 = 15;
+    private static final int RsBlas_dzasum = 16;
+    private static final int RsBlas_isamax = 17;
+    private static final int RsBlas_idamax = 18;
+    private static final int RsBlas_icamax = 19;
+    private static final int RsBlas_izamax = 20;
+    private static final int RsBlas_sswap = 21;
+    private static final int RsBlas_scopy = 22;
+    private static final int RsBlas_saxpy = 23;
+    private static final int RsBlas_dswap = 24;
+    private static final int RsBlas_dcopy = 25;
+    private static final int RsBlas_daxpy = 26;
+    private static final int RsBlas_cswap = 27;
+    private static final int RsBlas_ccopy = 28;
+    private static final int RsBlas_caxpy = 29;
+    private static final int RsBlas_zswap = 30;
+    private static final int RsBlas_zcopy = 31;
+    private static final int RsBlas_zaxpy = 32;
+    private static final int RsBlas_srotg = 33;
+    private static final int RsBlas_srotmg = 34;
+    private static final int RsBlas_srot = 35;
+    private static final int RsBlas_srotm = 36;
+    private static final int RsBlas_drotg = 37;
+    private static final int RsBlas_drotmg = 38;
+    private static final int RsBlas_drot = 39;
+    private static final int RsBlas_drotm = 40;
+    private static final int RsBlas_sscal = 41;
+    private static final int RsBlas_dscal = 42;
+    private static final int RsBlas_cscal = 43;
+    private static final int RsBlas_zscal = 44;
+    private static final int RsBlas_csscal = 45;
+    private static final int RsBlas_zdscal = 46;
+    private static final int RsBlas_sgemv = 47;
+    private static final int RsBlas_sgbmv = 48;
+    private static final int RsBlas_strmv = 49;
+    private static final int RsBlas_stbmv = 50;
+    private static final int RsBlas_stpmv = 51;
+    private static final int RsBlas_strsv = 52;
+    private static final int RsBlas_stbsv = 53;
+    private static final int RsBlas_stpsv = 54;
+    private static final int RsBlas_dgemv = 55;
+    private static final int RsBlas_dgbmv = 56;
+    private static final int RsBlas_dtrmv = 57;
+    private static final int RsBlas_dtbmv = 58;
+    private static final int RsBlas_dtpmv = 59;
+    private static final int RsBlas_dtrsv = 60;
+    private static final int RsBlas_dtbsv = 61;
+    private static final int RsBlas_dtpsv = 62;
+    private static final int RsBlas_cgemv = 63;
+    private static final int RsBlas_cgbmv = 64;
+    private static final int RsBlas_ctrmv = 65;
+    private static final int RsBlas_ctbmv = 66;
+    private static final int RsBlas_ctpmv = 67;
+    private static final int RsBlas_ctrsv = 68;
+    private static final int RsBlas_ctbsv = 69;
+    private static final int RsBlas_ctpsv = 70;
+    private static final int RsBlas_zgemv = 71;
+    private static final int RsBlas_zgbmv = 72;
+    private static final int RsBlas_ztrmv = 73;
+    private static final int RsBlas_ztbmv = 74;
+    private static final int RsBlas_ztpmv = 75;
+    private static final int RsBlas_ztrsv = 76;
+    private static final int RsBlas_ztbsv = 77;
+    private static final int RsBlas_ztpsv = 78;
+    private static final int RsBlas_ssymv = 79;
+    private static final int RsBlas_ssbmv = 80;
+    private static final int RsBlas_sspmv = 81;
+    private static final int RsBlas_sger = 82;
+    private static final int RsBlas_ssyr = 83;
+    private static final int RsBlas_sspr = 84;
+    private static final int RsBlas_ssyr2 = 85;
+    private static final int RsBlas_sspr2 = 86;
+    private static final int RsBlas_dsymv = 87;
+    private static final int RsBlas_dsbmv = 88;
+    private static final int RsBlas_dspmv = 89;
+    private static final int RsBlas_dger = 90;
+    private static final int RsBlas_dsyr = 91;
+    private static final int RsBlas_dspr = 92;
+    private static final int RsBlas_dsyr2 = 93;
+    private static final int RsBlas_dspr2 = 94;
+    private static final int RsBlas_chemv = 95;
+    private static final int RsBlas_chbmv = 96;
+    private static final int RsBlas_chpmv = 97;
+    private static final int RsBlas_cgeru = 98;
+    private static final int RsBlas_cgerc = 99;
+    private static final int RsBlas_cher = 100;
+    private static final int RsBlas_chpr = 101;
+    private static final int RsBlas_cher2 = 102;
+    private static final int RsBlas_chpr2 = 103;
+    private static final int RsBlas_zhemv = 104;
+    private static final int RsBlas_zhbmv = 105;
+    private static final int RsBlas_zhpmv = 106;
+    private static final int RsBlas_zgeru = 107;
+    private static final int RsBlas_zgerc = 108;
+    private static final int RsBlas_zher = 109;
+    private static final int RsBlas_zhpr = 110;
+    private static final int RsBlas_zher2 = 111;
+    private static final int RsBlas_zhpr2 = 112;
+    private static final int RsBlas_sgemm = 113;
+    private static final int RsBlas_ssymm = 114;
+    private static final int RsBlas_ssyrk = 115;
+    private static final int RsBlas_ssyr2k = 116;
+    private static final int RsBlas_strmm = 117;
+    private static final int RsBlas_strsm = 118;
+    private static final int RsBlas_dgemm = 119;
+    private static final int RsBlas_dsymm = 120;
+    private static final int RsBlas_dsyrk = 121;
+    private static final int RsBlas_dsyr2k = 122;
+    private static final int RsBlas_dtrmm = 123;
+    private static final int RsBlas_dtrsm = 124;
+    private static final int RsBlas_cgemm = 125;
+    private static final int RsBlas_csymm = 126;
+    private static final int RsBlas_csyrk = 127;
+    private static final int RsBlas_csyr2k = 128;
+    private static final int RsBlas_ctrmm = 129;
+    private static final int RsBlas_ctrsm = 130;
+    private static final int RsBlas_zgemm = 131;
+    private static final int RsBlas_zsymm = 132;
+    private static final int RsBlas_zsyrk = 133;
+    private static final int RsBlas_zsyr2k = 134;
+    private static final int RsBlas_ztrmm = 135;
+    private static final int RsBlas_ztrsm = 136;
+    private static final int RsBlas_chemm = 137;
+    private static final int RsBlas_cherk = 138;
+    private static final int RsBlas_cher2k = 139;
+    private static final int RsBlas_zhemm = 140;
+    private static final int RsBlas_zherk = 141;
+    private static final int RsBlas_zher2k = 142;
+
+    // BLAS extensions start here
+    private static final int RsBlas_bnnm = 1000;
+
+    /**
+     * Create an intrinsic to access BLAS subroutines.
+     *
+     * @param rs The RenderScript context
+     * @return ScriptIntrinsicBLAS
+     */
+    public static ScriptIntrinsicBLAS create(RenderScript rs) {
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(13, Element.U32(rs).getID(rs), mUseIncSupp);
+        ScriptIntrinsicBLAS si = new ScriptIntrinsicBLAS(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        return si;
+    }
+
+    /**
+     * @hide
+     */
+    @IntDef({NO_TRANSPOSE, TRANSPOSE, CONJ_TRANSPOSE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Transpose {}
+
+    /**
+     * @hide
+     */
+    @IntDef({UPPER, LOWER})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Uplo {}
+
+    /**
+     * @hide
+     */
+    @IntDef({NON_UNIT, UNIT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Diag {}
+
+    /**
+     * @hide
+     */
+    @IntDef({LEFT, RIGHT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Side {}
+
+    public static final int NO_TRANSPOSE = 111;
+    public static final int TRANSPOSE = 112;
+    public static final int CONJ_TRANSPOSE = 113;
+
+    public static final int UPPER = 121;
+    public static final int LOWER = 122;
+
+    public static final int NON_UNIT = 131;
+    public static final int UNIT = 132;
+
+    public static final int LEFT = 141;
+    public static final int RIGHT = 142;
+
+    static void validateSide(@Side int Side) {
+        if (Side != LEFT && Side != RIGHT) {
+            throw new RSRuntimeException("Invalid side passed to BLAS");
+        }
+    }
+
+    static void validateTranspose(@Transpose int Trans) {
+        if (Trans != NO_TRANSPOSE && Trans != TRANSPOSE &&
+            Trans != CONJ_TRANSPOSE) {
+            throw new RSRuntimeException("Invalid transpose passed to BLAS");
+        }
+    }
+
+    static void validateConjTranspose(@Transpose int Trans) {
+        if (Trans != NO_TRANSPOSE &&
+            Trans != CONJ_TRANSPOSE) {
+            throw new RSRuntimeException("Invalid transpose passed to BLAS");
+        }
+    }
+
+    static void validateDiag(@Diag int Diag) {
+        if (Diag != NON_UNIT && Diag != UNIT) {
+            throw new RSRuntimeException("Invalid diag passed to BLAS");
+        }
+    }
+
+    static void validateUplo(@Uplo int Uplo) {
+        if (Uplo != UPPER && Uplo != LOWER) {
+            throw new RSRuntimeException("Invalid uplo passed to BLAS");
+        }
+    }
+
+
+    /**
+     * Level 2 BLAS
+     */
+
+    static void validateGEMV(Element e, int TransA, Allocation A, Allocation X, int incX, Allocation Y, int incY) {
+        validateTranspose(TransA);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = -1, expectedYDim = -1;
+        if (TransA == NO_TRANSPOSE) {
+            expectedXDim = 1 + (N - 1) * incX;
+            expectedYDim = 1 + (M - 1) * incY;
+        } else {
+            expectedXDim = 1 + (M - 1) * incX;
+            expectedYDim = 1 + (N - 1) * incY;
+        }
+        if (X.getType().getX() != expectedXDim ||
+            Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GEMV");
+        }
+    }
+
+    /**
+     * SGEMV performs one of the matrix-vector operations
+     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/d58/sgemv_8f.html
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void SGEMV(@Transpose int TransA, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DGEMV performs one of the matrix-vector operations
+     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/dc/da8/dgemv_8f.html
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void DGEMV(@Transpose int TransA, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CGEMV performs one of the matrix-vector operations
+     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d4/d8a/cgemv_8f.html
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void CGEMV(@Transpose int TransA, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZGEMV performs one of the matrix-vector operations
+     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/d40/zgemv_8f.html
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void ZGEMV(@Transpose int TransA, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SGBMV performs one of the matrix-vector operations
+     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d6/d46/sgbmv_8f.html
+     *
+     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
+     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, m):
+     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
+     *                  b[i, j-i+kl] = a[i, j]
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param KL The number of sub-diagonals of the matrix A.
+     * @param KU The number of super-diagonals of the matrix A.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void SGBMV(@Transpose int TransA, int KL, int KU, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
+        validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
+        if (KL < 0 || KU < 0) {
+            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
+        }
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, KL, KU, mUseIncSupp);
+    }
+
+    /**
+     * DGBMV performs one of the matrix-vector operations
+     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d2/d3f/dgbmv_8f.html
+     *
+     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
+     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, m):
+     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
+     *                  b[i, j-i+kl] = a[i, j]
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param KL The number of sub-diagonals of the matrix A.
+     * @param KU The number of super-diagonals of the matrix A.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void DGBMV(@Transpose int TransA, int KL, int KU, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
+        validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
+        if (KL < 0 || KU < 0) {
+            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
+        }
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, KL, KU, mUseIncSupp);
+    }
+
+    /**
+     * CGBMV performs one of the matrix-vector operations
+     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d0/d75/cgbmv_8f.html
+     *
+     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
+     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, m):
+     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
+     *                  b[i, j-i+kl] = a[i, j]
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param KL The number of sub-diagonals of the matrix A.
+     * @param KU The number of super-diagonals of the matrix A.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void CGBMV(@Transpose int TransA, int KL, int KU, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
+        validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
+        if (KL < 0 || KU < 0) {
+            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
+        }
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, KL, KU, mUseIncSupp);
+    }
+
+    /**
+     * ZGBMV performs one of the matrix-vector operations
+     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d9/d46/zgbmv_8f.html
+     *
+     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
+     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, m):
+     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
+     *                  b[i, j-i+kl] = a[i, j]
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param KL The number of sub-diagonals of the matrix A.
+     * @param KU The number of super-diagonals of the matrix A.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void ZGBMV(@Transpose int TransA, int KL, int KU, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
+        validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
+        if (KL < 0 || KU < 0) {
+            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
+        }
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, KL, KU, mUseIncSupp);
+    }
+
+    static void validateTRMV(Element e, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTranspose(TransA);
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        int N = A.getType().getY();
+        if (A.getType().getX() != N) {
+            throw new RSRuntimeException("A must be a square matrix for TRMV");
+        }
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (incX <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for TRMV");
+        }
+    }
+
+    static int validateTPMV(Element e, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation Ap, Allocation X, int incX) {
+        validateTranspose(TransA);
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        if (!Ap.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (Ap.getType().getY() > 1) {
+            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
+        }
+
+        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
+        //is it really doing anything?
+        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
+            throw new RSRuntimeException("Invalid dimension for Ap");
+        }
+        if (incX <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for TPMV");
+        }
+
+        return N;
+    }
+
+    /**
+     * STRMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/de/d45/strmv_8f.html
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void STRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DTRMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/dc/d7e/dtrmv_8f.html
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void DTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CTRMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x   or   x := A**H*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/df/d78/ctrmv_8f.html
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void CTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZTRMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x   or   x := A**H*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d0/dd1/ztrmv_8f.html
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void ZTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * STBMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d6/d7d/stbmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param K The number of off-diagonals of the matrix A
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void STBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DTBMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/df/d29/dtbmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param K The number of off-diagonals of the matrix A
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void DTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CTBMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x   or   x := A**H*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d3/dcd/ctbmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param K The number of off-diagonals of the matrix A
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void CTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZTBMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x   or   x := A**H*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d3/d39/ztbmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param K The number of off-diagonals of the matrix A
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void ZTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * STPMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/db1/stpmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void STPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DTPMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/dc/dcd/dtpmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void DTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CTPMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x   or   x := A**H*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d4/dbb/ctpmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void CTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZTPMV performs one of the matrix-vector operations
+     * x := A*x   or   x := A**T*x   or   x := A**H*x
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d2/d9e/ztpmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void ZTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * STRSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d0/d2a/strsv_8f.html
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void STRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+        // TRSV is the same as TRMV
+        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+
+    }
+
+    /**
+     * DTRSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d6/d96/dtrsv_8f.html
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void DTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+        // TRSV is the same as TRMV
+        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+
+    }
+
+    /**
+     * CTRSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b   or   A**H*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d4/dc8/ctrsv_8f.html
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void CTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+        // TRSV is the same as TRMV
+        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+
+    }
+
+    /**
+     * ZTRSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b   or   A**H*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d1/d2f/ztrsv_8f.html
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void ZTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+        // TRSV is the same as TRMV
+        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+
+    }
+
+    /**
+     * STBSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d0/d1f/stbsv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param K The number of off-diagonals of the matrix A
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void STBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV + K >= 0
+        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+        if (K < 0) {
+            throw new RSRuntimeException("Number of diagonals must be positive");
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DTBSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d4/dcf/dtbsv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param K The number of off-diagonals of the matrix A
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void DTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV + K >= 0
+        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+        if (K < 0) {
+            throw new RSRuntimeException("Number of diagonals must be positive");
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CTBSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b   or   A**H*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d9/d5f/ctbsv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param K The number of off-diagonals of the matrix A
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void CTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV + K >= 0
+        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+        if (K < 0) {
+            throw new RSRuntimeException("Number of diagonals must be positive");
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZTBSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b   or   A**H*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d4/d5a/ztbsv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param K The number of off-diagonals of the matrix A
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void ZTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV + K >= 0
+        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
+        int N = A.getType().getY();
+        if (K < 0) {
+            throw new RSRuntimeException("Number of diagonals must be positive");
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * STPSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d0/d7c/stpsv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void STPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        // TPSV is same as TPMV
+        int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DTPSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d9/d84/dtpsv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void DTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        // TPSV is same as TPMV
+        int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CTPSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b   or   A**H*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d8/d56/ctpsv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void CTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        // TPSV is same as TPMV
+        int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZTPSV solves one of the systems of equations
+     * A*x = b   or   A**T*x = b   or   A**H*x = b
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/da/d57/ztpsv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     */
+    public void ZTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        // TPSV is same as TPMV
+        int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * Level 2, S and D only
+     */
+    static int validateSYMV(Element e, @Uplo int Uplo, Allocation A, Allocation X, Allocation Y, int incX, int incY) {
+        validateUplo(Uplo);
+        int N = A.getType().getY();
+        if (A.getType().getX() != N) {
+            throw new RSRuntimeException("A must be a square matrix for SYMV");
+        }
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e) ) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
+        }
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
+        }
+        return N;
+    }
+    static int validateSPMV(Element e, @Uplo int Uplo, Allocation Ap, Allocation X, int incX, Allocation Y, int incY) {
+        validateUplo(Uplo);
+        if (!Ap.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (Ap.getType().getY() > 1) {
+            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
+        }
+
+        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
+        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
+            throw new RSRuntimeException("Invalid dimension for Ap");
+        }
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
+        }
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
+        }
+
+        return N;
+    }
+    static void validateGER(Element e, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e) ) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        if (N < 1 || M < 1) {
+            throw new RSRuntimeException("M and N must be 1 or greater for GER");
+        }
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (M - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GER");
+        }
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GER");
+        }
+
+
+    }
+    static int validateSYR(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation A) {
+        validateUplo(Uplo);
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+
+        int N = A.getType().getX();
+
+        if (X.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+        if (N != A.getType().getY()) {
+            throw new RSRuntimeException("A must be a symmetric matrix");
+        }
+        if (incX <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SYR");
+        }
+        return N;
+    }
+    static int validateSPR(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Ap) {
+        validateUplo(Uplo);
+        if (!Ap.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (Ap.getType().getY() > 1) {
+            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
+        }
+
+        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
+        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
+            throw new RSRuntimeException("Invalid dimension for Ap");
+        }
+        if (incX <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SPR");
+        }
+
+        return N;
+    }
+
+    static int validateSYR2(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        validateUplo(Uplo);
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        int N = A.getType().getX();
+
+        if (N != A.getType().getY()) {
+            throw new RSRuntimeException("A must be a symmetric matrix");
+        }
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SYR");
+        }
+        return N;
+
+    }
+    static int validateSPR2(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        validateUplo(Uplo);
+        if (!Ap.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (Ap.getType().getY() > 1) {
+            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
+        }
+
+        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
+        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
+            throw new RSRuntimeException("Invalid dimension for Ap");
+        }
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SPR2");
+        }
+
+        return N;
+    }
+
+    /**
+     * SSYMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d2/d94/ssymv_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void SSYMV(@Uplo int Uplo, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SSBMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d3/da1/ssbmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
+     * @param K The number of off-diagonals of the matrix A
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void SSBMV(@Uplo int Uplo, int K, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        // SBMV is the same as SYMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SSPMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d8/d68/sspmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
+     * @param alpha The scalar alpha.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void SSPMV(@Uplo int Uplo, float alpha, Allocation Ap, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        int N = validateSPMV(Element.F32(mRS), Uplo, Ap, X, incX, Y, incY);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, apID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SGER performs the rank 1 operation
+     * A := alpha*x*y**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/d5c/sger_8f.html
+     *
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     */
+    public void SGER(float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        validateGER(Element.F32(mRS), X, incX, Y, incY, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sger, 0, 0, 0, 0, 0, M, N, 0, alpha, xID, yID, 0.f, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SSYR performs the rank 1 operation
+     * A := alpha*x*x**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d6/dac/ssyr_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     */
+    public void SSYR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
+        int N = validateSYR(Element.F32(mRS), Uplo, X, incX, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, aID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SSPR performs the rank 1 operation
+     * A := alpha*x*x**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d2/d9b/sspr_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     */
+    public void SSPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
+        int N = validateSPR(Element.F32(mRS), Uplo, X, incX, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, apID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SSYR2 performs the symmetric rank 2 operation
+     * A := alpha*x*y**T + alpha*y*x**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/d99/ssyr2_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     */
+    public void SSYR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        int N = validateSYR2(Element.F32(mRS), Uplo, X, incX, Y, incY, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SSPR2 performs the symmetric rank 2 operation
+     * A := alpha*x*y**T + alpha*y*x**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/d3e/sspr2_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     */
+    public void SSPR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        int N = validateSPR2(Element.F32(mRS), Uplo, X, incX, Y, incY, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, apID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSYMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d8/dbe/dsymv_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void DSYMV(@Uplo int Uplo, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSBMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d8/d1e/dsbmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
+     * @param K The number of off-diagonals of the matrix A
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void DSBMV(@Uplo int Uplo, int K, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        // SBMV is the same as SYMV + K >= 0
+        if (K < 0) {
+            throw new RSRuntimeException("K must be greater than or equal to 0");
+        }
+        int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSPMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d4/d85/dspmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
+     * @param alpha The scalar alpha.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void DSPMV(@Uplo int Uplo, double alpha, Allocation Ap, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        int N = validateSPMV(Element.F64(mRS), Uplo, Ap, X, incX, Y, incY);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, apID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DGER performs the rank 1 operation
+     * A := alpha*x*y**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/dc/da8/dger_8f.html
+     *
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     */
+    public void DGER(double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        validateGER(Element.F64(mRS), X, incX, Y, incY, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dger, 0, 0, 0, 0, 0, M, N, 0, alpha, xID, yID, 0.f, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSYR performs the rank 1 operation
+     * A := alpha*x*x**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d3/d60/dsyr_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     */
+    public void DSYR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
+        int N = validateSYR(Element.F64(mRS), Uplo, X, incX, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, aID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSPR performs the rank 1 operation
+     * A := alpha*x*x**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/dd/dba/dspr_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     */
+    public void DSPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
+        int N = validateSPR(Element.F64(mRS), Uplo, X, incX, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, apID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSYR2 performs the symmetric rank 2 operation
+     * A := alpha*x*y**T + alpha*y*x**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/de/d41/dsyr2_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     */
+    public void DSYR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        int N = validateSYR2(Element.F64(mRS), Uplo, X, incX, Y, incY, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSPR2 performs the symmetric rank 2 operation
+     * A := alpha*x*y**T + alpha*y*x**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/dd/d9e/dspr2_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     */
+    public void DSPR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        int N = validateSPR2(Element.F64(mRS), Uplo, X, incX, Y, incY, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, apID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+
+    /**
+     * Level 2, C and Z only
+     */
+
+    static void validateGERU(Element e, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (M - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GERU");
+        }
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GERU");
+        }
+
+    }
+
+    /**
+     * CHEMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d7/d51/chemv_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void CHEMV(@Uplo int Uplo, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        // HEMV is the same as SYR2 validation-wise
+        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CHBMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/dc2/chbmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
+     * @param K The number of off-diagonals of the matrix A
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void CHBMV(@Uplo int Uplo, int K, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        // HBMV is the same as SYR2 validation-wise
+        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
+        if (K < 0) {
+            throw new RSRuntimeException("K must be 0 or greater for HBMV");
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CHPMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d2/d06/chpmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
+     * @param alpha The scalar alpha.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void CHPMV(@Uplo int Uplo, Float2 alpha, Allocation Ap, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        // HPMV is the same as SPR2
+        int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, apID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CGERU performs the rank 1 operation
+     * A := alpha*x*y**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/d5f/cgeru_8f.html
+     *
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     */
+    public void CGERU(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CGERC performs the rank 1 operation
+     * A := alpha*x*y**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/dd/d84/cgerc_8f.html
+     *
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     */
+    public void CGERC(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        // same as GERU
+        validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CHER performs the rank 1 operation
+     * A := alpha*x*x**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d3/d6d/cher_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     */
+    public void CHER(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
+        // same as SYR
+        int N = validateSYR(Element.F32_2(mRS), Uplo, X, incX, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, aID, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CHPR performs the rank 1 operation
+     * A := alpha*x*x**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/dcd/chpr_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     */
+    public void CHPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
+        // equivalent to SPR for validation
+        int N = validateSPR(Element.F32_2(mRS), Uplo, X, incX, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, apID, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CHER2 performs the symmetric rank 2 operation
+     * A := alpha*x*y**H + alpha*y*x**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/d87/cher2_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     */
+    public void CHER2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        // same as SYR2
+        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CHPR2 performs the symmetric rank 2 operation
+     * A := alpha*x*y**H + alpha*y*x**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d6/d44/chpr2_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     */
+    public void CHPR2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        // same as SPR2
+        int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, apID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHEMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d0/ddd/zhemv_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void ZHEMV(@Uplo int Uplo, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        // HEMV is the same as SYR2 validation-wise
+        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHBMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d3/d1a/zhbmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
+     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
+     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
+     *           for i in range(0, n):
+     *              for j in range(i, min(i+k+1, n)):
+     *                  b[i, j-i] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
+     * @param K The number of off-diagonals of the matrix A
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void ZHBMV(@Uplo int Uplo, int K, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        // HBMV is the same as SYR2 validation-wise
+        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
+        if (K < 0) {
+            throw new RSRuntimeException("K must be 0 or greater for HBMV");
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHPMV performs the matrix-vector operation
+     * y := alpha*A*x + beta*y
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d0/d60/zhpmv_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
+     * @param alpha The scalar alpha.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param beta The scalar beta.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     */
+    public void ZHPMV(@Uplo int Uplo, Double2 alpha, Allocation Ap, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        // HPMV is the same as SPR2
+        int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, apID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZGERU performs the rank 1 operation
+     * A := alpha*x*y**T + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d7/d12/zgeru_8f.html
+     *
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     */
+    public void ZGERU(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZGERC performs the rank 1 operation
+     * A := alpha*x*y**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d3/dad/zgerc_8f.html
+     *
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     */
+    public void ZGERC(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        // same as GERU
+        validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHER performs the rank 1 operation
+     * A := alpha*x*x**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/de/d0e/zher_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     */
+    public void ZHER(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
+        // same as SYR
+        int N = validateSYR(Element.F64_2(mRS), Uplo, X, incX, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, aID, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHPR performs the rank 1 operation
+     * A := alpha*x*x**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/de/de1/zhpr_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     */
+    public void ZHPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
+        // equivalent to SPR for validation
+        int N = validateSPR(Element.F64_2(mRS), Uplo, X, incX, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, apID, incX, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHER2 performs the symmetric rank 2 operation
+     * A := alpha*x*y**H + alpha*y*x**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/da/d8a/zher2_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     */
+    public void ZHER2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        // same as SYR2
+        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHPR2 performs the symmetric rank 2 operation
+     * A := alpha*x*y**H + alpha*y*x**H + A
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d5/d52/zhpr2_8f.html
+     *
+     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
+     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
+     *       'a' to packed matrix 'b'.
+     *           k = 0
+     *           for i in range(0, n):
+     *              for j in range(i, n):
+     *                  b[k++] = a[i, j]
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
+     * @param alpha The scalar alpha.
+     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
+     * @param incX The increment for the elements of vector x, must be larger than zero.
+     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
+     * @param incY The increment for the elements of vector y, must be larger than zero.
+     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     */
+    public void ZHPR2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        // same as SPR2
+        int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
+
+        boolean mUseIncSupp = isIncSupp();
+        long apID = Ap.getID(mRS);
+        long xID = X.getID(mRS);
+        long yID = Y.getID(mRS);
+        if (mUseIncSupp) {
+            apID = getDummyAlloc(Ap);
+            xID = getDummyAlloc(X);
+            yID = getDummyAlloc(Y);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, apID, incX, incY, 0, 0, mUseIncSupp);
+    }
+
+
+    /**
+     * Level 3 BLAS
+     */
+
+    static void validateL3(Element e, int TransA, int TransB, int Side, Allocation A, Allocation B, Allocation C) {
+        int aM = -1, aN = -1, bM = -1, bN = -1, cM = -1, cN = -1;
+        if ((A != null && !A.getType().getElement().isCompatible(e)) ||
+            (B != null && !B.getType().getElement().isCompatible(e)) ||
+            (C != null && !C.getType().getElement().isCompatible(e))) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (C == null) {
+            //since matrix C is used to store the result, it cannot be null.
+            throw new RSRuntimeException("Allocation C cannot be null");
+        }
+        cM = C.getType().getY();
+        cN = C.getType().getX();
+
+        if (Side == RIGHT) {
+            if ((A == null && B != null) || (A != null && B == null)) {
+                throw new RSRuntimeException("Provided Matrix A without Matrix B, or vice versa");
+            }
+            if (B != null) {
+                bM = A.getType().getY();
+                bN = A.getType().getX();
+            }
+            if (A != null) {
+                aM = B.getType().getY();
+                aN = B.getType().getX();
+            }
+        } else {
+            if (A != null) {
+                if (TransA == TRANSPOSE || TransA == CONJ_TRANSPOSE) {
+                    aN = A.getType().getY();
+                    aM = A.getType().getX();
+                } else {
+                    aM = A.getType().getY();
+                    aN = A.getType().getX();
+                }
+            }
+            if (B != null) {
+                if (TransB == TRANSPOSE || TransB == CONJ_TRANSPOSE) {
+                    bN = B.getType().getY();
+                    bM = B.getType().getX();
+                } else {
+                    bM = B.getType().getY();
+                    bN = B.getType().getX();
+                }
+            }
+        }
+        if (A != null && B != null && C != null) {
+            if (aN != bM || aM != cM || bN != cN) {
+                throw new RSRuntimeException("Called BLAS with invalid dimensions");
+            }
+        } else if (A != null && C != null) {
+            // A and C only, for SYRK
+            if (cM != cN) {
+                throw new RSRuntimeException("Matrix C is not symmetric");
+            }
+            if (aM != cM) {
+                throw new RSRuntimeException("Called BLAS with invalid dimensions");
+            }
+        } else if (A != null && B != null) {
+            // A and B only
+            if (aN != bM) {
+                throw new RSRuntimeException("Called BLAS with invalid dimensions");
+            }
+        }
+
+    }
+
+    /**
+     * SGEMM performs one of the matrix-matrix operations
+     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d4/de2/sgemm_8f.html
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param TransB The type of transpose applied to matrix B.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
+     */
+    public void SGEMM(@Transpose int TransA, @Transpose int TransB, float alpha, Allocation A,
+                      Allocation B, float beta, Allocation C) {
+        validateTranspose(TransA);
+        validateTranspose(TransB);
+        validateL3(Element.F32(mRS), TransA, TransB, 0, A, B, C);
+
+        int M = -1, N = -1, K = -1;
+        if (TransA != NO_TRANSPOSE) {
+            M = A.getType().getX();
+            K = A.getType().getY();
+        } else {
+            M = A.getType().getY();
+            K = A.getType().getX();
+        }
+        if (TransB != NO_TRANSPOSE) {
+            N = B.getType().getY();
+        } else {
+            N = B.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha, aID, bID,
+                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DGEMM performs one of the matrix-matrix operations
+     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d7/d2b/dgemm_8f.html
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param TransB The type of transpose applied to matrix B.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
+     */
+    public void DGEMM(@Transpose int TransA, @Transpose int TransB, double alpha, Allocation A,
+                      Allocation B, double beta, Allocation C) {
+        validateTranspose(TransA);
+        validateTranspose(TransB);
+        validateL3(Element.F64(mRS), TransA, TransB, 0, A, B, C);
+        int M = -1, N = -1, K = -1;
+        if (TransA != NO_TRANSPOSE) {
+            M = A.getType().getX();
+            K = A.getType().getY();
+        } else {
+            M = A.getType().getY();
+            K = A.getType().getX();
+        }
+        if (TransB != NO_TRANSPOSE) {
+            N = B.getType().getY();
+        } else {
+            N = B.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha, aID, bID,
+                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CGEMM performs one of the matrix-matrix operations
+     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T  or  op(X) = X**H
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d6/d5b/cgemm_8f.html
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param TransB The type of transpose applied to matrix B.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
+     */
+    public void CGEMM(@Transpose int TransA, @Transpose int TransB, Float2 alpha, Allocation A,
+                      Allocation B, Float2 beta, Allocation C) {
+        validateTranspose(TransA);
+        validateTranspose(TransB);
+        validateL3(Element.F32_2(mRS), TransA, TransB, 0, A, B, C);
+        int M = -1, N = -1, K = -1;
+        if (TransA != NO_TRANSPOSE) {
+            M = A.getType().getX();
+            K = A.getType().getY();
+        } else {
+            M = A.getType().getY();
+            K = A.getType().getX();
+        }
+        if (TransB != NO_TRANSPOSE) {
+            N = B.getType().getY();
+        } else {
+            N = B.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha.x, alpha.y, aID, bID,
+                                         beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZGEMM performs one of the matrix-matrix operations
+     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T  or  op(X) = X**H
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d7/d76/zgemm_8f.html
+     *
+     * @param TransA The type of transpose applied to matrix A.
+     * @param TransB The type of transpose applied to matrix B.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2
+     */
+    public void ZGEMM(@Transpose int TransA, @Transpose int TransB, Double2 alpha, Allocation A,
+                      Allocation B, Double2 beta, Allocation C) {
+        validateTranspose(TransA);
+        validateTranspose(TransB);
+        validateL3(Element.F64_2(mRS), TransA, TransB, 0, A, B, C);
+        int M = -1, N = -1, K = -1;
+        if (TransA != NO_TRANSPOSE) {
+            M = A.getType().getX();
+            K = A.getType().getY();
+        } else {
+            M = A.getType().getY();
+            K = A.getType().getX();
+        }
+        if (TransB != NO_TRANSPOSE) {
+            N = B.getType().getY();
+        } else {
+            N = B.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha.x, alpha.y, aID, bID,
+                                   beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SSYMM performs one of the matrix-matrix operations
+     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d7/d42/ssymm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
+     */
+    public void SSYMM(@Side int Side, @Uplo int Uplo, float alpha, Allocation A,
+                      Allocation B, float beta, Allocation C) {
+        validateSide(Side);
+        validateUplo(Uplo);
+        //For SYMM, Matrix A should be symmetric
+        if (A.getType().getX() != A.getType().getY()) {
+            throw new RSRuntimeException("Matrix A is not symmetric");
+        }
+        validateL3(Element.F32(mRS), 0, 0, Side, A, B, C);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, aID, bID,
+                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSYMM performs one of the matrix-matrix operations
+     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d8/db0/dsymm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
+     */
+    public void DSYMM(@Side int Side, @Uplo int Uplo, double alpha, Allocation A,
+                      Allocation B, double beta, Allocation C) {
+        validateSide(Side);
+        validateUplo(Uplo);
+        if (A.getType().getX() != A.getType().getY()) {
+            throw new RSRuntimeException("Matrix A is not symmetric");
+        }
+        validateL3(Element.F64(mRS), 0, 0, Side, A, B, C);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, aID, bID,
+                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CSYMM performs one of the matrix-matrix operations
+     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/db/d59/csymm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
+     */
+    public void CSYMM(@Side int Side, @Uplo int Uplo, Float2 alpha, Allocation A,
+                      Allocation B, Float2 beta, Allocation C) {
+        validateSide(Side);
+        validateUplo(Uplo);
+        if (A.getType().getX() != A.getType().getY()) {
+            throw new RSRuntimeException("Matrix A is not symmetric");
+        }
+        validateL3(Element.F32_2(mRS), 0, 0, Side, A, B, C);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, aID, bID,
+                                         beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZSYMM performs one of the matrix-matrix operations
+     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/df/d51/zsymm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
+     */
+    public void ZSYMM(@Side int Side, @Uplo int Uplo, Double2 alpha, Allocation A,
+                      Allocation B, Double2 beta, Allocation C) {
+        validateSide(Side);
+        validateUplo(Uplo);
+        if (A.getType().getX() != A.getType().getY()) {
+            throw new RSRuntimeException("Matrix A is not symmetric");
+        }
+        validateL3(Element.F64_2(mRS), 0, 0, Side, A, B, C);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, aID, bID,
+                                   beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * SSYRK performs one of the symmetric rank k operations
+     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d0/d40/ssyrk_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
+     */
+    public void SSYRK(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, float beta, Allocation C) {
+        validateTranspose(Trans);
+        validateUplo(Uplo);
+        validateL3(Element.F32(mRS), Trans, 0, 0, A, null, C);
+        int K = -1;
+        if (Trans != NO_TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, 0, beta, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSYRK performs one of the symmetric rank k operations
+     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/dc/d05/dsyrk_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
+     */
+    public void DSYRK(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, double beta, Allocation C) {
+        validateTranspose(Trans);
+        validateUplo(Uplo);
+        validateL3(Element.F64(mRS), Trans, 0, 0, A, null, C);
+        int K = -1;
+        if (Trans != NO_TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, 0, beta, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CSYRK performs one of the symmetric rank k operations
+     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d3/d6a/csyrk_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
+     */
+    public void CSYRK(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Float2 beta, Allocation C) {
+        validateTranspose(Trans);
+        validateUplo(Uplo);
+        validateL3(Element.F32_2(mRS), Trans, 0, 0, A, null, C);
+        int K = -1;
+        if (Trans != NO_TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, 0, beta.x, beta.y,
+                                         C.getID(mRS), 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZSYRK performs one of the symmetric rank k operations
+     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/de/d54/zsyrk_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
+     */
+    public void ZSYRK(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Double2 beta, Allocation C) {
+        validateTranspose(Trans);
+        validateUplo(Uplo);
+        validateL3(Element.F64_2(mRS), Trans, 0, 0, A, null, C);
+        int K = -1;
+        if (Trans != NO_TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, 0, beta.x, beta.y,
+                                   C.getID(mRS), 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    static void validateSYR2K(Element e, @Transpose int Trans, Allocation A, Allocation B, Allocation C) {
+        validateTranspose(Trans);
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e) ||
+            !C.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        int Cdim = -1;
+        // A is n x k if no transpose, k x n if transpose
+        // C is n x n
+        if (Trans == TRANSPOSE) {
+            // check columns versus C
+            Cdim = A.getType().getX();
+        } else {
+            // check rows versus C
+            Cdim = A.getType().getY();
+        }
+        if (C.getType().getX() != Cdim || C.getType().getY() != Cdim) {
+            throw new RSRuntimeException("Invalid symmetric matrix in SYR2K");
+        }
+        // A dims == B dims
+        if (A.getType().getX() != B.getType().getX() || A.getType().getY() != B.getType().getY()) {
+            throw new RSRuntimeException("Invalid A and B in SYR2K");
+        }
+    }
+
+    /**
+     * SSYR2K performs one of the symmetric rank 2k operations
+     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/df/d3d/ssyr2k_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
+     */
+    public void SSYR2K(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, Allocation B, float beta, Allocation C) {
+        validateUplo(Uplo);
+        validateSYR2K(Element.F32(mRS), Trans, A, B, C);
+        int K = -1;
+        if (Trans != NO_TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, bID, beta, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DSYR2K performs one of the symmetric rank 2k operations
+     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d1/dec/dsyr2k_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
+     */
+    public void DSYR2K(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, Allocation B, double beta, Allocation C) {
+        validateUplo(Uplo);
+        validateSYR2K(Element.F64(mRS), Trans, A, B, C);
+        int K = -1;
+        if (Trans != NO_TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, bID, beta, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CSYR2K performs one of the symmetric rank 2k operations
+     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/de/d7e/csyr2k_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
+     */
+    public void CSYR2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
+        validateUplo(Uplo);
+        validateSYR2K(Element.F32_2(mRS), Trans, A, B, C);
+        int K = -1;
+        if (Trans != NO_TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZSYR2K performs one of the symmetric rank 2k operations
+     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/df/d20/zsyr2k_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
+     */
+    public void ZSYR2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
+        validateUplo(Uplo);
+        validateSYR2K(Element.F64_2(mRS), Trans, A, B, C);
+        int K = -1;
+        if (Trans != NO_TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    static void validateTRMM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
+        validateSide(Side);
+        validateTranspose(TransA);
+        int aM = -1, aN = -1, bM = -1, bN = -1;
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+
+        aM = A.getType().getY();
+        aN = A.getType().getX();
+        if (aM != aN) {
+            throw new RSRuntimeException("Called TRMM with a non-symmetric matrix A");
+        }
+
+        bM = B.getType().getY();
+        bN = B.getType().getX();
+        if (Side == LEFT) {
+            if (aN != bM) {
+                throw new RSRuntimeException("Called TRMM with invalid matrices");
+            }
+        } else {
+            if (bN != aM) {
+                throw new RSRuntimeException("Called TRMM with invalid matrices");
+            }
+        }
+    }
+
+    /**
+     * STRMM performs one of the matrix-matrix operations
+     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
+     * op(A) is one of  op(A) = A  or  op(A) = A**T
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/df/d01/strmm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether matrix A is upper or lower triangular.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
+     */
+    public void STRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, float alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRMM(Element.F32(mRS), Side, TransA, A, B);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                        alpha, aID, bID, 0.f, 0, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DTRMM performs one of the matrix-matrix operations
+     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
+     * op(A) is one of  op(A) = A  or  op(A) = A**T
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/dd/d19/dtrmm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether matrix A is upper or lower triangular.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
+     */
+    public void DTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, double alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRMM(Element.F64(mRS), Side, TransA, A, B);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                        alpha, aID, bID, 0, 0, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CTRMM performs one of the matrix-matrix operations
+     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
+     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d4/d9b/ctrmm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether matrix A is upper or lower triangular.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
+     */
+    public void CTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRMM(Element.F32_2(mRS), Side, TransA, A, B);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                         alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZTRMM performs one of the matrix-matrix operations
+     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
+     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d8/de1/ztrmm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether matrix A is upper or lower triangular.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
+     */
+    public void ZTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRMM(Element.F64_2(mRS), Side, TransA, A, B);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                   alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    static void validateTRSM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
+        int adim = -1, bM = -1, bN = -1;
+        validateSide(Side);
+        validateTranspose(TransA);
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        adim = A.getType().getX();
+        if (adim != A.getType().getY()) {
+            // this may be unnecessary, the restriction could potentially be relaxed
+            // A needs to contain at least that symmetric matrix but could theoretically be larger
+            // for now we assume adapters are sufficient, will reevaluate in the future
+            throw new RSRuntimeException("Called TRSM with a non-symmetric matrix A");
+        }
+        bM = B.getType().getY();
+        bN = B.getType().getX();
+        if (Side == LEFT) {
+            // A is M*M
+            if (adim != bM) {
+                throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
+            }
+        } else {
+            // A is N*N
+            if (adim != bN) {
+                throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
+            }
+        }
+    }
+
+    /**
+     * STRSM solves one of the matrix equations
+     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
+     * op(A) is one of  op(A) = A  or  op(A) = A**T
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d2/d8b/strsm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether matrix A is upper or lower triangular.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
+     */
+    public void STRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, float alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRSM(Element.F32(mRS), Side, TransA, A, B);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                        alpha, aID, bID, 0, 0, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * DTRSM solves one of the matrix equations
+     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
+     * op(A) is one of  op(A) = A  or  op(A) = A**T
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/de/da7/dtrsm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether matrix A is upper or lower triangular.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
+     */
+    public void DTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, double alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRSM(Element.F64(mRS), Side, TransA, A, B);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                        alpha, aID, bID, 0, 0, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * CTRSM solves one of the matrix equations
+     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
+     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/de/d30/ctrsm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether matrix A is upper or lower triangular.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
+     */
+    public void CTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRSM(Element.F32_2(mRS), Side, TransA, A, B);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                         alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZTRSM solves one of the matrix equations
+     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
+     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d1/d39/ztrsm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether matrix A is upper or lower triangular.
+     * @param TransA The type of transpose applied to matrix A.
+     * @param Diag Specifies whether or not A is unit triangular.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
+     */
+    public void ZTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRSM(Element.F64_2(mRS), Side, TransA, A, B);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                   alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    static void validateHEMM(Element e, @Side int Side, Allocation A, Allocation B, Allocation C) {
+        validateSide(Side);
+
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e) ||
+            !C.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+
+        // A must be square; can potentially be relaxed similar to TRSM
+        int adim = A.getType().getX();
+        if (adim != A.getType().getY()) {
+            throw new RSRuntimeException("Called HEMM with non-square A");
+        }
+        if ((Side == LEFT && adim != B.getType().getY()) ||
+            (Side == RIGHT && adim != B.getType().getX())) {
+            throw new RSRuntimeException("Called HEMM with invalid B");
+        }
+        if (B.getType().getX() != C.getType().getX() ||
+            B.getType().getY() != C.getType().getY()) {
+            throw new RSRuntimeException("Called HEMM with mismatched B and C");
+        }
+    }
+
+    /**
+     * CHEMM performs one of the matrix-matrix operations
+     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d3/d66/chemm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
+     */
+    public void CHEMM(@Side int Side, @Uplo int Uplo, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHEMM(Element.F32_2(mRS), Side, A, B, C);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
+                                         alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHEMM performs one of the matrix-matrix operations
+     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d6/d3e/zhemm_8f.html
+     *
+     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
+     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
+     */
+    public void ZHEMM(@Side int Side, @Uplo int Uplo, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHEMM(Element.F64_2(mRS), Side, A, B, C);
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
+                                   alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    static void validateHERK(Element e, @Transpose int Trans, Allocation A, Allocation C) {
+        if (!A.getType().getElement().isCompatible(e) ||
+            !C.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        validateConjTranspose(Trans);
+        int cdim = C.getType().getX();
+        if (cdim != C.getType().getY()) {
+            throw new RSRuntimeException("Called HERK with non-square C");
+        }
+        if (Trans == NO_TRANSPOSE) {
+            if (cdim != A.getType().getY()) {
+                throw new RSRuntimeException("Called HERK with invalid A");
+            }
+        } else {
+            if (cdim != A.getType().getX()) {
+                throw new RSRuntimeException("Called HERK with invalid A");
+            }
+        }
+    }
+
+    /**
+     * CHERK performs one of the hermitian rank k operations
+     * C := alpha*A*A**H + beta*C   or   C := alpha*A**H*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d8/d52/cherk_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
+     */
+    public void CHERK(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, float beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHERK(Element.F32_2(mRS), Trans, A, C);
+        int k = 0;
+        if (Trans == CONJ_TRANSPOSE) {
+            k = A.getType().getY();
+        } else {
+            k = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cherk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k,
+                                         alpha, 0, aID, 0, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHERK performs one of the hermitian rank k operations
+     * C := alpha*A*A**H + beta*C   or   C := alpha*A**H*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d1/db1/zherk_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
+     */
+    public void ZHERK(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, double beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHERK(Element.F64_2(mRS), Trans, A, C);
+        int k = 0;
+        if (Trans == CONJ_TRANSPOSE) {
+            k = A.getType().getY();
+        } else {
+            k = A.getType().getX();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zherk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k,
+                                   alpha, 0, aID, 0, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    static void validateHER2K(Element e, @Transpose int Trans, Allocation A, Allocation B, Allocation C) {
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e) ||
+            !C.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        validateConjTranspose(Trans);
+        int cdim = C.getType().getX();
+        if (cdim != C.getType().getY()) {
+            throw new RSRuntimeException("Called HER2K with non-square C");
+        }
+        if (Trans == NO_TRANSPOSE) {
+            if (A.getType().getY() != cdim) {
+                throw new RSRuntimeException("Called HER2K with invalid matrices");
+            }
+        } else {
+            if (A.getType().getX() != cdim) {
+                throw new RSRuntimeException("Called HER2K with invalid matrices");
+            }
+        }
+        if (A.getType().getX() != B.getType().getX() || A.getType().getY() != B.getType().getY()) {
+            throw new RSRuntimeException("Called HER2K with invalid A and B matrices");
+        }
+    }
+
+    /**
+     * CHER2K performs one of the hermitian rank 2k operations
+     * C := alpha*A*B**H + conjg( alpha )*B*A**H + beta*C   or   C := alpha*A**H*B + conjg( alpha )*B**H*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d1/d82/cher2k_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
+     */
+    public void CHER2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, float beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHER2K(Element.F32_2(mRS), Trans, A, B, C);
+        int k = 0;
+        if (Trans == NO_TRANSPOSE) {
+            k = A.getType().getX();
+        } else {
+            k = A.getType().getY();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k, alpha.x, alpha.y,
+                                         A.getID(mRS), bID, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+    /**
+     * ZHER2K performs one of the hermitian rank 2k operations
+     * C := alpha*A*B**H + conjg( alpha )*B*A**H + beta*C   or   C := alpha*A**H*B + conjg( alpha )*B**H*A + beta*C
+     *
+     * Details: http://www.netlib.org/lapack/explore-html/d7/dfa/zher2k_8f.html
+     *
+     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
+     * @param Trans The type of transpose applied to the operation.
+     * @param alpha The scalar alpha.
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
+     * @param beta The scalar beta.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
+     */
+    public void ZHER2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, double beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHER2K(Element.F64_2(mRS), Trans, A, B, C);
+        int k = 0;
+        if (Trans == NO_TRANSPOSE) {
+            k = A.getType().getX();
+        } else {
+            k = A.getType().getY();
+        }
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k, alpha.x, alpha.y,
+                                   A.getID(mRS), bID, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
+    }
+
+
+    /**
+     * 8-bit GEMM-like operation for neural networks: C = A * Transpose(B)
+     * Calculations are done in 1.10.21 fixed-point format for the final output,
+     * just before there's a shift down to drop the fractional parts. The output
+     * values are gated to 0 to 255 to fit in a byte, but the 10-bit format
+     * gives some headroom to avoid wrapping around on small overflows.
+     *
+     * @param A The input allocation contains matrix A, supported elements type {@link Element#U8}.
+     * @param a_offset The offset for all values in matrix A, e.g A[i,j] = A[i,j] - a_offset. Value should be from 0 to 255.
+     * @param B The input allocation contains matrix B, supported elements type {@link Element#U8}.
+     * @param b_offset The offset for all values in matrix B, e.g B[i,j] = B[i,j] - b_offset. Value should be from 0 to 255.
+     * @param C The input allocation contains matrix C, supported elements type {@link Element#U8}.
+     * @param c_offset The offset for all values in matrix C.
+     * @param c_mult The multiplier for all values in matrix C, e.g C[i,j] = (C[i,j] + c_offset) * c_mult.
+     **/
+    public void BNNM(Allocation A, int a_offset, Allocation B, int b_offset, Allocation C, int c_offset, int c_mult) {
+        validateL3(Element.U8(mRS), NO_TRANSPOSE, TRANSPOSE, 0, A, B, C);
+
+        if (a_offset < 0 || a_offset > 255) {
+            throw new RSRuntimeException("Invalid a_offset passed to BNNM");
+        }
+        if (b_offset < 0 || b_offset > 255) {
+            throw new RSRuntimeException("Invalid b_offset passed to BNNM");
+        }
+        int M = -1, N = -1, K = -1;
+        M = A.getType().getY();
+        N = B.getType().getY();
+        K = A.getType().getX();
+
+        boolean mUseIncSupp = isIncSupp();
+        long aID = A.getID(mRS);
+        long bID = B.getID(mRS);
+        long cID = C.getID(mRS);
+        if (mUseIncSupp) {
+            aID = getDummyAlloc(A);
+            bID = getDummyAlloc(B);
+            cID = getDummyAlloc(C);
+        }
+        mRS.nScriptIntrinsicBLAS_BNNM(getID(mRS), M, N, K, aID, a_offset, bID, b_offset, cID, c_offset, c_mult, mUseIncSupp);
+
+    }
+
+}
diff --git a/androidx/renderscript/ScriptIntrinsicBlend.java b/androidx/renderscript/ScriptIntrinsicBlend.java
new file mode 100644
index 0000000..c7e174d
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicBlend.java
@@ -0,0 +1,477 @@
+/*
+ * 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 androidx.renderscript;
+
+
+/**
+ * Intrinsic kernels for blending two
+ * {@link androidx.renderscript.Allocation} objects.
+ **/
+public class ScriptIntrinsicBlend extends ScriptIntrinsic {
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 19;
+
+    ScriptIntrinsicBlend(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Supported elements types are {@link Element#U8_4}
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for inputs and outputs
+     *
+     * @return ScriptIntrinsicBlend
+     */
+    public static ScriptIntrinsicBlend create(RenderScript rs, Element e) {
+        // 7 comes from RS_SCRIPT_INTRINSIC_ID_BLEND in rsDefines.h
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(7, e.getID(rs), mUseIncSupp);
+
+        ScriptIntrinsicBlend si = new ScriptIntrinsicBlend(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        return si;
+
+    }
+
+    private void blend(int id, Allocation ain, Allocation aout) {
+        if (!ain.getElement().isCompatible(Element.U8_4(mRS))) {
+            throw new RSIllegalArgumentException("Input is not of expected format.");
+        }
+        if (!aout.getElement().isCompatible(Element.U8_4(mRS))) {
+            throw new RSIllegalArgumentException("Output is not of expected format.");
+        }
+        forEach(id, ain, aout, null);
+    }
+
+    /**
+     * Sets dst = {0, 0, 0, 0}
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachClear(Allocation ain, Allocation aout) {
+        blend(0, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Clear kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDClear() {
+        return createKernelID(0, 3, null, null);
+    }
+
+
+    /**
+     * Sets dst = src
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrc(Allocation ain, Allocation aout) {
+        blend(1, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Src kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrc() {
+        return createKernelID(1, 3, null, null);
+    }
+
+    /**
+     * Sets dst = dst
+     *
+     * This is a NOP.
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDst(Allocation ain, Allocation aout) {
+        // NOP
+    }
+
+    /**
+     * Get a KernelID for the Dst kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDst() {
+        return createKernelID(2, 3, null, null);
+    }
+
+    /**
+     * Sets dst = src + dst * (1.0 - src.a)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrcOver(Allocation ain, Allocation aout) {
+        blend(3, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the SrcOver kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrcOver() {
+        return createKernelID(3, 3, null, null);
+    }
+
+    /**
+     * Sets dst = dst + src * (1.0 - dst.a)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDstOver(Allocation ain, Allocation aout) {
+        blend(4, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the DstOver kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDstOver() {
+        return createKernelID(4, 3, null, null);
+    }
+
+    /**
+     * Sets dst = src * dst.a
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrcIn(Allocation ain, Allocation aout) {
+        blend(5, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the SrcIn kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrcIn() {
+        return createKernelID(5, 3, null, null);
+    }
+
+    /**
+     * Sets dst = dst * src.a
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDstIn(Allocation ain, Allocation aout) {
+        blend(6, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the DstIn kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDstIn() {
+        return createKernelID(6, 3, null, null);
+    }
+
+    /**
+     * Sets dst = src * (1.0 - dst.a)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrcOut(Allocation ain, Allocation aout) {
+        blend(7, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the SrcOut kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrcOut() {
+        return createKernelID(7, 3, null, null);
+    }
+
+    /**
+     * Sets dst = dst * (1.0 - src.a)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDstOut(Allocation ain, Allocation aout) {
+        blend(8, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the DstOut kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDstOut() {
+        return createKernelID(8, 3, null, null);
+    }
+
+    /**
+     * dst.rgb = src.rgb * dst.a + (1.0 - src.a) * dst.rgb
+     * dst.a = dst.a
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSrcAtop(Allocation ain, Allocation aout) {
+        blend(9, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the SrcAtop kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSrcAtop() {
+        return createKernelID(9, 3, null, null);
+    }
+
+    /**
+     * dst = dst.rgb * src.a + (1.0 - dst.a) * src.rgb
+     * dst.a = src.a
+     * Note: Before API 23, the alpha channel was not correctly set.
+     *       Please use with caution when targeting older APIs.
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachDstAtop(Allocation ain, Allocation aout) {
+        blend(10, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the DstAtop kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDDstAtop() {
+        return createKernelID(10, 3, null, null);
+    }
+
+    /**
+     * Sets dst = {src.r ^ dst.r, src.g ^ dst.g, src.b ^ dst.b, src.a ^ dst.a}
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachXor(Allocation ain, Allocation aout) {
+        blend(11, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Xor kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDXor() {
+        return createKernelID(11, 3, null, null);
+    }
+
+    ////////
+/*
+    public void forEachNormal(Allocation ain, Allocation aout) {
+        blend(12, ain, aout);
+    }
+
+    public void forEachAverage(Allocation ain, Allocation aout) {
+        blend(13, ain, aout);
+    }
+*/
+    /**
+     * Sets dst = src * dst
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachMultiply(Allocation ain, Allocation aout) {
+        blend(14, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Multiply kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDMultiply() {
+        return createKernelID(14, 3, null, null);
+    }
+
+/*
+    public void forEachScreen(Allocation ain, Allocation aout) {
+        blend(15, ain, aout);
+    }
+
+    public void forEachDarken(Allocation ain, Allocation aout) {
+        blend(16, ain, aout);
+    }
+
+    public void forEachLighten(Allocation ain, Allocation aout) {
+        blend(17, ain, aout);
+    }
+
+    public void forEachOverlay(Allocation ain, Allocation aout) {
+        blend(18, ain, aout);
+    }
+
+    public void forEachHardlight(Allocation ain, Allocation aout) {
+        blend(19, ain, aout);
+    }
+
+    public void forEachSoftlight(Allocation ain, Allocation aout) {
+        blend(20, ain, aout);
+    }
+
+    public void forEachDifference(Allocation ain, Allocation aout) {
+        blend(21, ain, aout);
+    }
+
+    public void forEachNegation(Allocation ain, Allocation aout) {
+        blend(22, ain, aout);
+    }
+
+    public void forEachExclusion(Allocation ain, Allocation aout) {
+        blend(23, ain, aout);
+    }
+
+    public void forEachColorDodge(Allocation ain, Allocation aout) {
+        blend(24, ain, aout);
+    }
+
+    public void forEachInverseColorDodge(Allocation ain, Allocation aout) {
+        blend(25, ain, aout);
+    }
+
+    public void forEachSoftDodge(Allocation ain, Allocation aout) {
+        blend(26, ain, aout);
+    }
+
+    public void forEachColorBurn(Allocation ain, Allocation aout) {
+        blend(27, ain, aout);
+    }
+
+    public void forEachInverseColorBurn(Allocation ain, Allocation aout) {
+        blend(28, ain, aout);
+    }
+
+    public void forEachSoftBurn(Allocation ain, Allocation aout) {
+        blend(29, ain, aout);
+    }
+
+    public void forEachReflect(Allocation ain, Allocation aout) {
+        blend(30, ain, aout);
+    }
+
+    public void forEachGlow(Allocation ain, Allocation aout) {
+        blend(31, ain, aout);
+    }
+
+    public void forEachFreeze(Allocation ain, Allocation aout) {
+        blend(32, ain, aout);
+    }
+
+    public void forEachHeat(Allocation ain, Allocation aout) {
+        blend(33, ain, aout);
+    }
+*/
+    /**
+     * Sets dst = min(src + dst, 1.0)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachAdd(Allocation ain, Allocation aout) {
+        blend(34, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Add kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDAdd() {
+        return createKernelID(34, 3, null, null);
+    }
+
+    /**
+     * Sets dst = max(dst - src, 0.0)
+     *
+     * @param ain The source buffer
+     * @param aout The destination buffer
+     */
+    public void forEachSubtract(Allocation ain, Allocation aout) {
+        blend(35, ain, aout);
+    }
+
+    /**
+     * Get a KernelID for the Subtract kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelIDSubtract() {
+        return createKernelID(35, 3, null, null);
+    }
+
+/*
+    public void forEachStamp(Allocation ain, Allocation aout) {
+        blend(36, ain, aout);
+    }
+
+    public void forEachRed(Allocation ain, Allocation aout) {
+        blend(37, ain, aout);
+    }
+
+    public void forEachGreen(Allocation ain, Allocation aout) {
+        blend(38, ain, aout);
+    }
+
+    public void forEachBlue(Allocation ain, Allocation aout) {
+        blend(39, ain, aout);
+    }
+
+    public void forEachHue(Allocation ain, Allocation aout) {
+        blend(40, ain, aout);
+    }
+
+    public void forEachSaturation(Allocation ain, Allocation aout) {
+        blend(41, ain, aout);
+    }
+
+    public void forEachColor(Allocation ain, Allocation aout) {
+        blend(42, ain, aout);
+    }
+
+    public void forEachLuminosity(Allocation ain, Allocation aout) {
+        blend(43, ain, aout);
+    }
+*/
+}
+
diff --git a/androidx/renderscript/ScriptIntrinsicBlur.java b/androidx/renderscript/ScriptIntrinsicBlur.java
new file mode 100644
index 0000000..4024416
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicBlur.java
@@ -0,0 +1,128 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+/**
+ * Intrinsic Gausian blur filter. Applies a gaussian blur of the
+ * specified radius to all elements of an allocation.
+ *
+ *
+ **/
+public class ScriptIntrinsicBlur extends ScriptIntrinsic {
+    private final float[] mValues = new float[9];
+    private Allocation mInput;
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 19;
+
+    protected ScriptIntrinsicBlur(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Create an intrinsic for applying a blur to an allocation. The
+     * default radius is 5.0.
+     *
+     * Supported elements types are {@link Element#U8},
+     * {@link Element#U8_4}.
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for inputs and outputs
+     *
+     * @return ScriptIntrinsicBlur
+     */
+    public static ScriptIntrinsicBlur create(RenderScript rs, Element e) {
+        if ((!e.isCompatible(Element.U8_4(rs))) && (!e.isCompatible(Element.U8(rs)))) {
+            throw new RSIllegalArgumentException("Unsupported element type.");
+        }
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(5, e.getID(rs), mUseIncSupp);
+
+        ScriptIntrinsicBlur si = new ScriptIntrinsicBlur(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        si.setRadius(5.f);
+
+        return si;
+    }
+
+    /**
+     * Set the input of the blur.
+     * Must match the element type supplied during create.
+     *
+     * @param ain The input allocation
+     */
+    public void setInput(Allocation ain) {
+        if (ain.getType().getY() == 0) {
+            throw new RSIllegalArgumentException("Input set to a 1D Allocation");
+        }
+        mInput = ain;
+        setVar(1, ain);
+    }
+
+    /**
+     * Set the radius of the Blur.
+     *
+     * Supported range 0 < radius <= 25
+     *
+     * @param radius The radius of the blur
+     */
+    public void setRadius(float radius) {
+        if (radius <= 0 || radius > 25) {
+            throw new RSIllegalArgumentException("Radius out of range (0 < r <= 25).");
+        }
+        setVar(0, radius);
+    }
+
+    /**
+     * Apply the filter to the input and save to the specified
+     * allocation.
+     *
+     * @param aout Output allocation. Must match creation element
+     *             type.
+     */
+    public void forEach(Allocation aout) {
+        if (aout.getType().getY() == 0) {
+            throw new RSIllegalArgumentException("Output is a 1D Allocation");
+        }
+        forEach(0, (Allocation) null, aout, null);
+    }
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID() {
+        return createKernelID(0, 2, null, null);
+    }
+
+    /**
+     * Get a FieldID for the input field of this intrinsic.
+     *
+     * @return Script.FieldID The FieldID object.
+     */
+    public Script.FieldID getFieldID_Input() {
+        return createFieldID(1, null);
+    }
+}
+
diff --git a/androidx/renderscript/ScriptIntrinsicColorMatrix.java b/androidx/renderscript/ScriptIntrinsicColorMatrix.java
new file mode 100644
index 0000000..a0a247d
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicColorMatrix.java
@@ -0,0 +1,262 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.util.Log;
+
+/**
+ * Intrinsic for applying a color matrix to allocations.
+ *
+ * This has the same effect as loading each element and
+ * converting it to a {@link Element#F32_4}, multiplying the
+ * result by the 4x4 color matrix as performed by
+ * rsMatrixMultiply() and writing it to the output after
+ * conversion back to {@link Element#U8_4}.
+ **/
+public class ScriptIntrinsicColorMatrix extends ScriptIntrinsic {
+    private final Matrix4f mMatrix = new Matrix4f();
+    private final Float4 mAdd = new Float4();
+    private Allocation mInput;
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 19;
+
+    protected ScriptIntrinsicColorMatrix(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Create an intrinsic for applying a color matrix to an
+     * allocation.
+     *
+     * Supported elements types are {@link Element#U8_4}
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for intputs and outputs
+     *
+     * @return ScriptIntrinsicColorMatrix
+     */
+    public static ScriptIntrinsicColorMatrix create(RenderScript rs, Element e) {
+        if (!e.isCompatible(Element.U8_4(rs))) {
+            throw new RSIllegalArgumentException("Unsupported element type.");
+        }
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(2, e.getID(rs), mUseIncSupp);
+
+        ScriptIntrinsicColorMatrix si = new ScriptIntrinsicColorMatrix(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        return si;
+
+    }
+
+    private void setMatrix() {
+        FieldPacker fp = new FieldPacker(16*4);
+        fp.addMatrix(mMatrix);
+        setVar(0, fp);
+    }
+
+    /**
+     * Set the color matrix which will be applied to each cell of
+     * the image.
+     *
+     * @param m The 4x4 matrix to set.
+     */
+    public void setColorMatrix(Matrix4f m) {
+        mMatrix.load(m);
+        setMatrix();
+    }
+
+    /**
+     * Set the color matrix which will be applied to each cell of the image.
+     * This will set the alpha channel to be a copy.
+     *
+     * @param m The 3x3 matrix to set.
+     */
+    public void setColorMatrix(Matrix3f m) {
+        mMatrix.load(m);
+        setMatrix();
+    }
+
+    /**
+     * Set the value to be added after the color matrix has been
+     * applied. The default value is {0, 0, 0, 0}
+     *
+     * @param f The float4 value to be added.
+     */
+    public void setAdd(Float4 f) {
+        mAdd.x = f.x;
+        mAdd.y = f.y;
+        mAdd.z = f.z;
+        mAdd.w = f.w;
+
+        FieldPacker fp = new FieldPacker(4*4);
+        fp.addF32(f.x);
+        fp.addF32(f.y);
+        fp.addF32(f.z);
+        fp.addF32(f.w);
+        setVar(1, fp);
+    }
+
+    /**
+     * Set the value to be added after the color matrix has been
+     * applied. The default value is {0, 0, 0, 0}
+     *
+     * @param r The red add value.
+     * @param g The green add value.
+     * @param b The blue add value.
+     * @param a The alpha add value.
+     */
+    public void setAdd(float r, float g, float b, float a) {
+        mAdd.x = r;
+        mAdd.y = g;
+        mAdd.z = b;
+        mAdd.w = a;
+
+        FieldPacker fp = new FieldPacker(4*4);
+        fp.addF32(mAdd.x);
+        fp.addF32(mAdd.y);
+        fp.addF32(mAdd.z);
+        fp.addF32(mAdd.w);
+        setVar(1, fp);
+    }
+
+    /**
+     * Set a color matrix to convert from RGB to luminance. The alpha channel
+     * will be a copy.
+     *
+     */
+    public void setGreyscale() {
+        mMatrix.loadIdentity();
+        mMatrix.set(0, 0, 0.299f);
+        mMatrix.set(1, 0, 0.587f);
+        mMatrix.set(2, 0, 0.114f);
+        mMatrix.set(0, 1, 0.299f);
+        mMatrix.set(1, 1, 0.587f);
+        mMatrix.set(2, 1, 0.114f);
+        mMatrix.set(0, 2, 0.299f);
+        mMatrix.set(1, 2, 0.587f);
+        mMatrix.set(2, 2, 0.114f);
+        setMatrix();
+    }
+
+    /**
+     * Set the matrix to convert from YUV to RGB with a direct copy of the 4th
+     * channel.
+     *
+     */
+    public void setYUVtoRGB() {
+        mMatrix.loadIdentity();
+        mMatrix.set(0, 0, 1.f);
+        mMatrix.set(1, 0, 0.f);
+        mMatrix.set(2, 0, 1.13983f);
+        mMatrix.set(0, 1, 1.f);
+        mMatrix.set(1, 1, -0.39465f);
+        mMatrix.set(2, 1, -0.5806f);
+        mMatrix.set(0, 2, 1.f);
+        mMatrix.set(1, 2, 2.03211f);
+        mMatrix.set(2, 2, 0.f);
+        setMatrix();
+    }
+
+    /**
+     * Set the matrix to convert from RGB to YUV with a direct copy of the 4th
+     * channel.
+     *
+     */
+    public void setRGBtoYUV() {
+        mMatrix.loadIdentity();
+        mMatrix.set(0, 0, 0.299f);
+        mMatrix.set(1, 0, 0.587f);
+        mMatrix.set(2, 0, 0.114f);
+        mMatrix.set(0, 1, -0.14713f);
+        mMatrix.set(1, 1, -0.28886f);
+        mMatrix.set(2, 1, 0.436f);
+        mMatrix.set(0, 2, 0.615f);
+        mMatrix.set(1, 2, -0.51499f);
+        mMatrix.set(2, 2, -0.10001f);
+        setMatrix();
+    }
+
+
+    /**
+     * Invoke the kernel and apply the matrix to each cell of ain and copy to
+     * aout.
+     *
+     * @param ain Input allocation
+     * @param aout Output allocation
+     */
+    public void forEach(Allocation ain, Allocation aout) {
+        forEach(0, ain, aout, null);
+    }
+
+    /**
+     * Invoke the kernel and apply the matrix to each cell of input
+     * {@link Allocation} and copy to the output {@link Allocation}.
+     *
+     * If the vector size of the input is less than four, the
+     * remaining components are treated as zero for the matrix
+     * multiply.
+     *
+     * If the output vector size is less than four, the unused
+     * vector components are discarded.
+     *
+     *
+     * @param ain Input allocation
+     * @param aout Output allocation
+     * @param opt LaunchOptions for clipping
+     */
+    public void forEach(Allocation ain, Allocation aout, Script.LaunchOptions opt) {
+        if (!ain.getElement().isCompatible(Element.U8(mRS)) &&
+            !ain.getElement().isCompatible(Element.U8_2(mRS)) &&
+            !ain.getElement().isCompatible(Element.U8_3(mRS)) &&
+            !ain.getElement().isCompatible(Element.U8_4(mRS)) &&
+            !ain.getElement().isCompatible(Element.F32(mRS)) &&
+            !ain.getElement().isCompatible(Element.F32_2(mRS)) &&
+            !ain.getElement().isCompatible(Element.F32_3(mRS)) &&
+            !ain.getElement().isCompatible(Element.F32_4(mRS))) {
+
+            throw new RSIllegalArgumentException("Unsupported element type.");
+        }
+
+        if (!aout.getElement().isCompatible(Element.U8(mRS)) &&
+            !aout.getElement().isCompatible(Element.U8_2(mRS)) &&
+            !aout.getElement().isCompatible(Element.U8_3(mRS)) &&
+            !aout.getElement().isCompatible(Element.U8_4(mRS)) &&
+            !aout.getElement().isCompatible(Element.F32(mRS)) &&
+            !aout.getElement().isCompatible(Element.F32_2(mRS)) &&
+            !aout.getElement().isCompatible(Element.F32_3(mRS)) &&
+            !aout.getElement().isCompatible(Element.F32_4(mRS))) {
+
+            throw new RSIllegalArgumentException("Unsupported element type.");
+        }
+
+        forEach(0, ain, aout, null, opt);
+    }
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID() {
+        return createKernelID(0, 3, null, null);
+    }
+
+}
+
diff --git a/androidx/renderscript/ScriptIntrinsicConvolve3x3.java b/androidx/renderscript/ScriptIntrinsicConvolve3x3.java
new file mode 100644
index 0000000..d4e57b0
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicConvolve3x3.java
@@ -0,0 +1,151 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.util.Log;
+
+/**
+ * Intrinsic for applying a 3x3 convolve to an allocation.
+ *
+ **/
+public class ScriptIntrinsicConvolve3x3 extends ScriptIntrinsic {
+    private final float[] mValues = new float[9];
+    private Allocation mInput;
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 19;
+
+    ScriptIntrinsicConvolve3x3(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Supported elements types are {@link Element#U8}, {@link
+     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
+     * {@link Element#F32}, {@link Element#F32_2}, {@link
+     * Element#F32_3}, and {@link Element#F32_4}.
+     *
+     * <p> The default coefficients are:
+     * <code>
+     * <p> [ 0,  0,  0 ]
+     * <p> [ 0,  1,  0 ]
+     * <p> [ 0,  0,  0 ]
+     * </code>
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for intputs and outputs
+     *
+     * @return ScriptIntrinsicConvolve3x3
+     */
+    public static ScriptIntrinsicConvolve3x3 create(RenderScript rs, Element e) {
+        float f[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0};
+        if (!e.isCompatible(Element.U8(rs)) &&
+            !e.isCompatible(Element.U8_2(rs)) &&
+            !e.isCompatible(Element.U8_3(rs)) &&
+            !e.isCompatible(Element.U8_4(rs)) &&
+            !e.isCompatible(Element.F32(rs)) &&
+            !e.isCompatible(Element.F32_2(rs)) &&
+            !e.isCompatible(Element.F32_3(rs)) &&
+            !e.isCompatible(Element.F32_4(rs))) {
+            throw new RSIllegalArgumentException("Unsupported element type.");
+        }
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(1, e.getID(rs), mUseIncSupp);
+
+        ScriptIntrinsicConvolve3x3 si = new ScriptIntrinsicConvolve3x3(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        si.setCoefficients(f);
+        return si;
+    }
+
+    /**
+     * Set the input of the 3x3 convolve.
+     * Must match the element type supplied during create.
+     *
+     * @param ain The input allocation.
+     */
+    public void setInput(Allocation ain) {
+        mInput = ain;
+        setVar(1, ain);
+    }
+
+    /**
+     * Set the coefficients for the convolve.
+     *
+     * <p> The convolve layout is:
+     * <code>
+     * <p> [ 0,  1,  2 ]
+     * <p> [ 3,  4,  5 ]
+     * <p> [ 6,  7,  8 ]
+     * </code>
+     *
+     * @param v The array of coefficients to set
+     */
+    public void setCoefficients(float v[]) {
+        FieldPacker fp = new FieldPacker(9*4);
+        for (int ct=0; ct < mValues.length; ct++) {
+            mValues[ct] = v[ct];
+            fp.addF32(mValues[ct]);
+        }
+        setVar(0, fp);
+    }
+
+    /**
+     * Apply the filter to the input and save to the specified
+     * allocation.
+     *
+     * @param aout Output allocation. Must match creation element
+     *             type.
+     */
+    public void forEach(Allocation aout) {
+        forEach(0, (Allocation) null, aout, null);
+    }
+
+    /**
+     * Apply the filter to the input and save to the specified
+     * allocation.
+     *
+     * @param aout Output allocation. Must match creation element
+     *             type.
+     * @param opt LaunchOptions for clipping
+     */
+    public void forEach(Allocation aout, Script.LaunchOptions opt) {
+        forEach(0, (Allocation) null, aout, null, opt);
+    }
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID() {
+        return createKernelID(0, 2, null, null);
+    }
+
+    /**
+     * Get a FieldID for the input field of this intrinsic.
+     *
+     * @return Script.FieldID The FieldID object.
+     */
+    public Script.FieldID getFieldID_Input() {
+        return createFieldID(1, null);
+    }
+
+}
+
diff --git a/androidx/renderscript/ScriptIntrinsicConvolve5x5.java b/androidx/renderscript/ScriptIntrinsicConvolve5x5.java
new file mode 100644
index 0000000..298596e
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicConvolve5x5.java
@@ -0,0 +1,154 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.util.Log;
+
+/**
+ * Intrinsic for applying a 5x5 convolve to an allocation.
+ *
+ **/
+public class ScriptIntrinsicConvolve5x5 extends ScriptIntrinsic {
+    private final float[] mValues = new float[25];
+    private Allocation mInput;
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 19;
+
+    ScriptIntrinsicConvolve5x5(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Supported elements types are {@link Element#U8}, {@link
+     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
+     * {@link Element#F32}, {@link Element#F32_2}, {@link
+     * Element#F32_3}, and {@link Element#F32_4}.
+     *
+     * <p> The default coefficients are:
+     * <code>
+     * <p> [ 0,  0,  0,  0,  0  ]
+     * <p> [ 0,  0,  0,  0,  0  ]
+     * <p> [ 0,  0,  1,  0,  0  ]
+     * <p> [ 0,  0,  0,  0,  0  ]
+     * <p> [ 0,  0,  0,  0,  0  ]
+     * </code>
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for intputs and outputs
+     *
+     * @return ScriptIntrinsicConvolve5x5
+     */
+    public static ScriptIntrinsicConvolve5x5 create(RenderScript rs, Element e) {
+        if (!e.isCompatible(Element.U8(rs)) &&
+            !e.isCompatible(Element.U8_2(rs)) &&
+            !e.isCompatible(Element.U8_3(rs)) &&
+            !e.isCompatible(Element.U8_4(rs)) &&
+            !e.isCompatible(Element.F32(rs)) &&
+            !e.isCompatible(Element.F32_2(rs)) &&
+            !e.isCompatible(Element.F32_3(rs)) &&
+            !e.isCompatible(Element.F32_4(rs))) {
+            throw new RSIllegalArgumentException("Unsupported element type.");
+        }
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(4, e.getID(rs), mUseIncSupp);
+
+        ScriptIntrinsicConvolve5x5 si = new ScriptIntrinsicConvolve5x5(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        return si;
+
+    }
+
+    /**
+     * Set the input of the 5x5 convolve.
+     * Must match the element type supplied during create.
+     *
+     * @param ain The input allocation.
+     */
+    public void setInput(Allocation ain) {
+        mInput = ain;
+        setVar(1, ain);
+    }
+
+    /**
+    * Set the coefficients for the convolve.
+    *
+    * <p> The convolve layout is:
+    * <code>
+    * <p> [ 0,  1,  2,  3,  4  ]
+    * <p> [ 5,  6,  7,  8,  9  ]
+    * <p> [ 10, 11, 12, 13, 14 ]
+    * <p> [ 15, 16, 17, 18, 19 ]
+    * <p> [ 20, 21, 22, 23, 24 ]
+    * </code>
+    *
+    * @param v The array of coefficients to set
+    */
+    public void setCoefficients(float v[]) {
+        FieldPacker fp = new FieldPacker(25*4);
+        for (int ct=0; ct < mValues.length; ct++) {
+            mValues[ct] = v[ct];
+            fp.addF32(mValues[ct]);
+        }
+        setVar(0, fp);
+    }
+
+    /**
+     * Apply the filter to the input and save to the specified
+     * allocation.
+     *
+     * @param aout Output allocation. Must match creation element
+     *             type.
+     */
+    public void forEach(Allocation aout) {
+        forEach(0, (Allocation) null, aout, null);
+    }
+
+    /**
+     * Apply the filter to the input and save to the specified
+     * allocation.
+     *
+     * @param aout Output allocation. Must match creation element
+     *             type.
+     * @param opt LaunchOptions for clipping
+     */
+    public void forEach(Allocation aout, Script.LaunchOptions opt) {
+        forEach(0, (Allocation) null, aout, null, opt);
+    }
+
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID() {
+        return createKernelID(0, 2, null, null);
+    }
+
+    /**
+     * Get a FieldID for the input field of this intrinsic.
+     *
+     * @return Script.FieldID The FieldID object.
+     */
+    public Script.FieldID getFieldID_Input() {
+        return createFieldID(1, null);
+    }
+}
+
diff --git a/androidx/renderscript/ScriptIntrinsicHistogram.java b/androidx/renderscript/ScriptIntrinsicHistogram.java
new file mode 100644
index 0000000..3437f2c
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicHistogram.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2015 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 androidx.renderscript;
+
+import android.util.Log;
+
+/**
+ * Intrinsic Histogram filter.
+ *
+ *
+ **/
+public class ScriptIntrinsicHistogram extends ScriptIntrinsic {
+    private Allocation mOut;
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 19;
+
+    protected ScriptIntrinsicHistogram(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Create an intrinsic for calculating the histogram of an uchar
+     * or uchar4 image.
+     *
+     * Supported elements types are
+     * {@link Element#U8_4}, {@link Element#U8_3},
+     * {@link Element#U8_2}, {@link Element#U8}
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for inputs
+     *
+     * @return ScriptIntrinsicHistogram
+     */
+    public static ScriptIntrinsicHistogram create(RenderScript rs, Element e) {
+        if ((!e.isCompatible(Element.U8_4(rs))) &&
+            (!e.isCompatible(Element.U8_3(rs))) &&
+            (!e.isCompatible(Element.U8_2(rs))) &&
+            (!e.isCompatible(Element.U8(rs)))) {
+            throw new RSIllegalArgumentException("Unsupported element type.");
+        }
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(9, e.getID(rs), mUseIncSupp);
+
+        ScriptIntrinsicHistogram si = new ScriptIntrinsicHistogram(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        return si;
+    }
+
+    /**
+     * Process an input buffer and place the histogram into the
+     * output allocation. The output allocation may be a narrower
+     * vector size than the input. In this case the vector size of
+     * the output is used to determine how many of the input
+     * channels are used in the computation. This is useful if you
+     * have an RGBA input buffer but only want the histogram for
+     * RGB.
+     *
+     * 1D and 2D input allocations are supported.
+     *
+     * @param ain The input image
+     */
+    public void forEach(Allocation ain) {
+        forEach(ain, null);
+    }
+
+    /**
+     * Process an input buffer and place the histogram into the
+     * output allocation. The output allocation may be a narrower
+     * vector size than the input. In this case the vector size of
+     * the output is used to determine how many of the input
+     * channels are used in the computation. This is useful if you
+     * have an RGBA input buffer but only want the histogram for
+     * RGB.
+     *
+     * 1D and 2D input allocations are supported.
+     *
+     * @param ain The input image
+     * @param opt LaunchOptions for clipping
+     */
+    public void forEach(Allocation ain, Script.LaunchOptions opt) {
+        if (ain.getType().getElement().getVectorSize() <
+            mOut.getType().getElement().getVectorSize()) {
+
+            throw new RSIllegalArgumentException(
+                "Input vector size must be >= output vector size.");
+        }
+        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
+            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
+            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
+            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
+            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
+        }
+
+        forEach(0, ain, null, null, opt);
+    }
+
+
+
+    /**
+     * Set the coefficients used for the RGBA to Luminocity
+     * calculation. The default is {0.299f, 0.587f, 0.114f, 0.f}.
+     *
+     * Coefficients must be >= 0 and sum to 1.0 or less.
+     *
+     * @param r Red coefficient
+     * @param g Green coefficient
+     * @param b Blue coefficient
+     * @param a Alpha coefficient
+     */
+    public void setDotCoefficients(float r, float g, float b, float a) {
+        if ((r < 0.f) || (g < 0.f) || (b < 0.f) || (a < 0.f)) {
+            throw new RSIllegalArgumentException("Coefficient may not be negative.");
+        }
+        if ((r + g + b + a) > 1.f) {
+            throw new RSIllegalArgumentException("Sum of coefficients must be 1.0 or less.");
+        }
+
+        FieldPacker fp = new FieldPacker(16);
+        fp.addF32(r);
+        fp.addF32(g);
+        fp.addF32(b);
+        fp.addF32(a);
+        setVar(0, fp);
+    }
+
+    /**
+     * Set the output of the histogram.  32 bit integer types are
+     * supported.
+     *
+     * @param aout The output allocation
+     */
+    public void setOutput(Allocation aout) {
+        mOut = aout;
+        if (mOut.getType().getElement() != Element.U32(mRS) &&
+            mOut.getType().getElement() != Element.U32_2(mRS) &&
+            mOut.getType().getElement() != Element.U32_3(mRS) &&
+            mOut.getType().getElement() != Element.U32_4(mRS) &&
+            mOut.getType().getElement() != Element.I32(mRS) &&
+            mOut.getType().getElement() != Element.I32_2(mRS) &&
+            mOut.getType().getElement() != Element.I32_3(mRS) &&
+            mOut.getType().getElement() != Element.I32_4(mRS)) {
+
+            throw new RSIllegalArgumentException("Output type must be U32 or I32.");
+        }
+        if ((mOut.getType().getX() != 256) ||
+            (mOut.getType().getY() != 0) ||
+            mOut.getType().hasMipmaps() ||
+            (mOut.getType().getYuv() != 0)) {
+
+            throw new RSIllegalArgumentException("Output must be 1D, 256 elements.");
+        }
+        setVar(1, aout);
+    }
+
+
+    /**
+     * Process an input buffer and place the histogram into the
+     * output allocation. The dot product of the input channel and
+     * the coefficients from 'setDotCoefficients' are used to
+     * calculate the output values.
+     *
+     * 1D and 2D input allocations are supported.
+     *
+     * @param ain The input image
+     */
+    public void forEach_Dot(Allocation ain) {
+        forEach_Dot(ain, null);
+    }
+
+    /**
+     * Process an input buffer and place the histogram into the
+     * output allocation. The dot product of the input channel and
+     * the coefficients from 'setDotCoefficients' are used to
+     * calculate the output values.
+     *
+     * 1D and 2D input allocations are supported.
+     *
+     * @param ain The input image
+     * @param opt LaunchOptions for clipping
+     */
+    public void forEach_Dot(Allocation ain, Script.LaunchOptions opt) {
+        if (mOut.getType().getElement().getVectorSize() != 1) {
+            throw new RSIllegalArgumentException("Output vector size must be one.");
+        }
+        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
+            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
+            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
+            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
+            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
+        }
+
+        forEach(1, ain, null, null, opt);
+    }
+
+
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID_Separate() {
+        return createKernelID(0, 3, null, null);
+    }
+
+    /**
+     * Get a FieldID for the input field of this intrinsic.
+     *
+     * @return Script.FieldID The FieldID object.
+     */
+    public Script.FieldID getFieldID_Input() {
+        return createFieldID(1, null);
+    }
+}
+
diff --git a/androidx/renderscript/ScriptIntrinsicLUT.java b/androidx/renderscript/ScriptIntrinsicLUT.java
new file mode 100644
index 0000000..6434903
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicLUT.java
@@ -0,0 +1,152 @@
+/*
+ * 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 androidx.renderscript;
+
+import android.util.Log;
+
+/**
+ * Intrinsic for applying a per-channel lookup table. Each
+ * channel of the input has an independant lookup table. The
+ * tables are 256 entries in size and can cover the full value
+ * range of {@link Element#U8_4}.
+ **/
+public class ScriptIntrinsicLUT extends ScriptIntrinsic {
+    private final Matrix4f mMatrix = new Matrix4f();
+    private Allocation mTables;
+    private final byte mCache[] = new byte[1024];
+    private boolean mDirty = true;
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 19;
+
+    protected ScriptIntrinsicLUT(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Supported elements types are {@link Element#U8_4}
+     *
+     * The defaults tables are identity.
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for intputs and outputs
+     *
+     * @return ScriptIntrinsicLUT
+     */
+    public static ScriptIntrinsicLUT create(RenderScript rs, Element e) {
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(3, e.getID(rs), mUseIncSupp);
+
+        ScriptIntrinsicLUT si = new ScriptIntrinsicLUT(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        si.mTables = Allocation.createSized(rs, Element.U8(rs), 1024);
+        for (int ct=0; ct < 256; ct++) {
+            si.mCache[ct] = (byte)ct;
+            si.mCache[ct + 256] = (byte)ct;
+            si.mCache[ct + 512] = (byte)ct;
+            si.mCache[ct + 768] = (byte)ct;
+        }
+        si.setVar(0, si.mTables);
+        return si;
+    }
+
+
+    private void validate(int index, int value) {
+        if (index < 0 || index > 255) {
+            throw new RSIllegalArgumentException("Index out of range (0-255).");
+        }
+        if (value < 0 || value > 255) {
+            throw new RSIllegalArgumentException("Value out of range (0-255).");
+        }
+    }
+
+    /**
+     * Set an entry in the red channel lookup table
+     *
+     * @param index Must be 0-255
+     * @param value Must be 0-255
+     */
+    public void setRed(int index, int value) {
+        validate(index, value);
+        mCache[index] = (byte)value;
+        mDirty = true;
+    }
+
+    /**
+     * Set an entry in the green channel lookup table
+     *
+     * @param index Must be 0-255
+     * @param value Must be 0-255
+     */
+    public void setGreen(int index, int value) {
+        validate(index, value);
+        mCache[index+256] = (byte)value;
+        mDirty = true;
+    }
+
+    /**
+     * Set an entry in the blue channel lookup table
+     *
+     * @param index Must be 0-255
+     * @param value Must be 0-255
+     */
+    public void setBlue(int index, int value) {
+        validate(index, value);
+        mCache[index+512] = (byte)value;
+        mDirty = true;
+    }
+
+    /**
+     * Set an entry in the alpha channel lookup table
+     *
+     * @param index Must be 0-255
+     * @param value Must be 0-255
+     */
+    public void setAlpha(int index, int value) {
+        validate(index, value);
+        mCache[index+768] = (byte)value;
+        mDirty = true;
+    }
+
+
+    /**
+     * Invoke the kernel and apply the lookup to each cell of ain
+     * and copy to aout.
+     *
+     * @param ain Input allocation
+     * @param aout Output allocation
+     */
+    public void forEach(Allocation ain, Allocation aout) {
+        if (mDirty) {
+            mDirty = false;
+            mTables.copyFromUnchecked(mCache);
+        }
+        forEach(0, ain, aout, null);
+    }
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID() {
+        return createKernelID(0, 3, null, null);
+    }
+}
+
diff --git a/androidx/renderscript/ScriptIntrinsicResize.java b/androidx/renderscript/ScriptIntrinsicResize.java
new file mode 100644
index 0000000..c3450f1
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicResize.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 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 androidx.renderscript;
+
+import android.util.Log;
+
+/**
+ * Intrinsic for performing a resize of a 2D allocation.
+ */
+public class ScriptIntrinsicResize extends ScriptIntrinsic {
+    private Allocation mInput;
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 21;
+
+    protected ScriptIntrinsicResize(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Supported elements types are {@link Element#U8}, {@link
+     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4}
+     * {@link Element#F32}, {@link Element#F32_2}, {@link
+     * Element#F32_3}, {@link Element#F32_4}
+     *
+     * @param rs The RenderScript context
+     *
+     * @return ScriptIntrinsicResize
+     */
+    public static ScriptIntrinsicResize create(RenderScript rs) {
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(12, 0, mUseIncSupp);
+
+        ScriptIntrinsicResize si = new ScriptIntrinsicResize(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        return si;
+
+    }
+
+    /**
+     * Set the input of the resize.
+     * Must match the element type supplied during create.
+     *
+     * @param ain The input allocation.
+     */
+    public void setInput(Allocation ain) {
+        Element e = ain.getElement();
+        if (!e.isCompatible(Element.U8(mRS)) &&
+            !e.isCompatible(Element.U8_2(mRS)) &&
+            !e.isCompatible(Element.U8_3(mRS)) &&
+            !e.isCompatible(Element.U8_4(mRS)) &&
+            !e.isCompatible(Element.F32(mRS)) &&
+            !e.isCompatible(Element.F32_2(mRS)) &&
+            !e.isCompatible(Element.F32_3(mRS)) &&
+            !e.isCompatible(Element.F32_4(mRS))) {
+            throw new RSIllegalArgumentException("Unsupported element type.");
+        }
+
+        mInput = ain;
+        setVar(0, ain);
+    }
+
+    /**
+     * Get a FieldID for the input field of this intrinsic.
+     *
+     * @return Script.FieldID The FieldID object.
+     */
+    public Script.FieldID getFieldID_Input() {
+        return createFieldID(0, null);
+    }
+
+
+    /**
+     * Resize copy the input allocation to the output specified. The
+     * Allocation is rescaled if necessary using bi-cubic
+     * interpolation.
+     *
+     * @param aout Output allocation. Element type must match
+     *             current input.  Must not be same as input.
+     */
+    public void forEach_bicubic(Allocation aout) {
+        if (aout == mInput) {
+            throw new RSIllegalArgumentException("Output cannot be same as Input.");
+        }
+        forEach_bicubic(aout, null);
+    }
+
+    /**
+     * Resize copy the input allocation to the output specified. The
+     * Allocation is rescaled if necessary using bi-cubic
+     * interpolation.
+     *
+     * @param aout Output allocation. Element type must match
+     *             current input.
+     * @param opt LaunchOptions for clipping
+     */
+    public void forEach_bicubic(Allocation aout, Script.LaunchOptions opt) {
+        forEach(0, (Allocation) null, aout, null, opt);
+    }
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID_bicubic() {
+        return createKernelID(0, 2, null, null);
+    }
+
+
+}
diff --git a/androidx/renderscript/ScriptIntrinsicYuvToRGB.java b/androidx/renderscript/ScriptIntrinsicYuvToRGB.java
new file mode 100644
index 0000000..8749398
--- /dev/null
+++ b/androidx/renderscript/ScriptIntrinsicYuvToRGB.java
@@ -0,0 +1,97 @@
+/*
+ * 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 androidx.renderscript;
+
+
+/**
+ * Intrinsic for converting an Android YUV buffer to RGB.
+ *
+ * The input allocation is supplied in NV21 format as a U8
+ * element type. The output is RGBA, the alpha channel will be
+ * set to 255.
+ */
+public class ScriptIntrinsicYuvToRGB extends ScriptIntrinsic {
+    private Allocation mInput;
+    // API level for the intrinsic
+    private static final int INTRINSIC_API_LEVEL = 19;
+
+    ScriptIntrinsicYuvToRGB(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Create an intrinsic for converting YUV to RGB.
+     *
+     * Supported elements types are {@link Element#U8_4}
+     *
+     * @param rs The RenderScript context
+     * @param e Element type for output
+     *
+     * @return ScriptIntrinsicYuvToRGB
+     */
+    public static ScriptIntrinsicYuvToRGB create(RenderScript rs, Element e) {
+        // 6 comes from RS_SCRIPT_INTRINSIC_YUV_TO_RGB in rsDefines.h
+        long id;
+        boolean mUseIncSupp = rs.isUseNative() &&
+                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
+
+        id = rs.nScriptIntrinsicCreate(6, e.getID(rs), mUseIncSupp);
+
+        ScriptIntrinsicYuvToRGB si = new ScriptIntrinsicYuvToRGB(id, rs);
+        si.setIncSupp(mUseIncSupp);
+        return si;
+    }
+
+
+    /**
+     * Set the input yuv allocation, must be {@link Element#U8}.
+     *
+     * @param ain The input allocation.
+     */
+    public void setInput(Allocation ain) {
+        mInput = ain;
+        setVar(0, ain);
+    }
+
+    /**
+     * Convert the image to RGB.
+     *
+     * @param aout Output allocation. Must match creation element
+     *             type.
+     */
+    public void forEach(Allocation aout) {
+        forEach(0, (Allocation) null, aout, null);
+    }
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID() {
+        return createKernelID(0, 2, null, null);
+    }
+
+    /**
+     * Get a FieldID for the input field of this intrinsic.
+     *
+     * @return Script.FieldID The FieldID object.
+     */
+    public Script.FieldID getFieldID_Input() {
+        return createFieldID(0, null);
+    }
+}
diff --git a/androidx/renderscript/Short2.java b/androidx/renderscript/Short2.java
new file mode 100644
index 0000000..f06d746
--- /dev/null
+++ b/androidx/renderscript/Short2.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript Short2 type back to the Android system.
+ *
+ **/
+public class Short2 {
+    public Short2() {
+    }
+
+    public Short2(short initX, short initY) {
+        x = initX;
+        y = initY;
+    }
+
+    public short x;
+    public short y;
+}
+
+
+
+
diff --git a/androidx/renderscript/Short3.java b/androidx/renderscript/Short3.java
new file mode 100644
index 0000000..fbf9a89
--- /dev/null
+++ b/androidx/renderscript/Short3.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript short3 type back to the Android system.
+ *
+ **/
+public class Short3 {
+    public Short3() {
+    }
+
+    public Short3(short initX, short initY, short initZ) {
+        x = initX;
+        y = initY;
+        z = initZ;
+    }
+
+    public short x;
+    public short y;
+    public short z;
+}
+
+
+
+
diff --git a/androidx/renderscript/Short4.java b/androidx/renderscript/Short4.java
new file mode 100644
index 0000000..1e479d2
--- /dev/null
+++ b/androidx/renderscript/Short4.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 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 androidx.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * Class for exposing the native RenderScript short4 type back to the Android system.
+ *
+ **/
+public class Short4 {
+    public Short4() {
+    }
+
+    public Short4(short initX, short initY, short initZ, short initW) {
+        x = initX;
+        y = initY;
+        z = initZ;
+        w = initW;
+    }
+
+    public short x;
+    public short y;
+    public short z;
+    public short w;
+}
+
+
+
diff --git a/androidx/renderscript/Type.java b/androidx/renderscript/Type.java
new file mode 100644
index 0000000..cec834c
--- /dev/null
+++ b/androidx/renderscript/Type.java
@@ -0,0 +1,411 @@
+/*
+ * 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 androidx.renderscript;
+
+
+import java.lang.reflect.Field;
+
+import android.graphics.ImageFormat;
+import android.util.Log;
+
+/**
+ * <p>A Type describes the {@link androidx.renderscript.Element} and
+ * dimensions used for an {@link androidx.renderscript.Allocation} or
+ * a parallel operation. Types are created through
+ * {@link androidx.renderscript.Type.Builder}.</p>
+ *
+ * <p>A Type always includes an {@link androidx.renderscript.Element}
+ * and an X dimension. A Type may be multidimensional, up to three dimensions.
+ * A nonzero value in the Y or Z dimensions indicates that the dimension is
+ * present. Note that a Type with only a given X dimension and a Type with the
+ * same X dimension but Y = 1 are not equivalent.</p>
+ *
+ * <p>A Type also supports inclusion of level of detail (LOD) or cube map
+ * faces. LOD and cube map faces are booleans to indicate present or not
+ * present. </p>
+ *
+ * <p>A Type also supports YUV format information to support an {@link
+ * androidx.renderscript.Allocation} in a YUV format. The YUV formats
+ * supported are {@link android.graphics.ImageFormat#YV12} and {@link
+ * android.graphics.ImageFormat#NV21}.</p>
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about creating an application that uses RenderScript,
+ * read the
+ * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
+ * developer guide.</p>
+ * </div>
+ **/
+public class Type extends BaseObj {
+    int mDimX;
+    int mDimY;
+    int mDimZ;
+    boolean mDimMipmaps;
+    boolean mDimFaces;
+    int mDimYuv;
+    int mElementCount;
+    Element mElement;
+
+    public enum CubemapFace {
+        POSITIVE_X (0),
+        NEGATIVE_X (1),
+        POSITIVE_Y (2),
+        NEGATIVE_Y (3),
+        POSITIVE_Z (4),
+        NEGATIVE_Z (5);
+
+        int mID;
+        CubemapFace(int id) {
+            mID = id;
+        }
+    }
+
+    /**
+     * Return the element associated with this Type.
+     *
+     * @return Element
+     */
+    public Element getElement() {
+        return mElement;
+    }
+
+    /**
+     * Return the value of the X dimension.
+     *
+     * @return int
+     */
+    public int getX() {
+        return mDimX;
+    }
+
+    /**
+     * Return the value of the Y dimension or 0 for a 1D allocation.
+     *
+     * @return int
+     */
+    public int getY() {
+        return mDimY;
+    }
+
+    /**
+     * Return the value of the Z dimension or 0 for a 1D or 2D allocation.
+     *
+     * @return int
+     */
+    public int getZ() {
+        return mDimZ;
+    }
+
+    /**
+     * Get the YUV format
+     *
+     * @return int
+     */
+    public int getYuv() {
+        return mDimYuv;
+    }
+
+    /**
+     * Return if the Type has a mipmap chain.
+     *
+     * @return boolean
+     */
+    public boolean hasMipmaps() {
+        return mDimMipmaps;
+    }
+
+    /**
+     * Return if the Type is a cube map.
+     *
+     * @return boolean
+     */
+    public boolean hasFaces() {
+        return mDimFaces;
+    }
+
+    /**
+     * Return the total number of accessable cells in the Type.
+     *
+     * @return int
+     */
+    public int getCount() {
+        return mElementCount;
+    }
+
+    void calcElementCount() {
+        boolean hasLod = hasMipmaps();
+        int x = getX();
+        int y = getY();
+        int z = getZ();
+        int faces = 1;
+        if (hasFaces()) {
+            faces = 6;
+        }
+        if (x == 0) {
+            x = 1;
+        }
+        if (y == 0) {
+            y = 1;
+        }
+        if (z == 0) {
+            z = 1;
+        }
+
+        int count = x * y * z * faces;
+
+        while (hasLod && ((x > 1) || (y > 1) || (z > 1))) {
+            if(x > 1) {
+                x >>= 1;
+            }
+            if(y > 1) {
+                y >>= 1;
+            }
+            if(z > 1) {
+                z >>= 1;
+            }
+
+            count += x * y * z * faces;
+        }
+        mElementCount = count;
+    }
+
+
+    Type(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /*
+     * Get an identical dummy Type for Compat Context
+     *
+     */
+    public long getDummyType(RenderScript mRS, long eid) {
+        return mRS.nIncTypeCreate(eid, mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mDimYuv);
+    }
+
+    /**
+     * Utility function for creating basic 1D types. The type is
+     * created without mipmaps enabled.
+     *
+     * @param rs The RenderScript context
+     * @param e The Element for the Type
+     * @param dimX The X dimension, must be > 0
+     *
+     * @return Type
+     */
+    static public Type createX(RenderScript rs, Element e, int dimX) {
+        if (dimX < 1) {
+            throw new RSInvalidStateException("Dimension must be >= 1.");
+        }
+
+        long id = rs.nTypeCreate(e.getID(rs), dimX, 0, 0, false, false, 0);
+        Type t = new Type(id, rs);
+        t.mElement = e;
+        t.mDimX = dimX;
+        t.calcElementCount();
+        return t;
+    }
+
+    /**
+     * Utility function for creating basic 2D types. The type is
+     * created without mipmaps or cubemaps.
+     *
+     * @param rs The RenderScript context
+     * @param e The Element for the Type
+     * @param dimX The X dimension, must be > 0
+     * @param dimY The Y dimension, must be > 0
+     *
+     * @return Type
+     */
+    static public Type createXY(RenderScript rs, Element e, int dimX, int dimY) {
+        if ((dimX < 1) || (dimY < 1)) {
+            throw new RSInvalidStateException("Dimension must be >= 1.");
+        }
+
+        long id = rs.nTypeCreate(e.getID(rs), dimX, dimY, 0, false, false, 0);
+        Type t = new Type(id, rs);
+        t.mElement = e;
+        t.mDimX = dimX;
+        t.mDimY = dimY;
+        t.calcElementCount();
+        return t;
+    }
+
+    /**
+     * Utility function for creating basic 3D types. The type is
+     * created without mipmaps.
+     *
+     * @param rs The RenderScript context
+     * @param e The Element for the Type
+     * @param dimX The X dimension, must be > 0
+     * @param dimY The Y dimension, must be > 0
+     * @param dimZ The Z dimension, must be > 0
+     *
+     * @return Type
+     */
+    static public Type createXYZ(RenderScript rs, Element e, int dimX, int dimY, int dimZ) {
+        if ((dimX < 1) || (dimY < 1) || (dimZ < 1)) {
+            throw new RSInvalidStateException("Dimension must be >= 1.");
+        }
+
+        long id = rs.nTypeCreate(e.getID(rs), dimX, dimY, dimZ, false, false, 0);
+        Type t = new Type(id, rs);
+        t.mElement = e;
+        t.mDimX = dimX;
+        t.mDimY = dimY;
+        t.mDimZ = dimZ;
+        t.calcElementCount();
+        return t;
+    }
+
+    /**
+     * Builder class for Type.
+     *
+     */
+    public static class Builder {
+        RenderScript mRS;
+        int mDimX = 1;
+        int mDimY;
+        int mDimZ;
+        boolean mDimMipmaps;
+        boolean mDimFaces;
+        int mYuv;
+
+        Element mElement;
+
+        /**
+         * Create a new builder object.
+         *
+         * @param rs
+         * @param e The element for the type to be created.
+         */
+        public Builder(RenderScript rs, Element e) {
+            e.checkValid();
+            mRS = rs;
+            mElement = e;
+        }
+
+        /**
+         * Add a dimension to the Type.
+         *
+         *
+         * @param value
+         */
+        public Builder setX(int value) {
+            if(value < 1) {
+                throw new RSIllegalArgumentException("Values of less than 1 for Dimension X are not valid.");
+            }
+            mDimX = value;
+            return this;
+        }
+
+        public Builder setY(int value) {
+            if(value < 1) {
+                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Y are not valid.");
+            }
+            mDimY = value;
+            return this;
+        }
+
+        public Builder setZ(int value) {
+            if(value < 1) {
+                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Z are not valid.");
+            }
+            mDimZ = value;
+            return this;
+        }
+
+        public Builder setMipmaps(boolean value) {
+            mDimMipmaps = value;
+            return this;
+        }
+
+        public Builder setFaces(boolean value) {
+            mDimFaces = value;
+            return this;
+        }
+
+        /**
+         * Set the YUV layout for a Type.
+         *
+         * @param yuvFormat {@link android.graphics.ImageFormat#YV12} or {@link android.graphics.ImageFormat#NV21}
+         */
+        public Builder setYuvFormat(int yuvFormat) {
+            switch (yuvFormat) {
+            case android.graphics.ImageFormat.NV21:
+            case android.graphics.ImageFormat.YV12:
+                break;
+
+            default:
+                throw new RSIllegalArgumentException("Only NV21 and YV12 are supported..");
+            }
+
+            mYuv = yuvFormat;
+            return this;
+        }
+
+
+        /**
+         * Validate structure and create a new Type.
+         *
+         * @return Type
+         */
+        public Type create() {
+            if (mDimZ > 0) {
+                if ((mDimX < 1) || (mDimY < 1)) {
+                    throw new RSInvalidStateException("Both X and Y dimension required when Z is present.");
+                }
+                if (mDimFaces) {
+                    throw new RSInvalidStateException("Cube maps not supported with 3D types.");
+                }
+            }
+            if (mDimY > 0) {
+                if (mDimX < 1) {
+                    throw new RSInvalidStateException("X dimension required when Y is present.");
+                }
+            }
+            if (mDimFaces) {
+                if (mDimY < 1) {
+                    throw new RSInvalidStateException("Cube maps require 2D Types.");
+                }
+            }
+
+            if (mYuv != 0) {
+                if ((mDimZ != 0) || mDimFaces || mDimMipmaps) {
+                    throw new RSInvalidStateException("YUV only supports basic 2D.");
+                }
+            }
+
+            Type t;
+            long id = mRS.nTypeCreate(mElement.getID(mRS),
+                                     mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mYuv);
+            t = new Type(id, mRS);
+
+            t.mElement = mElement;
+            t.mDimX = mDimX;
+            t.mDimY = mDimY;
+            t.mDimZ = mDimZ;
+            t.mDimMipmaps = mDimMipmaps;
+            t.mDimFaces = mDimFaces;
+            t.mDimYuv = mYuv;
+
+            t.calcElementCount();
+            return t;
+        }
+    }
+
+}
diff --git a/androidx/window/extensions/ExtensionHelper.java b/androidx/window/extensions/ExtensionHelper.java
new file mode 100644
index 0000000..c4f11a0
--- /dev/null
+++ b/androidx/window/extensions/ExtensionHelper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2020 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 androidx.window.extensions;
+
+import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.app.Activity;
+import android.app.ActivityThread;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
+import android.view.DisplayInfo;
+import android.view.Surface;
+
+/**
+ * Toolkit class for calculation of the display feature bounds within the window.
+ * NOTE: This sample implementation only works for Activity windows, because there is no public APIs
+ * to obtain layout params or bounds for arbitrary windows.
+ */
+class ExtensionHelper {
+    /**
+     * Rotate the input rectangle specified in default display orientation to the current display
+     * rotation.
+     */
+    static void rotateRectToDisplayRotation(Rect inOutRect, int displayId) {
+        DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
+        DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
+        int rotation = displayInfo.rotation;
+
+        boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270;
+        int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
+        int displayHeight = isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
+
+        inOutRect.intersect(0, 0, displayWidth, displayHeight);
+
+        rotateBounds(inOutRect, displayWidth, displayHeight, rotation);
+    }
+
+    /**
+     * Rotate the input rectangle within parent bounds for a given delta.
+     */
+    private static void rotateBounds(Rect inOutRect, int parentWidth, int parentHeight,
+            @Surface.Rotation int delta) {
+        int origLeft = inOutRect.left;
+        switch (delta) {
+            case ROTATION_0:
+                return;
+            case ROTATION_90:
+                inOutRect.left = inOutRect.top;
+                inOutRect.top = parentWidth - inOutRect.right;
+                inOutRect.right = inOutRect.bottom;
+                inOutRect.bottom = parentWidth - origLeft;
+                return;
+            case ROTATION_180:
+                inOutRect.left = parentWidth - inOutRect.right;
+                inOutRect.right = parentWidth - origLeft;
+                return;
+            case ROTATION_270:
+                inOutRect.left = parentHeight - inOutRect.bottom;
+                inOutRect.bottom = inOutRect.right;
+                inOutRect.right = parentHeight - inOutRect.top;
+                inOutRect.top = origLeft;
+                return;
+        }
+    }
+
+    /** Transform rectangle from absolute coordinate space to the window coordinate space. */
+    static void transformToWindowSpaceRect(Rect inOutRect, IBinder windowToken) {
+        Rect windowRect = getWindowRect(windowToken);
+        if (windowRect == null) {
+            inOutRect.setEmpty();
+            return;
+        }
+        if (!Rect.intersects(inOutRect, windowRect)) {
+            inOutRect.setEmpty();
+            return;
+        }
+        inOutRect.intersect(windowRect);
+        inOutRect.offset(-windowRect.left, -windowRect.top);
+    }
+
+    /**
+     * Get the current window bounds in absolute coordinates.
+     * NOTE: Only works with Activity windows.
+     */
+    private static Rect getWindowRect(IBinder windowToken) {
+        Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+        final Rect windowRect = new Rect();
+        if (activity != null) {
+            activity.getWindow().getDecorView().getWindowDisplayFrame(windowRect);
+        }
+        return windowRect;
+    }
+
+    /**
+     * Check if this window is an Activity window that is in multi-window mode.
+     */
+    static boolean isInMultiWindow(IBinder windowToken) {
+        Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+        return activity != null && activity.isInMultiWindowMode();
+    }
+
+    /**
+     * Get the id of the parent display for the window.
+     * NOTE: Only works with Activity windows.
+     */
+    static int getWindowDisplay(IBinder windowToken) {
+        Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+        return activity != null
+                ? activity.getWindowManager().getDefaultDisplay().getDisplayId() : INVALID_DISPLAY;
+    }
+}
diff --git a/androidx/window/extensions/ExtensionProvider.java b/androidx/window/extensions/ExtensionProvider.java
new file mode 100644
index 0000000..47349f1
--- /dev/null
+++ b/androidx/window/extensions/ExtensionProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 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 androidx.window.extensions;
+
+import android.content.Context;
+
+/**
+ * Provider class that will instantiate the library implementation. It must be included in the
+ * vendor library, and the vendor implementation must match the signature of this class.
+ */
+public class ExtensionProvider {
+
+    /**
+     * The support library will instantiate the vendor implementation using this interface.
+     * @return An implementation of {@link ExtensionInterface}.
+     */
+    public static ExtensionInterface getExtensionImpl(Context context) {
+        return new SettingsExtensionImpl(context);
+    }
+
+    /**
+     * The support library will use this method to check API version compatibility.
+     * @return API version string in MAJOR.MINOR.PATCH-description format.
+     */
+    public static String getApiVersion() {
+        return "1.0.0-settings_sample";
+    }
+}
diff --git a/androidx/window/extensions/SettingsExtensionImpl.java b/androidx/window/extensions/SettingsExtensionImpl.java
new file mode 100644
index 0000000..7a3fbf3
--- /dev/null
+++ b/androidx/window/extensions/SettingsExtensionImpl.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2020 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 androidx.window.extensions;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static androidx.window.extensions.ExtensionHelper.getWindowDisplay;
+import static androidx.window.extensions.ExtensionHelper.isInMultiWindow;
+import static androidx.window.extensions.ExtensionHelper.rotateRectToDisplayRotation;
+import static androidx.window.extensions.ExtensionHelper.transformToWindowSpaceRect;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class SettingsExtensionImpl extends StubExtension {
+    private static final String TAG = "SettingsExtension";
+
+    private static final String DEVICE_POSTURE = "device_posture";
+    private static final String DISPLAY_FEATURES = "display_features";
+
+    private static final Pattern FEATURE_PATTERN =
+            Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]");
+
+    private static final String FEATURE_TYPE_FOLD = "fold";
+    private static final String FEATURE_TYPE_HINGE = "hinge";
+
+    private Context mContext;
+    private SettingsObserver mSettingsObserver;
+
+    final class SettingsObserver extends ContentObserver {
+        private final Uri mDevicePostureUri =
+                Settings.Global.getUriFor(DEVICE_POSTURE);
+        private final Uri mDisplayFeaturesUri =
+                Settings.Global.getUriFor(DISPLAY_FEATURES);
+        private final ContentResolver mResolver = mContext.getContentResolver();
+        private boolean mRegisteredObservers;
+
+
+        private SettingsObserver() {
+            super(new Handler(Looper.getMainLooper()));
+        }
+
+        private void registerObserversIfNeeded() {
+            if (mRegisteredObservers) {
+                return;
+            }
+            mRegisteredObservers = true;
+            mResolver.registerContentObserver(mDevicePostureUri, false /* notifyForDescendents */,
+                    this /* ContentObserver */);
+            mResolver.registerContentObserver(mDisplayFeaturesUri, false /* notifyForDescendents */,
+                    this /* ContentObserver */);
+        }
+
+        private void unregisterObserversIfNeeded() {
+            if (!mRegisteredObservers) {
+                return;
+            }
+            mRegisteredObservers = false;
+            mResolver.unregisterContentObserver(this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (uri == null) {
+                return;
+            }
+
+            if (mDevicePostureUri.equals(uri)) {
+                updateDevicePosture();
+                return;
+            }
+            if (mDisplayFeaturesUri.equals(uri)) {
+                updateDisplayFeatures();
+                return;
+            }
+        }
+    }
+
+    SettingsExtensionImpl(Context context) {
+        mContext = context;
+        mSettingsObserver = new SettingsObserver();
+    }
+
+    private void updateDevicePosture() {
+        updateDeviceState(getDeviceState());
+    }
+
+    /** Update display features with values read from settings. */
+    private void updateDisplayFeatures() {
+        for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
+            ExtensionWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
+            updateWindowLayout(windowToken, newLayout);
+        }
+    }
+
+    @NonNull
+    @Override
+    public ExtensionDeviceState getDeviceState() {
+        ContentResolver resolver = mContext.getContentResolver();
+        int posture = Settings.Global.getInt(resolver, DEVICE_POSTURE,
+                ExtensionDeviceState.POSTURE_UNKNOWN);
+        return new ExtensionDeviceState(posture);
+    }
+
+    @NonNull
+    @Override
+    public ExtensionWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
+        List<ExtensionDisplayFeature> displayFeatures = readDisplayFeatures(windowToken);
+        return new ExtensionWindowLayoutInfo(displayFeatures);
+    }
+
+    private List<ExtensionDisplayFeature> readDisplayFeatures(IBinder windowToken) {
+        List<ExtensionDisplayFeature> features = new ArrayList<ExtensionDisplayFeature>();
+        int displayId = getWindowDisplay(windowToken);
+        if (displayId != DEFAULT_DISPLAY) {
+            Log.w(TAG, "This sample doesn't support display features on secondary displays");
+            return features;
+        }
+
+        ContentResolver resolver = mContext.getContentResolver();
+        final String displayFeaturesString = Settings.Global.getString(resolver, DISPLAY_FEATURES);
+        if (isInMultiWindow(windowToken)) {
+            // It is recommended not to report any display features in multi-window mode, since it
+            // won't be possible to synchronize the display feature positions with window movement.
+            return features;
+        }
+        if (TextUtils.isEmpty(displayFeaturesString)) {
+            return features;
+        }
+
+        String[] featureStrings = displayFeaturesString.split(";");
+        for (String featureString : featureStrings) {
+            Matcher featureMatcher = FEATURE_PATTERN.matcher(featureString);
+            if (!featureMatcher.matches()) {
+                Log.e(TAG, "Malformed feature description format: " + featureString);
+                continue;
+            }
+            try {
+                String featureType = featureMatcher.group(1);
+                int type;
+                switch (featureType) {
+                    case FEATURE_TYPE_FOLD:
+                        type = ExtensionDisplayFeature.TYPE_FOLD;
+                        break;
+                    case FEATURE_TYPE_HINGE:
+                        type = ExtensionDisplayFeature.TYPE_HINGE;
+                        break;
+                    default: {
+                        Log.e(TAG, "Malformed feature type: " + featureType);
+                        continue;
+                    }
+                }
+
+                int left = Integer.parseInt(featureMatcher.group(2));
+                int top = Integer.parseInt(featureMatcher.group(3));
+                int right = Integer.parseInt(featureMatcher.group(4));
+                int bottom = Integer.parseInt(featureMatcher.group(5));
+                Rect featureRect = new Rect(left, top, right, bottom);
+                rotateRectToDisplayRotation(featureRect, displayId);
+                transformToWindowSpaceRect(featureRect, windowToken);
+                if (!featureRect.isEmpty()) {
+                    ExtensionDisplayFeature feature =
+                            new ExtensionDisplayFeature(featureRect, type);
+                    features.add(feature);
+                } else {
+                    Log.w(TAG, "Failed to adjust feature to window");
+                }
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "Malformed feature description: " + featureString);
+            }
+        }
+        return features;
+    }
+
+    @Override
+    protected void onListenersChanged() {
+        if (mSettingsObserver == null) {
+            return;
+        }
+
+        if (hasListeners()) {
+            mSettingsObserver.registerObserversIfNeeded();
+        } else {
+            mSettingsObserver.unregisterObserversIfNeeded();
+        }
+    }
+}