diff --git a/.github/workflows/attach_debug_apks_to_release.yml b/.github/workflows/attach_debug_apks_to_release.yml new file mode 100644 index 000000000..05540dcf0 --- /dev/null +++ b/.github/workflows/attach_debug_apks_to_release.yml @@ -0,0 +1,36 @@ +name: Attach Debug APKs To Release + +on: + release: + types: + - published + +jobs: + attach-apks: + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Clone repository + uses: actions/checkout@v2 + with: + ref: ${{ env.GITHUB_REF }} + - name: Set vars + run: | + RELEASE_VERSION_NAME="${GITHUB_REF/refs\/tags\//}" + if ! printf "%s" "${RELEASE_VERSION_NAME/v/}" | grep -qP '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'; then + echo "The versionName '${RELEASE_VERSION_NAME/v/}' is not a valid version as per semantic version '2.0.0' spec in the format 'major.minor.patch(-prerelease)(+buildmetadata)'. https://semver.org/spec/v2.0.0.html." + exit 1 + fi + echo "TERMUX_API_RELEASE_TAG=$RELEASE_VERSION_NAME" >> $GITHUB_ENV + echo "TERMUX_API_APK_VERSION_TAG=$RELEASE_VERSION_NAME+github-debug" >> $GITHUB_ENV # Used by app/build.gradle + - name: Echo release + run: echo "Attaching debug APK to '${{ env.TERMUX_API_RELEASE_TAG }}' release" + - name: Build + run: ./gradlew assembleDebug + - name: Attach APKs to release + run: >- + hub release edit + -m "" + -a "./app/build/outputs/apk/debug/termux-api_${{ env.TERMUX_API_APK_VERSION_TAG }}.apk" + "${{ env.TERMUX_API_RELEASE_TAG }}" diff --git a/.github/workflows/debug_build.yml b/.github/workflows/debug_build.yml index 210c54a09..239a65dde 100644 --- a/.github/workflows/debug_build.yml +++ b/.github/workflows/debug_build.yml @@ -6,13 +6,24 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: Clone repository - uses: actions/checkout@v2 - - name: Build - run: | - ./gradlew assembleDebug - - name: Store generated APK file - uses: actions/upload-artifact@v2 - with: - name: termux-api - path: ./app/build/outputs/apk/debug/app-debug.apk + - name: Clone repository + uses: actions/checkout@v2 + - name: Set vars + run: | + # Set NEW_VERSION_NAME to "+" + CURRENT_VERSION_NAME_REGEX='\s+versionName "([^"]+)"$' + CURRENT_VERSION_NAME="$(grep -m 1 -E "$CURRENT_VERSION_NAME_REGEX" ./app/build.gradle | sed -r "s/$CURRENT_VERSION_NAME_REGEX/\1/")" + NEW_VERSION_NAME="$CURRENT_VERSION_NAME+${GITHUB_SHA:0:7}" + echo "TERMUX_WIDGET_APP_VERSION_NAME=$NEW_VERSION_NAME" >> $GITHUB_ENV # Used by app/build.gradle + echo "TERMUX_WIDGET_APK_VERSION_TAG=v$NEW_VERSION_NAME-github-debug" >> $GITHUB_ENV # Used by app/build.gradle + - name: Echo version + run: echo "Building APK for '$TERMUX_WIDGET_APP_VERSION_NAME'" + - name: Build + run: ./gradlew assembleDebug + - name: Store generated APK file + uses: actions/upload-artifact@v2 + with: + name: termux-api + path: | + ./app/build/outputs/apk/debug/termux-api_${{ env.TERMUX_WIDGET_APK_VERSION_TAG }}.apk + ./app/build/outputs/apk/debug/output-metadata.json diff --git a/.gitignore b/.gitignore index 6c8b41f86..247b4bcbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,11 @@ -# .gitignore from https://gist.github.com/iainconnor/8605514: - # Built application files build/ +release/ +*.apk +*.so +.externalNativeBuild +.cxx +*.zip # Crashlytics configuations com_crashlytics_export_strings.xml diff --git a/app/build.gradle b/app/build.gradle index d01ad3539..2f13295bd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,14 +1,23 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 30 + compileSdkVersion project.properties.compileSdkVersion.toInteger() + def appVersionName = System.getenv("TERMUX_API_APP_VERSION_NAME") ?: "" + def apkVersionTag = System.getenv("TERMUX_API_APK_VERSION_TAG") ?: "" defaultConfig { applicationId "com.termux.api" - minSdkVersion 24 - targetSdkVersion 28 + minSdkVersion project.properties.minSdkVersion.toInteger() + targetSdkVersion project.properties.targetSdkVersion.toInteger() versionCode 49 - versionName "0.49" + versionName "0.49.0" + + if (appVersionName) versionName = appVersionName + validateVersionName(versionName) + + manifestPlaceholders.TERMUX_PACKAGE_NAME = "com.termux" + manifestPlaceholders.TERMUX_APP_NAME = "Termux" + manifestPlaceholders.TERMUX_API_APP_NAME = "Termux:API" } signingConfigs { @@ -22,7 +31,8 @@ android { buildTypes { release { - minifyEnabled false + minifyEnabled true + shrinkResources false // Reproducible builds proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' } @@ -36,6 +46,16 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } + applicationVariants.all { variant -> + variant.outputs.all { output -> + if (variant.buildType.name == "debug") { + outputFileName = new File("termux-api_" + (apkVersionTag ? apkVersionTag : "debug") + ".apk") + } else if (variant.buildType.name == "release") { + outputFileName = new File("termux-api_" + (apkVersionTag ? apkVersionTag : "release") + ".apk") + } + } + } + lintOptions { disable 'ExpiredTargetSdkVersion' } @@ -43,12 +63,20 @@ android { dependencies { implementation 'com.google.android.material:material:1.4.0' - implementation 'androidx.biometric:biometric:1.2.0-alpha02' - implementation 'androidx.media:media:1.4.1' + implementation 'androidx.biometric:biometric:1.2.0-alpha03' + implementation 'androidx.media:media:1.4.3' + implementation 'com.termux.termux-app:termux-shared:f3ffc36bfd' } task versionName { - doLast { - print android.defaultConfig.versionName - } + doLast { + print android.defaultConfig.versionName + } +} + +def validateVersionName(String versionName) { + // https://semver.org/spec/v2.0.0.html#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string + // ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ + if (!java.util.regex.Pattern.matches("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?\$", versionName)) + throw new GradleException("The versionName '" + versionName + "' is not a valid version as per semantic version '2.0.0' spec in the format 'major.minor.patch(-prerelease)(+buildmetadata)'. https://semver.org/spec/v2.0.0.html.") } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 000000000..bd0e223e8 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,10 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +-dontobfuscate diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 974f38218..ff328bb67 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ + android:sharedUserId="${TERMUX_PACKAGE_NAME}"> @@ -48,18 +48,19 @@ - + - - - + + + @@ -72,23 +73,23 @@ android:noHistory="true" android:excludeFromRecents="true" android:exported="false"/> - - - - + + - + android:name=".ShareAPI$ContentProvider" /> diff --git a/app/src/main/java/com/termux/api/DialogActivity.java b/app/src/main/java/com/termux/api/DialogActivity.java index 69c412ef0..25f5ddd56 100644 --- a/app/src/main/java/com/termux/api/DialogActivity.java +++ b/app/src/main/java/com/termux/api/DialogActivity.java @@ -57,6 +57,9 @@ import java.util.Objects; import java.util.Properties; +import static com.termux.shared.termux.TermuxConstants.TERMUX_PROPERTIES_PRIMARY_FILE_PATH; +import static com.termux.shared.termux.TermuxConstants.TERMUX_PROPERTIES_SECONDARY_FILE_PATH; + /** * API that allows receiving user input interactively in a variety of different ways */ @@ -65,10 +68,10 @@ public class DialogActivity extends AppCompatActivity { private boolean resultReturned = false; protected boolean getBlackUI() { - File propsFile = new File("/data/data/com.termux/files/home/.termux/termux.properties"); + File propsFile = new File(TERMUX_PROPERTIES_PRIMARY_FILE_PATH); if (!propsFile.exists()) - propsFile = new File("/data/data/com.termux/files/home/.config/termux.properties"); + propsFile = new File(TERMUX_PROPERTIES_SECONDARY_FILE_PATH); boolean mUseBlackUi = false; diff --git a/app/src/main/java/com/termux/api/NotificationAPI.java b/app/src/main/java/com/termux/api/NotificationAPI.java index d1bc33914..d407cc243 100644 --- a/app/src/main/java/com/termux/api/NotificationAPI.java +++ b/app/src/main/java/com/termux/api/NotificationAPI.java @@ -29,12 +29,14 @@ import java.util.Objects; import java.util.UUID; +import static com.termux.shared.termux.TermuxConstants.TERMUX_PREFIX_DIR_PATH; + public class NotificationAPI { public static final String TERMUX_SERVICE = "com.termux.app.TermuxService"; public static final String ACTION_EXECUTE = "com.termux.service_execute"; public static final String EXTRA_ARGUMENTS = "com.termux.execute.arguments"; - public static final String BIN_SH = "/data/data/com.termux/files/usr/bin/sh"; + public static final String BIN_SH = TERMUX_PREFIX_DIR_PATH+"/bin/sh"; private static final String EXTRA_EXECUTE_IN_BACKGROUND = "com.termux.execute.background"; private static final String CHANNEL_ID = "termux-notification"; private static final String CHANNEL_TITLE = "Termux API notification channel"; diff --git a/app/src/main/java/com/termux/api/TermuxAPIApplication.java b/app/src/main/java/com/termux/api/TermuxAPIApplication.java new file mode 100644 index 000000000..2184070eb --- /dev/null +++ b/app/src/main/java/com/termux/api/TermuxAPIApplication.java @@ -0,0 +1,32 @@ +package com.termux.api; + +import android.app.Application; +import android.content.Context; + +import com.termux.shared.crash.TermuxCrashUtils; +import com.termux.shared.logger.Logger; +import com.termux.shared.settings.preferences.TermuxAPIAppSharedPreferences; + + +public class TermuxAPIApplication extends Application { + + public void onCreate() { + super.onCreate(); + + // Set crash handler for the app + TermuxCrashUtils.setCrashHandler(this); + + // Set log config for the app + setLogLevel(getApplicationContext(), true); + + Logger.logDebug("Starting Application"); + } + + public static void setLogLevel(Context context, boolean commitToFile) { + // Load the log level from shared preferences and set it to the {@link Logger.CURRENT_LOG_LEVEL} + TermuxAPIAppSharedPreferences preferences = TermuxAPIAppSharedPreferences.build(context); + if (preferences == null) return; + preferences.setLogLevel(null, preferences.getLogLevel(true), commitToFile); + } + +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bd13a9b20..3c789642a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,8 +1,16 @@ + + + + + + ]> + - Termux:API + &TERMUX_API_APP_NAME; Share with Grant permission - Termux:API needs the following permission(s):\n + This app needs the following permission(s):\n diff --git a/build.gradle b/build.gradle index 338aa18d5..5675f8e61 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,7 @@ allprojects { repositories { google() mavenCentral() + maven { url "https://jitpack.io" } } } diff --git a/gradle.properties b/gradle.properties index 1a04b66fb..8ec0981b8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,4 +18,8 @@ org.gradle.jvmargs=-Xmx2048M # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true android.enableJetifier=true -android.useAndroidX=true \ No newline at end of file +android.useAndroidX=true + +minSdkVersion=24 +targetSdkVersion=28 +compileSdkVersion=30 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ffed3a254..3cd8500c1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists