This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j-samples.git


The following commit(s) were added to refs/heads/main by this push:
     new 2d692e8  Enable automatic Android tests (#198)
2d692e8 is described below

commit 2d692e89323fffcc2ba0267106b06cb96d0d7128
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Thu Oct 10 17:06:10 2024 +0200

    Enable automatic Android tests (#198)
    
    This PR cleans up the `log4j-samples-android` project and enables a CI 
workflow to check the compatibility of releases with Android.
---
 .github/workflows/android-reusable-test.yaml       |  71 ++++--
 .github/workflows/android-test.yaml                |  14 +-
 README.adoc                                        |  12 +-
 log4j-samples-android/README.adoc                  |  40 ++++
 log4j-samples-android/app/build.gradle             |  25 +-
 .../samples/android/ExampleInstrumentedTest.java   |  42 ----
 .../log4j/samples/android/MainActivityTest.java    | 116 ++++++++++
 .../app/src/androidTest/resources/log4j2-test.xml  |  41 ++++
 .../app/src/main/AndroidManifest.xml               |   3 +-
 .../log4j/samples/android/MainActivity.java        |  99 ++++----
 .../app/src/main/res/values/strings.xml            |   2 +-
 .../log4j2.StatusLogger.properties}                |  23 +-
 .../main/resources/log4j2.component.properties}    |   2 -
 .../values/strings.xml => resources/log4j2.xml}    |  23 +-
 .../log4j/samples/android/ExampleUnitTest.java     |  33 ---
 log4j-samples-android/build.gradle                 |   8 +-
 log4j-samples-android/gradle.properties            |  14 +-
 .../gradle/wrapper/gradle-wrapper.jar              | Bin 59203 -> 59536 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   4 +-
 log4j-samples-android/gradlew                      | 257 ++++++++++++---------
 log4j-samples-android/settings.gradle              |   9 +-
 21 files changed, 527 insertions(+), 311 deletions(-)

diff --git a/.github/workflows/android-reusable-test.yaml 
b/.github/workflows/android-reusable-test.yaml
index 6bd06ab..70812c9 100644
--- a/.github/workflows/android-reusable-test.yaml
+++ b/.github/workflows/android-reusable-test.yaml
@@ -41,33 +41,50 @@ jobs:
       - name: Setup Java
         uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73   # 
4.4.0
         with:
+          distribution: 'temurin'
           java-version: 17
 
-      - name: Setup Android SDK
+      - name: Setup Gradle
+        uses: 
gradle/actions/setup-gradle@d156388eb19639ec20ade50009f3d199ce1e2808   # 4.1.0
+
+      - name: Enable KVM
+        run: |
+          echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", 
OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
+          sudo udevadm control --reload-rules
+          sudo udevadm trigger --name-match=kvm
+
+      - name: Create AVD Device
+        id: avd
         shell: bash
         env:
           ANDROID_SDK_VERSION: 10406996
           ANDROID_SDK_CHECKSUM: 
8919e8752979db73d8321e9babe2caedcc393750817c1a5f56c128ec442fb540
         run: |
-          # Create home directory
-          export ANDROID_HOME=$HOME/.android/sdk
-          mkdir -p $ANDROID_HOME
-          
-          # Download and verify the `cmdline-tools`
-          curl -O $ANDROID_HOME/cmdline-tools.zip 
https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_VERSION}_latest.zip
-          echo "$ANDROID_SDK_CHECKSUM $ANDROID_HOME/cmdline-tools.zip" | 
sha256sum -c
-          unzip -d $ANDROID_HOME/cmdline-tools{,.zip}
-          mv $ANDROID_HOME/cmdline-tools/{cmdline-tools,latest}
-          
-          # Accept licenses
-          yes | $ANDROID_HOME/cmdline-tools/bin/sdkmanager --licenses
-          
-          # Installing the remaining tools
-          $ANDROID_HOME/cmdline-tools/bin/sdkmanager tools platform-tools
-          
-          # Exporting ANDROID_HOME and adding sdkmanager to the PATH
-          echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
-          echo $ANDROID_HOME/cmdline-tools/bin >> $GITHUB_PATH
+          # List installed and available packages
+          $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --list
+          # Download images
+          echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager \
+          --install "system-images;android-31;default;x86_64" \
+          emulator platform-tools
+          # Create device
+          $ANDROID_HOME/cmdline-tools/latest/bin/avdmanager create avd \
+          --name generic-api-31-device \
+          --device "5.4in FWVGA" \
+          --package "system-images;android-31;default;x86_64"
+          # Run emulator
+          $ANDROID_HOME/emulator/emulator \
+          -no-audio -no-window \
+          -avd generic-api-31-device &
+          # Enabled the cleanup job
+          echo EMULATOR_STARTED=true >> $GITHUB_ENV
+          # Wait for device to go online
+          # It might take up to 5 minutes
+          for i in {1..300}; do
+            # Don't stop the script if `adb` fails
+            boot_completed=$($ANDROID_HOME/platform-tools/adb shell getprop 
sys.boot_completed 2> /dev/null || echo "0")
+            if [ "${boot_completed}" = "1" ]; then break; fi
+            sleep 1
+          done
 
       - name: Build
         id: build
@@ -75,7 +92,17 @@ jobs:
         env:
           LOG4J_VERSION: ${{ inputs.log4j-version }}
         run: |
-          log4j-samples-android/gradlew -p log4j-samples-gradlew \
+          log4j-samples-android/gradlew -p log4j-samples-android \
           --console plain \
-          -Plog4jVersion=$LOG4J_VERSION \
+          -Plog4j.version=$LOG4J_VERSION \
           build connectedCheck
+
+      - name: Remove AVD Device
+        if: ${{ always() && env.EMULATOR_STARTED == 'true' }}
+        shell: bash
+        run: |
+          # Kill the emulator
+          $ANDROID_HOME/platform-tools/adb -s emulator-5554 emu kill
+          # Delete the device
+          $ANDROID_HOME/cmdline-tools/latest/bin/avdmanager delete avd \
+          --name generic-api-31-device
diff --git a/.github/workflows/android-test.yaml 
b/.github/workflows/android-test.yaml
index 0f5d0d0..65aadaa 100644
--- a/.github/workflows/android-test.yaml
+++ b/.github/workflows/android-test.yaml
@@ -19,18 +19,16 @@ name: android-test
 
 on:
   workflow_dispatch:
-  schedule:
-    - cron: "29 17 * * *"
+    inputs:
+      log4j-version:
+        description: The version of Log4j Core to use
+        default: "2.25.0-SNAPSHOT"
 
 permissions: read-all
 
 jobs:
 
   android-test:
-    strategy:
-      fail-fast: false
-      matrix:
-        log4j-version: [ "2.25.0-SNAPSHOT" ]
-    uses: 
apache/logging-log4j-samples/.github/workflows/android-reusable-test.yaml@main
+    uses: 
apache/logging-log4j-samples/.github/workflows/android-reusable-test.yaml@feature/android-tests
     with:
-      log4j-version: ${{ matrix.log4j-version }}
+      log4j-version: ${{ inputs.log4j-version }}
diff --git a/README.adoc b/README.adoc
index 44f47ae..a2e5b42 100644
--- a/README.adoc
+++ b/README.adoc
@@ -18,20 +18,26 @@ limitations under the License.
 
 This repository contains several examples to help the user with some of the 
more advanced Log4j features.
 
+xref:log4j-samples-android/README.adoc[`log4j-samples-android`]::
+Explains how to use Log4j Core on Android.
+
 xref:log4j-samples-configuration/README.adoc[`log4j-samples-configuration`]::
-Explains how to use a custom programmatic configuration,
+Explains how to use a custom programmatic configuration.
 
 xref:log4j-samples-flume-embedded/README.adoc[`log4j-samples-flume-embedded`]::
-Explains how to use an embedded Flume agent to send logs to 
https://flume.apache.org[Apache Flume],
+Explains how to use an embedded Flume agent to send logs to 
https://flume.apache.org[Apache Flume.]
 
 xref:log4j-samples-flume-remote/README.adoc[`log4j-samples-flume-remote`]::
 Explains how to send logs to https://flume.apache.org[Apache Flume],
 
+xref:log4j-samples-graalvm/README.adoc[`log4j-samples-graalvm`]::
+Explains how to use Log4j API and its implementation to create native GraalVM 
images.
+
 xref:log4j-samples-jlink/README.adoc[`log4j-samples-jlink`]::
 An example of JLink custom JRE.
 
 
