Skip to content

Commit

Permalink
APL-VH-Android: December 2022 Release of APL 2022.2.2 compliant Viewh…
Browse files Browse the repository at this point in the history
…ost Code
  • Loading branch information
pranavsu1997 committed Dec 9, 2022
1 parent bcb4462 commit 75aad11
Show file tree
Hide file tree
Showing 573 changed files with 9,777 additions and 19,316 deletions.
119 changes: 39 additions & 80 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,86 +1,61 @@
#README: APL Android
# Alexa Presentation Language (APL) ViewHost Android version 2022.2

The APL Android target contains 3 modules
APLViewHostAndroid is a view host implementation for the Android Platform. It consists of
a thin JNI layer that interacts with APL Core Engine for component inflation and command
handling, and a native Android layout that maps APL Components to Android Views and ViewGroups.

- APL jni adapter: 'libaplcore-jni.so' allows in process communication between the
core C++ and Java Android layers.
The APL Android Viewhost consists of two elements:

- APL Android Library: .aar library exposing functionality of the APL spec, for use by Android
applications. This library embeds the core and jni libraries. The aar build targets SDK 28 and
supports a minimum SDK 22, it has 4 flavors:

- apl-core-release.aar - The release library
- apl-demo-release.aar - The release library with sample APL layout assets included.
- apl-core-debug.aar - The debug library
- apl-demo-debug.aar - The debug library with sample APL layout assets included.
- APL JNI adapter: 'libaplcore-jni.so' allows in process communication between the
core C++ and Java Android layers.

- APL Android Sample App: A simple sample application that uses the demo library sample assets.
- APL Android Library: .aar library exposing functionality of the APL spec, for use by Android
applications. This library embeds the Core and JNI libraries. The aar build targets SDK 28 and
supports a minimum SDK 22, it has 2 flavors:

The Android library and Sample application are built with gradle. The Gradle cmake integration plugin
will build the the APL core library and core jni dependencies.
- apl-release.aar - The release library
- apl-debug.aar - The debug library

The Android library is built with Gradle. The Gradle CMake integration plugin
will build the APL Core Library and Core JNI dependencies.

### Prerequisites