xref:log4j-samples-loggerProperties/README.adoc[`log4j-samples-loggerProperties`]::
-Explains how to write a custom property lookup,
+Explains how to write a custom property lookup.
 
 
xref:log4j-spring-cloud-config-sample-application/README.md[`log4j-spring-cloud-config-sample-application`]::
 An example of Spring Boot application that reads its logging configuration 
from a Spring Cloud Configuration Server.
diff --git a/log4j-samples-android/README.adoc 
b/log4j-samples-android/README.adoc
new file mode 100644
index 0000000..cfb318c
--- /dev/null
+++ b/log4j-samples-android/README.adoc
@@ -0,0 +1,40 @@
+////
+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
+
+    https://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 Log4j Samples: Android application
+
+This project is an example of Android application that uses
+https://logging.apache.org/log4j/2.x/manual/api.html[the Log4j API]
+for logging together with its reference implementation
+https://logging.apache.org/log4j/2.x/manual/implementation.html[Log4j Core].
+
+To build the project, run:
+
+[source,shell]
+----
+./gradlew build
+----
+
+inside this directory.
+
+Since version `2.25.0` this application is part of the integration tests for a 
Log4j release.
+
+== Known Android limitations
+
+The Android platform does not implement all the features of a standard JRE, 
which will prevent you from using all the features offered by Log4j Core.
+For a list of known limitations, see
+https://logging.apache.org/log4j/2.x/faq.html#android[our Android F.A.Q. 
entry].
+
diff --git a/log4j-samples-android/app/build.gradle 
b/log4j-samples-android/app/build.gradle
index 05f2310..c08592c 100644
--- a/log4j-samples-android/app/build.gradle
+++ b/log4j-samples-android/app/build.gradle
@@ -20,6 +20,7 @@ plugins {
 
 android {
     compileSdk 34
+    namespace "org.apache.logging.log4j.samples.android"
 
     defaultConfig {
         applicationId "org.apache.logging.log4j.samples.android"
@@ -48,17 +49,29 @@ android {
     }
 }
 
+def log4jVersion = providers.gradleProperty("log4j.version").get()
+
 dependencies {
 
-    implementation 'androidx.appcompat:appcompat:1.6.1'
-    implementation 'com.google.android.material:material:1.11.0'
+    implementation 'androidx.appcompat:appcompat:1.7.0'
+    implementation 'com.google.android.material:material:1.12.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
 
     testImplementation 'junit:junit:4.13.2'
     androidTestImplementation 'androidx.test.ext:junit:1.2.1'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
+    androidTestImplementation 'org.assertj:assertj-core:3.26.3'
+
+    // Log4j
+    implementation group: 'org.apache.logging.log4j', name: 'log4j-api', 
version: log4jVersion
+    implementation group: 'org.apache.logging.log4j', name: 'log4j-core', 
version: log4jVersion
+    androidTestImplementation(group: 'org.apache.logging.log4j', name: 
'log4j-core-test', version: log4jVersion) {
+        exclude group: 'com.google.code.java-allocation-instrumenter'
+        exclude group: 'org.apache.logging.log4j', module: 'log4j-api-test'
+        exclude group: 'org.hamcrest'
+        exclude group: 'org.junit.jupiter'
+        exclude group: 'org.junit.platform'
+        exclude group: 'org.springframework'
+    }
 
-    //Log4j
-    implementation 'org.apache.logging.log4j:log4j-api:2.24.1'
-    implementation 'org.apache.logging.log4j:log4j-core:2.24.1'
-}
\ No newline at end of file
+}
diff --git 
a/log4j-samples-android/app/src/androidTest/java/org/apache/logging/log4j/samples/android/ExampleInstrumentedTest.java
 
b/log4j-samples-android/app/src/androidTest/java/org/apache/logging/log4j/samples/android/ExampleInstrumentedTest.java
deleted file mode 100644
index 8c1487c..0000000
--- 
a/log4j-samples-android/app/src/androidTest/java/org/apache/logging/log4j/samples/android/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.
- */
-package org.apache.logging.log4j.samples.android;
-
-import android.content.Context;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * @see <a href="http://d.android.com/tools/testing";>Testing documentation</a>
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
-    @Test
-    public void useAppContext() {
-        // Context of the app under test.
-        Context appContext = 
InstrumentationRegistry.getInstrumentation().getTargetContext();
-        assertEquals("com.example.log4japi", appContext.getPackageName());
-    }
-}
\ No newline at end of file
diff --git 
a/log4j-samples-android/app/src/androidTest/java/org/apache/logging/log4j/samples/android/MainActivityTest.java
 
b/log4j-samples-android/app/src/androidTest/java/org/apache/logging/log4j/samples/android/MainActivityTest.java
new file mode 100644
index 0000000..0ab867a
--- /dev/null
+++ 
b/log4j-samples-android/app/src/androidTest/java/org/apache/logging/log4j/samples/android/MainActivityTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.samples.android;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Map;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ */
+@RunWith(AndroidJUnit4.class)
+public class MainActivityTest {
+
+    @Rule
+    public ActivityScenarioRule<MainActivity> activityScenarioRule = new 
ActivityScenarioRule<>(MainActivity.class);
+
+    private static Configuration configuration;
+    private static ListAppender appender;
+    private static Logger logger;
+
+    @BeforeClass
+    public static void setup() {
+        LoggerContext context = LoggerContext.getContext(false);
+        configuration = context.getConfiguration();
+        appender = configuration.getAppender("LIST");
+        logger = context.getLogger(MainActivity.class);
+    }
+
+    @Test
+    public void hasExpectedConfiguration() {
+        assertThat(configuration.getConfigurationSource().getLocation())
+                .startsWith("jar:file:")
+                .endsWith("!/log4j2-test.xml");
+        // Check appenders
+        Appender console = configuration.getAppender("CONSOLE");
+        assertThat(console).as("Console 
Appender").isInstanceOf(ConsoleAppender.class);
+        Appender list = configuration.getAppender("LIST");
+        assertThat(list).as("List Appender").isInstanceOf(ListAppender.class);
+        // Check logger configurations
+        assertThat(configuration.getLoggers()).hasSize(2);
+        
assertThat(configuration.getRootLogger().getExplicitLevel()).isEqualTo(Level.INFO);
+        assertThat(configuration.getRootLogger().getAppenders())
+                .hasSize(2)
+                .containsExactly(entry("CONSOLE", console), entry("LIST", 
list));
+        assertThat(configuration.getLoggerConfig(MainActivity.class.getName()))
+                .isNotNull()
+                .extracting(LoggerConfig::getExplicitLevel)
+                .isEqualTo(Level.DEBUG);
+    }
+
+    @Test
+    public void logMessagesAreDelivered() {
+        assertThat(logger.getLevel()).isEqualTo(Level.DEBUG);
+        appender.clear();
+        for (int buttonId : MainActivity.buttonIds) {
+            onView(withId(buttonId)).perform(click());
+        }
+        Level[] expectedLevels = {Level.FATAL, Level.ERROR, Level.WARN, 
Level.INFO, Level.DEBUG};
+        String[] expectedMessages =
+                Arrays.stream(expectedLevels).map(l -> l + "-Hello " + l + 
"!").toArray(String[]::new);
+        
assertThat(appender.getMessages()).hasSize(expectedLevels.length).containsExactly(expectedMessages);
+    }
+
+    @Test
+    public void logLevelChanges() {
+        assertThat(logger.getLevel()).isEqualTo(Level.DEBUG);
+        onView(withId(R.id.setLogLevelBtn)).perform(click());
+        onView(withText("Set log level")).check(matches(isDisplayed()));
+        onView(withText("ERROR")).perform(click());
+        onView(withText("Select")).perform(click());
+        onView(withText("Set log level")).check(doesNotExist());
+        assertThat(logger.getLevel()).isEqualTo(Level.ERROR);
+    }
+
+    private static Map.Entry<String, Appender> entry(String name, Appender 
appender) {
+        return new AbstractMap.SimpleImmutableEntry<>(name, appender);
+    }
+}
\ No newline at end of file
diff --git 
a/log4j-samples-android/app/src/androidTest/resources/log4j2-test.xml 
b/log4j-samples-android/app/src/androidTest/resources/log4j2-test.xml
new file mode 100644
index 0000000..c6b153c
--- /dev/null
+++ b/log4j-samples-android/app/src/androidTest/resources/log4j2-test.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<Configuration xmlns="https://logging.apache.org/xml/ns";
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+               xsi:schemaLocation="
+                   https://logging.apache.org/xml/ns
+                   https://logging.apache.org/xml/ns/log4j-config-2.xsd";>
+  <Appenders>
+    <Console name="CONSOLE"
+             ignoreExceptions="false">
+      <PatternLayout pattern="%d %-5p [%t] %C:%M - %m%n"/>
+    </Console>
+    <List name="LIST"
+          ignoreExceptions="false">
+      <PatternLayout pattern="%p-%m"/>
+    </List>
+  </Appenders>
+  <Loggers>
+    <Root level="INFO">
+      <AppenderRef ref="CONSOLE"/>
+      <AppenderRef ref="LIST"/>
+    </Root>
+    <Logger name="org.apache.logging.log4j.samples.android.MainActivity"
+            level="DEBUG"/>
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/log4j-samples-android/app/src/main/AndroidManifest.xml 
b/log4j-samples-android/app/src/main/AndroidManifest.xml
index 90140f5..2b5ba9e 100644
--- a/log4j-samples-android/app/src/main/AndroidManifest.xml
+++ b/log4j-samples-android/app/src/main/AndroidManifest.xml
@@ -16,8 +16,7 @@
   ~ limitations under the License.
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android";
-    xmlns:tools="http://schemas.android.com/tools";
-    package="org.apache.logging.log4j.samples.android">
+    xmlns:tools="http://schemas.android.com/tools";>
 
     <application
         android:allowBackup="true"
diff --git 
a/log4j-samples-android/app/src/main/java/org/apache/logging/log4j/samples/android/MainActivity.java
 
b/log4j-samples-android/app/src/main/java/org/apache/logging/log4j/samples/android/MainActivity.java
index 3ac0526..b2fefdc 100644
--- 
a/log4j-samples-android/app/src/main/java/org/apache/logging/log4j/samples/android/MainActivity.java
+++ 
b/log4j-samples-android/app/src/main/java/org/apache/logging/log4j/samples/android/MainActivity.java
@@ -16,67 +16,63 @@
  */
 package org.apache.logging.log4j.samples.android;
 
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-
-import android.os.Bundle;
-import android.widget.Button;
-import android.widget.TextView;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.Configurator;
 
-import java.util.Arrays;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
 
 public class MainActivity extends AppCompatActivity {
 
-    private int logLevelIdx;
+    private static final Logger logger = 
LogManager.getLogger(MainActivity.class);
+    static final int[] buttonIds = {
+        R.id.fatalLogBtn, R.id.errorLogBtn, R.id.warnLogBtn, R.id.infoLogBtn, 
R.id.debugLogBtn, R.id.traceLogBtn
+    };
+    /**
+     * All log levels
+     */
+    private static final List<Level> logLevels = Arrays.asList(
+            Level.OFF, Level.FATAL, Level.ERROR, Level.WARN, Level.INFO, 
Level.DEBUG, Level.TRACE, Level.ALL);
 
-    //Logger log = LogManager.getLogger(MainActivity.class);
-    Logger log = LogManager.getRootLogger();
+    private int logLevelIdx;
+    private final Map<View, Level> buttonToLevel = new HashMap<>();
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        logger.info("Creating Main Activity...");
         setContentView(R.layout.activity_main);
 
-        /*// Manually read in log4j2.properties
-        LoggerContext context = (LoggerContext) LogManager.getContext(false);
-        try {
-            InputStream inputStream = getAssets().open("log4j2.properties");
-            ConfigurationSource source = new ConfigurationSource(inputStream);
-            
context.start(ConfigurationFactory.getInstance().getConfiguration(context, 
source));
-        } catch (IOException e) {
-            e.printStackTrace();
-        }*/
-
-        /*// Explicitly set the logging level for this logger to INFO
-        //Configurator.setLevel(log, Level.INFO);
-        LoggerConfig loggerConfig = 
context.getConfiguration().getLoggerConfig(log.getName());
-        loggerConfig.setLevel(Level.INFO);*/
-
-        //
-        // UI bindings
-        //
-        //TextView displaying Log Level
+        // TextView displaying Log Level
         TextView logLevelTxt = findViewById(R.id.logLevelTxt);
-        logLevelTxt.setText(log.getLevel().name());
+        logLevelTxt.setText(logger.getLevel().name());
 
-        //Change log level
+        // Change log level
         Button setLogLevelBtn = findViewById(R.id.setLogLevelBtn);
         setLogLevelBtn.setOnClickListener(v -> {
             AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
             alertDialog.setTitle("Set log level");
 
-            String[] logLevels = new String[]{"OFF", "FATAL", "ERROR", "WARN", 
"INFO", "DEBUG", "TRACE", "ALL"};
-            logLevelIdx = 
Arrays.asList(logLevels).indexOf(log.getLevel().name());
+            logLevelIdx = logLevels.indexOf(logger.getLevel());
 
-            alertDialog.setSingleChoiceItems(logLevels, logLevelIdx, (dialog, 
which) -> logLevelIdx = which);
+            alertDialog.setSingleChoiceItems(
+                    logLevels.stream().map(Level::name).toArray(String[]::new),
+                    logLevelIdx,
+                    (dialog, which) -> logLevelIdx = which);
             alertDialog.setPositiveButton("Select", (dialog, which) -> {
-                Configurator.setLevel(log, 
Level.valueOf(Arrays.asList(logLevels).get(logLevelIdx)));
-                logLevelTxt.setText(log.getLevel().name());
+                Configurator.setLevel(logger, logLevels.get(logLevelIdx));
+                logLevelTxt.setText(logger.getLevel().name());
                 dialog.dismiss();
             });
             alertDialog.setNegativeButton("Cancel", (dialog, which) -> 
dialog.dismiss());
@@ -84,23 +80,20 @@ public class MainActivity extends AppCompatActivity {
             alertDialog.show();
         });
 
-        //Log messages
-        Button fatalLogBtn = findViewById(R.id.fatalLogBtn);
-        fatalLogBtn.setOnClickListener(v -> log.fatal("Current log level is: " 
+ log.getLevel().name()));
-
-        Button errorLogBtn = findViewById(R.id.errorLogBtn);
-        errorLogBtn.setOnClickListener(v -> log.error("Current log level is: " 
+ log.getLevel().name()));
-
-        Button warnLogBtn = findViewById(R.id.warnLogBtn);
-        warnLogBtn.setOnClickListener(v -> log.warn("Current log level is: " + 
log.getLevel().name()));
-
-        Button infoLogBtn = findViewById(R.id.infoLogBtn);
-        infoLogBtn.setOnClickListener(v -> log.info("Current log level is: " + 
log.getLevel().name()));
-
-        Button debugLogBtn = findViewById(R.id.debugLogBtn);
-        debugLogBtn.setOnClickListener(v -> log.debug("Current log level is: " 
+ log.getLevel().name()));
+        // Log messages
+        for (int i = 0; i < buttonIds.length; i++) {
+            Button button = findViewById(buttonIds[i]);
+            // The `OFF` level should not have a button
+            buttonToLevel.put(button, logLevels.get(i + 1));
+            button.setOnClickListener(this::onLevelButtonClick);
+        }
+        logger.info("Main Activity created.");
+    }
 
-        Button traceLogBtn = findViewById(R.id.traceLogBtn);
-        traceLogBtn.setOnClickListener(v -> log.trace("Current log level is: " 
+ log.getLevel().name()));
+    void onLevelButtonClick(View view) {
+        Level level = buttonToLevel.get(view);
+        if (level != null) {
+            logger.log(level, "Hello {}!", level);
+        }
     }
 }
\ No newline at end of file
diff --git a/log4j-samples-android/app/src/main/res/values/strings.xml 
b/log4j-samples-android/app/src/main/res/values/strings.xml
index 354a979..e9ed6e2 100644
--- a/log4j-samples-android/app/src/main/res/values/strings.xml
+++ b/log4j-samples-android/app/src/main/res/values/strings.xml
@@ -16,5 +16,5 @@
   ~ limitations under the License.
   -->
 <resources>
-    <string name="app_name">Log4jAPI</string>
+    <string name="app_name">Log4j Core test</string>
 </resources>
\ No newline at end of file
diff --git a/log4j-samples-android/app/src/main/assets/log4j2.properties 
b/log4j-samples-android/app/src/main/resources/log4j2.StatusLogger.properties
similarity index 50%
rename from log4j-samples-android/app/src/main/assets/log4j2.properties
rename to 
log4j-samples-android/app/src/main/resources/log4j2.StatusLogger.properties
index c05bb88..92ff5ca 100644
--- a/log4j-samples-android/app/src/main/assets/log4j2.properties
+++ 
b/log4j-samples-android/app/src/main/resources/log4j2.StatusLogger.properties
@@ -15,24 +15,5 @@
 # limitations under the License.
 #
 ##
-# Root logger configuration
-status = error
-name = PropertiesConfig
-
-# Appenders
-appender.console.type = Console
-appender.console.name = Console
-appender.console.target = SYSTEM_OUT
-appender.console.layout.type = PatternLayout
-appender.console.layout.pattern = [%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5p- %m%n
-
-# Root logger level and appenders
-rootLogger.level = INFO
-rootLogger.appenderRefs = stdout
-rootLogger.appenderRef.stdout.ref = Console
-
-logger.com.example.log4japi.MainActivity.name = 
com.example.log4japi.MainActivity
-logger.com.example.log4japi.MainActivity.level = DEBUG
-logger.com.example.log4japi.MainActivity.additivity = false
-logger.com.example.log4japi.MainActivity.appenderRefs = stdout
-logger.com.example.log4japi.MainActivity.appenderRef.stdout.ref = Console
\ No newline at end of file
+# Set the level to `WARN`
+log4j2.statusLoggerLevel = WARN
\ No newline at end of file
diff --git a/log4j-samples-android/gradle.properties 
b/log4j-samples-android/app/src/main/resources/log4j2.component.properties
similarity index 92%
copy from log4j-samples-android/gradle.properties
copy to log4j-samples-android/app/src/main/resources/log4j2.component.properties
index 1ddc0d2..d501067 100644
--- a/log4j-samples-android/gradle.properties
+++ b/log4j-samples-android/app/src/main/resources/log4j2.component.properties
@@ -15,5 +15,3 @@
 # limitations under the License.
 #
 ##
-# Required by AndroidX dependencies
-android.useAndroidX = true
\ No newline at end of file
diff --git a/log4j-samples-android/app/src/main/res/values/strings.xml 
b/log4j-samples-android/app/src/main/resources/log4j2.xml
similarity index 54%
copy from log4j-samples-android/app/src/main/res/values/strings.xml
copy to log4j-samples-android/app/src/main/resources/log4j2.xml
index 354a979..73eb743 100644
--- a/log4j-samples-android/app/src/main/res/values/strings.xml
+++ b/log4j-samples-android/app/src/main/resources/log4j2.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   ~ Licensed to the Apache Software Foundation (ASF) under one or more
   ~ contributor license agreements.  See the NOTICE file distributed with
@@ -15,6 +15,21 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<resources>
-    <string name="app_name">Log4jAPI</string>
-</resources>
\ No newline at end of file
+<Configuration xmlns="https://logging.apache.org/xml/ns";
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+               xsi:schemaLocation="
+                   https://logging.apache.org/xml/ns
+                   https://logging.apache.org/xml/ns/log4j-config-2.xsd";>
+  <Appenders>
+    <Console name="CONSOLE">
+      <PatternLayout pattern="%d %-5p [%t] %C:%M - %m%n"/>
+    </Console>
+  </Appenders>
+  <Loggers>
+    <Root level="INFO">
+      <AppenderRef ref="CONSOLE"/>
+    </Root>
+    <Logger name="org.apache.logging.log4j.samples.android.MainActivity"
+            level="DEBUG"/>
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git 
a/log4j-samples-android/app/src/test/java/org/apache/logging/log4j/samples/android/ExampleUnitTest.java
 
b/log4j-samples-android/app/src/test/java/org/apache/logging/log4j/samples/android/ExampleUnitTest.java
deleted file mode 100644
index 67d09bd..0000000
--- 
a/log4j-samples-android/app/src/test/java/org/apache/logging/log4j/samples/android/ExampleUnitTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.
- */
-package org.apache.logging.log4j.samples.android;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine 
(host).
- *
- * @see <a href="http://d.android.com/tools/testing";>Testing documentation</a>
- */
-public class ExampleUnitTest {
-    @Test
-    public void addition_isCorrect() {
-        assertEquals(4, 2 + 2);
-    }
-}
\ No newline at end of file
diff --git a/log4j-samples-android/build.gradle 
b/log4j-samples-android/build.gradle
index b50e0db..10ca053 100644
--- a/log4j-samples-android/build.gradle
+++ b/log4j-samples-android/build.gradle
@@ -15,10 +15,6 @@
  * limitations under the License.
  */
 plugins {
-    id 'com.android.application' version '7.2.1' apply false
-    id 'com.android.library' version '7.2.1' apply false
+    id 'com.android.application' version '8.2.0' apply false
+    id 'com.android.library' version '8.2.0' apply false
 }
-
-tasks.register('clean', Delete) {
-    delete rootProject.buildDir
-}
\ No newline at end of file
diff --git a/log4j-samples-android/gradle.properties 
b/log4j-samples-android/gradle.properties
index 1ddc0d2..63e8e74 100644
--- a/log4j-samples-android/gradle.properties
+++ b/log4j-samples-android/gradle.properties
@@ -16,4 +16,16 @@
 #
 ##
 # Required by AndroidX dependencies
-android.useAndroidX = true
\ No newline at end of file
+android.useAndroidX = true
+
+##
+# Version of Log4j to use
+#
+# Defaults to the last stable 2.x release
+log4j.version = 2.24.1
+
+##
+# Additional Maven Repository to use
+#
+# Defaults to Apache Snapshots Repository
+log4j.repository.url = https://repository.apache.org/snapshots
\ No newline at end of file
diff --git a/log4j-samples-android/gradle/wrapper/gradle-wrapper.jar 
b/log4j-samples-android/gradle/wrapper/gradle-wrapper.jar
index e708b1c..7454180 100644
Binary files a/log4j-samples-android/gradle/wrapper/gradle-wrapper.jar and 
b/log4j-samples-android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/log4j-samples-android/gradle/wrapper/gradle-wrapper.properties 
b/log4j-samples-android/gradle/wrapper/gradle-wrapper.properties
index 8609210..880b651 100644
--- a/log4j-samples-android/gradle/wrapper/gradle-wrapper.properties
+++ b/log4j-samples-android/gradle/wrapper/gradle-wrapper.properties
@@ -16,7 +16,7 @@
 #
 ##
 distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
 distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/log4j-samples-android/gradlew b/log4j-samples-android/gradlew
index 4f906e0..1b6c787 100755
--- a/log4j-samples-android/gradlew
+++ b/log4j-samples-android/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
 
 #
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
 #
 
 ##############################################################################
-##
-##  Gradle start up script for UN*X
-##
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       
https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
 ##############################################################################
 
 # Attempt to set APP_HOME
+
 # Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no 
leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
 done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to 
pass JVM options to this script.
 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
 
 warn () {
     echo "$*"
-}
+} >&2
 
 die () {
     echo
     echo "$*"
     echo
     exit 1
-}
+} >&2
 
 # OS specific support (must be 'true' or 'false').
 cygwin=false
 msys=false
 darwin=false
 nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
 esac
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
         # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