- [Install NDK](https://developer.android.com/ndk/guides/#download-ndk) version 20
- Higher versions of NDK are not currently compatible with the current gradle plugin.
- [Install Android SDK](https://developer.android.com/studio/intro/update) version 28 or higher
- Install Ninja (Needed for APLCoreEngine when building from APLViewhostAndroid)
- Setup a workspace with the APL Android, and (optionally) APL Core code
```bash
$ ls
APLCoreEngine
APLViewhostAndroid
```
> The APL Core code is required for building the APL Android project. The Gradle build
> assumes it is in a sibling folder to the APLAndroidViewhost project. If the APL Core
> code is located elsewhere gradle commands must be augmented with `-PaplCoreDir=<path.to.core>`
> or set the value in the `gradle.properties` file.
## Android Studio
Make sure you have installed:

The APL Android sample application is used to test and demo the APL Android functionality. It has a fixed
build dependency on apl-demo-debug.aar . The sample app targets Android SDK 28 and can be run with
an emulator for desktop display and projection.
- [Android SDK](https://developer.android.com/studio/intro/update) version 28 or higher
- [Android NDK](https://developer.android.com/ndk/guides/#download-ndk) version 22 or higher
- APL Core build dependencies (e.g. one of supported C++ compilers, CMake)
- Ninja (Needed for APLCoreEngine when building from APLViewhostAndroid)

To run the project in Android Studio:
Setup a directory with the APL Android and APL Core - https://github.com/alexa/apl-core-library

- Launch the latest Android Studio (3.3.0+)
- Import the gradle project located at <workspace>/APLAndroidViewhost/
- You will see Android Studio Modules for "apl" and "app"
- Open file app/com/amazon/apl/examples/AplSampleActivity and select your preferred demo data, or add your own
- Run AplSampleActivity

> To debug the project configure Android Studio to find the debug symbols.
> "Run"->"Edit Configuration"->"Debugger"->"Symbol Directories" add the APL
> Android target root directory <workspace>/APLViewhostAndroid
## Building the APL Core for the Android APL Library

The APL Core library is a required dependency of the Android Viewhost and must be built using the CMAKE defines for Android.

To compile 'libaplcore.a' and 'libaplcore-jni.so' for armeabi-v7a devices, do the following, from the APL Core Library project:
```
$ mkdir build
$ cd build
$ cmake -DANDROID_ABI="armeabi-v7a" -DANDROID_PLATFORM=android-28 -DCMAKE_TOOLCHAIN_FILE=$NDK_HOME/build/cmake/android.toolchain.cmake -DAPL_JNI=ON ..
$ make -j4
```bash
$ ls
apl-core-library
apl-viewhost-android
```
For other architectures, the ANDROID_ABI flag should be set appropriately:
for example, -DANDROID_ABI="x86" for an x86 build
The APL Core code is required for building the APL Android project. The Gradle build
assumes it is in a sibling folder to the `apl-viewhost-android` project. If the APL Core
code is located elsewhere, Gradle commands must be augmented with `-PaplCoreDir=<path.to.core>`
or you can set the value in the `gradle.properties` file.

## Building the Android APL Library

Set the Android SDK root environment variable:

To build the Android APL library and the Sample application:
```bash
$ ./gradlew build
$ export ANDROID_SDK_ROOT=/Users/YOUR-LOGIN-HERE/Library/Android/sdk/
```
To install the `APL Sample App` connect your device or emulator:

Build the Android APL library:
```bash
$ ./gradlew app:installDebug
$ ./gradlew build
```
To see a full list of gradle tasks:

This step will also build the APL Core Library as a dependency.

To see a full list of Gradle tasks:
```bash
$ ./gradlew tasks
```
Expand All @@ -89,23 +64,7 @@ To see a full list of gradle tasks:

### CMake Error
```
CMake Error at /Volumes/workplace/APLAndroid/src/APLCoreEngine/thirdparty/thirdparty.cmake:120 (message):
CMake Error at ...APLCoreEngine/thirdparty/thirdparty.cmake:120 (message):
CMake step for googletest failed: 1
```
The `ninja` build tool needs to be available on the `PATH`.

### Gradle Error
```
> Could not get unknown property 'externalNativeBuildCoreDebug' for project ':apl' of type org.gradle.api.Project.
```

The current android gradle version (3.3.0) requires a NDK install that includes a `platforms` folder.
Starting with NDK 22.x, the `platforms` folder no longer exists. Additionally,
the default ndk location for 3.3.0 is `$ANDROID_SDK_HOME/ndk-bundle`, but the current version of
Android Studio (4.1.2) is no longer capable of installing the NDK to that location.

To work around this error (on a mac), you should download a compatible ndk version (< 22.x) and then
symbolic link it to the `ndk-bundle` folder:
```
ln -s /Users/$USER/Library/Android/sdk/ndk/20.0.5594570/ /Users/$USER/Library/Android/sdk/ndk-bundle
```
The `ninja` build tool needs to be available on the `PATH`.
4 changes: 2 additions & 2 deletions apl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ add_custom_target(generate-android-enums ALL
${APL_CORE_DIR}/aplcore/include/apl/touch/*.h
${APL_CORE_DIR}/aplcore/include/apl/focus/*.h
DEPENDS enumgen
)
)

add_dependencies(apl-jni generate-android-enums)

Expand All @@ -222,4 +222,4 @@ find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif(CCACHE_FOUND)
endif(CCACHE_FOUND)
63 changes: 46 additions & 17 deletions apl/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['test']) {
classDirectories.from(files(debugTree))

executionData.from(fileTree(dir: "$buildDir", includes: [
"jacoco/*.exec"
"jacoco/*.exec",
"outputs/code_coverage/debugAndroidTest/connected/*coverage.ec"
]))
reports {
xml.enabled = true
Expand All @@ -35,7 +36,7 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['test']) {
}

ext {
aplAndroidCmakeArgs = " -DCMAKE_VERBOSE_MAKEFILE=ON"
aplAndroidCmakeArgs = "-DCMAKE_VERBOSE_MAKEFILE=ON"
aplCoreDirCmakeArg = "-DAPL_CORE_DIR=" + projectDir + "/../../apl-core-library"
if (project.hasProperty('aplCoreDir')) {
aplCoreDirCmakeArg = "-DAPL_CORE_DIR=" + aplCoreDir
Expand All @@ -57,8 +58,7 @@ android {
externalNativeBuild {
cmake {
// Sets optional flags for the C++ compiler.
// Enables RTTI (RunTime Type Information) support and C++ exceptions.
cppFlags "-std=c++11", "-frtti", "-fexceptions", "-DBUILD_ALEXAEXTENSIONS=On", "-DALEXAEXTENSIONS=1"
cppFlags "-std=c++11", "-fno-rtti", "-fno-exceptions"
// Build the APL Core JNI library (excludes all other targets)
targets "apl", "apl-jni"
// Enable APL Core JNI build, and be verbose.
Expand All @@ -76,13 +76,15 @@ android {
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField("long", "VERSION_CODE", "${defaultConfig.versionCode}")
buildConfigField("String","VERSION_NAME","\"${defaultConfig.versionName}-core\"")
buildConfigField 'boolean', 'DEBUG_LOGGING', 'false'
}
debug {
testCoverageEnabled true
debuggable true
aplAndroidCmakeArgs += " -DDEBUG_MEMORY_USE=ON"
buildConfigField("long", "VERSION_CODE", "${defaultConfig.versionCode}")
buildConfigField("String","VERSION_NAME","\"${defaultConfig.versionName}-core\"")
buildConfigField 'boolean', 'DEBUG_LOGGING', 'true'
}
}
// Temporary fix until alpha10 - "More than one file was found with OS independent path 'META-INF/proguard/androidx-annotations.pro"
Expand All @@ -92,7 +94,7 @@ android {

externalNativeBuild {
cmake {
version "3.10.2"
version "3.18.1"

// Tells Gradle to find the root CMake APL build script. path is relative to
// the directory containing the module's build.gradle file. Gradle requires this
Expand All @@ -112,47 +114,63 @@ android {
fatal 'StopShip'
disable 'LongLogTag'
}

testOptions {
animationsDisabled true

unitTests {
includeAndroidResources = true
}
unitTests.all {
systemProperty "java.library.path", String.join(":",
"""${projectDir.absolutePath}/.cxx/cmake/debug/host/""",
"""${projectDir.absolutePath}/../discovery/.cxx/cmake/debug/host/""",
"""${projectDir.absolutePath}/../common/.cxx/cmake/debug/host/"""
)
}
}
}

dependencies {
compileOnly 'org.projectlombok:lombok:1.18.12'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.annotation:annotation:1.0.0'
implementation 'androidx.annotation:annotation:1.4.0'
implementation 'androidx.core:core:1.0.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.github.bumptech.glide:glide:4.6.1'
implementation project(':common')
implementation (project(':discovery')) { transitive = false }
testImplementation 'junit:junit:4.12'
testImplementation 'org.robolectric:robolectric:4.2'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.8.1'
testImplementation 'org.robolectric:shadows-httpclient:4.2'
testImplementation 'androidx.test:core:1.1.0'
testImplementation 'org.mockito:mockito-core:2.25.0'
androidTestImplementation 'org.mockito:mockito-core:2.25.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.annotation:annotation:1.0.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test:rules:1.1.1'
testImplementation 'androidx.test:core:1.4.0'
testImplementation 'androidx.test.ext:junit:1.1.3'
testImplementation 'org.mockito:mockito-core:4.7.0'
testImplementation 'androidx.test:rules:1.4.0'
androidTestImplementation 'org.mockito:mockito-core:3.12.4'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test:core:1.4.0'
androidTestImplementation 'androidx.annotation:annotation:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test:rules:1.4.0'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
androidTestImplementation 'com.linkedin.dexmaker:dexmaker:2.25.0'
androidTestImplementation 'com.linkedin.dexmaker:dexmaker-mockito:2.25.0'
androidTestImplementation project(":commonTest")
androidTestImplementation 'com.squareup.leakcanary:leakcanary-android-instrumentation:2.9.1'
androidTestImplementation 'com.squareup.leakcanary:leakcanary-object-watcher-android:2.9.1'
androidTestUtil 'androidx.test:orchestrator:1.1.1'
api "com.google.auto.value:auto-value-annotations:1.7"
api 'com.google.guava:guava:27.0.1-jre'
annotationProcessor "com.google.auto.value:auto-value:1.7"
annotationProcessor 'org.projectlombok:lombok:1.18.12'
}

task buildHostJNI(type: com.amazon.apl.android.CMakeTask) {
cmakeArgs aplCoreDirCmakeArg, aplAndroidCmakeArgs
makeTargets 'apl-jni'
}

project.afterEvaluate {
// Dump configuration settings
println "APL CMake Args: " + aplAndroidCmakeArgs
Expand All @@ -164,7 +182,18 @@ project.afterEvaluate {
compileDebugJavaWithJavac.dependsOn externalNativeBuildDebug
compileReleaseJavaWithJavac.dependsOn externalNativeBuildRelease

javaPreCompileDebug.dependsOn externalNativeBuildDebug

// We need to make sure the host jni library is built before any debug or release unit testing.
tasks.preDebugUnitTestBuild.dependsOn(buildHostJNI)
tasks.preReleaseUnitTestBuild.dependsOn(buildHostJNI)
tasks.preDebugUnitTestBuild.dependsOn(':discovery:buildHostJNI')
tasks.preReleaseUnitTestBuild.dependsOn(':discovery:buildHostJNI')
tasks.preDebugUnitTestBuild.dependsOn(':common:buildHostJNI')
tasks.preReleaseUnitTestBuild.dependsOn(':common:buildHostJNI')

tasks.test.finalizedBy(jacocoTestReport)
}


tasks.build.dependsOn(assembleAndroidTest)
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public final class APLTestDocs {
// can have optional template properties.
public final static String COMPONENT_BASE_DOC = "{" +
" \"type\": \"APL\"," +
" \"version\": \"1.0\"," +
" \"version\": \"%s\"," +
" \"onConfigChange\": [\n" +
" {\n" +
" \"type\": \"SendEvent\",\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

package com.amazon.apl.android;

public class APLViewhostTest {
import com.amazon.common.test.LeakRulesBaseClass;

public class APLViewhostTest extends LeakRulesBaseClass {
// Load the APL library.
static {
System.loadLibrary("common-jni");
Expand Down

0 comments on commit 75aad11

Please sign in to comment.