+        JAVACMD=$JAVA_HOME/jre/sh/java
     else
-        JAVACMD="$JAVA_HOME/bin/java"
+        JAVACMD=$JAVA_HOME/bin/java
     fi
     if [ ! -x "$JAVACMD" ] ; then
         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to 
match the
 location of your Java installation."
     fi
 else
-    JAVACMD="java"
+    JAVACMD=java
     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 
'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,95 @@ location of your Java installation."
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; 
then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
 fi
 
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" 
\"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
 
 # For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
     # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### 
Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### 
Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with 
options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX 
filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
         fi
-        i=`expr $i + 1`
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
     done
-    case $i in
-        0) set -- ;;
-        1) set -- "$args0" ;;
-        2) set -- "$args0" "$args1" ;;
-        3) set -- "$args0" "$args1" "$args2" ;;
-        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" 
"$args6" ;;
-        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" 
"$args6" "$args7" ;;
-        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" 
"$args6" "$args7" "$args8" ;;
-    esac
 fi
 
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; 
done
-    echo " "
-}
-APP_ARGS=`save "$@"`
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes 
removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
 
-# Collect all arguments for the java command, following the shell quoting and 
substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 
"\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" 
org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
 
 exec "$JAVACMD" "$@"
diff --git a/log4j-samples-android/settings.gradle 
b/log4j-samples-android/settings.gradle
index 5c07617..018f37e 100644
--- a/log4j-samples-android/settings.gradle
+++ b/log4j-samples-android/settings.gradle
@@ -26,7 +26,14 @@ dependencyResolutionManagement {
     repositories {
         google()
         mavenCentral()
+        // Points to the correct Apache snapshot/staging repository
+        //
+        // See gradle.properties
+        maven {
+            name = 'Apache Repository'
+            url = providers.gradleProperty("log4j.repository.url")
+        }
     }
 }
-rootProject.name = "Log4jAPI"
+rootProject.name = "Log4j Core Android"
 include ':app'

Reply via email to