diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 373805813..000000000 --- a/.cirrus.yml +++ /dev/null @@ -1,33 +0,0 @@ -container: - image: cirrusci/android-sdk:28 - cpu: 4 - memory: 8G - -task: - name: Build release apk - - environment: - KEYSTORE: ENCRYPTED[67a87d3a7b5682faf7f4f82cd2cc8be407e3959a31bc413d80926f6e037264332c851b2b0f7d1d55b6d8f7aed9d483c4] - KEYSTORE_PASSWORD: ENCRYPTED[d8681b1b9435bfb2a0b7d4fb77edd108e01b48d0b414a9c849836aef828db27aac9be95f39e9738d0f7fce6cbdcd0fd8] - - build_release_apk_script: | - ./gradlew assembleRelease - - build_apksigner_script: | - cd ../ - git clone https://github.com/fornwall/apksigner - cd apksigner - ./gradlew - cp ./build/libs/apksigner-all.jar /tmp/apksigner.jar - - sign_release_apk_script: | - echo "$KEYSTORE" | base64 -d > keystore.jks - java -jar /tmp/apksigner.jar -p "$KEYSTORE_PASSWORD" keystore.jks \ - ./app/build/outputs/apk/release/app-release-unsigned.apk \ - ./termux-api-release-g${CIRRUS_CHANGE_IN_REPO:0:8}.apk - - release_artifacts: - path: "./*.apk" - - unsigned_artifacts: - path: "./app/build/outputs/apk/release/*.apk" diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index e847b7026..305cac117 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,20 +1,36 @@ --- name: Bug report -about: Create a report to help us improve termux-api +about: Create a report to help us improve Termux:API application --- - + **Problem description** -A clear and concise description of what the problem with termux-api is. You may post screenshots or paste error messages in addition to description. + **Steps to reproduce** -Please post all steps that are needed to reproduce the issue. + **Expected behavior** + **Additional information** -Post output of command `termux-info`. -If you are rooted or have access to adb then capture a logcat with `logcat -d "*:W"`, from a adb or root shell. + +* termux-api application version: +* termux-api package version (installed through apt): +* Android OS version: +* Device model: diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 5d78658b4..09339f972 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,12 +1,22 @@ --- name: Feature request -about: Suggest a new feature in termux-api +about: Suggest a new feature for Termux:API application --- + + **Feature description** + + +**Reference implementation** -**Background information** -Have you checked if the feature is accessible through the android API? +Have you checked if the feature is accessible through the Android API? Do you know of other open-source apps that has a similar feature as the one you want? (Provide links) diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..a83ef3851 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: +- package-ecosystem: github-actions + directory: / + schedule: + interval: daily diff --git a/.github/workflows/github_action_build.yml b/.github/workflows/github_action_build.yml new file mode 100644 index 000000000..4fa6ad7b1 --- /dev/null +++ b/.github/workflows/github_action_build.yml @@ -0,0 +1,75 @@ +name: GitHub Action Build + +on: + push: + branches: + - master + pull_request: + branches: + - master + schedule: + - cron: "15 0 1 */2 *" + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v4 + + - name: Build + shell: bash {0} + run: | + exit_on_error() { echo "$1"; exit 1; } + + echo "Setting vars" + + if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then + GITHUB_SHA="${{ github.event.pull_request.head.sha }}" # Do not use last merge commit set in GITHUB_SHA + fi + + # Set RELEASE_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/")" + RELEASE_VERSION_NAME="v$CURRENT_VERSION_NAME+${GITHUB_SHA:0:7}" # The "+" is necessary so that versioning precedence is not affected + 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 + exit_on_error "The release version '${RELEASE_VERSION_NAME/v/}' generated from current version '$CURRENT_VERSION_NAME' 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." + fi + + APK_DIR_PATH="./app/build/outputs/apk/debug" + APK_VERSION_TAG="$RELEASE_VERSION_NAME.github.debug" # Note the ".", GITHUB_SHA will already have "+" before it + APK_BASENAME_PREFIX="termux-api-app_$APK_VERSION_TAG" + + # Used by upload step later + echo "APK_DIR_PATH=$APK_DIR_PATH" >> $GITHUB_ENV + echo "APK_VERSION_TAG=$APK_VERSION_TAG" >> $GITHUB_ENV + echo "APK_BASENAME_PREFIX=$APK_BASENAME_PREFIX" >> $GITHUB_ENV + + echo "Building APK file for '$RELEASE_VERSION_NAME' release with '$APK_VERSION_TAG' tag" + export TERMUX_API_APP__BUILD__APP_VERSION_NAME="${RELEASE_VERSION_NAME/v/}" # Used by app/build.gradle + export TERMUX_API_APP__BUILD__APK_VERSION_TAG="$APK_VERSION_TAG" # Used by app/build.gradle + if ! ./gradlew assembleDebug; then + exit_on_error "Build failed for '$RELEASE_VERSION_NAME' release with '$APK_VERSION_TAG' tag." + fi + + echo "Validating APK file" + if ! test -f "$APK_DIR_PATH/${APK_BASENAME_PREFIX}.apk"; then + files_found="$(ls "$APK_DIR_PATH")" + exit_on_error "Failed to find built APK file at '$APK_DIR_PATH/${APK_BASENAME_PREFIX}.apk'. Files found: "$'\n'"$files_found" + fi + + echo "Generating checksums-sha256.txt file" + if ! (cd "$APK_DIR_PATH"; sha256sum "${APK_BASENAME_PREFIX}.apk" > checksums-sha256.txt); then + exit_on_error "Generate checksums-sha256.txt file failed for '$RELEASE_VERSION_NAME' release." + fi + echo "checksums-sha256.txt:"$'\n```\n'"$(cat "$APK_DIR_PATH/checksums-sha256.txt")"$'\n```' + + - name: Upload files to action + uses: actions/upload-artifact@v4 + with: + name: ${{ env.APK_BASENAME_PREFIX }} + path: | + ${{ env.APK_DIR_PATH }}/${{ env.APK_BASENAME_PREFIX }}.apk + ${{ env.APK_DIR_PATH }}/checksums-sha256.txt + ${{ env.APK_DIR_PATH }}/output-metadata.json diff --git a/.github/workflows/github_release_build.yml b/.github/workflows/github_release_build.yml new file mode 100644 index 000000000..b438db9ec --- /dev/null +++ b/.github/workflows/github_release_build.yml @@ -0,0 +1,64 @@ +name: GitHub Release Build + +on: + release: + types: + - published + +jobs: + build: + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Clone repository + uses: actions/checkout@v4 + with: + ref: ${{ env.GITHUB_REF }} + + - name: Build and upload files to release + shell: bash {0} + run: | + exit_on_error() { + echo "$1" + echo "Deleting '$RELEASE_VERSION_NAME' release and '$GITHUB_REF' tag" + hub release delete "$RELEASE_VERSION_NAME" + git push --delete origin "$GITHUB_REF" + exit 1 + } + + echo "Setting vars" + 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 + exit_on_error "The release version '${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." + fi + + APK_DIR_PATH="./app/build/outputs/apk/debug" + APK_VERSION_TAG="$RELEASE_VERSION_NAME+github.debug" + APK_BASENAME_PREFIX="termux-api-app_$APK_VERSION_TAG" + + echo "Building APK file for '$RELEASE_VERSION_NAME' release with '$APK_VERSION_TAG' tag" + export TERMUX_API_APP__BUILD__APK_VERSION_TAG="$APK_VERSION_TAG" # Used by app/build.gradle + if ! ./gradlew assembleDebug; then + exit_on_error "Build failed for '$RELEASE_VERSION_NAME' release with '$APK_VERSION_TAG' tag." + fi + + echo "Validating APK file" + if ! test -f "$APK_DIR_PATH/${APK_BASENAME_PREFIX}.apk"; then + files_found="$(ls "$APK_DIR_PATH")" + exit_on_error "Failed to find built APK file at '$APK_DIR_PATH/${APK_BASENAME_PREFIX}.apk'. Files found: "$'\n'"$files_found" + fi + + echo "Generating checksums-sha256.txt file" + if ! (cd "$APK_DIR_PATH"; sha256sum "${APK_BASENAME_PREFIX}.apk" > checksums-sha256.txt); then + exit_on_error "Generate checksums-sha256.txt file failed for '$RELEASE_VERSION_NAME' release." + fi + echo "checksums-sha256.txt:"$'\n```\n'"$(cat "$APK_DIR_PATH/checksums-sha256.txt")"$'\n```' + + echo "Uploading files to release" + if ! gh release upload "$RELEASE_VERSION_NAME" \ + "$APK_DIR_PATH/${APK_BASENAME_PREFIX}.apk" \ + "$APK_DIR_PATH/checksums-sha256.txt" \ + ; then + exit_on_error "Upload files to release failed for '$RELEASE_VERSION_NAME' release." + fi diff --git a/.gitignore b/.gitignore index 6c8b41f86..002f6725b 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 @@ -27,3 +31,6 @@ local.properties .Trashes ehthumbs.db Thumbs.db + +# Temp/backup files +*~ diff --git a/README.md b/README.md index 5266ce2a3..a1cdc5207 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,29 @@ # Termux API -[![Build status](https://api.cirrus-ci.com/github/termux/termux-api.svg?branch=master)](https://cirrus-ci.com/termux/termux-api) +[![Build status](https://github.com/termux/termux-api/workflows/Build/badge.svg)](https://github.com/termux/termux-api/actions) [![Join the chat at https://gitter.im/termux/termux](https://badges.gitter.im/termux/termux.svg)](https://gitter.im/termux/termux) This is an app exposing Android API to command line usage and scripts or programs. -- [Termux:API on Google Play](https://play.google.com/store/apps/details?id=com.termux.api) - When developing or packaging, note that this app needs to be signed with the same key as the main Termux app for permissions to work (only the main Termux app are allowed to call the API methods in this app). +## Installation + +Latest version is `v0.53.0`. + +Termux:API application can be obtained from [F-Droid](https://f-droid.org/en/packages/com.termux.api/). + +Additionally we provide per-commit debug builds for those who want to try +out the latest features or test their pull request. This build can be obtained +from one of the workflow runs listed on [Github Actions](https://github.com/termux/termux-api/actions/workflows/github_action_build.yml?query=branch%3Amaster+event%3Apush) +page. + +Signature keys of all offered builds are different. Before you switch the +installation source, you will have to uninstall the Termux application and +all currently installed plugins. Check https://github.com/termux/termux-app#Installation for more info. + ## License Released under the [GPLv3 license](http://www.gnu.org/licenses/gpl-3.0.en.html). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..479f15cb8 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1 @@ +Check https://termux.dev/security for info on Termux security policies and how to report vulnerabilities. diff --git a/app/build.gradle b/app/build.gradle index 3502274e1..b64dd4746 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,36 +1,97 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 28 + namespace "com.termux.api" + + compileSdk project.properties.compileSdkVersion.toInteger() + def appVersionName = System.getenv("TERMUX_API_APP__BUILD__APP_VERSION_NAME") ?: "" + def apkVersionTag = System.getenv("TERMUX_API_APP__BUILD__APK_VERSION_TAG") ?: "" defaultConfig { applicationId "com.termux.api" - minSdkVersion 21 - targetSdkVersion 28 - versionCode 38 - versionName "0.38" + minSdk project.properties.minSdkVersion.toInteger() + targetSdk project.properties.targetSdkVersion.toInteger() + versionCode 1002 + versionName "0.53.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 { + debug { + storeFile file('testkey_untrusted.jks') + keyAlias 'alias' + storePassword 'xrj45yWGLbsO7W0v' + keyPassword 'xrj45yWGLbsO7W0v' + } } buildTypes { release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + minifyEnabled true + shrinkResources false // Reproducible builds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + + debug { + signingConfig signingConfigs.debug } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + // Flag to enable support for the new language APIs + coreLibraryDesugaringEnabled true + + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + applicationVariants.all { variant -> + variant.outputs.all { output -> + outputFileName = new File("termux-api-app_" + + (apkVersionTag ? apkVersionTag : "v" + versionName + "+" + variant.buildType.name) + ".apk") + } + } + + packagingOptions { + // Remove terminal-emulator and termux-shared JNI libs added via termux-shared dependency + exclude "lib/*/libtermux.so" + exclude "lib/*/liblocal-socket.so" } } dependencies { - implementation 'com.google.android.material:material:1.0.0' - implementation 'androidx.biometric:biometric:1.0.0-alpha04' + coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5" + + implementation "com.google.android.material:material:1.12.0" + implementation "androidx.biometric:biometric:1.2.0-alpha05" + implementation "androidx.media:media:1.7.0" + implementation "androidx.preference:preference:1.2.1" + + implementation "com.termux.termux-app:termux-shared:8aca6dbbf4" + // Use if below libraries are published locally by termux-app with `./gradlew publishReleasePublicationToMavenLocal` and used with `mavenLocal()`. + // If updates are done, republish there and sync project with gradle files here + // https://github.com/termux/termux-app/wiki/Termux-Libraries + //implementation "com.termux:termux-shared:0.118.0" + + implementation "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava" } task versionName { - doLast { - print android.defaultConfig.versionName - } + doLast { + print android.defaultConfig.versionName + } +} + +@SuppressWarnings("UnnecessaryQualifiedReference") +static 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 3562da708..f9d371212 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,28 +1,49 @@ + android:sharedUserId="${TERMUX_PACKAGE_NAME}"> - - - - - - + + - - - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -33,48 +54,141 @@ + - - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + android:exported="true" /> + + + + + + + + + + + + + + + + + + @@ -83,9 +197,22 @@ - + + + + + + + + + + + diff --git a/app/src/main/java/com/termux/api/AudioAPI.java b/app/src/main/java/com/termux/api/AudioAPI.java deleted file mode 100644 index ebb4c2dee..000000000 --- a/app/src/main/java/com/termux/api/AudioAPI.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.termux.api; - -import android.content.Context; -import android.content.Intent; -import android.media.AudioAttributes; -import android.media.AudioManager; -import android.media.AudioTrack; -import android.os.Build; -import android.util.JsonWriter; - -import com.termux.api.util.ResultReturner; - -public class AudioAPI { - - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { - AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - final String SampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - final String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER); - final boolean bluetootha2dp = am.isBluetoothA2dpOn(); - final boolean wiredhs = am.isWiredHeadsetOn(); - - final int sr, bs, sr_ll, bs_ll, sr_ps, bs_ps, nosr; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - nosr = 0; - AudioTrack at; - at = new AudioTrack.Builder() - .setBufferSizeInBytes(4) // one 16bit 2ch frame - .build(); - sr = at.getSampleRate(); - bs = at.getBufferSizeInFrames(); - at.release(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - at = new AudioTrack.Builder() - .setBufferSizeInBytes(4) // one 16bit 2ch frame - .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY) - .build(); - } else { - AudioAttributes aa = new AudioAttributes.Builder() - .setFlags(AudioAttributes.FLAG_LOW_LATENCY) - .build(); - at = new AudioTrack.Builder() - .setAudioAttributes(aa) - .setBufferSizeInBytes(4) // one 16bit 2ch frame - .build(); - } - sr_ll = at.getSampleRate(); - bs_ll = at.getBufferSizeInFrames(); - at.release(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - at = new AudioTrack.Builder() - .setBufferSizeInBytes(4) // one 16bit 2ch frame - .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_POWER_SAVING) - .build(); - sr_ps = at.getSampleRate(); - bs_ps = at.getBufferSizeInFrames(); - at.release(); - } else { - sr_ps = sr; - bs_ps = bs; - } - } else { - sr = bs = sr_ll = bs_ll = sr_ps = bs_ps = 0; - nosr = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); - } - - ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { - public void writeJson(JsonWriter out) throws Exception { - out.beginObject(); - out.name("PROPERTY_OUTPUT_SAMPLE_RATE").value(SampleRate); - out.name("PROPERTY_OUTPUT_FRAMES_PER_BUFFER").value(framesPerBuffer); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - out.name("AUDIOTRACK_SAMPLE_RATE").value(sr); - out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES").value(bs); - if (sr_ll != sr || bs_ll != bs) { // all or nothing - out.name("AUDIOTRACK_SAMPLE_RATE_LOW_LATENCY").value(sr_ll); - out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES_LOW_LATENCY").value(bs_ll); - } - if (sr_ps != sr || bs_ps != bs) { // all or nothing - out.name("AUDIOTRACK_SAMPLE_RATE_POWER_SAVING").value(sr_ps); - out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES_POWER_SAVING").value(bs_ps); - } - } else { - out.name("AUDIOTRACK_NATIVE_OUTPUT_SAMPLE_RATE").value(nosr); - } - out.name("BLUETOOTH_A2DP_IS_ON").value(bluetootha2dp); - out.name("WIREDHEADSET_IS_CONNECTED").value(wiredhs); - out.endObject(); - } - }); - } - -} diff --git a/app/src/main/java/com/termux/api/BatteryStatusAPI.java b/app/src/main/java/com/termux/api/BatteryStatusAPI.java deleted file mode 100644 index d51143f6a..000000000 --- a/app/src/main/java/com/termux/api/BatteryStatusAPI.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.termux.api; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.BatteryManager; -import android.util.JsonWriter; - -import com.termux.api.util.ResultReturner; -import com.termux.api.util.ResultReturner.ResultJsonWriter; -import com.termux.api.util.TermuxApiLogger; - -public class BatteryStatusAPI { - - public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { - ResultReturner.returnData(apiReceiver, intent, new ResultJsonWriter() { - @Override - public void writeJson(JsonWriter out) throws Exception { - Intent batteryStatus = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - - int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); - int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); - final int batteryPercentage = (level * 100) / scale; - - int health = batteryStatus.getIntExtra(BatteryManager.EXTRA_HEALTH, -1); - String batteryHealth; - switch (health) { - case BatteryManager.BATTERY_HEALTH_COLD: - batteryHealth = "COLD"; - break; - case BatteryManager.BATTERY_HEALTH_DEAD: - batteryHealth = "DEAD"; - break; - case BatteryManager.BATTERY_HEALTH_GOOD: - batteryHealth = "GOOD"; - break; - case BatteryManager.BATTERY_HEALTH_OVERHEAT: - batteryHealth = "OVERHEAT"; - break; - case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE: - batteryHealth = "OVER_VOLTAGE"; - break; - case BatteryManager.BATTERY_HEALTH_UNKNOWN: - batteryHealth = "UNKNOWN"; - break; - case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE: - batteryHealth = "UNSPECIFIED_FAILURE"; - break; - default: - batteryHealth = Integer.toString(health); - } - - // BatteryManager.EXTRA_PLUGGED: "Extra for ACTION_BATTERY_CHANGED: integer indicating whether the - // device is plugged in to a power source; 0 means it is on battery, other constants are different types - // of power sources." - int pluggedInt = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); - String batteryPlugged; - switch (pluggedInt) { - case 0: - batteryPlugged = "UNPLUGGED"; - break; - case BatteryManager.BATTERY_PLUGGED_AC: - batteryPlugged = "PLUGGED_AC"; - break; - case BatteryManager.BATTERY_PLUGGED_USB: - batteryPlugged = "PLUGGED_USB"; - break; - case BatteryManager.BATTERY_PLUGGED_WIRELESS: - batteryPlugged = "PLUGGED_WIRELESS"; - break; - default: - batteryPlugged = "PLUGGED_" + pluggedInt; - } - - double batteryTemperature = batteryStatus.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1) / 10.f; - - String batteryStatusString; - int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); - switch (status) { - case BatteryManager.BATTERY_STATUS_CHARGING: - batteryStatusString = "CHARGING"; - break; - case BatteryManager.BATTERY_STATUS_DISCHARGING: - batteryStatusString = "DISCHARGING"; - break; - case BatteryManager.BATTERY_STATUS_FULL: - batteryStatusString = "FULL"; - break; - case BatteryManager.BATTERY_STATUS_NOT_CHARGING: - batteryStatusString = "NOT_CHARGING"; - break; - case BatteryManager.BATTERY_STATUS_UNKNOWN: - batteryStatusString = "UNKNOWN"; - break; - default: - TermuxApiLogger.error("Invalid BatteryManager.EXTRA_STATUS value: " + status); - batteryStatusString = "UNKNOWN"; - } - - BatteryManager batteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE); - - out.beginObject(); - out.name("health").value(batteryHealth); - out.name("percentage").value(batteryPercentage); - out.name("plugged").value(batteryPlugged); - out.name("status").value(batteryStatusString); - out.name("temperature").value(batteryTemperature); - out.name("current").value(batteryManager.getLongProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW)); - out.endObject(); - } - }); - - } -} diff --git a/app/src/main/java/com/termux/api/CallLogAPI.java b/app/src/main/java/com/termux/api/CallLogAPI.java deleted file mode 100644 index dacb2e0cd..000000000 --- a/app/src/main/java/com/termux/api/CallLogAPI.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.termux.api; - -import android.content.Context; -import android.content.Intent; -import android.util.JsonWriter; - -import com.termux.api.util.ResultReturner; - -/** - * API that allows you to get call log history information - */ -public class CallLogAPI { - - static void onReceive(final Context context, final Intent intent) { - ResultReturner.returnData(context, intent, new ResultReturner.ResultJsonWriter() { - public void writeJson(JsonWriter out) throws Exception { - out.beginObject(); - out.name("error").value("Call log is no longer permitted by Google"); - out.endObject(); - } - }); - - } - -} diff --git a/app/src/main/java/com/termux/api/DialogActivity.java b/app/src/main/java/com/termux/api/DialogActivity.java deleted file mode 100644 index 2cabc1562..000000000 --- a/app/src/main/java/com/termux/api/DialogActivity.java +++ /dev/null @@ -1,1018 +0,0 @@ -package com.termux.api; - -import android.Manifest; -import android.app.Activity; -import android.app.ActivityManager; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.ResolveInfo; -import android.os.Build; -import android.os.Bundle; -import android.speech.RecognitionListener; -import android.speech.RecognizerIntent; -import android.speech.SpeechRecognizer; -import androidx.annotation.NonNull; -import com.google.android.material.bottomsheet.BottomSheetDialog; -import com.google.android.material.bottomsheet.BottomSheetDialogFragment; -import androidx.core.widget.NestedScrollView; -import androidx.appcompat.app.AppCompatActivity; -import android.text.InputType; -import android.util.JsonWriter; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.inputmethod.InputMethodManager; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.DatePicker; -import android.widget.EditText; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.RadioButton; -import android.widget.RadioGroup; -import android.widget.ScrollView; -import android.widget.Spinner; -import android.widget.TextView; -import android.widget.TimePicker; -import android.widget.Toast; - -import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiPermissionActivity; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; -import java.util.Locale; -import java.util.Objects; - -/** - * API that allows receiving user input interactively in a variety of different ways - */ -public class DialogActivity extends AppCompatActivity { - - private boolean resultReturned = false; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final Intent intent = getIntent(); - final Context context = this; - - - String methodType = intent.hasExtra("input_method") ? intent.getStringExtra("input_method") : ""; - - InputMethod method = InputMethodFactory.get(methodType, this); - method.create(this, result -> { - postResult(context, result); - finish(); - }); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - setIntent(intent); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - - if (!resultReturned) { - postResult(this, null); - } - } - - /** - * Extract value extras from intent into String array - */ - static String[] getInputValues(Intent intent) { - String[] items = new String[] { }; - - if (intent != null && intent.hasExtra("input_values")) { - String[] temp = intent.getStringExtra("input_values").split(","); - items = new String[temp.length]; - - // remove possible whitespace from strings in temp array - for (int j = 0; j < temp.length; ++j) { - String s = temp[j]; - items[j] = s.trim(); - } - } - return items; - } - - /** - * Writes the InputResult to the console - */ - protected void postResult(final Context context, final InputResult result) { - ResultReturner.returnData(context, getIntent(), new ResultReturner.ResultJsonWriter() { - - @Override - public void writeJson(JsonWriter out) throws Exception { - out.beginObject(); - - out.name("code").value(result.code); - out.name("text").value(result.text); - if(result.index > -1) { - out.name("index").value(result.index); - } - if (result.values.size() > 0) { - out.name("values"); - out.beginArray(); - for (Value value : result.values) { - out.beginObject(); - out.name("index").value(value.index); - out.name("text").value(value.text); - out.endObject(); - } - out.endArray(); - } - if (!result.error.equals("")) { - out.name("error").value(result.error); - } - - out.endObject(); - out.flush(); - resultReturned = true; - } - }); - } - - - /** - * Factory for returning proper input method type that we received in our incoming intent - */ - static class InputMethodFactory { - - public static InputMethod get(final String type, final AppCompatActivity activity) { - - switch (type == null ? "" : type) { - case "confirm": - return new ConfirmInputMethod(activity); - case "checkbox": - return new CheckBoxInputMethod(activity); - case "counter": - return new CounterInputMethod(activity); - case "date": - return new DateInputMethod(activity); - case "radio": - return new RadioInputMethod(activity); - case "sheet": - return new BottomSheetInputMethod(); - case "speech": - return new SpeechInputMethod(activity); - case "spinner": - return new SpinnerInputMethod(activity); - case "text": - return new TextInputMethod(activity); - case "time": - return new TimeInputMethod(activity); - default: - return (activity1, resultListener) -> { - InputResult result = new InputResult(); - result.error = "Unknown Input Method: " + type; - resultListener.onResult(result); - }; - } - } - } - - - /** - * Interface for creating an input method type - */ - interface InputMethod { - void create(AppCompatActivity activity, InputResultListener resultListener); - } - - - /** - * Callback interface for receiving an InputResult - */ - interface InputResultListener { - void onResult(InputResult result); - } - - - /** - * Simple POJO to store the result of input methods - */ - static class InputResult { - public String text = ""; - public String error = ""; - public int code = 0; - public static int index = -1; - public List values = new ArrayList<>(); - } - - - public static class Value { - public int index = -1; - public String text = ""; - } - - /* - * -------------------------------------- - * InputMethod Implementations - * -------------------------------------- - */ - - - /** - * CheckBox InputMethod - * Allow users to select multiple options from a range of values - */ - static class CheckBoxInputMethod extends InputDialog { - - CheckBoxInputMethod(AppCompatActivity activity) { - super(activity); - } - - @Override - LinearLayout createWidgetView(AppCompatActivity activity) { - LinearLayout layout = new LinearLayout(activity); - layout.setOrientation(LinearLayout.VERTICAL); - - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - layoutParams.topMargin = 32; - layoutParams.bottomMargin = 32; - - String[] values = getInputValues(activity.getIntent()); - - for (int j = 0; j < values.length; ++j) { - String value = values[j]; - - CheckBox checkBox = new CheckBox(activity); - checkBox.setText(value); - checkBox.setId(j); - checkBox.setTextSize(18); - checkBox.setPadding(16, 16, 16, 16); - checkBox.setLayoutParams(layoutParams); - - layout.addView(checkBox); - } - return layout; - } - - @Override - String getResult() { - int checkBoxCount = widgetView.getChildCount(); - - List values = new ArrayList<>(); - StringBuilder sb = new StringBuilder(); - sb.append("["); - - for (int j = 0; j < checkBoxCount; ++j) { - CheckBox box = widgetView.findViewById(j); - if (box.isChecked()) { - Value value = new Value(); - value.index = j; - value.text = box.getText().toString(); - values.add(value); - sb.append(box.getText().toString()).append(", "); - } - } - inputResult.values = values; - // remove trailing comma and add closing bracket - return sb.toString().replaceAll(", $", "") + "]"; - } - } - - - /** - * Confirm InputMethod - * Allow users to confirm YES or NO. - */ - static class ConfirmInputMethod extends InputDialog { - - ConfirmInputMethod(AppCompatActivity activity) { - super(activity); - } - - @Override - InputResult onDialogClick(int button) { - inputResult.text = button == Dialog.BUTTON_POSITIVE ? "yes" : "no"; - return inputResult; - } - - @Override - TextView createWidgetView(AppCompatActivity activity) { - TextView textView = new TextView(activity); - final Intent intent = activity.getIntent(); - - String text = intent.hasExtra("input_hint") ? intent.getStringExtra("input_hint") : "Confirm"; - textView.setText(text); - return textView; - } - - @Override - String getNegativeButtonText() { - return "No"; - } - - @Override - String getPositiveButtonText() { - return "Yes"; - } - } - - - /** - * Counter InputMethod - * Allow users to increment or decrement a number in a given range - */ - static class CounterInputMethod extends InputDialog { - static final int DEFAULT_MIN = 0; - static final int DEFAULT_MAX = 100; - static final int RANGE_LENGTH = 3; - - int min; - int max; - int counter; - - TextView counterLabel; - - CounterInputMethod(AppCompatActivity activity) { - super(activity); - } - - @Override - View createWidgetView(AppCompatActivity activity) { - View layout = View.inflate(activity, R.layout.dialog_counter, null); - counterLabel = layout.findViewById(R.id.counterTextView); - - final Button incrementButton = layout.findViewById(R.id.incrementButton); - incrementButton.setOnClickListener(view -> increment()); - - final Button decrementButton = layout.findViewById(R.id.decrementButton); - decrementButton.setOnClickListener(view -> decrement()); - updateCounterRange(); - - return layout; - } - - void updateCounterRange() { - final Intent intent = activity.getIntent(); - - if (intent.hasExtra("input_range")) { - int[] values = intent.getIntArrayExtra("input_range"); - if (values.length != RANGE_LENGTH) { - inputResult.error = "Invalid range! Must be 3 int values!"; - postCanceledResult(); - dialog.dismiss(); - } else { - min = Math.min(values[0], values[1]); - max = Math.max(values[0], values[1]); - counter = values[2]; - } - } else { - min = DEFAULT_MIN; - max = DEFAULT_MAX; - - // halfway - counter = (DEFAULT_MAX - DEFAULT_MIN) / 2; - } - updateLabel(); - } - - @Override - String getResult() { - return counterLabel.getText().toString(); - } - - void updateLabel() { - counterLabel.setText(String.valueOf(counter)); - } - - void increment() { - if ((counter + 1) <= max) { - ++counter; - updateLabel(); - } - } - - void decrement() { - if ((counter - 1) >= min) { - --counter; - updateLabel(); - } - } - } - - - /** - * Date InputMethod - * Allow users to pick a specific date - */ - static class DateInputMethod extends InputDialog { - - DateInputMethod(AppCompatActivity activity) { - super(activity); - } - - @Override - String getResult() { - int month = widgetView.getMonth(); - int day = widgetView.getDayOfMonth(); - int year = widgetView.getYear(); - - Calendar calendar = Calendar.getInstance(); - calendar.set(year, month, day, 0, 0, 0); - - final Intent intent = activity.getIntent(); - if (intent.hasExtra("date_format")) { - String date_format = intent.getStringExtra("date_format"); - try { - SimpleDateFormat dateFormat = new SimpleDateFormat(date_format); - dateFormat.setTimeZone(calendar.getTimeZone()); - return dateFormat.format(calendar.getTime()); - } catch (Exception e) { - inputResult.error = e.toString(); - postCanceledResult(); - } - } - return calendar.getTime().toString(); - } - - @Override - DatePicker createWidgetView(AppCompatActivity activity) { - return new DatePicker(activity); - } - } - - - /** - * Text InputMethod - * Allow users to enter plaintext or a password - */ - static class TextInputMethod extends InputDialog { - - TextInputMethod(AppCompatActivity activity) { - super(activity); - } - - @Override - String getResult() { - return widgetView.getText().toString(); - } - - @Override - EditText createWidgetView(AppCompatActivity activity) { - final Intent intent = activity.getIntent(); - EditText editText = new EditText(activity); - - if (intent.hasExtra("input_hint")) { - editText.setHint(intent.getStringExtra("input_hint")); - } - - boolean multiLine = intent.getBooleanExtra("multiple_lines", false); - boolean numeric = intent.getBooleanExtra("numeric", false); - boolean password = intent.getBooleanExtra("password", false); - - int flags = InputType.TYPE_CLASS_TEXT; - - if (password) { - flags = numeric ? (flags | InputType.TYPE_NUMBER_VARIATION_PASSWORD) : (flags | InputType.TYPE_TEXT_VARIATION_PASSWORD); - } - - if (multiLine) { - flags |= InputType.TYPE_TEXT_FLAG_MULTI_LINE; - editText.setLines(4); - } - - if (numeric) { - flags &= ~InputType.TYPE_CLASS_TEXT; // clear to allow only numbers - flags |= InputType.TYPE_CLASS_NUMBER; - } - - editText.setInputType(flags); - - return editText; - } - } - - - /** - * Time InputMethod - * Allow users to pick a specific time - */ - static class TimeInputMethod extends InputDialog { - - TimeInputMethod(AppCompatActivity activity) { - super(activity); - } - - @Override - String getResult() { - String result; - - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { - result = String.format(Locale.getDefault(), "%02d:%02d", widgetView.getHour(), widgetView.getMinute()); - } else { - result = String.format(Locale.getDefault(), "%02d:%02d", widgetView.getCurrentHour(), widgetView.getCurrentMinute()); - } - return result; - } - - @Override - TimePicker createWidgetView(AppCompatActivity activity) { - return new TimePicker(activity); - } - } - - - /** - * Radio InputMethod - * Allow users to confirm from radio button options - */ - static class RadioInputMethod extends InputDialog { - RadioGroup radioGroup; - - RadioInputMethod(AppCompatActivity activity) { - super(activity); - } - - @Override - RadioGroup createWidgetView(AppCompatActivity activity) { - radioGroup = new RadioGroup(activity); - radioGroup.setPadding(16, 16, 16, 16); - - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - layoutParams.topMargin = 32; - layoutParams.bottomMargin = 32; - - String[] values = getInputValues(activity.getIntent()); - - for (int j = 0; j < values.length; ++j) { - String value = values[j]; - - RadioButton button = new RadioButton(activity); - button.setText(value); - button.setId(j); - button.setTextSize(18); - button.setPadding(16, 16, 16, 16); - button.setLayoutParams(layoutParams); - - radioGroup.addView(button); - } - return radioGroup; - } - - @Override - String getResult() { - int radioIndex = radioGroup.indexOfChild(widgetView.findViewById(radioGroup.getCheckedRadioButtonId())); - RadioButton radioButton = (RadioButton) radioGroup.getChildAt(radioIndex); - InputResult.index = radioIndex; - return (radioButton != null) ? radioButton.getText().toString() : ""; - } - } - - - /** - * BottomSheet InputMethod - * Allow users to select from a variety of options in a bottom sheet dialog - */ - public static class BottomSheetInputMethod extends BottomSheetDialogFragment implements InputMethod { - private InputResultListener resultListener; - - - @Override - public void create(AppCompatActivity activity, InputResultListener resultListener) { - this.resultListener = resultListener; - show(activity.getSupportFragmentManager(), "BOTTOM_SHEET"); - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - // create custom BottomSheetDialog that has friendlier dismissal behavior - return new BottomSheetDialog(getActivity(), getTheme()) { - @Override - public void onBackPressed() { - super.onBackPressed(); - // make it so that user only has to hit back key one time to get rid of bottom sheet - getActivity().onBackPressed(); - postCanceledResult(); - } - - @Override - public void cancel() { - super.cancel(); - - if (isCurrentAppTermux()) { - showKeyboard(); - } - // dismiss on single touch outside of dialog - getActivity().onBackPressed(); - postCanceledResult(); - } - }; - } - - @Override - public void setupDialog(final Dialog dialog, int style) { - LinearLayout layout = new LinearLayout(getContext()); - layout.setMinimumHeight(100); - layout.setPadding(16, 16, 16, 16); - layout.setOrientation(LinearLayout.VERTICAL); - - NestedScrollView scrollView = new NestedScrollView(getContext()); - final String[] values = getInputValues(Objects.requireNonNull(getActivity()).getIntent()); - - for (int i = 0; i < values.length; ++i) { - final int j = i; - final TextView textView = new TextView(getContext()); - textView.setText(values[j]); - textView.setTextSize(20); - textView.setPadding(56, 56, 56, 56); - textView.setOnClickListener(view -> { - InputResult result = new InputResult(); - result.text = values[j]; - result.index = j; - dialog.dismiss(); - resultListener.onResult(result); - }); - - layout.addView(textView); - } - scrollView.addView(layout); - dialog.setContentView(scrollView); - hideKeyboard(); - } - - /** - * These keyboard methods exist to work around inconsistent show / hide behavior - * from canceling BottomSheetDialog and produces the desired result of hiding keyboard - * on creation of dialog and showing it after a selection or cancellation, as long as - * we are still within the Termux application - */ - - protected void hideKeyboard() { - getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); - } - - protected void showKeyboard() { - getInputMethodManager().showSoftInput(getView(), InputMethodManager.SHOW_FORCED); - } - - protected InputMethodManager getInputMethodManager() { - return (InputMethodManager) Objects.requireNonNull(getContext()).getSystemService(Context.INPUT_METHOD_SERVICE); - } - - /** - * Checks to see if foreground application is Termux - */ - protected boolean isCurrentAppTermux() { - final ActivityManager activityManager = (ActivityManager) Objects.requireNonNull(getContext()).getSystemService(Context.ACTIVITY_SERVICE); - final List runningProcesses = Objects.requireNonNull(activityManager).getRunningAppProcesses(); - for (final ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) { - if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { - for (final String activeProcess : processInfo.pkgList) { - if (activeProcess.equals("com.termux")) { - return true; - } - } - } - } - return false; - } - - protected void postCanceledResult() { - InputResult result = new InputResult(); - result.code = Dialog.BUTTON_NEGATIVE; - resultListener.onResult(result); - } - } - - - /** - * Spinner InputMethod - * Allow users to make a selection based on a list of specified values - */ - static class SpinnerInputMethod extends InputDialog { - - SpinnerInputMethod(AppCompatActivity activity) { - super(activity); - } - - @Override - String getResult() { - InputResult.index = widgetView.getSelectedItemPosition(); - return widgetView.getSelectedItem().toString(); - } - - @Override - Spinner createWidgetView(AppCompatActivity activity) { - Spinner spinner = new Spinner(activity); - - final Intent intent = activity.getIntent(); - final String[] items = getInputValues(intent); - final ArrayAdapter adapter = new ArrayAdapter<>(activity, R.layout.spinner_item, items); - - spinner.setAdapter(adapter); - return spinner; - } - } - - - /** - * Speech InputMethod - * Allow users to use the built in microphone to get text from speech - */ - static class SpeechInputMethod extends InputDialog { - - SpeechInputMethod(AppCompatActivity activity) { - super(activity); - } - - @Override - TextView createWidgetView(AppCompatActivity activity) { - TextView textView = new TextView(activity); - final Intent intent = activity.getIntent(); - - String text = intent.hasExtra("input_hint") ? intent.getStringExtra("input_hint") : "Listening for speech..."; - - textView.setText(text); - textView.setTextSize(20); - return textView; - } - - @Override - public void create(final AppCompatActivity activity, final InputResultListener resultListener) { - // Since we're using the microphone, we need to make sure we have proper permission - if (!TermuxApiPermissionActivity.checkAndRequestPermissions(activity, activity.getIntent(), Manifest.permission.RECORD_AUDIO)) { - activity.finish(); - } - - if (!hasSpeechRecognizer(activity)) { - Toast.makeText(activity, "No voice recognition found!", Toast.LENGTH_SHORT).show(); - activity.finish(); - } - - - Intent speechIntent = createSpeechIntent(); - final SpeechRecognizer recognizer = createSpeechRecognizer(activity, resultListener); - - // create intermediate InputResultListener so that we can stop our speech listening - // if user hits the cancel button - DialogInterface.OnClickListener clickListener = getClickListener(result -> { - recognizer.stopListening(); - resultListener.onResult(result); - }); - - Dialog dialog = getDialogBuilder(activity, clickListener) - .setPositiveButton(null, null) - .setOnDismissListener(null) - .create(); - - dialog.setCanceledOnTouchOutside(false); - dialog.show(); - - recognizer.startListening(speechIntent); - } - - private boolean hasSpeechRecognizer(Context context) { - List installList = context.getPackageManager().queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0); - return !installList.isEmpty(); - } - - private Intent createSpeechIntent() { - Intent speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); - speechIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); - speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); - return speechIntent; - } - - private SpeechRecognizer createSpeechRecognizer(AppCompatActivity activity, final InputResultListener listener) { - SpeechRecognizer recognizer = SpeechRecognizer.createSpeechRecognizer(activity); - recognizer.setRecognitionListener(new RecognitionListener() { - - @Override - public void onResults(Bundle results) { - List voiceResults = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); - - if (voiceResults != null && voiceResults.size() > 0) { - inputResult.text = voiceResults.get(0); - } - listener.onResult(inputResult); - } - - /** - * Get string description for error code - */ - @Override - public void onError(int error) { - String errorDescription; - - switch (error) { - case SpeechRecognizer.ERROR_AUDIO: - errorDescription = "ERROR_AUDIO"; - break; - case SpeechRecognizer.ERROR_CLIENT: - errorDescription = "ERROR_CLIENT"; - break; - case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: - errorDescription = "ERROR_INSUFFICIENT_PERMISSIONS"; - break; - case SpeechRecognizer.ERROR_NETWORK: - errorDescription = "ERROR_NETWORK"; - break; - case SpeechRecognizer.ERROR_NETWORK_TIMEOUT: - errorDescription = "ERROR_NETWORK_TIMEOUT"; - break; - case SpeechRecognizer.ERROR_SPEECH_TIMEOUT: - errorDescription = "ERROR_SPEECH_TIMEOUT"; - break; - default: - errorDescription = "ERROR_UNKNOWN"; - break; - } - inputResult.error = errorDescription; - listener.onResult(inputResult); - } - - - // unused - @Override - public void onEndOfSpeech() { } - - @Override - public void onReadyForSpeech(Bundle bundle) { } - - @Override - public void onBeginningOfSpeech() { } - - @Override - public void onRmsChanged(float v) { } - - @Override - public void onBufferReceived(byte[] bytes) { } - - @Override - public void onPartialResults(Bundle bundle) { } - - @Override - public void onEvent(int i, Bundle bundle) { } - }); - return recognizer; - } - } - - - /** - * Base Dialog class to extend from for adding specific views / widgets to a Dialog interface - * @param Main view type that will be displayed within dialog - */ - abstract static class InputDialog implements InputMethod { - // result that belongs to us - InputResult inputResult = new InputResult(); - - // listener for our input result - InputResultListener resultListener; - - // view that will be placed in our dialog - T widgetView; - - // dialog that holds everything - Dialog dialog; - - // our activity context - AppCompatActivity activity; - - - // method to be implemented that handles creating view that is placed in our dialog - abstract T createWidgetView(AppCompatActivity activity); - - // method that should be implemented that handles returning a result obtained through user input - String getResult() { - return null; - } - - - InputDialog(AppCompatActivity activity) { - this.activity = activity; - widgetView = createWidgetView(activity); - initActivityDisplay(activity); - } - - - @Override - public void create(AppCompatActivity activity, final InputResultListener resultListener) { - this.resultListener = resultListener; - - // Handle OK and Cancel button clicks - DialogInterface.OnClickListener clickListener = getClickListener(resultListener); - - // Dialog interface that will display to user - dialog = getDialogBuilder(activity, clickListener).create(); - dialog.show(); - } - - void postCanceledResult() { - inputResult.code = Dialog.BUTTON_NEGATIVE; - resultListener.onResult(inputResult); - } - - void initActivityDisplay(Activity activity) { - activity.setFinishOnTouchOutside(false); - activity.requestWindowFeature(Window.FEATURE_NO_TITLE); - } - - /** - * Places our generic widget view type inside a FrameLayout - */ - View getLayoutView(AppCompatActivity activity, T view) { - FrameLayout layout = getFrameLayout(activity); - ViewGroup.LayoutParams params = layout.getLayoutParams(); - - view.setLayoutParams(params); - layout.addView(view); - layout.setScrollbarFadingEnabled(false); - - // wrap everything in scrollview - ScrollView scrollView = new ScrollView(activity); - scrollView.addView(layout); - - return scrollView; - } - - DialogInterface.OnClickListener getClickListener(final InputResultListener listener) { - return (dialogInterface, button) -> { - InputResult result = onDialogClick(button); - listener.onResult(result); - }; - } - - DialogInterface.OnDismissListener getDismissListener() { - return dialogInterface -> { - // force dismiss behavior on single tap outside of dialog - activity.onBackPressed(); - onDismissed(); - }; - } - - /** - * Creates a dialog builder to initialize a dialog w/ a view and button click listeners - */ - AlertDialog.Builder getDialogBuilder(AppCompatActivity activity, DialogInterface.OnClickListener clickListener) { - final Intent intent = activity.getIntent(); - final View layoutView = getLayoutView(activity, widgetView); - - return new AlertDialog.Builder(activity) - .setTitle(intent.hasExtra("input_title") ? intent.getStringExtra("input_title") : "") - .setNegativeButton(getNegativeButtonText(), clickListener) - .setPositiveButton(getPositiveButtonText(), clickListener) - .setOnDismissListener(getDismissListener()) - .setView(layoutView); - - } - - String getNegativeButtonText() { - return "Cancel"; - } - - String getPositiveButtonText() { - return "OK"; - } - - void onDismissed() { - postCanceledResult(); - } - - /** - * Create a basic frame layout that will add a margin around our main widget view - */ - FrameLayout getFrameLayout(AppCompatActivity activity) { - FrameLayout layout = new FrameLayout(activity); - FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - - final int margin = 56; - params.setMargins(margin, margin, margin, margin); - - params.setMargins(56, 56, 56, 56); - layout.setLayoutParams(params); - return layout; - } - - /** - * Returns an InputResult containing code of our button and the text if we hit OK - */ - InputResult onDialogClick(int button) { - // receive indication of whether the OK or CANCEL button is clicked - inputResult.code = button; - - // OK clicked - if (button == Dialog.BUTTON_POSITIVE) { - inputResult.text = getResult(); - } - return inputResult; - } - } -} diff --git a/app/src/main/java/com/termux/api/JobSchedulerAPI.java b/app/src/main/java/com/termux/api/JobSchedulerAPI.java deleted file mode 100644 index 1feca8e79..000000000 --- a/app/src/main/java/com/termux/api/JobSchedulerAPI.java +++ /dev/null @@ -1,198 +0,0 @@ -package com.termux.api; - -import android.app.job.JobInfo; -import android.app.job.JobScheduler; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.os.PersistableBundle; -import androidx.annotation.RequiresApi; -import android.text.TextUtils; -import android.util.Log; - -import com.termux.api.util.ResultReturner; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class JobSchedulerAPI { - - private static final String LOG_TAG = "JobSchedulerAPI"; - - - private static String formatJobInfo(JobInfo jobInfo) { - final String path = jobInfo.getExtras().getString(SchedulerJobService.SCRIPT_FILE_PATH); - List description = new ArrayList(); - if (jobInfo.isPeriodic()) { - description.add(String.format(Locale.ENGLISH, "(periodic: %dms)", jobInfo.getIntervalMillis())); - } - if (jobInfo.isRequireCharging()) { - description.add("(while charging)"); - } - if (jobInfo.isRequireDeviceIdle()) { - description.add("(while idle)"); - } - if (jobInfo.isPersisted()) { - description.add("(persisted)"); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - if (jobInfo.isRequireBatteryNotLow()) { - description.add("(battery not low)"); - } - if (jobInfo.isRequireStorageNotLow()) { - description.add("(storage not low)"); - } - } - if (Build.VERSION.SDK_INT >= 28) { - description.add(String.format(Locale.ENGLISH, "(network: %s)", jobInfo.getRequiredNetwork().toString())); - } - - return String.format(Locale.ENGLISH, "Job %d: %s\t%s", jobInfo.getId(), path, - TextUtils.join(" ", description)); - } - - static void onReceive(TermuxApiReceiver apiReceiver, Context context, Intent intent) { - - final String scriptPath = intent.getStringExtra("script"); - - final int jobId = intent.getIntExtra("job_id", 0); - - final boolean pending = intent.getBooleanExtra("pending", false); - - final boolean cancel = intent.getBooleanExtra("cancel", false); - final boolean cancelAll = intent.getBooleanExtra("cancel_all", false); - - final int periodicMillis = intent.getIntExtra("period_ms", 0); - final String networkType = intent.getStringExtra("network"); - final boolean batteryNotLow = intent.getBooleanExtra("battery_not_low", true); - final boolean charging = intent.getBooleanExtra("charging", false); - final boolean idle = intent.getBooleanExtra("idle", false); - final boolean storageNotLow = intent.getBooleanExtra("storage_not_low", false); - - int networkTypeCode; - if (networkType != null) { - switch (networkType) { - case "any": - networkTypeCode = JobInfo.NETWORK_TYPE_ANY; - break; - case "unmetered": - networkTypeCode = JobInfo.NETWORK_TYPE_UNMETERED; - break; - case "cellular": - networkTypeCode = JobInfo.NETWORK_TYPE_CELLULAR; - break; - case "not_roaming": - networkTypeCode = JobInfo.NETWORK_TYPE_NOT_ROAMING; - break; - default: - case "none": - networkTypeCode = JobInfo.NETWORK_TYPE_NONE; - break; - } - } else { // networkType == null - networkTypeCode = JobInfo.NETWORK_TYPE_ANY; - } - - - JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - - if (pending) { - displayPendingJobs(apiReceiver, intent, jobScheduler); - return; - } - if (cancelAll) { - displayPendingJobs(apiReceiver, intent, jobScheduler); - ResultReturner.returnData(apiReceiver, intent, out -> out.println("Cancelling all jobs")); - jobScheduler.cancelAll(); - return; - } else if (cancel) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - cancelJob(apiReceiver, intent, jobScheduler, jobId); - } else { - ResultReturner.returnData(apiReceiver, intent, out -> out.println("Need at least Android N to cancel individual jobs")); - } - return; - } - - // Schedule new job - if (scriptPath == null) { - ResultReturner.returnData(apiReceiver, intent, out -> out.println("No script path given")); - return; - } - final File file = new File(scriptPath); - final String fileCheckMsg; - if (!file.isFile()) { - fileCheckMsg = "No such file: %s"; - } else if (!file.canRead()) { - fileCheckMsg = "Cannot read file: %s"; - } else if (!file.canExecute()) { - fileCheckMsg = "Cannot execute file: %s"; - } else { - fileCheckMsg = ""; - } - - if (!fileCheckMsg.isEmpty()) { - ResultReturner.returnData(apiReceiver, intent, out -> out.println(String.format(fileCheckMsg, scriptPath))); - return; - } - - PersistableBundle extras = new PersistableBundle(); - extras.putString(SchedulerJobService.SCRIPT_FILE_PATH, file.getAbsolutePath()); - - ComponentName serviceComponent = new ComponentName(context, SchedulerJobService.class); - JobInfo.Builder builder = new JobInfo.Builder(jobId, serviceComponent) - .setExtras(extras) - .setRequiredNetworkType(networkTypeCode) - .setRequiresCharging(charging) - .setRequiresDeviceIdle(idle); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - builder = builder.setRequiresBatteryNotLow(batteryNotLow); - builder = builder.setRequiresStorageNotLow(storageNotLow); - } - - if (periodicMillis > 0) { - builder = builder.setPeriodic(periodicMillis); - } - - JobInfo job = builder.build(); - - final int scheduleResponse = jobScheduler.schedule(job); - - final String message = String.format(Locale.ENGLISH, "Scheduling %s - response %d", formatJobInfo(job), scheduleResponse); - Log.i(LOG_TAG, message); - ResultReturner.returnData(apiReceiver, intent, out -> out.println(message)); - - - displayPendingJobs(apiReceiver, intent, jobScheduler); - - } - - private static void displayPendingJobs(TermuxApiReceiver apiReceiver, Intent intent, JobScheduler jobScheduler) { - // Display pending jobs - final List jobs = jobScheduler.getAllPendingJobs(); - if (jobs.isEmpty()) { - ResultReturner.returnData(apiReceiver, intent, out -> out.println("No pending jobs")); - return; - } - for (JobInfo job : jobs) { - ResultReturner.returnData(apiReceiver, intent, out -> out.println(String.format(Locale.ENGLISH, "Pending %s", formatJobInfo(job)))); - } - } - - @RequiresApi(api = Build.VERSION_CODES.N) - private static void cancelJob(TermuxApiReceiver apiReceiver, Intent intent, JobScheduler jobScheduler, int jobId) { - final JobInfo jobInfo = jobScheduler.getPendingJob(jobId); - if (jobInfo == null) { - ResultReturner.returnData(apiReceiver, intent, out -> out.println(String.format(Locale.ENGLISH, "No job %d found", jobId))); - return; - } - ResultReturner.returnData(apiReceiver, intent, out -> out.println(String.format(Locale.ENGLISH, "Cancelling %s", formatJobInfo(jobInfo)))); - jobScheduler.cancel(jobId); - - } - -} diff --git a/app/src/main/java/com/termux/api/KeepAliveService.java b/app/src/main/java/com/termux/api/KeepAliveService.java new file mode 100644 index 000000000..30b6eacc3 --- /dev/null +++ b/app/src/main/java/com/termux/api/KeepAliveService.java @@ -0,0 +1,27 @@ +package com.termux.api; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import androidx.annotation.Nullable; + +import com.termux.shared.logger.Logger; + +public class KeepAliveService extends Service { + + private static final String LOG_TAG = "KeepAliveService"; + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Logger.logDebug(LOG_TAG, "onStartCommand"); + + return Service.START_STICKY; + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } +} diff --git a/app/src/main/java/com/termux/api/NotificationAPI.java b/app/src/main/java/com/termux/api/NotificationAPI.java deleted file mode 100644 index 55fb0c414..000000000 --- a/app/src/main/java/com/termux/api/NotificationAPI.java +++ /dev/null @@ -1,228 +0,0 @@ -package com.termux.api; - -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Build; -import android.provider.Settings; -import android.text.TextUtils; - -import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; - -import java.io.File; -import java.io.PrintWriter; -import java.util.Arrays; -import java.util.Objects; -import java.util.UUID; - -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"; - 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"; - - /** - * Show a notification. Driven by the termux-show-notification script. - */ - static void onReceiveShowNotification(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { - String priorityExtra = intent.getStringExtra("priority"); - if (priorityExtra == null) priorityExtra = "default"; - int priority; - switch (priorityExtra) { - case "high": - priority = Notification.PRIORITY_HIGH; - break; - case "low": - priority = Notification.PRIORITY_LOW; - break; - case "max": - priority = Notification.PRIORITY_MAX; - break; - case "min": - priority = Notification.PRIORITY_MIN; - break; - default: - priority = Notification.PRIORITY_DEFAULT; - break; - } - - String title = intent.getStringExtra("title"); - - String lightsArgbExtra = intent.getStringExtra("led-color"); - - int ledColor = 0; - - if (lightsArgbExtra != null) { - try { - ledColor = Integer.parseInt(lightsArgbExtra, 16) | 0xff000000; - } catch (NumberFormatException e) { - TermuxApiLogger.error("Invalid LED color format! Ignoring!"); - } - } - - int ledOnMs = intent.getIntExtra("led-on", 800); - int ledOffMs = intent.getIntExtra("led-off", 800); - - long[] vibratePattern = intent.getLongArrayExtra("vibrate"); - boolean useSound = intent.getBooleanExtra("sound", false); - boolean ongoing = intent.getBooleanExtra("ongoing", false); - boolean alertOnce = intent.getBooleanExtra("alert-once", false); - - String actionExtra = intent.getStringExtra("action"); - - String id = intent.getStringExtra("id"); - if (id == null) id = UUID.randomUUID().toString(); - final String notificationId = id; - - String groupKey = intent.getStringExtra("group"); - - final Notification.Builder notification = new Notification.Builder(context); - notification.setSmallIcon(R.drawable.ic_event_note_black_24dp); - notification.setColor(0xFF000000); - notification.setContentTitle(title); - notification.setPriority(priority); - notification.setOngoing(ongoing); - notification.setOnlyAlertOnce(alertOnce); - notification.setWhen(System.currentTimeMillis()); - notification.setShowWhen(true); - - String ImagePath = intent.getStringExtra("image-path"); - - if(ImagePath != null){ - File imgFile = new File(ImagePath); - if(imgFile.exists()) { - Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath()); - - notification.setLargeIcon(myBitmap) - .setStyle(new Notification.BigPictureStyle() - .bigPicture(myBitmap)); - } - } - - String styleType = intent.getStringExtra("type"); - if(Objects.equals(styleType, "media")) { - String mediaPrevious = intent.getStringExtra("media-previous"); - String mediaPause = intent.getStringExtra("media-pause"); - String mediaPlay = intent.getStringExtra("media-play"); - String mediaNext = intent.getStringExtra("media-next"); - - if (mediaPrevious != null && mediaPause != null && mediaPlay != null && mediaNext != null) { - notification.setSmallIcon(android.R.drawable.ic_media_play); - - PendingIntent previousIntent = createAction(context, mediaPrevious); - PendingIntent pauseIntent = createAction(context, mediaPause); - PendingIntent playIntent = createAction(context, mediaPlay); - PendingIntent nextIntent = createAction(context, mediaNext); - - notification.addAction(new Notification.Action(android.R.drawable.ic_media_previous, "previous", previousIntent)); - notification.addAction(new Notification.Action(android.R.drawable.ic_media_pause, "pause", pauseIntent)); - notification.addAction(new Notification.Action(android.R.drawable.ic_media_play, "play", playIntent)); - notification.addAction(new Notification.Action(android.R.drawable.ic_media_next, "next", nextIntent)); - - notification.setStyle(new Notification.MediaStyle() - .setShowActionsInCompactView(0, 1, 3)); - } - } - - if (groupKey != null) notification.setGroup(groupKey); - - if (ledColor != 0) { - notification.setLights(ledColor, ledOnMs, ledOffMs); - - if (vibratePattern == null) { - // Hack to make led work without vibrating. - vibratePattern = new long[]{0}; - } - } - - if (vibratePattern != null) { - // Do not force the user to specify a delay first element, let it be 0. - long[] vibrateArg = new long[vibratePattern.length + 1]; - System.arraycopy(vibratePattern, 0, vibrateArg, 1, vibratePattern.length); - notification.setVibrate(vibrateArg); - } - - if (useSound) notification.setSound(Settings.System.DEFAULT_NOTIFICATION_URI); - - notification.setAutoCancel(true); - - if (actionExtra != null) { - PendingIntent pi = createAction(context, actionExtra); - notification.setContentIntent(pi); - } - - for (int button = 1; button <= 3; button++) { - String buttonText = intent.getStringExtra("button_text_" + button); - String buttonAction = intent.getStringExtra("button_action_" + button); - if (buttonText != null && buttonAction != null) { - PendingIntent pi = createAction(context, buttonAction); - notification.addAction(new Notification.Action(android.R.drawable.ic_input_add, buttonText, pi)); - } - } - - String onDeleteActionExtra = intent.getStringExtra("on_delete_action"); - if (onDeleteActionExtra != null) { - PendingIntent pi = createAction(context, onDeleteActionExtra); - notification.setDeleteIntent(pi); - } - - ResultReturner.returnData(apiReceiver, intent, new ResultReturner.WithStringInput() { - @Override - public void writeResult(PrintWriter out) { - NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - - if (!TextUtils.isEmpty(inputString)) { - if (inputString.contains("\n")) { - Notification.BigTextStyle style = new Notification.BigTextStyle(); - style.bigText(inputString); - notification.setStyle(style); - } else { - notification.setContentText(inputString); - } - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationChannel channel = new NotificationChannel(CHANNEL_ID, - CHANNEL_TITLE, NotificationManager.IMPORTANCE_DEFAULT); - manager.createNotificationChannel(channel); - notification.setChannelId(CHANNEL_ID); - } - - manager.notify(notificationId, 0, notification.build()); - } - }); - } - - static void onReceiveRemoveNotification(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { - ResultReturner.noteDone(apiReceiver, intent); - String notificationId = intent.getStringExtra("id"); - if (notificationId != null) { - NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - manager.cancel(notificationId, 0); - } - } - - static PendingIntent createAction(final Context context, String action){ - String[] arguments = new String[]{"-c", action}; - Uri executeUri = new Uri.Builder().scheme("com.termux.file") - .path(BIN_SH) - .appendQueryParameter("arguments", Arrays.toString(arguments)) - .build(); - Intent executeIntent = new Intent(ACTION_EXECUTE, executeUri); - executeIntent.setClassName("com.termux", TERMUX_SERVICE); - executeIntent.putExtra(EXTRA_EXECUTE_IN_BACKGROUND, true); - executeIntent.putExtra(EXTRA_ARGUMENTS, arguments); - return PendingIntent.getService(context, 0, executeIntent, 0); - } -} diff --git a/app/src/main/java/com/termux/api/NotificationService.java b/app/src/main/java/com/termux/api/NotificationService.java deleted file mode 100644 index 541217864..000000000 --- a/app/src/main/java/com/termux/api/NotificationService.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.termux.api; - -import android.service.notification.NotificationListenerService; - -public class NotificationService extends NotificationListenerService { - static NotificationService _this; - - public static NotificationService get() { - return _this; - } - - @Override - public void onListenerConnected() { - _this = this; - } - - @Override - public void onListenerDisconnected() { - _this = null; - } -} diff --git a/app/src/main/java/com/termux/api/SchedulerJobService.java b/app/src/main/java/com/termux/api/SchedulerJobService.java deleted file mode 100644 index 65594a7c6..000000000 --- a/app/src/main/java/com/termux/api/SchedulerJobService.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.termux.api; -import android.app.job.JobParameters; -import android.app.job.JobService; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.os.PersistableBundle; -import android.util.Log; - -public class SchedulerJobService extends JobService { - - private static final String LOG_TAG = "TermuxAPISchedulerJob"; - public static final String SCRIPT_FILE_PATH = "com.termux.api.jobscheduler_script_path"; - - // Constants from TermuxService. - private static final String TERMUX_SERVICE = "com.termux.app.TermuxService"; - private static final String ACTION_EXECUTE = "com.termux.service_execute"; - private static final String EXTRA_EXECUTE_IN_BACKGROUND = "com.termux.execute.background"; - - @Override - public boolean onStartJob(JobParameters params) { - - Log.i(LOG_TAG, "Starting job " + params.toString()); - PersistableBundle extras = params.getExtras(); - String filePath = extras.getString(SCRIPT_FILE_PATH); - - Uri scriptUri = new Uri.Builder().scheme("com.termux.file").path(filePath).build(); - Intent executeIntent = new Intent(ACTION_EXECUTE, scriptUri); - executeIntent.setClassName("com.termux", TERMUX_SERVICE); - executeIntent.putExtra(EXTRA_EXECUTE_IN_BACKGROUND, true); - - Context context = getApplicationContext(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - // https://developer.android.com/about/versions/oreo/background.html - context.startForegroundService(executeIntent); - } else { - context.startService(executeIntent); - } - - Log.i(LOG_TAG, "Started job " + params.toString()); - return false; - } - - @Override - public boolean onStopJob(JobParameters params) { - Log.i(LOG_TAG, "Stopped job " + params.toString()); - return false; - } -} diff --git a/app/src/main/java/com/termux/api/SmsInboxAPI.java b/app/src/main/java/com/termux/api/SmsInboxAPI.java deleted file mode 100644 index 53dc0e7de..000000000 --- a/app/src/main/java/com/termux/api/SmsInboxAPI.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.termux.api; - -import android.content.Context; -import android.content.Intent; -import android.util.JsonWriter; - -import com.termux.api.util.ResultReturner; -import com.termux.api.util.ResultReturner.ResultJsonWriter; - -public class SmsInboxAPI { - - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { - ResultReturner.returnData(apiReceiver, intent, new ResultJsonWriter() { - @Override - public void writeJson(JsonWriter out) throws Exception { - out.beginObject(); - out.name("error").value("Reading SMS is no longer permitted by Google"); - out.endObject(); - } - }); - } - -} diff --git a/app/src/main/java/com/termux/api/SmsSendAPI.java b/app/src/main/java/com/termux/api/SmsSendAPI.java deleted file mode 100644 index 6da9a7109..000000000 --- a/app/src/main/java/com/termux/api/SmsSendAPI.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.termux.api; - -import android.content.Intent; -import android.util.JsonWriter; - -import com.termux.api.util.ResultReturner; - -public class SmsSendAPI { - - static void onReceive(TermuxApiReceiver apiReceiver, final Intent intent) { - ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { - @Override - public void writeJson(JsonWriter out) throws Exception { - out.beginObject(); - out.name("error").value("Sending SMS is no longer permitted by Google"); - out.endObject(); - } - }); - } - -} diff --git a/app/src/main/java/com/termux/api/SocketListener.java b/app/src/main/java/com/termux/api/SocketListener.java new file mode 100644 index 000000000..ed41ac7d8 --- /dev/null +++ b/app/src/main/java/com/termux/api/SocketListener.java @@ -0,0 +1,262 @@ +package com.termux.api; + +import android.app.Application; +import android.content.Intent; +import android.net.LocalServerSocket; +import android.net.LocalSocket; + +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.TermuxConstants; + +import java.io.BufferedWriter; +import java.io.DataInputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SocketListener { + + public static final String LISTEN_ADDRESS = TermuxConstants.TERMUX_API_PACKAGE_NAME + "://listen"; + private static final Pattern EXTRA_STRING = Pattern.compile("(-e|--es|--esa) +([^ ]+) +\"(.*?)(? { + try (LocalServerSocket listen = new LocalServerSocket(LISTEN_ADDRESS)) { + while (true) { + try (LocalSocket con = listen.accept(); + DataInputStream in = new DataInputStream(con.getInputStream()); + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream()))) { + // only accept connections from Termux programs + if (con.getPeerCredentials().getUid() != app.getApplicationInfo().uid) { + continue; + } + try { + //System.out.println("connection"); + int length = in.readUnsignedShort(); + byte[] b = new byte[length]; + in.readFully(b); + String cmdline = new String(b, StandardCharsets.UTF_8); + + Intent intent = new Intent(app.getApplicationContext(), TermuxApiReceiver.class); + //System.out.println(cmdline.replaceAll("--es socket_input \".*?\"","").replaceAll("--es socket_output \".*?\"","")); + HashMap stringExtras = new HashMap<>(); + HashMap stringArrayExtras = new HashMap<>(); + HashMap booleanExtras = new HashMap<>(); + HashMap intExtras = new HashMap<>(); + HashMap floatExtras = new HashMap<>(); + HashMap intArrayExtras = new HashMap<>(); + HashMap longArrayExtras = new HashMap<>(); + boolean err = false; + + // extract and remove the string extras first, so another argument embedded in a string isn't counted as an argument + Matcher m = EXTRA_STRING.matcher(cmdline); + while (m.find()) { + String option = m.group(1); + if ("-e".equals(option) || "--es".equals(option)) { + // unescape " + stringExtras.put(m.group(2), Objects.requireNonNull(m.group(3)).replaceAll("\\\\\"", "\"")); + } + else { + // split the list + String[] list = Objects.requireNonNull(m.group(3)).split("(? e : stringExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : stringArrayExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : intExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : booleanExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : floatExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : intArrayExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : longArrayExtras.entrySet()) { + intent.putExtra(e.getKey(), e.getValue()); + } + app.getApplicationContext().sendOrderedBroadcast(intent, null); + // send a null byte as a sign that the arguments have been successfully received, parsed and the broadcast receiver is called + con.getOutputStream().write(0); + con.getOutputStream().flush(); + } + catch (Exception e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Error parsing arguments", e); + out.write("Exception in the plugin\n"); + out.flush(); + } + } + catch (java.io.IOException e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Connection error", e); + } + } + } + catch (Exception e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Error listening for connections", e); + } + }); + listener.start(); + } + } + +} diff --git a/app/src/main/java/com/termux/api/TelephonyAPI.java b/app/src/main/java/com/termux/api/TelephonyAPI.java deleted file mode 100644 index 6a998c324..000000000 --- a/app/src/main/java/com/termux/api/TelephonyAPI.java +++ /dev/null @@ -1,320 +0,0 @@ -package com.termux.api; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.telephony.CellInfo; -import android.telephony.CellInfoCdma; -import android.telephony.CellInfoGsm; -import android.telephony.CellInfoLte; -import android.telephony.CellInfoWcdma; -import android.telephony.TelephonyManager; -import android.util.JsonWriter; -import android.util.Log; - -import com.termux.api.util.ResultReturner; - -import java.io.IOException; - -/** - * Exposing {@link android.telephony.TelephonyManager}. - */ -public class TelephonyAPI { - - private static void writeIfKnown(JsonWriter out, String name, int value) throws IOException { - if (value != Integer.MAX_VALUE) out.name(name).value(value); - } - - static void onReceiveTelephonyCellInfo(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { - ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { - @Override - public void writeJson(JsonWriter out) throws Exception { - TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - out.beginArray(); - - for (CellInfo cellInfo : manager.getAllCellInfo()) { - out.beginObject(); - if (cellInfo instanceof CellInfoGsm) { - CellInfoGsm gsmInfo = (CellInfoGsm) cellInfo; - out.name("type").value("gsm"); - out.name("registered").value(cellInfo.isRegistered()); - - out.name("asu").value(gsmInfo.getCellSignalStrength().getAsuLevel()); - writeIfKnown(out, "dbm", gsmInfo.getCellSignalStrength().getDbm()); - out.name("level").value(gsmInfo.getCellSignalStrength().getLevel()); - - writeIfKnown(out, "cid", gsmInfo.getCellIdentity().getCid()); - writeIfKnown(out, "lac", gsmInfo.getCellIdentity().getLac()); - writeIfKnown(out, "mcc", gsmInfo.getCellIdentity().getMcc()); - writeIfKnown(out, "mnc", gsmInfo.getCellIdentity().getMnc()); - } else if (cellInfo instanceof CellInfoLte) { - CellInfoLte lteInfo = (CellInfoLte) cellInfo; - out.name("type").value("lte"); - out.name("registered").value(cellInfo.isRegistered()); - - out.name("asu").value(lteInfo.getCellSignalStrength().getAsuLevel()); - out.name("dbm").value(lteInfo.getCellSignalStrength().getDbm()); - writeIfKnown(out, "level", lteInfo.getCellSignalStrength().getLevel()); - writeIfKnown(out, "timing_advance", lteInfo.getCellSignalStrength().getTimingAdvance()); - - writeIfKnown(out, "ci", lteInfo.getCellIdentity().getCi()); - writeIfKnown(out, "pci", lteInfo.getCellIdentity().getPci()); - writeIfKnown(out, "tac", lteInfo.getCellIdentity().getTac()); - writeIfKnown(out, "mcc", lteInfo.getCellIdentity().getMcc()); - writeIfKnown(out, "mnc", lteInfo.getCellIdentity().getMnc()); - } else if (cellInfo instanceof CellInfoCdma) { - CellInfoCdma cdmaInfo = (CellInfoCdma) cellInfo; - out.name("type").value("cdma"); - out.name("registered").value(cellInfo.isRegistered()); - - out.name("asu").value(cdmaInfo.getCellSignalStrength().getAsuLevel()); - out.name("dbm").value(cdmaInfo.getCellSignalStrength().getDbm()); - out.name("level").value(cdmaInfo.getCellSignalStrength().getLevel()); - out.name("cdma_dbm").value(cdmaInfo.getCellSignalStrength().getCdmaDbm()); - out.name("cdma_ecio").value(cdmaInfo.getCellSignalStrength().getCdmaEcio()); - out.name("cdma_level").value(cdmaInfo.getCellSignalStrength().getCdmaLevel()); - out.name("evdo_dbm").value(cdmaInfo.getCellSignalStrength().getEvdoDbm()); - out.name("evdo_ecio").value(cdmaInfo.getCellSignalStrength().getEvdoEcio()); - out.name("evdo_level").value(cdmaInfo.getCellSignalStrength().getEvdoLevel()); - out.name("evdo_snr").value(cdmaInfo.getCellSignalStrength().getEvdoSnr()); - - out.name("basestation").value(cdmaInfo.getCellIdentity().getBasestationId()); - out.name("latitude").value(cdmaInfo.getCellIdentity().getLatitude()); - out.name("longitude").value(cdmaInfo.getCellIdentity().getLongitude()); - out.name("network").value(cdmaInfo.getCellIdentity().getNetworkId()); - out.name("system").value(cdmaInfo.getCellIdentity().getSystemId()); - } else if (cellInfo instanceof CellInfoWcdma) { - CellInfoWcdma wcdmaInfo = (CellInfoWcdma) cellInfo; - out.name("type").value("wcdma"); - out.name("registered").value(cellInfo.isRegistered()); - - out.name("asu").value(wcdmaInfo.getCellSignalStrength().getAsuLevel()); - writeIfKnown(out, "dbm", wcdmaInfo.getCellSignalStrength().getDbm()); - out.name("level").value(wcdmaInfo.getCellSignalStrength().getLevel()); - - writeIfKnown(out, "cid", wcdmaInfo.getCellIdentity().getCid()); - writeIfKnown(out, "lac", wcdmaInfo.getCellIdentity().getLac()); - writeIfKnown(out, "mcc", wcdmaInfo.getCellIdentity().getMcc()); - writeIfKnown(out, "mnc", wcdmaInfo.getCellIdentity().getMnc()); - writeIfKnown(out, "psc", wcdmaInfo.getCellIdentity().getPsc()); - } - out.endObject(); - } - - out.endArray(); - } - }); - } - - - static void onReceiveTelephonyDeviceInfo(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { - ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { - @SuppressLint("HardwareIds") - @Override - public void writeJson(JsonWriter out) throws Exception { - TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - out.beginObject(); - - { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - out.name("data_enabled").value(Boolean.toString(manager.isDataEnabled())); - } - - int dataActivity = manager.getDataActivity(); - String dataActivityString; - switch (dataActivity) { - case TelephonyManager.DATA_ACTIVITY_NONE: - dataActivityString = "none"; - break; - case TelephonyManager.DATA_ACTIVITY_IN: - dataActivityString = "in"; - break; - case TelephonyManager.DATA_ACTIVITY_OUT: - dataActivityString = "out"; - break; - case TelephonyManager.DATA_ACTIVITY_INOUT: - dataActivityString = "inout"; - break; - case TelephonyManager.DATA_ACTIVITY_DORMANT: - dataActivityString = "dormant"; - break; - default: - dataActivityString = Integer.toString(dataActivity); - break; - } - out.name("data_activity").value(dataActivityString); - - int dataState = manager.getDataState(); - String dataStateString; - switch (dataState) { - case TelephonyManager.DATA_DISCONNECTED: - dataStateString = "disconnected"; - break; - case TelephonyManager.DATA_CONNECTING: - dataStateString = "connecting"; - break; - case TelephonyManager.DATA_CONNECTED: - dataStateString = "connected"; - break; - case TelephonyManager.DATA_SUSPENDED: - dataStateString = "suspended"; - break; - default: - dataStateString = Integer.toString(dataState); - break; - } - out.name("data_state").value(dataStateString); - - out.name("device_id").value(manager.getDeviceId()); - out.name("device_software_version").value(manager.getDeviceSoftwareVersion()); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - out.name("phone_count").value(manager.getPhoneCount()); - } - int phoneType = manager.getPhoneType(); - String phoneTypeString; - switch (phoneType) { - case TelephonyManager.PHONE_TYPE_CDMA: - phoneTypeString = "cdma"; - break; - case TelephonyManager.PHONE_TYPE_GSM: - phoneTypeString = "gsm"; - break; - case TelephonyManager.PHONE_TYPE_NONE: - phoneTypeString = "none"; - break; - case TelephonyManager.PHONE_TYPE_SIP: - phoneTypeString = "sip"; - break; - default: - phoneTypeString = Integer.toString(phoneType); - break; - } - out.name("phone_type").value(phoneTypeString); - - out.name("network_operator").value(manager.getNetworkOperator()); - out.name("network_operator_name").value(manager.getNetworkOperatorName()); - out.name("network_country_iso").value(manager.getNetworkCountryIso()); - int networkType = manager.getNetworkType(); - String networkTypeName; - switch (networkType) { - case TelephonyManager.NETWORK_TYPE_1xRTT: - networkTypeName = "1xrtt"; - break; - case TelephonyManager.NETWORK_TYPE_CDMA: - networkTypeName = "cdma"; - break; - case TelephonyManager.NETWORK_TYPE_EDGE: - networkTypeName = "edge"; - break; - case TelephonyManager.NETWORK_TYPE_EHRPD: - networkTypeName = "ehrpd"; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - networkTypeName = "evdo_0"; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_A: - networkTypeName = "evdo_a"; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_B: - networkTypeName = "evdo_b"; - break; - case TelephonyManager.NETWORK_TYPE_GPRS: - networkTypeName = "gprs"; - break; - case TelephonyManager.NETWORK_TYPE_HSDPA: - networkTypeName = "hdspa"; - break; - case TelephonyManager.NETWORK_TYPE_HSPA: - networkTypeName = "hspa"; - break; - case TelephonyManager.NETWORK_TYPE_HSPAP: - networkTypeName = "hspap"; - break; - case TelephonyManager.NETWORK_TYPE_HSUPA: - networkTypeName = "hsupa"; - break; - case TelephonyManager.NETWORK_TYPE_IDEN: - networkTypeName = "iden"; - break; - case TelephonyManager.NETWORK_TYPE_LTE: - networkTypeName = "lte"; - break; - case TelephonyManager.NETWORK_TYPE_UMTS: - networkTypeName = "umts"; - break; - case TelephonyManager.NETWORK_TYPE_UNKNOWN: - networkTypeName = "unknown"; - break; - default: - networkTypeName = Integer.toString(networkType); - break; - } - out.name("network_type").value(networkTypeName); - out.name("network_roaming").value(manager.isNetworkRoaming()); - - out.name("sim_country_iso").value(manager.getSimCountryIso()); - out.name("sim_operator").value(manager.getSimOperator()); - out.name("sim_operator_name").value(manager.getSimOperatorName()); - out.name("sim_serial_number").value(manager.getSimSerialNumber()); - out.name("sim_subscriber_id").value(manager.getSubscriberId()); - int simState = manager.getSimState(); - String simStateString; - switch (simState) { - case TelephonyManager.SIM_STATE_ABSENT: - simStateString = "absent"; - break; - case TelephonyManager.SIM_STATE_NETWORK_LOCKED: - simStateString = "network_locked"; - break; - case TelephonyManager.SIM_STATE_PIN_REQUIRED: - simStateString = "pin_required"; - break; - case TelephonyManager.SIM_STATE_PUK_REQUIRED: - simStateString = "puk_required"; - break; - case TelephonyManager.SIM_STATE_READY: - simStateString = "ready"; - break; - case TelephonyManager.SIM_STATE_UNKNOWN: - simStateString = "unknown"; - break; - default: - simStateString = Integer.toString(simState); - break; - } - out.name("sim_state").value(simStateString); - - - } - - out.endObject(); - } - }); - } - - static void onReceiveTelephonyCall(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { - String numberExtra = intent.getStringExtra("number"); - if (numberExtra == null) { - Log.e("termux-api", "No 'number extra"); - ResultReturner.noteDone(apiReceiver, intent); - } - - Uri data = Uri.parse("tel:" + numberExtra); - - Intent callIntent = new Intent(Intent.ACTION_CALL); - callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - callIntent.setData(data); - - try { - context.startActivity(callIntent); - } catch (SecurityException e) { - Log.e("termux-api", "Exception in phone call", e); - } - - ResultReturner.noteDone(apiReceiver, intent); - } - -} \ No newline at end of file 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..30f70b8b2 --- /dev/null +++ b/app/src/main/java/com/termux/api/TermuxAPIApplication.java @@ -0,0 +1,45 @@ +package com.termux.api; + +import android.app.Application; +import android.content.Context; +import android.util.Log; + +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.termux.crash.TermuxCrashUtils; +import com.termux.shared.termux.settings.preferences.TermuxAPIAppSharedPreferences; + + +public class TermuxAPIApplication extends Application { + + public static final String LOG_TAG = "TermuxAPIApplication"; + + public void onCreate() { + super.onCreate(); + + Log.i(LOG_TAG, "AppInit"); + + Context context = getApplicationContext(); + + // Set crash handler for the app + TermuxCrashUtils.setCrashHandler(context); + + ResultReturner.setContext(this); + + // Set log config for the app + setLogConfig(context, true); + + SocketListener.createSocketListener(this); + } + + public static void setLogConfig(Context context, boolean commitToFile) { + Logger.setDefaultLogTag(TermuxConstants.TERMUX_API_APP_NAME.replaceAll("[: ]", "")); + + // 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/java/com/termux/api/TermuxAPIConstants.java b/app/src/main/java/com/termux/api/TermuxAPIConstants.java new file mode 100644 index 000000000..e27e5b987 --- /dev/null +++ b/app/src/main/java/com/termux/api/TermuxAPIConstants.java @@ -0,0 +1,17 @@ +package com.termux.api; + +import com.termux.shared.termux.TermuxConstants; +import static com.termux.shared.termux.TermuxConstants.TERMUX_API_PACKAGE_NAME; +import static com.termux.shared.termux.TermuxConstants.TERMUX_PACKAGE_NAME; + +public class TermuxAPIConstants { + + /** + * Termux:API Receiver name. + */ + public static final String TERMUX_API_RECEIVER_NAME = TERMUX_API_PACKAGE_NAME + ".TermuxApiReceiver"; // Default to "com.termux.api.TermuxApiReceiver" + + /** The Uri authority for Termux:API app file shares */ + public static final String TERMUX_API_FILE_SHARE_URI_AUTHORITY = TERMUX_PACKAGE_NAME + ".sharedfiles"; // Default: "com.termux.sharedfiles" + +} diff --git a/app/src/main/java/com/termux/api/TermuxApiReceiver.java b/app/src/main/java/com/termux/api/TermuxApiReceiver.java index e3c66048f..b752864be 100644 --- a/app/src/main/java/com/termux/api/TermuxApiReceiver.java +++ b/app/src/main/java/com/termux/api/TermuxApiReceiver.java @@ -5,30 +5,81 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.os.Build; import android.provider.Settings; import android.widget.Toast; -import com.termux.api.util.TermuxApiLogger; -import com.termux.api.util.TermuxApiPermissionActivity; +import com.termux.api.apis.AudioAPI; +import com.termux.api.apis.BatteryStatusAPI; +import com.termux.api.apis.BrightnessAPI; +import com.termux.api.apis.CallLogAPI; +import com.termux.api.apis.CameraInfoAPI; +import com.termux.api.apis.CameraPhotoAPI; +import com.termux.api.apis.ClipboardAPI; +import com.termux.api.apis.ContactListAPI; +import com.termux.api.apis.DialogAPI; +import com.termux.api.apis.DownloadAPI; +import com.termux.api.apis.FingerprintAPI; +import com.termux.api.apis.InfraredAPI; +import com.termux.api.apis.JobSchedulerAPI; +import com.termux.api.apis.KeystoreAPI; +import com.termux.api.apis.LocationAPI; +import com.termux.api.apis.MediaPlayerAPI; +import com.termux.api.apis.MediaScannerAPI; +import com.termux.api.apis.MicRecorderAPI; +import com.termux.api.apis.NfcAPI; +import com.termux.api.apis.NotificationAPI; +import com.termux.api.apis.NotificationListAPI; +import com.termux.api.apis.SAFAPI; +import com.termux.api.apis.SensorAPI; +import com.termux.api.apis.ShareAPI; +import com.termux.api.apis.SmsInboxAPI; +import com.termux.api.apis.SmsSendAPI; +import com.termux.api.apis.SpeechToTextAPI; +import com.termux.api.apis.StorageGetAPI; +import com.termux.api.apis.TelephonyAPI; +import com.termux.api.apis.TextToSpeechAPI; +import com.termux.api.apis.ToastAPI; +import com.termux.api.apis.TorchAPI; +import com.termux.api.apis.UsbAPI; +import com.termux.api.apis.VibrateAPI; +import com.termux.api.apis.VolumeAPI; +import com.termux.api.apis.WallpaperAPI; +import com.termux.api.apis.WifiAPI; +import com.termux.api.activities.TermuxApiPermissionActivity; +import com.termux.api.util.ResultReturner; +import com.termux.shared.data.IntentUtils; +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.termux.plugins.TermuxPluginUtils; public class TermuxApiReceiver extends BroadcastReceiver { + private static final String LOG_TAG = "TermuxApiReceiver"; + @Override public void onReceive(Context context, Intent intent) { + TermuxAPIApplication.setLogConfig(context, false); + Logger.logDebug(LOG_TAG, "Intent Received:\n" + IntentUtils.getIntentString(intent)); + try { doWork(context, intent); - } catch (Exception e) { + } catch (Throwable t) { + String message = "Error in " + LOG_TAG; // Make sure never to throw exception from BroadCastReceiver to avoid "process is bad" // behaviour from the Android system. - TermuxApiLogger.error("Error in TermuxApiReceiver", e); + Logger.logStackTraceWithMessage(LOG_TAG, message, t); + + TermuxPluginUtils.sendPluginCommandErrorNotification(context, LOG_TAG, + TermuxConstants.TERMUX_API_APP_NAME + " Error", message, t); + + ResultReturner.noteDone(this, intent); } } private void doWork(Context context, Intent intent) { String apiMethod = intent.getStringExtra("api_method"); if (apiMethod == null) { - TermuxApiLogger.error("Missing 'api_method' extra"); + Logger.logError(LOG_TAG, "Missing 'api_method' extra"); return; } @@ -40,16 +91,14 @@ private void doWork(Context context, Intent intent) { BatteryStatusAPI.onReceive(this, context, intent); break; case "Brightness": - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - if (!Settings.System.canWrite(context)) { - TermuxApiPermissionActivity.checkAndRequestPermissions(context, intent, Manifest.permission.WRITE_SETTINGS); - Toast.makeText(context, "Please enable permission for Termux:API", Toast.LENGTH_LONG).show(); + if (!Settings.System.canWrite(context)) { + TermuxApiPermissionActivity.checkAndRequestPermissions(context, intent, Manifest.permission.WRITE_SETTINGS); + Toast.makeText(context, "Please enable permission for Termux:API", Toast.LENGTH_LONG).show(); - // user must enable WRITE_SETTINGS permission this special way - Intent settingsIntent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS); - context.startActivity(settingsIntent); - return; - } + // user must enable WRITE_SETTINGS permission this special way + Intent settingsIntent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS); + context.startActivity(settingsIntent); + return; } BrightnessAPI.onReceive(this, context, intent); break; @@ -58,11 +107,13 @@ private void doWork(Context context, Intent intent) { break; case "CameraPhoto": if (TermuxApiPermissionActivity.checkAndRequestPermissions(context, intent, Manifest.permission.CAMERA)) { - PhotoAPI.onReceive(this, context, intent); + CameraPhotoAPI.onReceive(this, context, intent); } break; case "CallLog": - CallLogAPI.onReceive(context, intent); + if (TermuxApiPermissionActivity.checkAndRequestPermissions(context, intent, Manifest.permission.READ_CALL_LOG)) { + CallLogAPI.onReceive(context, intent); + } break; case "Clipboard": ClipboardAPI.onReceive(this, context, intent); @@ -73,7 +124,7 @@ private void doWork(Context context, Intent intent) { } break; case "Dialog": - context.startActivity(new Intent(context, DialogActivity.class).putExtras(intent.getExtras()).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + DialogAPI.onReceive(context, intent); break; case "Download": DownloadAPI.onReceive(this, context, intent); @@ -113,8 +164,11 @@ private void doWork(Context context, Intent intent) { MicRecorderAPI.onReceive(context, intent); } break; + case "Nfc": + NfcAPI.onReceive(context, intent); + break; case "NotificationList": - ComponentName cn = new ComponentName(context, NotificationService.class); + ComponentName cn = new ComponentName(context, NotificationListAPI.NotificationService.class); String flat = Settings.Secure.getString(context.getContentResolver(), "enabled_notification_listeners"); final boolean NotificationServiceEnabled = flat != null && flat.contains(cn.flattenToString()); if (!NotificationServiceEnabled) { @@ -127,9 +181,18 @@ private void doWork(Context context, Intent intent) { case "Notification": NotificationAPI.onReceiveShowNotification(this, context, intent); break; + case "NotificationChannel": + NotificationAPI.onReceiveChannel(this, context, intent); + break; case "NotificationRemove": NotificationAPI.onReceiveRemoveNotification(this, context, intent); break; + case "NotificationReply": + NotificationAPI.onReceiveReplyToNotification(this, context, intent); + break; + case "SAF": + SAFAPI.onReceive(this, context, intent); + break; case "Sensor": SensorAPI.onReceive(context, intent); break; @@ -137,10 +200,14 @@ private void doWork(Context context, Intent intent) { ShareAPI.onReceive(this, context, intent); break; case "SmsInbox": - SmsInboxAPI.onReceive(this, context, intent); + if (TermuxApiPermissionActivity.checkAndRequestPermissions(context, intent, Manifest.permission.READ_SMS, Manifest.permission.READ_CONTACTS)) { + SmsInboxAPI.onReceive(this, context, intent); + } break; case "SmsSend": - SmsSendAPI.onReceive(this, intent); + if (TermuxApiPermissionActivity.checkAndRequestPermissions(context, intent, Manifest.permission.READ_PHONE_STATE, Manifest.permission.SEND_SMS)) { + SmsSendAPI.onReceive(this, context, intent); + } break; case "StorageGet": StorageGetAPI.onReceive(this, context, intent); @@ -175,7 +242,7 @@ private void doWork(Context context, Intent intent) { TorchAPI.onReceive(this, context, intent); break; case "Usb": - UsbAPI.onReceive(this, context, intent); + UsbAPI.onReceive(context, intent); break; case "Vibrate": VibrateAPI.onReceive(this, context, intent); @@ -198,7 +265,7 @@ private void doWork(Context context, Intent intent) { WifiAPI.onReceiveWifiEnable(this, context, intent); break; default: - TermuxApiLogger.error("Unrecognized 'api_method' extra: '" + apiMethod + "'"); + Logger.logError(LOG_TAG, "Unrecognized 'api_method' extra: '" + apiMethod + "'"); } } diff --git a/app/src/main/java/com/termux/api/UsbAPI.java b/app/src/main/java/com/termux/api/UsbAPI.java deleted file mode 100644 index d71f1181b..000000000 --- a/app/src/main/java/com/termux/api/UsbAPI.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.termux.api; - -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.hardware.usb.UsbDevice; -import android.hardware.usb.UsbDeviceConnection; -import android.hardware.usb.UsbManager; -import android.os.Looper; -import android.util.JsonWriter; -import android.util.SparseArray; - -import com.termux.api.util.ResultReturner; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Iterator; -import java.util.HashMap; - -import androidx.annotation.NonNull; - -public class UsbAPI { - - private static SparseArray openDevices = new SparseArray<>(); - - static void onReceive(final TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { - UsbDevice device; - String action = intent.getAction(); - if (action == null) { - ResultReturner.returnData(apiReceiver, intent, out -> out.append("Missing action\n")); - } else { - switch (action) { - case "list": - ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { - @Override - public void writeJson(JsonWriter out) throws Exception { - listDevices(context, out); - } - }); - break; - case "permission": - device = getDevice(apiReceiver, context, intent); - if (device == null) return; - ResultReturner.returnData(apiReceiver, intent, out -> { - boolean result = getPermission(device, context, intent); - out.append(result ? "yes\n" : "no\n"); - }); - break; - case "open": - device = getDevice(apiReceiver, context, intent); - if (device == null) return; - ResultReturner.returnData(apiReceiver, intent, new ResultReturner.WithAncillaryFd() { - @Override - public void writeResult(PrintWriter out) { - if (getPermission(device, context, intent)) { - int result = open(device, context); - if (result < 0) { - out.append("Failed to open device\n"); - } else { - this.setFd(result); - out.append("@"); // has to be non-empty - } - } else out.append("No permission\n"); - } - }); - - break; - default: - ResultReturner.returnData(apiReceiver, intent, out -> out.append("Invalid action\n")); - } - } - - } - - private static void listDevices(final Context context, JsonWriter out) throws IOException { - final UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); - HashMap deviceList = usbManager.getDeviceList(); - Iterator deviceIterator = deviceList.keySet().iterator(); - out.beginArray(); - while (deviceIterator.hasNext()) { - out.value(deviceIterator.next()); - } - out.endArray(); - } - - private static UsbDevice getDevice(final TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { - String deviceName = intent.getStringExtra("device"); - final UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); - HashMap deviceList = usbManager.getDeviceList(); - UsbDevice device = deviceList.get(deviceName); - if (device == null) { - ResultReturner.returnData(apiReceiver, intent, out -> out.append("No such device\n")); - } - return device; - } - - private static boolean hasPermission(final @NonNull UsbDevice device, final Context context) { - final UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); - return usbManager.hasPermission(device); - } - - private static boolean requestPermission(final @NonNull UsbDevice device, final Context context) { - Looper.prepare(); - Looper looper = Looper.myLooper(); - final boolean[] result = new boolean[1]; - - final String ACTION_USB_PERMISSION = "com.termux.api.USB_PERMISSION"; - final BroadcastReceiver usbReceiver = new BroadcastReceiver() { - @Override - public void onReceive(final Context usbContext, final Intent usbIntent) { - String action = usbIntent.getAction(); - if (ACTION_USB_PERMISSION.equals(action)) { - synchronized (this) { - UsbDevice device = usbIntent.getParcelableExtra(UsbManager.EXTRA_DEVICE); - if (usbIntent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { - if (device != null) { - result[0] = true; - if (looper != null) looper.quit(); - } - } else { - result[0] = false; - if (looper != null) looper.quit(); - } - } - - } - } - }; - - final UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); - PendingIntent permissionIntent = PendingIntent.getBroadcast(context, 0, - new Intent(ACTION_USB_PERMISSION), 0); - IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); - context.getApplicationContext().registerReceiver(usbReceiver, filter); - usbManager.requestPermission(device, permissionIntent); - Looper.loop(); - return result[0]; - } - - private static boolean getPermission(final @NonNull UsbDevice device, final Context context, final Intent intent) { - boolean request = intent.getBooleanExtra("request", false); - if(request) { - return requestPermission(device, context); - } else { - return hasPermission(device, context); - } - } - - private static int open(final @NonNull UsbDevice device, final Context context) { - final UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); - UsbDeviceConnection connection = usbManager.openDevice(device); - if (connection == null) - return -2; - int fd = connection.getFileDescriptor(); - if (fd == -1) { - connection.close(); - return -1; - } - openDevices.put(fd, connection); - return fd; - } - -} diff --git a/app/src/main/java/com/termux/api/VibrateAPI.java b/app/src/main/java/com/termux/api/VibrateAPI.java deleted file mode 100644 index 3c2cb88f5..000000000 --- a/app/src/main/java/com/termux/api/VibrateAPI.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.termux.api; - -import android.content.Context; -import android.content.Intent; -import android.media.AudioManager; -import android.os.Vibrator; - -import com.termux.api.util.ResultReturner; - -public class VibrateAPI { - - static void onReceive(TermuxApiReceiver apiReceiver, Context context, Intent intent) { - Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - int milliseconds = intent.getIntExtra("duration_ms", 1000); - boolean force = intent.getBooleanExtra("force", false); - - AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - if (am.getRingerMode() == AudioManager.RINGER_MODE_SILENT && !force) { - // Not vibrating since in silent mode and -f/--force option not used. - } else { - vibrator.vibrate(milliseconds); - } - - ResultReturner.noteDone(apiReceiver, intent); - } - -} diff --git a/app/src/main/java/com/termux/api/activities/TermuxAPIMainActivity.java b/app/src/main/java/com/termux/api/activities/TermuxAPIMainActivity.java new file mode 100644 index 000000000..e4f596da6 --- /dev/null +++ b/app/src/main/java/com/termux/api/activities/TermuxAPIMainActivity.java @@ -0,0 +1,217 @@ +package com.termux.api.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Button; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + +import com.termux.api.TermuxAPIApplication; +import com.termux.api.settings.activities.TermuxAPISettingsActivity; +import com.termux.api.util.ViewUtils; +import com.termux.shared.activity.ActivityUtils; +import com.termux.shared.activity.media.AppCompatActivityUtils; +import com.termux.shared.android.PackageUtils; +import com.termux.shared.android.PermissionUtils; +import com.termux.shared.data.IntentUtils; +import com.termux.shared.logger.Logger; +import com.termux.shared.markdown.MarkdownUtils; +import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.termux.theme.TermuxThemeUtils; +import com.termux.shared.theme.NightMode; +import com.termux.api.R; + +public class TermuxAPIMainActivity extends AppCompatActivity { + + private TextView mBatteryOptimizationNotDisabledWarning; + private TextView mDisplayOverOtherAppsPermissionNotGrantedWarning; + + private Button mDisableBatteryOptimization; + private Button mGrantDisplayOverOtherAppsPermission; + + public static final String LOG_TAG = "TermuxAPIMainActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + Logger.logDebug(LOG_TAG, "onCreate"); + + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_termux_api_main); + + // Set NightMode.APP_NIGHT_MODE + TermuxThemeUtils.setAppNightMode(this); + AppCompatActivityUtils.setNightMode(this, NightMode.getAppNightMode().getName(), true); + + AppCompatActivityUtils.setToolbar(this, com.termux.shared.R.id.toolbar); + AppCompatActivityUtils.setToolbarTitle(this, com.termux.shared.R.id.toolbar, TermuxConstants.TERMUX_API_APP_NAME, 0); + + TextView pluginInfo = findViewById(R.id.textview_plugin_info); + pluginInfo.setText(getString(R.string.plugin_info, TermuxConstants.TERMUX_GITHUB_REPO_URL, + TermuxConstants.TERMUX_API_GITHUB_REPO_URL, TermuxConstants.TERMUX_API_APT_PACKAGE_NAME, + TermuxConstants.TERMUX_API_APT_GITHUB_REPO_URL)); + + mBatteryOptimizationNotDisabledWarning = findViewById(R.id.textview_battery_optimization_not_disabled_warning); + mDisableBatteryOptimization = findViewById(R.id.btn_disable_battery_optimizations); + mDisableBatteryOptimization.setOnClickListener(v -> requestDisableBatteryOptimizations()); + + mDisplayOverOtherAppsPermissionNotGrantedWarning = findViewById(R.id.textview_display_over_other_apps_not_granted_warning); + mGrantDisplayOverOtherAppsPermission = findViewById(R.id.button_grant_display_over_other_apps_permission); + mGrantDisplayOverOtherAppsPermission.setOnClickListener(v -> requestDisplayOverOtherAppsPermission()); + } + + @Override + protected void onResume() { + super.onResume(); + + // Set log level for the app + TermuxAPIApplication.setLogConfig(this, false); + + Logger.logVerbose(LOG_TAG, "onResume"); + + checkIfBatteryOptimizationNotDisabled(); + checkIfDisplayOverOtherAppsPermissionNotGranted(); + setChangeLauncherActivityStateViews(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + getMenuInflater().inflate(R.menu.activity_termux_api_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + + if (id == R.id.menu_settings) { + openSettings(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + + + private void checkIfBatteryOptimizationNotDisabled() { + if (mBatteryOptimizationNotDisabledWarning == null) return; + + // If battery optimizations not disabled + if (!PermissionUtils.checkIfBatteryOptimizationsDisabled(this)) { + ViewUtils.setWarningTextViewAndButtonState(this, mBatteryOptimizationNotDisabledWarning, + mDisableBatteryOptimization, true, getString(R.string.action_disable_battery_optimizations)); + } else { + ViewUtils.setWarningTextViewAndButtonState(this, mBatteryOptimizationNotDisabledWarning, + mDisableBatteryOptimization, false, getString(R.string.action_already_disabled)); + } + } + + private void requestDisableBatteryOptimizations() { + Logger.logDebug(LOG_TAG, "Requesting to disable battery optimizations"); + PermissionUtils.requestDisableBatteryOptimizations(this, PermissionUtils.REQUEST_DISABLE_BATTERY_OPTIMIZATIONS); + } + + + + private void checkIfDisplayOverOtherAppsPermissionNotGranted() { + if (mDisplayOverOtherAppsPermissionNotGrantedWarning == null) return; + + // If display over other apps permission not granted + if (!PermissionUtils.checkDisplayOverOtherAppsPermission(this)) { + ViewUtils.setWarningTextViewAndButtonState(this, mDisplayOverOtherAppsPermissionNotGrantedWarning, + mGrantDisplayOverOtherAppsPermission, true, getString(R.string.action_grant_display_over_other_apps_permission)); + } else { + ViewUtils.setWarningTextViewAndButtonState(this, mDisplayOverOtherAppsPermissionNotGrantedWarning, + mGrantDisplayOverOtherAppsPermission, false, getString(R.string.action_already_granted)); + } + } + + private void requestDisplayOverOtherAppsPermission() { + Logger.logDebug(LOG_TAG, "Requesting to grant display over other apps permission"); + PermissionUtils.requestDisplayOverOtherAppsPermission(this, PermissionUtils.REQUEST_GRANT_DISPLAY_OVER_OTHER_APPS_PERMISSION); + } + + + + private void setChangeLauncherActivityStateViews() { + String packageName = TermuxConstants.TERMUX_API_PACKAGE_NAME; + String className = TermuxConstants.TERMUX_API_APP.TERMUX_API_LAUNCHER_ACTIVITY_NAME; + + TextView changeLauncherActivityStateTextView = findViewById(R.id.textview_change_launcher_activity_state_details); + changeLauncherActivityStateTextView.setText(MarkdownUtils.getSpannedMarkdownText(this, + getString(R.string.msg_change_launcher_activity_state_info, packageName, getClass().getName()))); + + Button changeLauncherActivityStateButton = findViewById(R.id.button_change_launcher_activity_state); + String stateChangeMessage; + boolean newState; + + Boolean currentlyDisabled = PackageUtils.isComponentDisabled(this, + packageName, className, false); + if (currentlyDisabled == null) { + Logger.logError(LOG_TAG, "Failed to check if \"" + packageName + "/" + className + "\" launcher activity is disabled"); + changeLauncherActivityStateButton.setEnabled(false); + changeLauncherActivityStateButton.setAlpha(.5f); + changeLauncherActivityStateButton.setText(com.termux.shared.R.string.action_disable_launcher_icon); + changeLauncherActivityStateButton.setOnClickListener(null); + return; + } + + changeLauncherActivityStateButton.setEnabled(true); + changeLauncherActivityStateButton.setAlpha(1f); + if (currentlyDisabled) { + changeLauncherActivityStateButton.setText(com.termux.shared.R.string.action_enable_launcher_icon); + stateChangeMessage = getString(com.termux.shared.R.string.msg_enabling_launcher_icon, TermuxConstants.TERMUX_API_APP_NAME); + newState = true; + } else { + changeLauncherActivityStateButton.setText(com.termux.shared.R.string.action_disable_launcher_icon); + stateChangeMessage = getString(com.termux.shared.R.string.msg_disabling_launcher_icon, TermuxConstants.TERMUX_API_APP_NAME); + newState = false; + } + + changeLauncherActivityStateButton.setOnClickListener(v -> { + Logger.logInfo(LOG_TAG, stateChangeMessage); + String errmsg = PackageUtils.setComponentState(this, + packageName, className, newState, stateChangeMessage, true); + if (errmsg == null) + setChangeLauncherActivityStateViews(); + else + Logger.logError(LOG_TAG, errmsg); + }); + } + + + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Logger.logVerbose(LOG_TAG, "onActivityResult: requestCode: " + requestCode + ", resultCode: " + resultCode + ", data: " + IntentUtils.getIntentString(data)); + + switch (requestCode) { + case PermissionUtils.REQUEST_DISABLE_BATTERY_OPTIMIZATIONS: + if(PermissionUtils.checkIfBatteryOptimizationsDisabled(this)) + Logger.logDebug(LOG_TAG, "Battery optimizations disabled by user on request."); + else + Logger.logDebug(LOG_TAG, "Battery optimizations not disabled by user on request."); + break; + case PermissionUtils.REQUEST_GRANT_DISPLAY_OVER_OTHER_APPS_PERMISSION: + if(PermissionUtils.checkDisplayOverOtherAppsPermission(this)) + Logger.logDebug(LOG_TAG, "Display over other apps granted by user on request."); + else + Logger.logDebug(LOG_TAG, "Display over other apps denied by user on request."); + break; + default: + Logger.logError(LOG_TAG, "Unknown request code \"" + requestCode + "\" passed to onRequestPermissionsResult"); + } + } + + + + private void openSettings() { + ActivityUtils.startActivity(this, new Intent().setClass(this, TermuxAPISettingsActivity.class)); + } + +} diff --git a/app/src/main/java/com/termux/api/activities/TermuxApiPermissionActivity.java b/app/src/main/java/com/termux/api/activities/TermuxApiPermissionActivity.java new file mode 100644 index 000000000..a7a2cb634 --- /dev/null +++ b/app/src/main/java/com/termux/api/activities/TermuxApiPermissionActivity.java @@ -0,0 +1,79 @@ +package com.termux.api.activities; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; +import android.util.JsonWriter; + +import com.termux.api.util.ResultReturner; +import com.termux.shared.android.PermissionUtils; +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.TermuxConstants; + +import java.util.ArrayList; + +public class TermuxApiPermissionActivity extends Activity { + + private static final String LOG_TAG = "TermuxApiPermissionActivity"; + + /** + * Intent extra containing the permissions to request. + */ + public static final String PERMISSIONS_EXTRA = TermuxConstants.TERMUX_API_PACKAGE_NAME + ".permission_extra"; + + /** + * Check for and request permissions if necessary. + * + * @return if all permissions were already granted + */ + public static boolean checkAndRequestPermissions(Context context, Intent intent, String... permissions) { + final ArrayList permissionsToRequest = new ArrayList<>(); + for (String permission : permissions) { + if (!PermissionUtils.checkPermission(context, permission)) { + permissionsToRequest.add(permission); + } + } + + if (permissionsToRequest.isEmpty()) { + return true; + } else { + ResultReturner.returnData(context, intent, new ResultReturner.ResultJsonWriter() { + @Override + public void writeJson(JsonWriter out) throws Exception { + String errorMessage = "Please grant the following permission" + + (permissionsToRequest.size() > 1 ? "s" : "") + + " to use this command: " + + TextUtils.join(" ,", permissionsToRequest); + out.beginObject().name("error").value(errorMessage).endObject(); + } + }); + + Intent startIntent = new Intent(context, TermuxApiPermissionActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .putStringArrayListExtra(TermuxApiPermissionActivity.PERMISSIONS_EXTRA, permissionsToRequest); + ResultReturner.copyIntentExtras(intent, startIntent); + context.startActivity(startIntent); + return false; + } + } + + @Override + protected void onNewIntent(Intent intent) { + Logger.logDebug(LOG_TAG, "onNewIntent"); + + super.onNewIntent(intent); + setIntent(intent); + } + + @Override + protected void onResume() { + Logger.logVerbose(LOG_TAG, "onResume"); + + super.onResume(); + ArrayList permissionValues = getIntent().getStringArrayListExtra(PERMISSIONS_EXTRA); + PermissionUtils.requestPermissions(this, permissionValues.toArray(new String[0]), 0); + finish(); + } + +} diff --git a/app/src/main/java/com/termux/api/apis/AudioAPI.java b/app/src/main/java/com/termux/api/apis/AudioAPI.java new file mode 100644 index 000000000..d69800b62 --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/AudioAPI.java @@ -0,0 +1,90 @@ +package com.termux.api.apis; + +import android.content.Context; +import android.content.Intent; +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.AudioTrack; +import android.os.Build; +import android.util.JsonWriter; + +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; + +public class AudioAPI { + + private static final String LOG_TAG = "AudioAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + final String SampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); + final String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER); + final boolean bluetootha2dp = am.isBluetoothA2dpOn(); + final boolean wiredhs = am.isWiredHeadsetOn(); + + final int sr, bs, sr_ll, bs_ll, sr_ps, bs_ps; + AudioTrack at; + at = new AudioTrack.Builder() + .setBufferSizeInBytes(4) // one 16bit 2ch frame + .build(); + sr = at.getSampleRate(); + bs = at.getBufferSizeInFrames(); + at.release(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + at = new AudioTrack.Builder() + .setBufferSizeInBytes(4) // one 16bit 2ch frame + .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY) + .build(); + } else { + AudioAttributes aa = new AudioAttributes.Builder() + .setFlags(AudioAttributes.FLAG_LOW_LATENCY) + .build(); + at = new AudioTrack.Builder() + .setAudioAttributes(aa) + .setBufferSizeInBytes(4) // one 16bit 2ch frame + .build(); + } + sr_ll = at.getSampleRate(); + bs_ll = at.getBufferSizeInFrames(); + at.release(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + at = new AudioTrack.Builder() + .setBufferSizeInBytes(4) // one 16bit 2ch frame + .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_POWER_SAVING) + .build(); + sr_ps = at.getSampleRate(); + bs_ps = at.getBufferSizeInFrames(); + at.release(); + } else { + sr_ps = sr; + bs_ps = bs; + } + + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { + public void writeJson(JsonWriter out) throws Exception { + out.beginObject(); + out.name("PROPERTY_OUTPUT_SAMPLE_RATE").value(SampleRate); + out.name("PROPERTY_OUTPUT_FRAMES_PER_BUFFER").value(framesPerBuffer); + out.name("AUDIOTRACK_SAMPLE_RATE").value(sr); + out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES").value(bs); + if (sr_ll != sr || bs_ll != bs) { // all or nothing + out.name("AUDIOTRACK_SAMPLE_RATE_LOW_LATENCY").value(sr_ll); + out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES_LOW_LATENCY").value(bs_ll); + } + if (sr_ps != sr || bs_ps != bs) { // all or nothing + out.name("AUDIOTRACK_SAMPLE_RATE_POWER_SAVING").value(sr_ps); + out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES_POWER_SAVING").value(bs_ps); + } + out.name("BLUETOOTH_A2DP_IS_ON").value(bluetootha2dp); + out.name("WIREDHEADSET_IS_CONNECTED").value(wiredhs); + out.endObject(); + } + }); + } + +} diff --git a/app/src/main/java/com/termux/api/apis/BatteryStatusAPI.java b/app/src/main/java/com/termux/api/apis/BatteryStatusAPI.java new file mode 100644 index 000000000..557bc9458 --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/BatteryStatusAPI.java @@ -0,0 +1,196 @@ +package com.termux.api.apis; + +import static com.termux.api.util.JsonUtils.*; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; +import android.os.Build; +import android.util.JsonWriter; + +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.ResultReturner; +import com.termux.api.util.ResultReturner.ResultJsonWriter; +import com.termux.shared.logger.Logger; + +public class BatteryStatusAPI { + + private static final String LOG_TAG = "BatteryStatusAPI"; + + private static int sTargetSdkVersion; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + sTargetSdkVersion = context.getApplicationContext().getApplicationInfo().targetSdkVersion; + + ResultReturner.returnData(apiReceiver, intent, new ResultJsonWriter() { + @SuppressLint("DefaultLocale") + @Override + public void writeJson(JsonWriter out) throws Exception { + // - https://cs.android.com/android/platform/superproject/+/android-15.0.0_r1:frameworks/base/services/core/java/com/android/server/BatteryService.java;l=745 + Intent batteryStatus = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + if (batteryStatus == null) batteryStatus = new Intent(); + + int batteryLevel = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); + int batteryScale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + + int health = batteryStatus.getIntExtra(BatteryManager.EXTRA_HEALTH, -1); + String batteryHealth; + switch (health) { + case BatteryManager.BATTERY_HEALTH_COLD: + batteryHealth = "COLD"; + break; + case BatteryManager.BATTERY_HEALTH_DEAD: + batteryHealth = "DEAD"; + break; + case BatteryManager.BATTERY_HEALTH_GOOD: + batteryHealth = "GOOD"; + break; + case BatteryManager.BATTERY_HEALTH_OVERHEAT: + batteryHealth = "OVERHEAT"; + break; + case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE: + batteryHealth = "OVER_VOLTAGE"; + break; + case BatteryManager.BATTERY_HEALTH_UNKNOWN: + batteryHealth = "UNKNOWN"; + break; + case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE: + batteryHealth = "UNSPECIFIED_FAILURE"; + break; + default: + batteryHealth = Integer.toString(health); + } + + // BatteryManager.EXTRA_PLUGGED: "Extra for ACTION_BATTERY_CHANGED: integer indicating whether the + // device is plugged in to a power source; 0 means it is on battery, other constants are different types + // of power sources." + int pluggedInt = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + String batteryPlugged; + switch (pluggedInt) { + case 0: + batteryPlugged = "UNPLUGGED"; + break; + case BatteryManager.BATTERY_PLUGGED_AC: + batteryPlugged = "PLUGGED_AC"; + break; + case BatteryManager.BATTERY_PLUGGED_DOCK: + batteryPlugged = "PLUGGED_DOCK"; + break; + case BatteryManager.BATTERY_PLUGGED_USB: + batteryPlugged = "PLUGGED_USB"; + break; + case BatteryManager.BATTERY_PLUGGED_WIRELESS: + batteryPlugged = "PLUGGED_WIRELESS"; + break; + default: + batteryPlugged = "PLUGGED_" + pluggedInt; + } + + // Android returns battery temperature as int in tenths of degrees Celsius, like 255, so convert it to a decimal like 25.5°C. + // - https://cs.android.com/android/platform/superproject/+/android-15.0.0_r1:hardware/interfaces/health/aidl/android/hardware/health/HealthInfo.aidl;l=77-80 + double batteryTemperature = ((double) batteryStatus.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, Integer.MIN_VALUE)) / 10f; + // Round the value to 1 decimal place. + batteryTemperature = (double) Math.round(batteryTemperature * 10.0f) / 10.0f; + + String batteryStatusString; + int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + switch (status) { + case BatteryManager.BATTERY_STATUS_CHARGING: + batteryStatusString = "CHARGING"; + break; + case BatteryManager.BATTERY_STATUS_DISCHARGING: + batteryStatusString = "DISCHARGING"; + break; + case BatteryManager.BATTERY_STATUS_FULL: + batteryStatusString = "FULL"; + break; + case BatteryManager.BATTERY_STATUS_NOT_CHARGING: + batteryStatusString = "NOT_CHARGING"; + break; + case BatteryManager.BATTERY_STATUS_UNKNOWN: + batteryStatusString = "UNKNOWN"; + break; + default: + Logger.logError(LOG_TAG, "Invalid BatteryManager.EXTRA_STATUS value: " + status); + batteryStatusString = "UNKNOWN"; + } + + // - https://stackoverflow.com/questions/24500795/android-battery-voltage-unit-discrepancies + int batteryVoltage = batteryStatus.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1); + // If in V, convert to mV. + if (batteryVoltage < 100) { + Logger.logVerbose(LOG_TAG, "Fixing voltage from " + batteryVoltage + " to " + (batteryVoltage * 1000)); + batteryVoltage = batteryVoltage * 1000; + } + + BatteryManager batteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE); + + // > Instantaneous battery current in microamperes, as an integer. + // > Positive values indicate net current entering the battery from a charge source, + // > negative values indicate net current discharging from the battery. + // However, some devices may return negative values while charging, and positive + // values while discharging. Inverting sign based on charging state is not a + // possibility as charging current may be lower than current being used by device if + // charger does not output enough current, and will result in false inversions. + // - https://developer.android.com/reference/android/os/BatteryManager#BATTERY_PROPERTY_CURRENT_NOW + // - https://issuetracker.google.com/issues/37131318 + Integer batteryCurrentNow = getIntProperty(batteryManager, BatteryManager.BATTERY_PROPERTY_CURRENT_NOW); + + // - https://stackoverflow.com/questions/64532112/batterymanagers-battery-property-current-now-returning-0-or-incorrect-current-v + if (batteryCurrentNow != null && Math.abs(batteryCurrentNow / 1000) < 1.0) { + Logger.logVerbose(LOG_TAG, "Fixing current_now from " + batteryCurrentNow + " to " + (batteryCurrentNow * 1000)); + batteryCurrentNow = batteryCurrentNow * 1000; + } + + out.beginObject(); + putBooleanValueIfSet(out, "present", batteryStatus.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false)); + putStringIfSet(out, "technology", batteryStatus.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY)); + putStringIfSet(out, "health", batteryHealth); + putStringIfSet(out, "plugged", batteryPlugged); + putStringIfSet(out, "status", batteryStatusString); + putDoubleIfSet(out, "temperature", batteryTemperature); + putIntegerIfSet(out, "voltage", batteryVoltage); + putIntegerIfSet(out, "current", batteryCurrentNow); + putIntegerIfSet(out, "current_average", getIntProperty(batteryManager, BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE)); + putIntegerIfSet(out, "percentage", getIntProperty(batteryManager, BatteryManager.BATTERY_PROPERTY_CAPACITY)); + putIntegerIfSet(out, "level", batteryLevel); + putIntegerIfSet(out, "scale", batteryScale); + putIntegerIfSet(out, "charge_counter", getIntProperty(batteryManager, BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)); + putLongIfSet(out, "energy", getLongProperty(batteryManager, BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + int batteryCycle = batteryStatus.getIntExtra(BatteryManager.EXTRA_CYCLE_COUNT, -1); + putIntegerIfSet(out, "cycle", batteryCycle != -1 ? batteryCycle : null); + } + out.endObject(); + } + }); + } + + + + /** + * - https://developer.android.com/reference/android/os/BatteryManager.html#getIntProperty(int) + */ + private static Integer getIntProperty(BatteryManager batteryManager, int id) { + if (batteryManager == null) return null; + int value = batteryManager.getIntProperty(id); + if (sTargetSdkVersion < Build.VERSION_CODES.P) + return value != 0 ? value : null; + else + return value != Integer.MIN_VALUE ? value : null; + } + + /** + * - https://developer.android.com/reference/android/os/BatteryManager.html#getLongProperty(int) + */ + private static Long getLongProperty(BatteryManager batteryManager, int id) { + if (batteryManager == null) return null; + long value = batteryManager.getLongProperty(id); + return value != Long.MIN_VALUE ? value : null; + } + +} diff --git a/app/src/main/java/com/termux/api/BrightnessAPI.java b/app/src/main/java/com/termux/api/apis/BrightnessAPI.java similarity index 83% rename from app/src/main/java/com/termux/api/BrightnessAPI.java rename to app/src/main/java/com/termux/api/apis/BrightnessAPI.java index 198dc962a..7bbeb5b8c 100644 --- a/app/src/main/java/com/termux/api/BrightnessAPI.java +++ b/app/src/main/java/com/termux/api/apis/BrightnessAPI.java @@ -1,15 +1,21 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.provider.Settings; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; public class BrightnessAPI { + private static final String LOG_TAG = "BrightnessAPI"; + public static void onReceive(final TermuxApiReceiver receiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + final ContentResolver contentResolver = context.getContentResolver(); if (intent.hasExtra("auto")) { boolean auto = intent.getBooleanExtra("auto", false); diff --git a/app/src/main/java/com/termux/api/apis/CallLogAPI.java b/app/src/main/java/com/termux/api/apis/CallLogAPI.java new file mode 100644 index 000000000..39c60b546 --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/CallLogAPI.java @@ -0,0 +1,110 @@ +package com.termux.api.apis; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.provider.CallLog; +import android.util.JsonWriter; + +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; + +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * API that allows you to get call log history information + */ +public class CallLogAPI { + + private static final String LOG_TAG = "CallLogAPI"; + + public static void onReceive(final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + final int offset = intent.getIntExtra("offset", 0); + final int limit = intent.getIntExtra("limit", 50); + + ResultReturner.returnData(context, intent, new ResultReturner.ResultJsonWriter() { + public void writeJson(JsonWriter out) throws Exception { + getCallLogs(context, out, offset, limit); + } + }); + + } + + private static void getCallLogs(Context context, JsonWriter out, int offset, int limit) throws IOException { + ContentResolver contentResolver = context.getContentResolver(); + + try (Cursor cur = contentResolver.query(CallLog.Calls.CONTENT_URI.buildUpon(). + appendQueryParameter(CallLog.Calls.LIMIT_PARAM_KEY, String.valueOf(limit)). + appendQueryParameter(CallLog.Calls.OFFSET_PARAM_KEY, String.valueOf(offset)) + .build(), null, null, null, "date DESC")) { + cur.moveToLast(); + + int nameIndex = cur.getColumnIndex(CallLog.Calls.CACHED_NAME); + int numberIndex = cur.getColumnIndex(CallLog.Calls.NUMBER); + int dateIndex = cur.getColumnIndex(CallLog.Calls.DATE); + int durationIndex = cur.getColumnIndex(CallLog.Calls.DURATION); + int callTypeIndex = cur.getColumnIndex(CallLog.Calls.TYPE); + int simTypeIndex = cur.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID); + + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + out.beginArray(); + + for (int j = 0, count = cur.getCount(); j < count; ++j) { + out.beginObject(); + + out.name("name").value(getCallerNameString(cur.getString(nameIndex))); + out.name("phone_number").value(cur.getString(numberIndex)); + out.name("type").value(getCallTypeString(cur.getInt(callTypeIndex))); + out.name("date").value(getDateString(cur.getLong(dateIndex), dateFormat)); + out.name("duration").value(getTimeString(cur.getInt(durationIndex))); + out.name("sim_id").value(cur.getString(simTypeIndex)); + + cur.moveToPrevious(); + out.endObject(); + } + out.endArray(); + } + } + + private static String getCallTypeString(int type) { + switch (type) { + case CallLog.Calls.BLOCKED_TYPE: return "BLOCKED"; + case CallLog.Calls.INCOMING_TYPE: return "INCOMING"; + case CallLog.Calls.MISSED_TYPE: return "MISSED"; + case CallLog.Calls.OUTGOING_TYPE: return "OUTGOING"; + case CallLog.Calls.REJECTED_TYPE: return "REJECTED"; + case CallLog.Calls.VOICEMAIL_TYPE: return "VOICEMAIL"; + default: return "UNKNOWN_TYPE"; + } + } + + private static String getCallerNameString(String name) { + return name == null ? "UNKNOWN_CALLER" : name; + } + + private static String getDateString(Long date, DateFormat dateFormat) { + return dateFormat.format(new Date(date)); + } + + private static String getTimeString(int totalSeconds) { + int hours = (totalSeconds / 3600); + int mins = (totalSeconds % 3600) / 60; + int secs = (totalSeconds % 60); + + String result = ""; + + // only show hours if we have them + if (hours > 0) { + result += String.format(Locale.getDefault(), "%02d:", hours); + } + result += String.format(Locale.getDefault(), "%02d:%02d", mins, secs); + return result; + } +} diff --git a/app/src/main/java/com/termux/api/CameraInfoAPI.java b/app/src/main/java/com/termux/api/apis/CameraInfoAPI.java similarity index 69% rename from app/src/main/java/com/termux/api/CameraInfoAPI.java rename to app/src/main/java/com/termux/api/apis/CameraInfoAPI.java index 93088c0ae..bf27a0f4d 100644 --- a/app/src/main/java/com/termux/api/CameraInfoAPI.java +++ b/app/src/main/java/com/termux/api/apis/CameraInfoAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.Context; import android.content.Intent; @@ -11,12 +11,18 @@ import android.util.Size; import android.util.SizeF; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; import com.termux.api.util.ResultReturner.ResultJsonWriter; +import com.termux.shared.logger.Logger; public class CameraInfoAPI { - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + private static final String LOG_TAG = "CameraInfoAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + ResultReturner.returnData(apiReceiver, intent, new ResultJsonWriter() { @Override public void writeJson(JsonWriter out) throws Exception { @@ -73,6 +79,9 @@ public void writeJson(JsonWriter out) throws Exception { case CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE: out.value("CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE"); break; + case CameraMetadata.CONTROL_AE_MODE_ON_EXTERNAL_FLASH: + out.value("CONTROL_AE_MODE_ON_EXTERNAL_FLASH"); + break; default: out.value(flashMode); } @@ -86,18 +95,45 @@ public void writeJson(JsonWriter out) throws Exception { out.name("capabilities").beginArray(); for (int capability : camera.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)) { switch (capability) { - case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR: - out.value("manual_sensor"); + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE: + out.value("backward_compatible"); + break; + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE: + out.value("burst_capture"); + break; + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO: + out.value("constrained_high_speed_video"); + break; + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT: + out.value("depth_output"); + break; + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA: + out.value("logical_multi_camera"); break; case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING: out.value("manual_post_processing"); break; - case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE: - out.value("backward_compatible"); + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR: + out.value("manual_sensor"); + break; + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME: + out.value("monochrome"); + break; + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING: + out.value("motion_tracking"); + break; + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING: + out.value("private_reprocessing"); break; case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW: out.value("raw"); break; + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS: + out.value("read_sensor_settings"); + break; + case CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING: + out.value("yuv_reprocessing"); + break; default: out.value(capability); } diff --git a/app/src/main/java/com/termux/api/PhotoAPI.java b/app/src/main/java/com/termux/api/apis/CameraPhotoAPI.java similarity index 65% rename from app/src/main/java/com/termux/api/PhotoAPI.java rename to app/src/main/java/com/termux/api/apis/CameraPhotoAPI.java index 86a851692..3cc6738a0 100644 --- a/app/src/main/java/com/termux/api/PhotoAPI.java +++ b/app/src/main/java/com/termux/api/apis/CameraPhotoAPI.java @@ -1,8 +1,9 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.Context; import android.content.Intent; import android.graphics.ImageFormat; +import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; @@ -19,8 +20,12 @@ import android.view.Surface; import android.view.WindowManager; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.errors.Error; +import com.termux.shared.file.FileUtils; +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.file.TermuxFileUtils; import java.io.File; import java.io.FileOutputStream; @@ -33,20 +38,41 @@ import java.util.List; import java.util.Objects; -public class PhotoAPI { +public class CameraPhotoAPI { + + private static final String LOG_TAG = "CameraPhotoAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { final String filePath = intent.getStringExtra("file"); - final File outputFile = new File(filePath); - final File outputDir = outputFile.getParentFile(); final String cameraId = Objects.toString(intent.getStringExtra("camera"), "0"); ResultReturner.returnData(apiReceiver, intent, stdout -> { - if (!(outputDir.isDirectory() || outputDir.mkdirs())) { - stdout.println("Not a folder (and unable to create it): " + outputDir.getAbsolutePath()); - } else { - takePicture(stdout, context, outputFile, cameraId); + if (filePath == null || filePath.isEmpty()) { + stdout.println("ERROR: " + "File path not passed"); + return; } + + // Get canonical path of photoFilePath + String photoFilePath = TermuxFileUtils.getCanonicalPath(filePath, null, true); + String photoDirPath = FileUtils.getFileDirname(photoFilePath); + Logger.logVerbose(LOG_TAG, "photoFilePath=\"" + photoFilePath + "\", photoDirPath=\"" + photoDirPath + "\""); + + // If workingDirectory is not a directory, or is not readable or writable, then just return + // Creation of missing directory and setting of read, write and execute permissions are only done if workingDirectory is + // under allowed termux working directory paths. + // We try to set execute permissions, but ignore if they are missing, since only read and write permissions are required + // for working directories. + Error error = TermuxFileUtils.validateDirectoryFileExistenceAndPermissions("photo directory", photoDirPath, + true, true, true, + false, true); + if (error != null) { + stdout.println("ERROR: " + error.getErrorLogString()); + return; + } + + takePicture(stdout, context, new File(photoFilePath), cameraId); }); } @@ -64,26 +90,26 @@ public void onOpened(final CameraDevice camera) { try { proceedWithOpenedCamera(context, manager, camera, outputFile, looper, stdout); } catch (Exception e) { - TermuxApiLogger.error("Exception in onOpened()", e); + Logger.logStackTraceWithMessage(LOG_TAG, "Exception in onOpened()", e); closeCamera(camera, looper); } } @Override public void onDisconnected(CameraDevice camera) { - TermuxApiLogger.info("onDisconnected() from camera"); + Logger.logInfo(LOG_TAG, "onDisconnected() from camera"); } @Override public void onError(CameraDevice camera, int error) { - TermuxApiLogger.error("Failed opening camera: " + error); + Logger.logError(LOG_TAG, "Failed opening camera: " + error); closeCamera(camera, looper); } }, null); Looper.loop(); } catch (Exception e) { - TermuxApiLogger.error("Error getting camera", e); + Logger.logStackTraceWithMessage(LOG_TAG, "Error getting camera", e); } } @@ -124,20 +150,40 @@ public void run() { output.write(bytes); } catch (Exception e) { stdout.println("Error writing image: " + e.getMessage()); - TermuxApiLogger.error("Error writing image", e); - } finally { - closeCamera(camera, looper); + Logger.logStackTraceWithMessage(LOG_TAG, "Error writing image", e); } + } finally { + mImageReader.close(); + releaseSurfaces(outputSurfaces); + closeCamera(camera, looper); } } }.start(), null); final Surface imageReaderSurface = mImageReader.getSurface(); outputSurfaces.add(imageReaderSurface); + // create a dummy PreviewSurface + SurfaceTexture previewTexture = new SurfaceTexture(1); + Surface dummySurface = new Surface(previewTexture); + outputSurfaces.add(dummySurface); + camera.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(final CameraCaptureSession session) { try { + // create preview Request + CaptureRequest.Builder previewReq = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); + previewReq.addTarget(dummySurface); + previewReq.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + previewReq.set(CaptureRequest.CONTROL_AE_MODE, autoExposureModeFinal); + + // continous preview-capture for 1/2 second + session.setRepeatingRequest(previewReq.build(), null, null); + Logger.logInfo(LOG_TAG, "preview started"); + Thread.sleep(500); + session.stopRepeating(); + Logger.logInfo(LOG_TAG, "preview stoppend"); + final CaptureRequest.Builder jpegRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); // Render to our image reader: jpegRequest.addTarget(imageReaderSurface); @@ -148,14 +194,18 @@ public void onConfigured(final CameraCaptureSession session) { saveImage(camera, session, jpegRequest.build()); } catch (Exception e) { - TermuxApiLogger.error("onConfigured() error in preview", e); + Logger.logStackTraceWithMessage(LOG_TAG, "onConfigured() error in preview", e); + mImageReader.close(); + releaseSurfaces(outputSurfaces); closeCamera(camera, looper); } } @Override public void onConfigureFailed(CameraCaptureSession session) { - TermuxApiLogger.error("onConfigureFailed() error in preview"); + Logger.logError(LOG_TAG, "onConfigureFailed() error in preview"); + mImageReader.close(); + releaseSurfaces(outputSurfaces); closeCamera(camera, looper); } }, null); @@ -165,8 +215,7 @@ static void saveImage(final CameraDevice camera, CameraCaptureSession session, C session.capture(request, new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(CameraCaptureSession completedSession, CaptureRequest request, TotalCaptureResult result) { - TermuxApiLogger.info("onCaptureCompleted()"); - closeCamera(camera, null); + Logger.logInfo(LOG_TAG, "onCaptureCompleted()"); } }, null); } @@ -178,13 +227,13 @@ public void onCaptureCompleted(CameraCaptureSession completedSession, CaptureReq static int correctOrientation(final Context context, final CameraCharacteristics characteristics) { final Integer lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING); final boolean isFrontFacing = lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_FRONT; - TermuxApiLogger.info((isFrontFacing ? "Using" : "Not using") + " a front facing camera."); + Logger.logInfo(LOG_TAG, (isFrontFacing ? "Using" : "Not using") + " a front facing camera."); Integer sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); if (sensorOrientation != null) { - TermuxApiLogger.info(String.format("Sensor orientation: %s degrees", sensorOrientation)); + Logger.logInfo(LOG_TAG, String.format("Sensor orientation: %s degrees", sensorOrientation)); } else { - TermuxApiLogger.info("CameraCharacteristics didn't contain SENSOR_ORIENTATION. Assuming 0 degrees."); + Logger.logInfo(LOG_TAG, "CameraCharacteristics didn't contain SENSOR_ORIENTATION. Assuming 0 degrees."); sensorOrientation = 0; } @@ -205,11 +254,11 @@ static int correctOrientation(final Context context, final CameraCharacteristics deviceOrientation = 270; break; default: - TermuxApiLogger.info( + Logger.logInfo(LOG_TAG, String.format("Default display has unknown rotation %d. Assuming 0 degrees.", deviceRotation)); deviceOrientation = 0; } - TermuxApiLogger.info(String.format("Device orientation: %d degrees", deviceOrientation)); + Logger.logInfo(LOG_TAG, String.format("Device orientation: %d degrees", deviceOrientation)); int jpegOrientation; if (isFrontFacing) { @@ -219,15 +268,22 @@ static int correctOrientation(final Context context, final CameraCharacteristics } // Add an extra 360 because (-90 % 360) == -90 and Android won't accept a negative rotation. jpegOrientation = (jpegOrientation + 360) % 360; - TermuxApiLogger.info(String.format("Returning JPEG orientation of %d degrees", jpegOrientation)); + Logger.logInfo(LOG_TAG, String.format("Returning JPEG orientation of %d degrees", jpegOrientation)); return jpegOrientation; } + static void releaseSurfaces(List outputSurfaces) { + for (Surface outputSurface : outputSurfaces) { + outputSurface.release(); + } + Logger.logInfo(LOG_TAG, "surfaces released"); + } + static void closeCamera(CameraDevice camera, Looper looper) { try { camera.close(); } catch (RuntimeException e) { - TermuxApiLogger.info("Exception closing camera: " + e.getMessage()); + Logger.logInfo(LOG_TAG, "Exception closing camera: " + e.getMessage()); } if (looper != null) looper.quit(); } diff --git a/app/src/main/java/com/termux/api/ClipboardAPI.java b/app/src/main/java/com/termux/api/apis/ClipboardAPI.java similarity index 89% rename from app/src/main/java/com/termux/api/ClipboardAPI.java rename to app/src/main/java/com/termux/api/apis/ClipboardAPI.java index e88583e1a..83d4ab640 100644 --- a/app/src/main/java/com/termux/api/ClipboardAPI.java +++ b/app/src/main/java/com/termux/api/apis/ClipboardAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.ClipData; import android.content.ClipData.Item; @@ -7,13 +7,19 @@ import android.content.Intent; import android.text.TextUtils; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; import java.io.PrintWriter; public class ClipboardAPI { - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + private static final String LOG_TAG = "ClipboardAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); final ClipData clipData = clipboard.getPrimaryClip(); diff --git a/app/src/main/java/com/termux/api/ContactListAPI.java b/app/src/main/java/com/termux/api/apis/ContactListAPI.java similarity index 88% rename from app/src/main/java/com/termux/api/ContactListAPI.java rename to app/src/main/java/com/termux/api/apis/ContactListAPI.java index 12df9393c..142e2a488 100644 --- a/app/src/main/java/com/termux/api/ContactListAPI.java +++ b/app/src/main/java/com/termux/api/apis/ContactListAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.ContentResolver; import android.content.Context; @@ -10,12 +10,18 @@ import android.util.JsonWriter; import android.util.SparseArray; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; import com.termux.api.util.ResultReturner.ResultJsonWriter; +import com.termux.shared.logger.Logger; public class ContactListAPI { - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + private static final String LOG_TAG = "ContactListAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + ResultReturner.returnData(apiReceiver, intent, new ResultJsonWriter() { @Override public void writeJson(JsonWriter out) throws Exception { diff --git a/app/src/main/java/com/termux/api/apis/DialogAPI.java b/app/src/main/java/com/termux/api/apis/DialogAPI.java new file mode 100644 index 000000000..c3c9d2c79 --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/DialogAPI.java @@ -0,0 +1,1078 @@ +package com.termux.api.apis; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ActivityManager; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.speech.RecognitionListener; +import android.speech.RecognizerIntent; +import android.speech.SpeechRecognizer; +import android.text.InputType; +import android.util.JsonWriter; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.ScrollView; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.TimePicker; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.widget.NestedScrollView; + +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.termux.api.R; +import com.termux.api.util.ResultReturner; +import com.termux.api.activities.TermuxApiPermissionActivity; +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.termux.theme.TermuxThemeUtils; +import com.termux.shared.theme.NightMode; +import com.termux.shared.theme.ThemeUtils; +import com.termux.shared.view.KeyboardUtils; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +/** + * API that allows receiving user input interactively in a variety of different ways + */ +public class DialogAPI { + + private static final String LOG_TAG = "DialogAPI"; + + public static void onReceive(final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + context.startActivity(new Intent(context, DialogActivity.class).putExtras(intent.getExtras()).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + + + + public static class DialogActivity extends AppCompatActivity { + + private static final String LOG_TAG = "DialogActivity"; + + private volatile boolean resultReturned = false; + private InputMethod mInputMethod; + + @Override + protected void onCreate(Bundle savedInstanceState) { + Logger.logDebug(LOG_TAG, "onCreate"); + + super.onCreate(savedInstanceState); + final Intent intent = getIntent(); + final Context context = this; + + + String methodType = intent.hasExtra("input_method") ? intent.getStringExtra("input_method") : ""; + + // Set NightMode.APP_NIGHT_MODE + TermuxThemeUtils.setAppNightMode(context); + boolean shouldEnableDarkTheme = ThemeUtils.shouldEnableDarkTheme(this, NightMode.getAppNightMode().getName()); + if (shouldEnableDarkTheme) + this.setTheme(R.style.DialogTheme_Dark); + + mInputMethod = InputMethodFactory.get(methodType, this); + if (mInputMethod != null) { + mInputMethod.create(this, result -> { + postResult(context, result); + finish(); + }); + } else { + InputResult result = new InputResult(); + result.error = "Unknown Input Method: " + methodType; + postResult(context, result); + } + } + + @Override + protected void onNewIntent(Intent intent) { + Logger.logDebug(LOG_TAG, "onNewIntent"); + + super.onNewIntent(intent); + setIntent(intent); + } + + @Override + protected void onDestroy() { + Logger.logDebug(LOG_TAG, "onDestroy"); + + super.onDestroy(); + + postResult(this, null); + + if (mInputMethod != null) { + Dialog dialog = mInputMethod.getDialog(); + dismissDialog(dialog); + } + } + + private static void dismissDialog(Dialog dialog) { + try { + if (dialog != null) + dialog.dismiss(); + } catch (Exception e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Failed tp dismiss dialog", e); + } + } + + /** + * Extract value extras from intent into String array + */ + static String[] getInputValues(Intent intent) { + String[] items = new String[] { }; + + if (intent != null && intent.hasExtra("input_values")) { + String[] temp = intent.getStringExtra("input_values").split("(? -1) { + out.name("index").value(result.index); + } + if (result.values.size() > 0) { + out.name("values"); + out.beginArray(); + for (Value value : result.values) { + out.beginObject(); + out.name("index").value(value.index); + out.name("text").value(value.text); + out.endObject(); + } + out.endArray(); + } + if (!result.error.equals("")) { + out.name("error").value(result.error); + } + + out.endObject(); + out.flush(); + resultReturned = true; + } + }); + } + + + /** + * Factory for returning proper input method type that we received in our incoming intent + */ + static class InputMethodFactory { + + public static InputMethod get(final String type, final AppCompatActivity activity) { + + switch (type == null ? "" : type) { + case "confirm": + return new ConfirmInputMethod(activity); + case "checkbox": + return new CheckBoxInputMethod(activity); + case "counter": + return new CounterInputMethod(activity); + case "date": + return new DateInputMethod(activity); + case "radio": + return new RadioInputMethod(activity); + case "sheet": + return new BottomSheetInputMethod(); + case "speech": + return new SpeechInputMethod(activity); + case "spinner": + return new SpinnerInputMethod(activity); + case "text": + return new TextInputMethod(activity); + case "time": + return new TimeInputMethod(activity); + default: + return null; + } + } + } + + + /** + * Interface for creating an input method type + */ + interface InputMethod { + Dialog getDialog(); + + void create(AppCompatActivity activity, InputResultListener resultListener); + } + + + /** + * Callback interface for receiving an InputResult + */ + interface InputResultListener { + void onResult(InputResult result); + } + + + /** + * Simple POJO to store the result of input methods + */ + static class InputResult { + public String text = ""; + public String error = ""; + public int code = 0; + public static int index = -1; + public List values = new ArrayList<>(); + } + + + public static class Value { + public int index = -1; + public String text = ""; + } + + /* + * -------------------------------------- + * InputMethod Implementations + * -------------------------------------- + */ + + + /** + * CheckBox InputMethod + * Allow users to select multiple options from a range of values + */ + static class CheckBoxInputMethod extends InputDialog { + + CheckBoxInputMethod(AppCompatActivity activity) { + super(activity); + } + + @Override + LinearLayout createWidgetView(AppCompatActivity activity) { + LinearLayout layout = new LinearLayout(activity); + layout.setOrientation(LinearLayout.VERTICAL); + + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + layoutParams.topMargin = 32; + layoutParams.bottomMargin = 32; + + String[] values = getInputValues(activity.getIntent()); + + for (int j = 0; j < values.length; ++j) { + String value = values[j]; + + CheckBox checkBox = new CheckBox(activity); + checkBox.setText(value); + checkBox.setId(j); + checkBox.setTextSize(18); + checkBox.setPadding(16, 16, 16, 16); + checkBox.setLayoutParams(layoutParams); + + layout.addView(checkBox); + } + return layout; + } + + @Override + String getResult() { + int checkBoxCount = widgetView.getChildCount(); + + List values = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + sb.append("["); + + for (int j = 0; j < checkBoxCount; ++j) { + CheckBox box = widgetView.findViewById(j); + if (box.isChecked()) { + Value value = new Value(); + value.index = j; + value.text = box.getText().toString(); + values.add(value); + sb.append(box.getText().toString()).append(", "); + } + } + inputResult.values = values; + // remove trailing comma and add closing bracket + return sb.toString().replaceAll(", $", "") + "]"; + } + } + + + /** + * Confirm InputMethod + * Allow users to confirm YES or NO. + */ + static class ConfirmInputMethod extends InputDialog { + + ConfirmInputMethod(AppCompatActivity activity) { + super(activity); + } + + @Override + InputResult onDialogClick(int button) { + inputResult.text = button == Dialog.BUTTON_POSITIVE ? "yes" : "no"; + return inputResult; + } + + @Override + TextView createWidgetView(AppCompatActivity activity) { + TextView textView = new TextView(activity); + final Intent intent = activity.getIntent(); + + String text = intent.hasExtra("input_hint") ? intent.getStringExtra("input_hint") : "Confirm"; + textView.setText(text); + return textView; + } + + @Override + String getNegativeButtonText() { + return "No"; + } + + @Override + String getPositiveButtonText() { + return "Yes"; + } + } + + + /** + * Counter InputMethod + * Allow users to increment or decrement a number in a given range + */ + static class CounterInputMethod extends InputDialog { + static final int DEFAULT_MIN = 0; + static final int DEFAULT_MAX = 100; + static final int RANGE_LENGTH = 3; + + int min; + int max; + int counter; + + TextView counterLabel; + + CounterInputMethod(AppCompatActivity activity) { + super(activity); + } + + @Override + View createWidgetView(AppCompatActivity activity) { + View layout = View.inflate(activity, R.layout.dialog_counter, null); + counterLabel = layout.findViewById(R.id.counterTextView); + + final Button incrementButton = layout.findViewById(R.id.incrementButton); + incrementButton.setOnClickListener(view -> increment()); + + final Button decrementButton = layout.findViewById(R.id.decrementButton); + decrementButton.setOnClickListener(view -> decrement()); + updateCounterRange(); + + return layout; + } + + void updateCounterRange() { + final Intent intent = activity.getIntent(); + + if (intent.hasExtra("input_range")) { + int[] values = intent.getIntArrayExtra("input_range"); + if (values.length != RANGE_LENGTH) { + inputResult.error = "Invalid range! Must be 3 int values!"; + postCanceledResult(); + dismissDialog(dialog); + } else { + min = Math.min(values[0], values[1]); + max = Math.max(values[0], values[1]); + counter = values[2]; + } + } else { + min = DEFAULT_MIN; + max = DEFAULT_MAX; + + // halfway + counter = (DEFAULT_MAX - DEFAULT_MIN) / 2; + } + updateLabel(); + } + + @Override + String getResult() { + return counterLabel.getText().toString(); + } + + void updateLabel() { + counterLabel.setText(String.valueOf(counter)); + } + + void increment() { + if ((counter + 1) <= max) { + ++counter; + updateLabel(); + } + } + + void decrement() { + if ((counter - 1) >= min) { + --counter; + updateLabel(); + } + } + } + + + /** + * Date InputMethod + * Allow users to pick a specific date + */ + static class DateInputMethod extends InputDialog { + + DateInputMethod(AppCompatActivity activity) { + super(activity); + } + + @Override + String getResult() { + int month = widgetView.getMonth(); + int day = widgetView.getDayOfMonth(); + int year = widgetView.getYear(); + + Calendar calendar = Calendar.getInstance(); + calendar.set(year, month, day, 0, 0, 0); + + final Intent intent = activity.getIntent(); + if (intent.hasExtra("date_format")) { + String date_format = intent.getStringExtra("date_format"); + try { + SimpleDateFormat dateFormat = new SimpleDateFormat(date_format); + dateFormat.setTimeZone(calendar.getTimeZone()); + return dateFormat.format(calendar.getTime()); + } catch (Exception e) { + inputResult.error = e.toString(); + postCanceledResult(); + } + } + return calendar.getTime().toString(); + } + + @Override + DatePicker createWidgetView(AppCompatActivity activity) { + return new DatePicker(activity); + } + } + + + /** + * Text InputMethod + * Allow users to enter plaintext or a password + */ + static class TextInputMethod extends InputDialog { + + TextInputMethod(AppCompatActivity activity) { + super(activity); + } + + @Override + String getResult() { + return widgetView.getText().toString(); + } + + @Override + EditText createWidgetView(AppCompatActivity activity) { + final Intent intent = activity.getIntent(); + EditText editText = new EditText(activity); + + if (intent.hasExtra("input_hint")) { + editText.setHint(intent.getStringExtra("input_hint")); + } + + boolean multiLine = intent.getBooleanExtra("multiple_lines", false); + boolean numeric = intent.getBooleanExtra("numeric", false); + boolean password = intent.getBooleanExtra("password", false); + + int flags = InputType.TYPE_CLASS_TEXT; + + if (password) { + flags = numeric ? (flags | InputType.TYPE_NUMBER_VARIATION_PASSWORD) : (flags | InputType.TYPE_TEXT_VARIATION_PASSWORD); + } + + if (multiLine) { + flags |= InputType.TYPE_TEXT_FLAG_MULTI_LINE; + editText.setLines(4); + } + + if (numeric) { + flags &= ~InputType.TYPE_CLASS_TEXT; // clear to allow only numbers + flags |= InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED | InputType.TYPE_NUMBER_FLAG_DECIMAL; + } + + editText.setInputType(flags); + + return editText; + } + } + + + /** + * Time InputMethod + * Allow users to pick a specific time + */ + static class TimeInputMethod extends InputDialog { + + TimeInputMethod(AppCompatActivity activity) { + super(activity); + } + + @Override + String getResult() { + return String.format(Locale.getDefault(), "%02d:%02d", widgetView.getHour(), widgetView.getMinute()); + } + + @Override + TimePicker createWidgetView(AppCompatActivity activity) { + return new TimePicker(activity); + } + } + + + /** + * Radio InputMethod + * Allow users to confirm from radio button options + */ + static class RadioInputMethod extends InputDialog { + RadioGroup radioGroup; + + RadioInputMethod(AppCompatActivity activity) { + super(activity); + } + + @Override + RadioGroup createWidgetView(AppCompatActivity activity) { + radioGroup = new RadioGroup(activity); + radioGroup.setPadding(16, 16, 16, 16); + + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + layoutParams.topMargin = 32; + layoutParams.bottomMargin = 32; + + String[] values = getInputValues(activity.getIntent()); + + for (int j = 0; j < values.length; ++j) { + String value = values[j]; + + RadioButton button = new RadioButton(activity); + button.setText(value); + button.setId(j); + button.setTextSize(18); + button.setPadding(16, 16, 16, 16); + button.setLayoutParams(layoutParams); + + radioGroup.addView(button); + } + return radioGroup; + } + + @Override + String getResult() { + int radioIndex = radioGroup.indexOfChild(widgetView.findViewById(radioGroup.getCheckedRadioButtonId())); + RadioButton radioButton = (RadioButton) radioGroup.getChildAt(radioIndex); + InputResult.index = radioIndex; + return (radioButton != null) ? radioButton.getText().toString() : ""; + } + } + + + /** + * BottomSheet InputMethod + * Allow users to select from a variety of options in a bottom sheet dialog + */ + public static class BottomSheetInputMethod extends BottomSheetDialogFragment implements InputMethod { + private InputResultListener resultListener; + + + @Override + public void create(AppCompatActivity activity, InputResultListener resultListener) { + this.resultListener = resultListener; + show(activity.getSupportFragmentManager(), "BOTTOM_SHEET"); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // create custom BottomSheetDialog that has friendlier dismissal behavior + return new BottomSheetDialog(requireActivity(), getTheme()) { + @Override + public void onBackPressed() { + super.onBackPressed(); + // make it so that user only has to hit back key one time to get rid of bottom sheet + requireActivity().onBackPressed(); + postCanceledResult(); + } + + @Override + public void cancel() { + super.cancel(); + + if (isCurrentAppTermux()) { + showKeyboard(); + } + // dismiss on single touch outside of dialog + requireActivity().onBackPressed(); + postCanceledResult(); + } + }; + } + + @SuppressLint("RestrictedApi") + @Override + public void setupDialog(final Dialog dialog, int style) { + LinearLayout layout = new LinearLayout(getContext()); + layout.setMinimumHeight(100); + layout.setPadding(16, 16, 16, 16); + layout.setOrientation(LinearLayout.VERTICAL); + + NestedScrollView scrollView = new NestedScrollView(requireContext()); + final String[] values = getInputValues(requireActivity().getIntent()); + + for (int i = 0; i < values.length; ++i) { + final int j = i; + final TextView textView = new TextView(getContext()); + textView.setText(values[j]); + textView.setTextSize(20); + textView.setPadding(56, 56, 56, 56); + textView.setOnClickListener(view -> { + InputResult result = new InputResult(); + result.text = values[j]; + result.index = j; + dismissDialog(dialog); + resultListener.onResult(result); + }); + + layout.addView(textView); + } + scrollView.addView(layout); + dialog.setContentView(scrollView); + hideKeyboard(); + } + + /** + * These keyboard methods exist to work around inconsistent show / hide behavior + * from canceling BottomSheetDialog and produces the desired result of hiding keyboard + * on creation of dialog and showing it after a selection or cancellation, as long as + * we are still within the Termux application + */ + + protected void hideKeyboard() { + KeyboardUtils.setSoftKeyboardAlwaysHiddenFlags(getActivity()); + } + + protected void showKeyboard() { + KeyboardUtils.showSoftKeyboard(getActivity(), getView()); + } + + /** + * Checks to see if foreground application is Termux + */ + protected boolean isCurrentAppTermux() { + final ActivityManager activityManager = (ActivityManager) requireContext().getSystemService(Context.ACTIVITY_SERVICE); + final List runningProcesses = Objects.requireNonNull(activityManager).getRunningAppProcesses(); + for (final ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) { + if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { + for (final String activeProcess : processInfo.pkgList) { + if (activeProcess.equals(TermuxConstants.TERMUX_PACKAGE_NAME)) { + return true; + } + } + } + } + return false; + } + + protected void postCanceledResult() { + InputResult result = new InputResult(); + result.code = Dialog.BUTTON_NEGATIVE; + resultListener.onResult(result); + } + } + + + /** + * Spinner InputMethod + * Allow users to make a selection based on a list of specified values + */ + static class SpinnerInputMethod extends InputDialog { + + SpinnerInputMethod(AppCompatActivity activity) { + super(activity); + } + + @Override + String getResult() { + InputResult.index = widgetView.getSelectedItemPosition(); + return widgetView.getSelectedItem().toString(); + } + + @Override + Spinner createWidgetView(AppCompatActivity activity) { + Spinner spinner = new Spinner(activity); + + final Intent intent = activity.getIntent(); + final String[] items = getInputValues(intent); + final ArrayAdapter adapter = new ArrayAdapter<>(activity, R.layout.spinner_item, items); + + spinner.setAdapter(adapter); + return spinner; + } + } + + + /** + * Speech InputMethod + * Allow users to use the built in microphone to get text from speech + */ + static class SpeechInputMethod extends InputDialog { + + SpeechInputMethod(AppCompatActivity activity) { + super(activity); + } + + @Override + TextView createWidgetView(AppCompatActivity activity) { + TextView textView = new TextView(activity); + final Intent intent = activity.getIntent(); + + String text = intent.hasExtra("input_hint") ? intent.getStringExtra("input_hint") : "Listening for speech..."; + + textView.setText(text); + textView.setTextSize(20); + return textView; + } + + @Override + public void create(final AppCompatActivity activity, final InputResultListener resultListener) { + // Since we're using the microphone, we need to make sure we have proper permission + if (!TermuxApiPermissionActivity.checkAndRequestPermissions(activity, activity.getIntent(), Manifest.permission.RECORD_AUDIO)) { + activity.finish(); + } + + if (!hasSpeechRecognizer(activity)) { + Toast.makeText(activity, "No voice recognition found!", Toast.LENGTH_SHORT).show(); + activity.finish(); + } + + + Intent speechIntent = createSpeechIntent(); + final SpeechRecognizer recognizer = createSpeechRecognizer(activity, resultListener); + + // create intermediate InputResultListener so that we can stop our speech listening + // if user hits the cancel button + DialogInterface.OnClickListener clickListener = getClickListener(result -> { + recognizer.stopListening(); + resultListener.onResult(result); + }); + + Dialog dialog = getDialogBuilder(activity, clickListener) + .setPositiveButton(null, null) + .setOnDismissListener(null) + .create(); + + dialog.setCanceledOnTouchOutside(false); + dialog.show(); + + recognizer.startListening(speechIntent); + } + + private boolean hasSpeechRecognizer(Context context) { + List installList = context.getPackageManager().queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0); + return !installList.isEmpty(); + } + + private Intent createSpeechIntent() { + Intent speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + speechIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1); + speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); + return speechIntent; + } + + private SpeechRecognizer createSpeechRecognizer(AppCompatActivity activity, final InputResultListener listener) { + SpeechRecognizer recognizer = SpeechRecognizer.createSpeechRecognizer(activity); + recognizer.setRecognitionListener(new RecognitionListener() { + + @Override + public void onResults(Bundle results) { + List voiceResults = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); + + if (voiceResults != null && voiceResults.size() > 0) { + inputResult.text = voiceResults.get(0); + } + listener.onResult(inputResult); + } + + /** + * Get string description for error code + */ + @Override + public void onError(int error) { + String errorDescription; + + switch (error) { + case SpeechRecognizer.ERROR_AUDIO: + errorDescription = "ERROR_AUDIO"; + break; + case SpeechRecognizer.ERROR_CLIENT: + errorDescription = "ERROR_CLIENT"; + break; + case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: + errorDescription = "ERROR_INSUFFICIENT_PERMISSIONS"; + break; + case SpeechRecognizer.ERROR_NETWORK: + errorDescription = "ERROR_NETWORK"; + break; + case SpeechRecognizer.ERROR_NETWORK_TIMEOUT: + errorDescription = "ERROR_NETWORK_TIMEOUT"; + break; + case SpeechRecognizer.ERROR_SPEECH_TIMEOUT: + errorDescription = "ERROR_SPEECH_TIMEOUT"; + break; + default: + errorDescription = "ERROR_UNKNOWN"; + break; + } + inputResult.error = errorDescription; + listener.onResult(inputResult); + } + + + // unused + @Override + public void onEndOfSpeech() { } + + @Override + public void onReadyForSpeech(Bundle bundle) { } + + @Override + public void onBeginningOfSpeech() { } + + @Override + public void onRmsChanged(float v) { } + + @Override + public void onBufferReceived(byte[] bytes) { } + + @Override + public void onPartialResults(Bundle bundle) { } + + @Override + public void onEvent(int i, Bundle bundle) { } + }); + return recognizer; + } + } + + + /** + * Base Dialog class to extend from for adding specific views / widgets to a Dialog interface + * @param Main view type that will be displayed within dialog + */ + abstract static class InputDialog implements InputMethod { + // result that belongs to us + InputResult inputResult = new InputResult(); + + // listener for our input result + InputResultListener resultListener; + + // view that will be placed in our dialog + T widgetView; + + // dialog that holds everything + Dialog dialog; + + // our activity context + AppCompatActivity activity; + + + // method to be implemented that handles creating view that is placed in our dialog + abstract T createWidgetView(AppCompatActivity activity); + + // method that should be implemented that handles returning a result obtained through user input + String getResult() { + return null; + } + + + InputDialog(AppCompatActivity activity) { + this.activity = activity; + widgetView = createWidgetView(activity); + initActivityDisplay(activity); + } + + @Override + public Dialog getDialog() { + return dialog; + } + + @Override + public void create(AppCompatActivity activity, final InputResultListener resultListener) { + this.resultListener = resultListener; + + // Handle OK and Cancel button clicks + DialogInterface.OnClickListener clickListener = getClickListener(resultListener); + + // Dialog interface that will display to user + dialog = getDialogBuilder(activity, clickListener).create(); + dialog.show(); + } + + void postCanceledResult() { + inputResult.code = Dialog.BUTTON_NEGATIVE; + resultListener.onResult(inputResult); + } + + void initActivityDisplay(Activity activity) { + activity.setFinishOnTouchOutside(false); + activity.requestWindowFeature(Window.FEATURE_NO_TITLE); + } + + /** + * Places our generic widget view type inside a FrameLayout + */ + View getLayoutView(AppCompatActivity activity, T view) { + FrameLayout layout = getFrameLayout(activity); + ViewGroup.LayoutParams params = layout.getLayoutParams(); + + view.setLayoutParams(params); + layout.addView(view); + layout.setScrollbarFadingEnabled(false); + + // wrap everything in scrollview + ScrollView scrollView = new ScrollView(activity); + scrollView.addView(layout); + + return scrollView; + } + + DialogInterface.OnClickListener getClickListener(final InputResultListener listener) { + return (dialogInterface, button) -> { + InputResult result = onDialogClick(button); + listener.onResult(result); + }; + } + + DialogInterface.OnDismissListener getDismissListener() { + return dialogInterface -> { + // force dismiss behavior on single tap outside of dialog + activity.onBackPressed(); + onDismissed(); + }; + } + + /** + * Creates a dialog builder to initialize a dialog w/ a view and button click listeners + */ + AlertDialog.Builder getDialogBuilder(AppCompatActivity activity, DialogInterface.OnClickListener clickListener) { + final Intent intent = activity.getIntent(); + final View layoutView = getLayoutView(activity, widgetView); + + return new AlertDialog.Builder(activity) + .setTitle(intent.hasExtra("input_title") ? intent.getStringExtra("input_title") : "") + .setNegativeButton(getNegativeButtonText(), clickListener) + .setPositiveButton(getPositiveButtonText(), clickListener) + .setOnDismissListener(getDismissListener()) + .setView(layoutView); + + } + + String getNegativeButtonText() { + return "Cancel"; + } + + String getPositiveButtonText() { + return "OK"; + } + + void onDismissed() { + postCanceledResult(); + } + + /** + * Create a basic frame layout that will add a margin around our main widget view + */ + FrameLayout getFrameLayout(AppCompatActivity activity) { + FrameLayout layout = new FrameLayout(activity); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + + final int margin = 56; + params.setMargins(margin, margin, margin, margin); + + params.setMargins(56, 56, 56, 56); + layout.setLayoutParams(params); + return layout; + } + + /** + * Returns an InputResult containing code of our button and the text if we hit OK + */ + InputResult onDialogClick(int button) { + // receive indication of whether the OK or CANCEL button is clicked + inputResult.code = button; + + // OK clicked + if (button == Dialog.BUTTON_POSITIVE) { + inputResult.text = getResult(); + } + return inputResult; + } + } + } + +} diff --git a/app/src/main/java/com/termux/api/DownloadAPI.java b/app/src/main/java/com/termux/api/apis/DownloadAPI.java similarity index 69% rename from app/src/main/java/com/termux/api/DownloadAPI.java rename to app/src/main/java/com/termux/api/apis/DownloadAPI.java index 9bea5b433..201e8094f 100644 --- a/app/src/main/java/com/termux/api/DownloadAPI.java +++ b/app/src/main/java/com/termux/api/apis/DownloadAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.app.DownloadManager; import android.app.DownloadManager.Request; @@ -6,11 +6,19 @@ import android.content.Intent; import android.net.Uri; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; + +import java.io.File; public class DownloadAPI { - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + private static final String LOG_TAG = "DownloadAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + ResultReturner.returnData(apiReceiver, intent, out -> { final Uri downloadUri = intent.getData(); if (downloadUri == null) { @@ -20,6 +28,7 @@ static void onReceive(TermuxApiReceiver apiReceiver, final Context context, fina String title = intent.getStringExtra("title"); String description = intent.getStringExtra("description"); + String path = intent.getStringExtra("path"); DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); Request req = new Request(downloadUri); @@ -32,6 +41,9 @@ static void onReceive(TermuxApiReceiver apiReceiver, final Context context, fina if (description != null) req.setDescription(description); + if (path != null) + req.setDestinationUri(Uri.fromFile(new File(path))); + manager.enqueue(req); }); } diff --git a/app/src/main/java/com/termux/api/FingerprintAPI.java b/app/src/main/java/com/termux/api/apis/FingerprintAPI.java similarity index 87% rename from app/src/main/java/com/termux/api/FingerprintAPI.java rename to app/src/main/java/com/termux/api/apis/FingerprintAPI.java index f0bc6aef4..233f2044f 100644 --- a/app/src/main/java/com/termux/api/FingerprintAPI.java +++ b/app/src/main/java/com/termux/api/apis/FingerprintAPI.java @@ -1,9 +1,7 @@ -package com.termux.api; +package com.termux.api.apis; -import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -11,13 +9,12 @@ import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.biometric.BiometricConstants; import androidx.biometric.BiometricPrompt; import androidx.core.hardware.fingerprint.FingerprintManagerCompat; import androidx.fragment.app.FragmentActivity; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; import java.util.ArrayList; import java.util.List; @@ -30,6 +27,7 @@ * This API allows users to use device fingerprint sensor as an authentication mechanism */ public class FingerprintAPI { + protected static final String TAG = "FingerprintAPI"; protected static final String KEY_NAME = "TermuxFingerprintAPIKey"; protected static final String KEYSTORE_NAME = "AndroidKeyStore"; @@ -64,26 +62,24 @@ public class FingerprintAPI { protected static boolean postedResult = false; + private static final String LOG_TAG = "FingerprintAPI"; + /** * Handles setup of fingerprint sensor and writes Fingerprint result to console */ - static void onReceive(final Context context, final Intent intent) { + public static void onReceive(final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + resetFingerprintResult(); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { - FingerprintManagerCompat fingerprintManagerCompat = FingerprintManagerCompat.from(context); - // make sure we have a valid fingerprint sensor before attempting to launch Fingerprint activity - if (validateFingerprintSensor(context, fingerprintManagerCompat)) { - Intent fingerprintIntent = new Intent(context, FingerprintActivity.class); - fingerprintIntent.putExtras(intent.getExtras()); - fingerprintIntent.setFlags(FLAG_ACTIVITY_NEW_TASK); - context.startActivity(fingerprintIntent); - } else { - postFingerprintResult(context, intent, fingerprintResult); - } + FingerprintManagerCompat fingerprintManagerCompat = FingerprintManagerCompat.from(context); + // make sure we have a valid fingerprint sensor before attempting to launch Fingerprint activity + if (validateFingerprintSensor(context, fingerprintManagerCompat)) { + Intent fingerprintIntent = new Intent(context, FingerprintActivity.class); + fingerprintIntent.putExtras(intent.getExtras()); + fingerprintIntent.setFlags(FLAG_ACTIVITY_NEW_TASK); + context.startActivity(fingerprintIntent); } else { - // pre-marshmallow is unsupported - appendFingerprintError(ERROR_UNSUPPORTED_OS_VERSION); postFingerprintResult(context, intent, fingerprintResult); } } @@ -119,7 +115,6 @@ public void writeJson(JsonWriter out) throws Exception { /** * Ensure that we have a fingerprint sensor and that the user has already enrolled fingerprints */ - @TargetApi(Build.VERSION_CODES.M) protected static boolean validateFingerprintSensor(Context context, FingerprintManagerCompat fingerprintManagerCompat) { boolean result = true; @@ -142,11 +137,14 @@ protected static boolean validateFingerprintSensor(Context context, FingerprintM /** * Activity that is necessary for authenticating w/ fingerprint sensor */ - @TargetApi(Build.VERSION_CODES.M) public static class FingerprintActivity extends FragmentActivity{ + private static final String LOG_TAG = "FingerprintActivity"; + @Override public void onCreate(Bundle savedInstanceState) { + Logger.logDebug(LOG_TAG, "onCreate"); + super.onCreate(savedInstanceState); handleFingerprint(); } @@ -166,7 +164,7 @@ protected static void authenticateWithFingerprint(final FragmentActivity context BiometricPrompt biometricPrompt = new BiometricPrompt(context, executor, new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { - if (errorCode == BiometricConstants.ERROR_LOCKOUT) { + if (errorCode == BiometricPrompt.ERROR_LOCKOUT) { appendFingerprintError(ERROR_LOCKOUT); // first time locked out, subsequent auth attempts will fail immediately for a bit @@ -176,7 +174,7 @@ public void onAuthenticationError(int errorCode, @NonNull CharSequence errString } setAuthResult(AUTH_RESULT_FAILURE); postFingerprintResult(context, intent, fingerprintResult); - TermuxApiLogger.error(errString.toString()); + Logger.logError(LOG_TAG, errString.toString()); } @Override diff --git a/app/src/main/java/com/termux/api/InfraredAPI.java b/app/src/main/java/com/termux/api/apis/InfraredAPI.java similarity index 83% rename from app/src/main/java/com/termux/api/InfraredAPI.java rename to app/src/main/java/com/termux/api/apis/InfraredAPI.java index 42d8ffcaa..249363088 100644 --- a/app/src/main/java/com/termux/api/InfraredAPI.java +++ b/app/src/main/java/com/termux/api/apis/InfraredAPI.java @@ -1,18 +1,24 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.Context; import android.content.Intent; import android.hardware.ConsumerIrManager; import android.util.JsonWriter; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; /** * Exposing {@link ConsumerIrManager}. */ public class InfraredAPI { - static void onReceiveCarrierFrequency(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + private static final String LOG_TAG = "InfraredAPI"; + + public static void onReceiveCarrierFrequency(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveCarrierFrequency"); + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { @Override public void writeJson(JsonWriter out) throws Exception { @@ -40,7 +46,9 @@ public void writeJson(JsonWriter out) throws Exception { } - static void onReceiveTransmit(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + public static void onReceiveTransmit(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveTransmit"); + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { @Override public void writeJson(JsonWriter out) throws Exception { diff --git a/app/src/main/java/com/termux/api/apis/JobSchedulerAPI.java b/app/src/main/java/com/termux/api/apis/JobSchedulerAPI.java new file mode 100644 index 000000000..bfd12a2d1 --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/JobSchedulerAPI.java @@ -0,0 +1,313 @@ +package com.termux.api.apis; + +import android.app.job.JobInfo; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.app.job.JobService; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.PersistableBundle; +import androidx.annotation.RequiresApi; +import android.text.TextUtils; + +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; +import com.termux.shared.shell.command.ExecutionCommand; +import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_SERVICE; + +import java.io.File; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class JobSchedulerAPI { + + private static final String LOG_TAG = "JobSchedulerAPI"; + + private static String formatJobInfo(JobInfo jobInfo) { + final String path = jobInfo.getExtras().getString(JobSchedulerService.SCRIPT_FILE_PATH); + List description = new ArrayList(); + if (jobInfo.isPeriodic()) { + description.add(String.format(Locale.ENGLISH, "(periodic: %dms)", jobInfo.getIntervalMillis())); + } + if (jobInfo.isRequireCharging()) { + description.add("(while charging)"); + } + if (jobInfo.isRequireDeviceIdle()) { + description.add("(while idle)"); + } + if (jobInfo.isPersisted()) { + description.add("(persisted)"); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (jobInfo.isRequireBatteryNotLow()) { + description.add("(battery not low)"); + } + if (jobInfo.isRequireStorageNotLow()) { + description.add("(storage not low)"); + } + } + if (Build.VERSION.SDK_INT >= 28) { + description.add(String.format(Locale.ENGLISH, "(network: %s)", jobInfo.getRequiredNetwork().toString())); + } + + return String.format(Locale.ENGLISH, "Job %d: %s %s", jobInfo.getId(), path, + TextUtils.join(" ", description)); + } + + public static void onReceive(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + final boolean pending = intent.getBooleanExtra("pending", false); + final boolean cancel = intent.getBooleanExtra("cancel", false); + final boolean cancelAll = intent.getBooleanExtra("cancel_all", false); + + if (pending) { + ResultReturner.returnData(apiReceiver, intent, out -> { + runDisplayPendingJobsAction(context, out); + }); + } else if (cancelAll) { + ResultReturner.returnData(apiReceiver, intent, out -> { + runCancelAllJobsAction(context, out); + }); + } else if (cancel) { + ResultReturner.returnData(apiReceiver, intent, out -> { + runCancelJobAction(context, intent, out); + }); + } else { + ResultReturner.returnData(apiReceiver, intent, out -> { + runScheduleJobAction(context, intent, out); + }); + } + } + + private static void runScheduleJobAction(Context context, Intent intent, PrintWriter out) { + JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + + int jobId = intent.getIntExtra("job_id", 0); + + Logger.logVerbose(LOG_TAG, "schedule_job: Running action for job " + jobId); + + String scriptPath = intent.getStringExtra("script"); + String networkType = intent.getStringExtra("network"); + int periodicMillis = intent.getIntExtra("period_ms", 0); + boolean batteryNotLow = intent.getBooleanExtra("battery_not_low", true); + boolean charging = intent.getBooleanExtra("charging", false); + boolean persisted = intent.getBooleanExtra("persisted", false); + boolean idle = intent.getBooleanExtra("idle", false); + boolean storageNotLow = intent.getBooleanExtra("storage_not_low", false); + + + int networkTypeCode; + if (networkType != null) { + switch (networkType) { + case "any": + networkTypeCode = JobInfo.NETWORK_TYPE_ANY; + break; + case "unmetered": + networkTypeCode = JobInfo.NETWORK_TYPE_UNMETERED; + break; + case "cellular": + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + networkTypeCode = JobInfo.NETWORK_TYPE_CELLULAR; + else + networkTypeCode = JobInfo.NETWORK_TYPE_UNMETERED; + break; + case "not_roaming": + networkTypeCode = JobInfo.NETWORK_TYPE_NOT_ROAMING; + break; + default: + case "none": + networkTypeCode = JobInfo.NETWORK_TYPE_NONE; + break; + } + } else { // networkType == null + networkTypeCode = JobInfo.NETWORK_TYPE_ANY; + } + + + if (scriptPath == null) { + Logger.logErrorPrivate(LOG_TAG, "schedule_job: " + "Script path not passed"); + out.println("No script path given"); + return; + } + + File file = new File(scriptPath); + String fileCheckMsg; + if (!file.isFile()) { + fileCheckMsg = "No such file: %s"; + } else if (!file.canRead()) { + fileCheckMsg = "Cannot read file: %s"; + } else if (!file.canExecute()) { + fileCheckMsg = "Cannot execute file: %s"; + } else { + fileCheckMsg = ""; + } + + if (!fileCheckMsg.isEmpty()) { + Logger.logErrorPrivate(LOG_TAG, "schedule_job: " + String.format(fileCheckMsg, scriptPath)); + out.println(String.format(fileCheckMsg, scriptPath)); + return; + } + + + PersistableBundle extras = new PersistableBundle(); + extras.putString(JobSchedulerService.SCRIPT_FILE_PATH, file.getAbsolutePath()); + + ComponentName serviceComponent = new ComponentName(context, JobSchedulerService.class); + JobInfo.Builder builder = new JobInfo.Builder(jobId, serviceComponent) + .setExtras(extras) + .setRequiredNetworkType(networkTypeCode) + .setRequiresCharging(charging) + .setPersisted(persisted) + .setRequiresDeviceIdle(idle); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + builder = builder.setRequiresBatteryNotLow(batteryNotLow); + builder = builder.setRequiresStorageNotLow(storageNotLow); + } + + if (periodicMillis > 0) { + // For Android `>= 7`, the minimum period is 900000ms (15 minutes). + // - https://developer.android.com/reference/android/app/job/JobInfo#getMinPeriodMillis() + // - https://cs.android.com/android/_/android/platform/frameworks/base/+/10be4e90 + builder = builder.setPeriodic(periodicMillis); + } + + JobInfo jobInfo = builder.build(); + final int scheduleResponse = jobScheduler.schedule(jobInfo); + String message = String.format(Locale.ENGLISH, "Scheduling %s - response %d", formatJobInfo(jobInfo), scheduleResponse); + printMessage(out, "schedule_job", message); + + displayPendingJob(out, jobScheduler, "schedule_job", "Pending", jobId); + } + + private static void runDisplayPendingJobsAction(Context context, PrintWriter out) { + JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + + Logger.logVerbose(LOG_TAG, "display_pending_jobs: Running action"); + displayPendingJobs(out, jobScheduler, "display_pending_jobs", "Pending"); + } + + private static void runCancelAllJobsAction(Context context, PrintWriter out) { + Logger.logVerbose(LOG_TAG, "cancel_all_jobs: Running action"); + JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + int jobsCount = displayPendingJobs(out, jobScheduler, "cancel_all_jobs", "Cancelling"); + if (jobsCount >= 0) { + Logger.logVerbose(LOG_TAG, "cancel_all_jobs: Cancelling " + jobsCount + " jobs"); + jobScheduler.cancelAll(); + } + } + + @RequiresApi(api = Build.VERSION_CODES.N) + private static void runCancelJobAction(Context context, Intent intent, PrintWriter out) { + JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + + if (!intent.hasExtra("job_id")) { + Logger.logErrorPrivate(LOG_TAG, "cancel_job: Job id not passed"); + out.println("Job id not passed"); + return; + } + + int jobId = intent.getIntExtra("job_id", 0); + Logger.logVerbose(LOG_TAG, "cancel_job: Running action for job " + jobId); + + if (displayPendingJob(out, jobScheduler, "cancel_job", "Cancelling", jobId)) { + Logger.logVerbose(LOG_TAG, "cancel_job: Cancelling job " + jobId); + jobScheduler.cancel(jobId); + } + } + + + + private static boolean displayPendingJob(PrintWriter out, JobScheduler jobScheduler, + String actionTag, String actionLabel, int jobId) { + JobInfo jobInfo = jobScheduler.getPendingJob(jobId); + if (jobInfo == null) { + printMessage(out, actionTag, String.format(Locale.ENGLISH, "No job %d found", jobId)); + return false; + } + + printMessage(out, actionTag, String.format(Locale.ENGLISH, actionLabel + " %s", formatJobInfo(jobInfo))); + return true; + } + + + private static int displayPendingJobs(PrintWriter out, JobScheduler jobScheduler, String actionTag, String actionLabel) { + List jobs = jobScheduler.getAllPendingJobs(); + if (jobs.isEmpty()) { + printMessage(out, actionTag, "No jobs found"); + return 0; + } + + StringBuilder stringBuilder = new StringBuilder(); + boolean jobAdded = false; + for (JobInfo job : jobs) { + if (jobAdded) stringBuilder.append("\n"); + stringBuilder.append(String.format(Locale.ENGLISH, actionLabel + " %s", formatJobInfo(job))); + jobAdded = true; + } + printMessage(out, actionTag, stringBuilder.toString()); + + return jobs.size(); + } + + + + private static void printMessage(PrintWriter out, String actionTag, String message) { + Logger.logVerbose(LOG_TAG, actionTag + ": " + message); + out.println(message); + } + + + + public static class JobSchedulerService extends JobService { + + public static final String SCRIPT_FILE_PATH = TermuxConstants.TERMUX_API_PACKAGE_NAME + ".jobscheduler_script_path"; + + private static final String LOG_TAG = "JobSchedulerService"; + + @Override + public boolean onStartJob(JobParameters params) { + Logger.logInfo(LOG_TAG, "onStartJob: " + params.toString()); + + PersistableBundle extras = params.getExtras(); + String filePath = extras.getString(SCRIPT_FILE_PATH); + + ExecutionCommand executionCommand = new ExecutionCommand(); + executionCommand.executableUri = new Uri.Builder().scheme(TERMUX_SERVICE.URI_SCHEME_SERVICE_EXECUTE).path(filePath).build(); + executionCommand.runner = ExecutionCommand.Runner.APP_SHELL.getName(); + + // Create execution intent with the action TERMUX_SERVICE#ACTION_SERVICE_EXECUTE to be sent to the TERMUX_SERVICE + Intent executionIntent = new Intent(TERMUX_SERVICE.ACTION_SERVICE_EXECUTE, executionCommand.executableUri); + executionIntent.setClassName(TermuxConstants.TERMUX_PACKAGE_NAME, TermuxConstants.TERMUX_APP.TERMUX_SERVICE_NAME); + executionIntent.putExtra(TERMUX_SERVICE.EXTRA_RUNNER, executionCommand.runner); + executionIntent.putExtra(TERMUX_SERVICE.EXTRA_BACKGROUND, true); // Also pass in case user using termux-app version < 0.119.0 + + Context context = getApplicationContext(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // https://developer.android.com/about/versions/oreo/background.html + context.startForegroundService(executionIntent); + } else { + context.startService(executionIntent); + } + + Logger.logInfo(LOG_TAG, "Job started for \"" + filePath + "\""); + + return false; + } + + @Override + public boolean onStopJob(JobParameters params) { + Logger.logInfo(LOG_TAG, "onStopJob: " + params.toString()); + return false; + } + } + +} diff --git a/app/src/main/java/com/termux/api/KeystoreAPI.java b/app/src/main/java/com/termux/api/apis/KeystoreAPI.java similarity index 97% rename from app/src/main/java/com/termux/api/KeystoreAPI.java rename to app/src/main/java/com/termux/api/apis/KeystoreAPI.java index 22bea18c3..ffe008dd4 100644 --- a/app/src/main/java/com/termux/api/KeystoreAPI.java +++ b/app/src/main/java/com/termux/api/apis/KeystoreAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.annotation.SuppressLint; import android.content.Intent; @@ -10,9 +10,11 @@ import android.util.Base64; import android.util.JsonWriter; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; import com.termux.api.util.ResultReturner.ResultJsonWriter; import com.termux.api.util.ResultReturner.WithInput; +import com.termux.shared.logger.Logger; import java.io.ByteArrayOutputStream; import java.io.File; @@ -35,17 +37,16 @@ import java.security.spec.RSAKeyGenParameterSpec; import java.util.Enumeration; -class KeystoreAPI { +public class KeystoreAPI { + + private static final String LOG_TAG = "KeystoreAPI"; + // this is the only provider name that is supported by Android private static final String PROVIDER = "AndroidKeyStore"; @SuppressLint("NewApi") - static void onReceive(TermuxApiReceiver apiReceiver, Intent intent) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - // most of the keystore features were added in Android 6 - printErrorMessage(apiReceiver, intent); - return; - } + public static void onReceive(TermuxApiReceiver apiReceiver, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); switch (intent.getStringExtra("command")) { case "list": diff --git a/app/src/main/java/com/termux/api/LocationAPI.java b/app/src/main/java/com/termux/api/apis/LocationAPI.java similarity index 90% rename from app/src/main/java/com/termux/api/LocationAPI.java rename to app/src/main/java/com/termux/api/apis/LocationAPI.java index 0b5ffd740..4924d4c90 100644 --- a/app/src/main/java/com/termux/api/LocationAPI.java +++ b/app/src/main/java/com/termux/api/apis/LocationAPI.java @@ -1,5 +1,6 @@ -package com.termux.api; +package com.termux.api.apis; +import android.Manifest; import android.content.Context; import android.content.Intent; import android.location.Location; @@ -10,22 +11,29 @@ import android.os.Looper; import android.os.SystemClock; import android.util.JsonWriter; -import android.util.Log; +import androidx.annotation.RequiresPermission; + +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; import com.termux.api.util.ResultReturner.ResultJsonWriter; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; import java.io.IOException; public class LocationAPI { + private static final String LOG_TAG = "LocationAPI"; + private static final String REQUEST_LAST_KNOWN = "last"; private static final String REQUEST_ONCE = "once"; private static final String REQUEST_UPDATES = "updates"; - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + ResultReturner.returnData(apiReceiver, intent, new ResultJsonWriter() { + @RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION) @Override public void writeJson(final JsonWriter out) throws Exception { LocationManager manager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); @@ -74,7 +82,7 @@ public void onLocationChanged(Location location) { try { locationToJson(location, out); } catch (IOException e) { - TermuxApiLogger.error("Writing json", e); + Logger.logStackTraceWithMessage(LOG_TAG, "Writing json", e); } finally { Looper.myLooper().quit(); } @@ -107,7 +115,7 @@ public void onLocationChanged(Location location) { locationToJson(location, out); out.flush(); } catch (IOException e) { - TermuxApiLogger.error("Writing json", e); + Logger.logStackTraceWithMessage(LOG_TAG, "Writing json", e); } } }, null); @@ -118,7 +126,7 @@ public void run() { try { Thread.sleep(30 * 1000); } catch (InterruptedException e) { - Log.e("termux", "INTER", e); + Logger.logStackTraceWithMessage(LOG_TAG, "INTER", e); } looper.quit(); } diff --git a/app/src/main/java/com/termux/api/MediaPlayerAPI.java b/app/src/main/java/com/termux/api/apis/MediaPlayerAPI.java similarity index 93% rename from app/src/main/java/com/termux/api/MediaPlayerAPI.java rename to app/src/main/java/com/termux/api/apis/MediaPlayerAPI.java index 8514d4a1a..081bc8125 100644 --- a/app/src/main/java/com/termux/api/MediaPlayerAPI.java +++ b/app/src/main/java/com/termux/api/apis/MediaPlayerAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.app.Service; import android.content.Context; @@ -8,7 +8,7 @@ import android.os.PowerManager; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; import java.io.File; import java.io.IOException; @@ -19,13 +19,17 @@ */ public class MediaPlayerAPI { + private static final String LOG_TAG = "MediaPlayerAPI"; + /** - * Starts our PlayerService + * Starts our MediaPlayerService */ - static void onReceive(final Context context, final Intent intent) { + public static void onReceive(final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + // Create intent for starting our player service and make sure // we retain all relevant info from this intent - Intent playerService = new Intent(context, PlayerService.class); + Intent playerService = new Intent(context, MediaPlayerService.class); playerService.setAction(intent.getAction()); playerService.putExtras(intent.getExtras()); @@ -55,7 +59,7 @@ public static String getTimeString(int totalSeconds) { /** * All media functionality exists in this background service */ - public static class PlayerService extends Service implements MediaPlayer.OnErrorListener, + public static class MediaPlayerService extends Service implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener { protected static MediaPlayer mediaPlayer; @@ -65,6 +69,7 @@ public static class PlayerService extends Service implements MediaPlayer.OnError protected static String trackName; + private static final String LOG_TAG = "MediaPlayerService"; /** * Returns our MediaPlayer instance and ensures it has all the necessary callbacks @@ -84,6 +89,8 @@ protected MediaPlayer getMediaPlayer() { * What we received from TermuxApiReceiver but now within this service */ public int onStartCommand(Intent intent, int flags, int startId) { + Logger.logDebug(LOG_TAG, "onStartCommand"); + String command = intent.getAction(); MediaPlayer player = getMediaPlayer(); Context context = getApplicationContext(); @@ -97,9 +104,10 @@ public int onStartCommand(Intent intent, int flags, int startId) { } public void onDestroy() { + Logger.logDebug(LOG_TAG, "onDestroy"); + super.onDestroy(); cleanUpMediaPlayer(); - TermuxApiLogger.info("MediaPlayerAPI PlayerService onDestroy()"); } /** @@ -120,7 +128,7 @@ public IBinder onBind(Intent intent) { @Override public boolean onError(MediaPlayer mediaPlayer, int what, int extra) { - TermuxApiLogger.error("MediaPlayerAPI error: " + what); + Logger.logVerbose(LOG_TAG, "onError: what: " + what + ", extra: " + extra); return false; } diff --git a/app/src/main/java/com/termux/api/MediaScannerAPI.java b/app/src/main/java/com/termux/api/apis/MediaScannerAPI.java similarity index 82% rename from app/src/main/java/com/termux/api/MediaScannerAPI.java rename to app/src/main/java/com/termux/api/apis/MediaScannerAPI.java index 218b44ed7..d911980dc 100644 --- a/app/src/main/java/com/termux/api/MediaScannerAPI.java +++ b/app/src/main/java/com/termux/api/apis/MediaScannerAPI.java @@ -1,11 +1,12 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.Context; import android.content.Intent; import android.media.MediaScannerConnection; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; import java.io.File; import java.io.PrintWriter; @@ -14,7 +15,11 @@ public class MediaScannerAPI { - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + private static final String LOG_TAG = "MediaScannerAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + final String[] filePaths = intent.getStringArrayExtra("paths"); final boolean recursive = intent.getBooleanExtra("recursive", false); final Integer[] totalScanned = {0}; @@ -35,7 +40,7 @@ private static void scanFiles(PrintWriter out, Context context, String[] filePat context.getApplicationContext(), filePaths, null, - (path, uri) -> TermuxApiLogger.info("'" + path + "'" + (uri != null ? " -> '" + uri + "'" : ""))); + (path, uri) -> Logger.logInfo(LOG_TAG, "'" + path + "'" + (uri != null ? " -> '" + uri + "'" : ""))); if (verbose) for (String path : filePaths) { out.println(path); @@ -54,7 +59,7 @@ private static void scanFilesRecursively(PrintWriter out, Context context, Strin try { fileList = currentPath.listFiles(); } catch (SecurityException e) { - TermuxApiLogger.error(String.format("Failed to open '%s'", currentPath.toString()), e); + Logger.logStackTraceWithMessage(LOG_TAG, String.format("Failed to open '%s'", currentPath.toString()), e); } if (fileList != null && fileList.length > 0) { diff --git a/app/src/main/java/com/termux/api/MicRecorderAPI.java b/app/src/main/java/com/termux/api/apis/MicRecorderAPI.java similarity index 89% rename from app/src/main/java/com/termux/api/MicRecorderAPI.java rename to app/src/main/java/com/termux/api/apis/MicRecorderAPI.java index 5ba8a7825..3b954ffd5 100644 --- a/app/src/main/java/com/termux/api/MicRecorderAPI.java +++ b/app/src/main/java/com/termux/api/apis/MicRecorderAPI.java @@ -1,9 +1,10 @@ -package com.termux.api; +package com.termux.api.apis; import android.app.Service; import android.content.Context; import android.content.Intent; import android.media.MediaRecorder; +import android.os.Build; import android.os.Environment; import android.os.IBinder; import android.util.ArrayMap; @@ -11,7 +12,7 @@ import android.util.SparseIntArray; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; import org.json.JSONException; import org.json.JSONObject; @@ -30,10 +31,14 @@ */ public class MicRecorderAPI { + private static final String LOG_TAG = "MicRecorderAPI"; + /** * Starts our MicRecorder service */ - static void onReceive(final Context context, final Intent intent) { + public static void onReceive(final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + Intent recorderService = new Intent(context, MicRecorderService.class); recorderService.setAction(intent.getAction()); recorderService.putExtras(intent.getExtras()); @@ -58,11 +63,15 @@ public static class MicRecorderService extends Service implements MediaRecorder. protected static File file; + private static final String LOG_TAG = "MicRecorderService"; + public void onCreate() { getMediaRecorder(this); } public int onStartCommand(Intent intent, int flags, int startId) { + Logger.logDebug(LOG_TAG, "onStartCommand"); + // get command handler and display result String command = intent.getAction(); Context context = getApplicationContext(); @@ -115,8 +124,9 @@ protected static void getMediaRecorder(MicRecorderService service) { } public void onDestroy() { + Logger.logDebug(LOG_TAG, "onDestroy"); + cleanupMediaRecorder(); - TermuxApiLogger.info("MicRecorderAPI MicRecorderService onDestroy()"); } /** @@ -138,19 +148,21 @@ public IBinder onBind(Intent intent) { @Override public void onError(MediaRecorder mr, int what, int extra) { + Logger.logVerbose(LOG_TAG, "onError: what: " + what + ", extra: " + extra); + isRecording = false; this.stopSelf(); - TermuxApiLogger.error("MicRecorderService onError() " + what); } @Override public void onInfo(MediaRecorder mr, int what, int extra) { + Logger.logVerbose(LOG_TAG, "onInfo: what: " + what + ", extra: " + extra); + switch (what) { case MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED: // intentional fallthrough case MEDIA_RECORDER_INFO_MAX_DURATION_REACHED: this.stopSelf(); } - TermuxApiLogger.info("MicRecorderService onInfo() " + what); } protected static String getDefaultRecordingFilename() { @@ -168,7 +180,7 @@ protected static String getRecordingInfoJSONString() { info.put("outputFile", file.getAbsolutePath()); result = info.toString(2); } catch (JSONException e) { - TermuxApiLogger.error("infoHandler json error", e); + Logger.logStackTraceWithMessage(LOG_TAG, "infoHandler json error", e); } return result; } @@ -202,10 +214,12 @@ public RecorderCommandResult handle(Context context, Intent intent) { duration = MIN_RECORDING_LIMIT; String sencoder = intent.hasExtra("encoder") ? intent.getStringExtra("encoder") : ""; - ArrayMap encoder_map = new ArrayMap<>(3); + ArrayMap encoder_map = new ArrayMap<>(4); encoder_map.put("aac", MediaRecorder.AudioEncoder.AAC); encoder_map.put("amr_nb", MediaRecorder.AudioEncoder.AMR_NB); encoder_map.put("amr_wb", MediaRecorder.AudioEncoder.AMR_WB); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + encoder_map.put("opus", MediaRecorder.AudioEncoder.OPUS); Integer encoder = encoder_map.get(sencoder.toLowerCase()); if (encoder == null) @@ -213,19 +227,23 @@ public RecorderCommandResult handle(Context context, Intent intent) { int format = intent.getIntExtra("format", MediaRecorder.OutputFormat.DEFAULT); if (format == MediaRecorder.OutputFormat.DEFAULT) { - SparseIntArray format_map = new SparseIntArray(3); + SparseIntArray format_map = new SparseIntArray(4); format_map.put(MediaRecorder.AudioEncoder.AAC, MediaRecorder.OutputFormat.MPEG_4); format_map.put(MediaRecorder.AudioEncoder.AMR_NB, MediaRecorder.OutputFormat.THREE_GPP); format_map.put(MediaRecorder.AudioEncoder.AMR_WB, MediaRecorder.OutputFormat.THREE_GPP); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + format_map.put(MediaRecorder.AudioEncoder.OPUS, MediaRecorder.OutputFormat.OGG); format = format_map.get(encoder, MediaRecorder.OutputFormat.DEFAULT); } - SparseArray extension_map = new SparseArray<>(2); + SparseArray extension_map = new SparseArray<>(3); extension_map.put(MediaRecorder.OutputFormat.MPEG_4, ".m4a"); extension_map.put(MediaRecorder.OutputFormat.THREE_GPP, ".3gp"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) + extension_map.put(MediaRecorder.OutputFormat.OGG, ".ogg"); String extension = extension_map.get(format); String filename = intent.hasExtra("file") ? intent.getStringExtra("file") : getDefaultRecordingFilename() + (extension != null ? extension : ""); @@ -238,7 +256,7 @@ public RecorderCommandResult handle(Context context, Intent intent) { file = new File(filename); - TermuxApiLogger.info("MediaRecording file is: " + file.getAbsolutePath()); + Logger.logInfo(LOG_TAG, "MediaRecording file is: " + file.getAbsolutePath()); if (file.exists()) { result.error = String.format("File: %s already exists! Please specify a different filename", file.getName()); @@ -269,7 +287,7 @@ public RecorderCommandResult handle(Context context, Intent intent) { 1000)); } catch (IllegalStateException | IOException e) { - TermuxApiLogger.error("MediaRecorder error", e); + Logger.logStackTraceWithMessage(LOG_TAG, "MediaRecorder error", e); result.error = "Recording error: " + e.getMessage(); } } diff --git a/app/src/main/java/com/termux/api/apis/NfcAPI.java b/app/src/main/java/com/termux/api/apis/NfcAPI.java new file mode 100644 index 000000000..d0d607941 --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/NfcAPI.java @@ -0,0 +1,339 @@ +package com.termux.api.apis; + +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.Ndef; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.JsonWriter; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.termux.api.util.PendingIntentUtils; +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; + +public class NfcAPI { + + private static final String LOG_TAG = "NfcAPI"; + + public static void onReceive(final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + context.startActivity(new Intent(context, NfcActivity.class).putExtras(intent.getExtras()).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + + + + public static class NfcActivity extends AppCompatActivity { + + private Intent mIntent; + private NfcAdapter mAdapter; + static String socket_input; + static String socket_output; + String mode; + String param; + String value; + + private static final String LOG_TAG = "NfcActivity"; + + //Check for NFC + protected void errorNfc(final Context context, Intent intent, String error) { + ResultReturner.returnData(context, intent, new ResultReturner.ResultJsonWriter() { + @Override + public void writeJson(JsonWriter out) throws Exception { + NfcAdapter adapter = NfcAdapter.getDefaultAdapter(context); + out.beginObject(); + if (error.length() > 0) + out.name("error").value(error); + out.name("nfcPresent").value(null != adapter); + if(null!=adapter) + out.name("nfcActive").value(adapter.isEnabled()); + out.endObject(); + } + }); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + Logger.logDebug(LOG_TAG, "onCreate"); + + super.onCreate(savedInstanceState); + Intent intent = this.getIntent(); + if (intent != null) { + mIntent = intent; + mode = intent.getStringExtra("mode"); + if (null == mode) + mode = "noData"; + param = intent.getStringExtra("param"); + if (null == param) + param = "noData"; + value = intent.getStringExtra("value"); + if (null == socket_input) socket_input = intent.getStringExtra("socket_input"); + if (null == socket_output) socket_output = intent.getStringExtra("socket_output"); + if (mode.equals("noData")) { + errorNfc(this, intent,""); + finish(); + return; + } + } + + NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this); + if (adapter == null || !adapter.isEnabled()) { + errorNfc(this, intent,""); + finish(); + } + } + + @Override + protected void onResume() { + Logger.logVerbose(LOG_TAG, "onResume"); + + super.onResume(); + + mAdapter = NfcAdapter.getDefaultAdapter(this); + if (mAdapter == null || !mAdapter.isEnabled()) { + if (mIntent != null) + errorNfc(this, mIntent,""); + finish(); + return; + } + + // - https://developer.android.com/develop/connectivity/nfc/advanced-nfc#foreground-dispatch + Intent intentNew = new Intent(this, NfcActivity.class).addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intentNew, + PendingIntentUtils.getPendingIntentMutableFlag()); + IntentFilter[] intentFilter = new IntentFilter[]{ + new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED), + new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED), + new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)}; + mAdapter.enableForegroundDispatch(this, pendingIntent, intentFilter, null); + } + + @Override + protected void onNewIntent(Intent intent) { + Logger.logDebug(LOG_TAG, "onNewIntent"); + + intent.putExtra("socket_input", socket_input); + intent.putExtra("socket_output", socket_output); + + if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { + try { + postResult(this, intent); + } catch (Exception e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Error posting result" ,e); + } + finish(); + } + super.onNewIntent(intent); + } + + @Override + protected void onPause() { + Logger.logDebug(LOG_TAG, "onPause"); + + mAdapter.disableForegroundDispatch(this); + super.onPause(); + } + + @Override + protected void onDestroy() { + Logger.logDebug(LOG_TAG, "onDestroy"); + + socket_input = null; + socket_output = null; + super.onDestroy(); + } + + protected void postResult(final Context context, Intent intent) { + ResultReturner.returnData(context, intent, new ResultReturner.ResultJsonWriter() { + @Override + public void writeJson(JsonWriter out) throws Exception { + Logger.logDebug(LOG_TAG, "postResult"); + try { + switch (mode) { + case "write": + switch (param) { + case "text": + Logger.logVerbose(LOG_TAG, "Write start"); + onReceiveNfcWrite(context, intent); + Logger.logVerbose(LOG_TAG, "Write end"); + break; + default: + onUnexpectedAction(out, "Wrong Params", "Should be text for TAG"); + break; + } + break; + case "read": + switch (param){ + case "short": + readNDEFTag(intent,out); + break; + case "full": + readFullNDEFTag(intent,out); + break; + case "noData": + readNDEFTag(intent,out); + break; + default: + onUnexpectedAction(out, "Wrong Params", "Should be correct param value"); + break; + } + break; + default: + onUnexpectedAction(out, "Wrong Params", "Should be correct mode value "); + break; + } + } catch (Exception e){ + onUnexpectedAction(out, "exception", e.getMessage()); + } + } + }); + } + + public void onReceiveNfcWrite( final Context context, Intent intent) throws Exception { + Logger.logVerbose(LOG_TAG, "onReceiveNfcWrite"); + + NfcAdapter adapter = NfcAdapter.getDefaultAdapter(context); + Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + NdefRecord record = NdefRecord.createTextRecord("en", value); + NdefMessage msg = new NdefMessage(new NdefRecord[]{record}); + Ndef ndef = Ndef.get(tag); + ndef.connect(); + ndef.writeNdefMessage(msg); + ndef.close(); + } + + + public void readNDEFTag(Intent intent, JsonWriter out) throws Exception { + Logger.logVerbose(LOG_TAG, "readNDEFTag"); + + NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this); + Parcelable[] msgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + Ndef ndefTag = Ndef.get(tag); + boolean bNdefPresent = false; + String[] strs = tag.getTechList(); + for (String s: strs){ + if (s.equals("android.nfc.tech.Ndef")) { + bNdefPresent = true; + break; + } + } + if (!bNdefPresent){ + onUnexpectedAction(out, "Wrong Technology","termux API support only NFEF Tag"); + return; + } + NdefMessage[] nmsgs = new NdefMessage[msgs.length]; + if (msgs.length == 1) { + nmsgs[0] = (NdefMessage) msgs[0]; + NdefRecord[] records = nmsgs[0].getRecords(); + out.beginObject(); + if (records.length >0 ) { + { + out.name("Record"); + if (records.length > 1) + out.beginArray(); + for (NdefRecord record: records){ + out.beginObject(); + int pos = 1 + record.getPayload()[0]; + pos = (NdefRecord.TNF_WELL_KNOWN==record.getTnf())?(int)record.getPayload()[0]+1:0; + int len = record.getPayload().length - pos; + byte[] msg = new byte[len]; + System.arraycopy(record.getPayload(), pos, msg, 0, len); + out.name("Payload").value(new String(msg)); + out.endObject(); + } + if (records.length > 1) + out.endArray(); + } + } + out.endObject(); + } + } + + public void readFullNDEFTag(Intent intent, JsonWriter out) throws Exception { + Logger.logVerbose(LOG_TAG, "readFullNDEFTag"); + + NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this); + Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + Ndef ndefTag = Ndef.get(tag); + Parcelable[] msgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + + String[] strs = tag.getTechList(); + boolean bNdefPresent = false; + for (String s: strs){ + if (s.equals("android.nfc.tech.Ndef")) { + bNdefPresent = true; + break; + } + } + if (!bNdefPresent){ + onUnexpectedAction(out, "Wrong Technology","termux API support only NFEF Tag"); + return; + } + NdefMessage[] nmsgs = new NdefMessage[msgs.length]; + out.beginObject(); + { + byte[] tagID = tag.getId(); + StringBuilder sp = new StringBuilder(); + for (byte tagIDpart : tagID) { sp.append(String.format("%02x", tagIDpart)); } + out.name("id").value(sp.toString()); + out.name("typeTag").value(ndefTag.getType()); + out.name("maxSize").value(ndefTag.getMaxSize()); + out.name("techList"); + { + out.beginArray(); + String[] tlist = tag.getTechList(); + for (String str : tlist) { + out.value(str); + } + out.endArray(); + } + if (msgs.length == 1) { + Logger.logInfo(LOG_TAG, "-->> readFullNDEFTag - 06"); + nmsgs[0] = (NdefMessage) msgs[0]; + NdefRecord[] records = nmsgs[0].getRecords(); + { + out.name("record"); + if (records.length > 1) + out.beginArray(); + for (NdefRecord record : records) { + out.beginObject(); + out.name("type").value(new String(record.getType())); + out.name("tnf").value(record.getTnf()); + if (records[0].toUri() != null) out.name("URI").value(record.toUri().toString()); + out.name("mime").value(record.toMimeType()); + int pos = 1 + record.getPayload()[0]; + pos = (NdefRecord.TNF_WELL_KNOWN==record.getTnf())?(int)record.getPayload()[0]+1:0; + int len = record.getPayload().length - pos; + byte[] msg = new byte[len]; + System.arraycopy(record.getPayload(), pos, msg, 0, len); + out.name("payload").value(new String(msg)); + out.endObject(); + } + if (records.length > 1) out.endArray(); + } + } + + } + out.endObject(); + } + + protected void onUnexpectedAction(JsonWriter out,String error, String description) throws Exception { + out.beginObject(); + out.name("error").value(error); + out.name("description").value(description); + out.endObject(); + out.flush(); + } + } + +} diff --git a/app/src/main/java/com/termux/api/apis/NotificationAPI.java b/app/src/main/java/com/termux/api/apis/NotificationAPI.java new file mode 100644 index 000000000..bc4ca8ae4 --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/NotificationAPI.java @@ -0,0 +1,440 @@ +package com.termux.api.apis; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.text.TextUtils; + +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; +import androidx.core.app.RemoteInput; +import androidx.core.util.Pair; + +import com.termux.api.R; +import com.termux.api.TermuxAPIConstants; +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.PendingIntentUtils; +import com.termux.api.util.PluginUtils; +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; +import com.termux.shared.shell.command.ExecutionCommand; +import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_SERVICE; + +import java.io.File; +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.util.Objects; +import java.util.UUID; + +public class NotificationAPI { + + private static final String LOG_TAG = "NotificationAPI"; + + public static final String BIN_SH = TermuxConstants.TERMUX_PREFIX_DIR_PATH + "/bin/sh"; + private static final String CHANNEL_ID = "termux-notification"; + private static final String CHANNEL_TITLE = "Termux API notification channel"; + private static final String KEY_TEXT_REPLY = "TERMUX_TEXT_REPLY"; + + /** + * Show a notification. Driven by the termux-show-notification script. + */ + public static void onReceiveShowNotification(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveShowNotification"); + + Pair pair = buildNotification(context, intent); + NotificationCompat.Builder notification = pair.first; + String notificationId = pair.second; + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.WithStringInput() { + @Override + public void writeResult(PrintWriter out) { + NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + if (!TextUtils.isEmpty(inputString)) { + if (inputString.contains("\n")) { + NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle(); + style.bigText(inputString); + notification.setStyle(style); + } else { + notification.setContentText(inputString); + } + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel(CHANNEL_ID, + CHANNEL_TITLE, priorityFromIntent(intent)); + manager.createNotificationChannel(channel); + } + + manager.notify(notificationId, 0, notification.build()); + } + }); + } + + public static void onReceiveChannel(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveChannel"); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + try { + NotificationManager m = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + String channelId = intent.getStringExtra("id"); + String channelName = intent.getStringExtra("name"); + + if (channelId == null || channelId.equals("")) { + ResultReturner.returnData(apiReceiver, intent, out -> out.println("Channel id not specified.")); + return; + } + + if (intent.getBooleanExtra("delete",false)) { + m.deleteNotificationChannel(channelId); + ResultReturner.returnData(apiReceiver, intent, out -> out.println("Deleted channel with id \""+channelId+"\".")); + return; + } + + if (channelName == null || channelName.equals("")) { + ResultReturner.returnData(apiReceiver, intent, out -> out.println("Cannot create a channel without a name.")); + } + + NotificationChannel c = new NotificationChannel(channelId, channelName, priorityFromIntent(intent)); + m.createNotificationChannel(c); + ResultReturner.returnData(apiReceiver, intent, out -> out.println("Created channel with id \""+channelId+"\" and name \""+channelName+"\".")); + } catch (Exception e) { + e.printStackTrace(); + ResultReturner.returnData(apiReceiver, intent, out -> out.println("Could not create/delete channel.")); + } + } else { + ResultReturner.returnData(apiReceiver, intent, out -> out.println("Notification channels are only available on Android 8.0 and higher, use the options for termux-notification instead.")); + } + } + + private static int priorityFromIntent(Intent intent) { + String priorityExtra = intent.getStringExtra("priority"); + if (priorityExtra == null) priorityExtra = "default"; + int importance; + switch (priorityExtra) { + case "high": + case "max": + importance = NotificationManager.IMPORTANCE_HIGH; + break; + case "low": + importance = NotificationManager.IMPORTANCE_LOW; + break; + case "min": + importance = NotificationManager.IMPORTANCE_MIN; + break; + default: + importance = NotificationManager.IMPORTANCE_DEFAULT; + } + return importance; + } + + static Pair buildNotification(final Context context, final Intent intent) { + String priorityExtra = intent.getStringExtra("priority"); + if (priorityExtra == null) priorityExtra = "default"; + int priority; + switch (priorityExtra) { + case "high": + priority = Notification.PRIORITY_HIGH; + break; + case "low": + priority = Notification.PRIORITY_LOW; + break; + case "max": + priority = Notification.PRIORITY_MAX; + break; + case "min": + priority = Notification.PRIORITY_MIN; + break; + default: + priority = Notification.PRIORITY_DEFAULT; + } + + String title = intent.getStringExtra("title"); + + String lightsArgbExtra = intent.getStringExtra("led-color"); + + int ledColor = 0; + + if (lightsArgbExtra != null) { + try { + ledColor = Integer.parseInt(lightsArgbExtra, 16) | 0xff000000; + } catch (NumberFormatException e) { + Logger.logError(LOG_TAG, "Invalid LED color format! Ignoring!"); + } + } + + int ledOnMs = intent.getIntExtra("led-on", 800); + int ledOffMs = intent.getIntExtra("led-off", 800); + + long[] vibratePattern = intent.getLongArrayExtra("vibrate"); + boolean useSound = intent.getBooleanExtra("sound", false); + boolean ongoing = intent.getBooleanExtra("ongoing", false); + boolean alertOnce = intent.getBooleanExtra("alert-once", false); + + String actionExtra = intent.getStringExtra("action"); + + final String notificationId = getNotificationId(intent); + + String groupKey = intent.getStringExtra("group"); + + String channel = intent.getStringExtra("channel"); + if (channel == null) { + channel = CHANNEL_ID; + } + + final NotificationCompat.Builder notification = new NotificationCompat.Builder(context, + channel); + notification.setSmallIcon(R.drawable.ic_event_note_black_24dp); + notification.setColor(0xFF000000); + notification.setContentTitle(title); + notification.setPriority(priority); + notification.setOngoing(ongoing); + notification.setOnlyAlertOnce(alertOnce); + notification.setWhen(System.currentTimeMillis()); + notification.setShowWhen(true); + + + String smallIconName = intent.getStringExtra("icon"); + if (smallIconName != null) { + // TODO: Add prefix to all icons used by `NotificationAPI` to force keep only those icons when providing termux-api-app as a library. + // TODO: Add new icons from https://fonts.google.com/icons | https://github.com/google/material-design-icons + // Use `String.format()` so that resource shrinker does not remove icons used by `NotificationAPI` for release builds. + // - https://web.archive.org/web/20250516083801/https://developer.android.com/build/shrink-code#keep-resources + String smallIconResourceName = String.format("ic_%1s_black_24dp", smallIconName); + Integer smallIconResourceId = null; + try { + //noinspection DiscouragedApi + smallIconResourceId = context.getResources().getIdentifier(smallIconResourceName, "drawable", context.getPackageName()); + if (smallIconResourceId == 0) { + smallIconResourceId = null; + Logger.logError(LOG_TAG, "Failed to find \"" + smallIconResourceName + "\" icon"); + } + } catch (Exception e) { + Logger.logError(LOG_TAG, "Failed to find \"" + smallIconResourceName + "\" icon: " + e.getMessage()); + } + + if (smallIconResourceId != null) { + notification.setSmallIcon(smallIconResourceId); + } + } + + + String imagePath = intent.getStringExtra("image-path"); + if (imagePath != null) { + File imgFile = new File(imagePath); + if (imgFile.exists()) { + Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath()); + + notification.setLargeIcon(myBitmap) + .setStyle(new NotificationCompat.BigPictureStyle() + .bigPicture(myBitmap)); + } + } + + String styleType = intent.getStringExtra("type"); + if (Objects.equals(styleType, "media")) { + String mediaPrevious = intent.getStringExtra("media-previous"); + String mediaPause = intent.getStringExtra("media-pause"); + String mediaPlay = intent.getStringExtra("media-play"); + String mediaNext = intent.getStringExtra("media-next"); + + if (mediaPrevious != null && mediaPause != null && mediaPlay != null && mediaNext != null) { + if (smallIconName == null) { + notification.setSmallIcon(android.R.drawable.ic_media_play); + } + + PendingIntent previousIntent = createAction(context, mediaPrevious); + PendingIntent pauseIntent = createAction(context, mediaPause); + PendingIntent playIntent = createAction(context, mediaPlay); + PendingIntent nextIntent = createAction(context, mediaNext); + + notification.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_previous, "previous", previousIntent)); + notification.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_pause, "pause", pauseIntent)); + notification.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_play, "play", playIntent)); + notification.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_next, "next", nextIntent)); + + notification.setStyle(new androidx.media.app.NotificationCompat.MediaStyle() + .setShowActionsInCompactView(0, 1, 3)); + } + } + + if (groupKey != null) notification.setGroup(groupKey); + + if (ledColor != 0) { + notification.setLights(ledColor, ledOnMs, ledOffMs); + + if (vibratePattern == null) { + // Hack to make led work without vibrating. + vibratePattern = new long[]{0}; + } + } + + if (vibratePattern != null) { + // Do not force the user to specify a delay first element, let it be 0. + long[] vibrateArg = new long[vibratePattern.length + 1]; + System.arraycopy(vibratePattern, 0, vibrateArg, 1, vibratePattern.length); + notification.setVibrate(vibrateArg); + } + + if (useSound) notification.setSound(Settings.System.DEFAULT_NOTIFICATION_URI); + + notification.setAutoCancel(true); + + if (actionExtra != null) { + PendingIntent pi = createAction(context, actionExtra); + notification.setContentIntent(pi); + } + + for (int button = 1; button <= 3; button++) { + String buttonText = intent.getStringExtra("button_text_" + button); + String buttonAction = intent.getStringExtra("button_action_" + button); + + if (buttonText != null && buttonAction != null) { + if (buttonAction.contains("$REPLY")) { + NotificationCompat.Action action = createReplyAction(context, intent, + button, + buttonText, buttonAction, notificationId); + notification.addAction(action); + } else { + PendingIntent pi = createAction(context, buttonAction); + notification.addAction(new NotificationCompat.Action(android.R.drawable.ic_input_add, buttonText, pi)); + } + } + } + + String onDeleteActionExtra = intent.getStringExtra("on_delete_action"); + if (onDeleteActionExtra != null) { + PendingIntent pi = createAction(context, onDeleteActionExtra); + notification.setDeleteIntent(pi); + } + + return new Pair<>(notification, notificationId); + } + + private static String getNotificationId(Intent intent) { + String id = intent.getStringExtra("id"); + if (id == null) id = UUID.randomUUID().toString(); + return id; + } + + public static void onReceiveRemoveNotification(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveRemoveNotification"); + + ResultReturner.noteDone(apiReceiver, intent); + String notificationId = intent.getStringExtra("id"); + if (notificationId != null) { + NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + manager.cancel(notificationId, 0); + } + } + + static NotificationCompat.Action createReplyAction(final Context context, Intent intent, + int buttonNum, + String buttonText, + String buttonAction, String notificationId) { + RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY) + .setLabel(buttonText) + .build(); + + // Build a PendingIntent for the reply action to trigger. + PendingIntent replyPendingIntent = + PendingIntent.getBroadcast(context, + buttonNum, + getMessageReplyIntent((Intent)intent.clone(), buttonText, buttonAction, notificationId), + PendingIntent.FLAG_UPDATE_CURRENT); + + // Create the reply action and add the remote input. + return new NotificationCompat.Action.Builder(R.drawable.ic_event_note_black_24dp, + buttonText, + replyPendingIntent) + .addRemoteInput(remoteInput) + .build(); + } + + private static Intent getMessageReplyIntent(Intent oldIntent, + String buttonText, String buttonAction, + String notificationId) { + return oldIntent. + setClassName(TermuxConstants.TERMUX_API_PACKAGE_NAME, TermuxAPIConstants.TERMUX_API_RECEIVER_NAME). + putExtra("api_method", "NotificationReply"). + putExtra("id", notificationId). + putExtra("action", buttonAction); + } + + + static private CharSequence getMessageText(Intent intent) { + Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); + if (remoteInput != null) { + return remoteInput.getCharSequence(KEY_TEXT_REPLY); + } + return null; + } + + static CharSequence shellEscape(CharSequence input) { + return "\"" + input.toString().replace("\"", "\\\"") + "\""; + } + + public static void onReceiveReplyToNotification(TermuxApiReceiver termuxApiReceiver, + Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveReplyToNotification"); + + CharSequence reply = getMessageText(intent); + + String action = intent.getStringExtra("action"); + + if (action != null && reply != null) + action = action.replace("$REPLY", shellEscape(reply)); + + try { + createAction(context, action).send(); + } catch (PendingIntent.CanceledException e) { + Logger.logError(LOG_TAG, "CanceledException when performing action: " + action); + } + + String notificationId = intent.getStringExtra("id"); + boolean ongoing = intent.getBooleanExtra("ongoing", false); + Notification repliedNotification; + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + if (ongoing) { + // Re-issue the new notification to clear the spinner + repliedNotification = buildNotification(context, intent).first.build(); + notificationManager.notify(notificationId, 0, repliedNotification); + } else { + // Cancel the notification + notificationManager.cancel(notificationId, 0); + } + } + + static Intent createExecuteIntent(String action){ + ExecutionCommand executionCommand = new ExecutionCommand(); + executionCommand.executableUri = new Uri.Builder().scheme(TERMUX_SERVICE.URI_SCHEME_SERVICE_EXECUTE).path(BIN_SH).build(); + executionCommand.arguments = new String[]{"-c", action}; + executionCommand.runner = ExecutionCommand.Runner.APP_SHELL.getName(); + + // Create execution intent with the action TERMUX_SERVICE#ACTION_SERVICE_EXECUTE to be sent to the TERMUX_SERVICE + Intent executionIntent = new Intent(TERMUX_SERVICE.ACTION_SERVICE_EXECUTE, executionCommand.executableUri); + executionIntent.setClassName(TermuxConstants.TERMUX_PACKAGE_NAME, TermuxConstants.TERMUX_APP.TERMUX_SERVICE_NAME); + executionIntent.putExtra(TERMUX_SERVICE.EXTRA_ARGUMENTS, executionCommand.arguments); + executionIntent.putExtra(TERMUX_SERVICE.EXTRA_RUNNER, executionCommand.runner); + executionIntent.putExtra(TERMUX_SERVICE.EXTRA_BACKGROUND, true); // Also pass in case user using termux-app version < 0.119.0 + return executionIntent; + } + + static PendingIntent createAction(final Context context, String action){ + Intent executeIntent = createExecuteIntent(action); + // Use unique request code for each action created so that pending intent extras are updated + // and do not conflict when same action is recreated or between actions of different notifications. + return PendingIntent.getService(context, + PluginUtils.getLastPendingIntentRequestCode(context), executeIntent, + PendingIntentUtils.getPendingIntentImmutableFlag()); + } +} diff --git a/app/src/main/java/com/termux/api/NotificationListAPI.java b/app/src/main/java/com/termux/api/apis/NotificationListAPI.java similarity index 57% rename from app/src/main/java/com/termux/api/NotificationListAPI.java rename to app/src/main/java/com/termux/api/apis/NotificationListAPI.java index 9b32bb9fe..388e3520a 100644 --- a/app/src/main/java/com/termux/api/NotificationListAPI.java +++ b/app/src/main/java/com/termux/api/apis/NotificationListAPI.java @@ -1,18 +1,27 @@ -package com.termux.api; +package com.termux.api.apis; import android.app.Notification; import android.content.Context; import android.content.Intent; +import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.util.JsonWriter; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; import com.termux.api.util.ResultReturner.ResultJsonWriter; +import com.termux.shared.logger.Logger; public class NotificationListAPI { + private static final String LOG_TAG = "NotificationListAPI"; + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); ResultReturner.returnData(apiReceiver, intent, new ResultJsonWriter() { @Override @@ -33,16 +42,24 @@ static void listNotifications(Context context, JsonWriter out) throws Exception String key = ""; String title = ""; String text = ""; + CharSequence[] lines = null; String packageName = ""; String tag = ""; String group = ""; + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String when = dateFormat.format(new Date(n.getNotification().when)); if (n.getNotification().extras.getCharSequence(Notification.EXTRA_TITLE) != null) { title = n.getNotification().extras.getCharSequence(Notification.EXTRA_TITLE).toString(); } - if (n.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT) != null) { + if (n.getNotification().extras.getCharSequence(Notification.EXTRA_BIG_TEXT) != null) { + text = n.getNotification().extras.getCharSequence(Notification.EXTRA_BIG_TEXT).toString(); + } else if (n.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT) != null) { text = n.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString(); } + if (n.getNotification().extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES) != null) { + lines = n.getNotification().extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES); + } if (n.getTag() != null) { tag = n.getTag(); } @@ -62,8 +79,38 @@ static void listNotifications(Context context, JsonWriter out) throws Exception .name("group").value(group) .name("packageName").value(packageName) .name("title").value(title) - .name("content").value(text).endObject(); + .name("content").value(text) + .name("when").value(when); + if (lines != null) { + out.name("lines").beginArray(); + for (CharSequence line : lines) { + out.value(line.toString()); + } + out.endArray(); + } + out.endObject(); } out.endArray(); + } + + + + public static class NotificationService extends NotificationListenerService { + static NotificationService _this; + + public static NotificationService get() { + return _this; + } + + @Override + public void onListenerConnected() { + _this = this; + } + + @Override + public void onListenerDisconnected() { + _this = null; } } + +} diff --git a/app/src/main/java/com/termux/api/apis/SAFAPI.java b/app/src/main/java/com/termux/api/apis/SAFAPI.java new file mode 100644 index 000000000..6dd5c297b --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/SAFAPI.java @@ -0,0 +1,348 @@ +package com.termux.api.apis; + +import android.content.Context; +import android.content.Intent; +import android.content.UriPermission; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.FileUtils; +import android.provider.DocumentsContract; +import android.util.JsonWriter; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.documentfile.provider.DocumentFile; + +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.ResultReturner; +import com.termux.shared.data.IntentUtils; +import com.termux.shared.logger.Logger; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; + +public class SAFAPI { + + private static final String LOG_TAG = "SAFAPI"; + + public static class SAFActivity extends AppCompatActivity { + + private boolean resultReturned = false; + + private static final String LOG_TAG = "SAFActivity"; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + Logger.logDebug(LOG_TAG, "onCreate"); + + super.onCreate(savedInstanceState); + Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + startActivityForResult(i, 0); + } + + @Override + protected void onDestroy() { + Logger.logDebug(LOG_TAG, "onDestroy"); + + super.onDestroy(); + finishAndRemoveTask(); + if (! resultReturned) { + ResultReturner.returnData(this, getIntent(), out -> out.write("")); + resultReturned = true; + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + Logger.logVerbose(LOG_TAG, "onActivityResult: requestCode: " + requestCode + ", resultCode: " + resultCode + ", data: " + IntentUtils.getIntentString(data)); + + super.onActivityResult(requestCode, resultCode, data); + if (data != null) { + Uri uri = data.getData(); + if (uri != null) { + getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + resultReturned = true; + ResultReturner.returnData(this, getIntent(), out -> out.println(data.getDataString())); + } + } + finish(); + } + } + + public static void onReceive(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + String method = intent.getStringExtra("safmethod"); + if (method == null) { + Logger.logError(LOG_TAG, "safmethod extra null"); + return; + } + try { + switch (method) { + case "getManagedDocumentTrees": + getManagedDocumentTrees(apiReceiver, context, intent); + break; + case "manageDocumentTree": + manageDocumentTree(context, intent); + break; + case "writeDocument": + writeDocument(apiReceiver, context, intent); + break; + case "createDocument": + createDocument(apiReceiver, context, intent); + break; + case "readDocument": + readDocument(apiReceiver, context, intent); + break; + case "listDirectory": + listDirectory(apiReceiver, context, intent); + break; + case "removeDocument": + removeDocument(apiReceiver, context, intent); + break; + case "statURI": + statURI(apiReceiver, context, intent); + break; + default: + Logger.logError(LOG_TAG, "Unrecognized safmethod: " + "'" + method + "'"); + } + } catch (Exception e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Error in SAFAPI", e); + } + } + + private static void getManagedDocumentTrees(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() + { + @Override + public void writeJson(JsonWriter out) throws Exception { + out.beginArray(); + for (UriPermission p : context.getContentResolver().getPersistedUriPermissions()) { + statDocument(out, context, treeUriToDocumentUri(p.getUri())); + } + out.endArray(); + } + }); + } + + private static void manageDocumentTree(Context context, Intent intent) { + Intent i = new Intent(context, SAFActivity.class); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + ResultReturner.copyIntentExtras(intent, i); + context.startActivity(i); + } + + private static void writeDocument(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + String uri = intent.getStringExtra("uri"); + if (uri == null) { + Logger.logError(LOG_TAG, "uri extra null"); + return; + } + DocumentFile f = DocumentFile.fromSingleUri(context, Uri.parse(uri)); + if (f == null) { + return; + } + writeDocumentFile(apiReceiver, context, intent, f); + } + + private static void createDocument(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + String treeURIString = intent.getStringExtra("treeuri"); + if (treeURIString == null) { + Logger.logError(LOG_TAG, "treeuri extra null"); + return; + } + String name = intent.getStringExtra("filename"); + if (name == null) { + Logger.logError(LOG_TAG, "filename extra null"); + return; + } + String mime = intent.getStringExtra("mimetype"); + if (mime == null) { + mime = "application/octet-stream"; + } + Uri treeURI = Uri.parse(treeURIString); + String id = DocumentsContract.getTreeDocumentId(treeURI); + try { + id = DocumentsContract.getDocumentId(Uri.parse(treeURIString)); + } catch (IllegalArgumentException ignored) {} + final String finalMime = mime; + final String finalId = id; + ResultReturner.returnData(apiReceiver, intent, out -> + out.println(DocumentsContract.createDocument(context.getContentResolver(), DocumentsContract.buildDocumentUriUsingTree(treeURI, finalId), finalMime, name).toString()) + ); + } + + private static void readDocument(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + String uri = intent.getStringExtra("uri"); + if (uri == null) { + Logger.logError(LOG_TAG, "uri extra null"); + return; + } + DocumentFile f = DocumentFile.fromSingleUri(context, Uri.parse(uri)); + if (f == null) { + return; + } + returnDocumentFile(apiReceiver, context, intent, f); + } + + private static void listDirectory(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + String treeURIString = intent.getStringExtra("treeuri"); + if (treeURIString == null) { + Logger.logError(LOG_TAG, "treeuri extra null"); + return; + } + Uri treeURI = Uri.parse(treeURIString); + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() + { + @Override + public void writeJson(JsonWriter out) throws Exception { + out.beginArray(); + String id = DocumentsContract.getTreeDocumentId(treeURI); + try { + id = DocumentsContract.getDocumentId(Uri.parse(treeURIString)); + } catch (IllegalArgumentException ignored) {} + try (Cursor c = context.getContentResolver().query(DocumentsContract.buildChildDocumentsUriUsingTree(Uri.parse(treeURIString), id), new String[] { + DocumentsContract.Document.COLUMN_DOCUMENT_ID }, null, null, null)) { + while (c.moveToNext()) { + String documentId = c.getString(0); + Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(treeURI, documentId); + statDocument(out, context, documentUri); + } + } catch (UnsupportedOperationException ignored) { } + out.endArray(); + } + }); + } + + private static void statURI(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + String uriString = intent.getStringExtra("uri"); + if (uriString == null) { + Logger.logError(LOG_TAG, "uri extra null"); + return; + } + Uri docUri = treeUriToDocumentUri(Uri.parse(uriString)); + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() + { + @Override + public void writeJson(JsonWriter out) throws Exception { + statDocument(out, context, Uri.parse(docUri.toString())); + } + }); + } + + + private static void removeDocument(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + String uri = intent.getStringExtra("uri"); + if (uri == null) { + Logger.logError(LOG_TAG, "uri extra null"); + return; + } + ResultReturner.returnData(apiReceiver, intent, out -> { + try { + if (DocumentsContract.deleteDocument(context.getContentResolver(), Uri.parse(uri))) { + out.println(0); + } else { + out.println(1); + } + } catch (FileNotFoundException | IllegalArgumentException e ) { + out.println(2); + } + }); + } + + + private static Uri treeUriToDocumentUri(Uri tree) { + String id = DocumentsContract.getTreeDocumentId(tree); + try { + id = DocumentsContract.getDocumentId(tree); + } catch (IllegalArgumentException ignored) {} + return DocumentsContract.buildDocumentUriUsingTree(tree, id); + } + + private static void statDocument(JsonWriter out, Context context, Uri uri) throws Exception { + try (Cursor c = context.getContentResolver().query(uri, null, null, null, null)) { + if (c == null || c.getCount() == 0) { + return; + } + int index; + String mime = null; + c.moveToNext(); + out.beginObject(); + + index = c.getColumnIndex(DocumentsContract.Document.COLUMN_DISPLAY_NAME); + if (index >= 0) { + out.name("name"); + out.value(c.getString(index)); + } + + index = c.getColumnIndex(DocumentsContract.Document.COLUMN_MIME_TYPE); + if (index >= 0) { + out.name("type"); + mime = c.getString(index); + out.value(mime); + } + + out.name("uri"); + out.value(uri.toString()); + + index = c.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED); + if (index >= 0) { + out.name("last_modified"); + out.value(c.getLong(index)); + } + + if (mime != null && !DocumentsContract.Document.MIME_TYPE_DIR.equals(mime)) { + index = c.getColumnIndex(DocumentsContract.Document.COLUMN_SIZE); + if (index >= 0) { + out.name("length"); + out.value(c.getInt(index)); + } + } + + out.endObject(); + } + } + + private static void returnDocumentFile(TermuxApiReceiver apiReceiver, Context context, Intent intent, DocumentFile f) { + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.BinaryOutput() + { + @Override + public void writeResult(OutputStream out) throws Exception { + try (InputStream in = context.getContentResolver().openInputStream(f.getUri())) { + writeInputStreamToOutputStream(in, out); + } + } + }); + } + + private static void writeDocumentFile(TermuxApiReceiver apiReceiver, Context context, Intent intent, DocumentFile f) { + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.WithInput() + { + @Override + public void writeResult(PrintWriter unused) throws Exception { + try (OutputStream out = context.getContentResolver().openOutputStream(f.getUri(), "rwt")) { + writeInputStreamToOutputStream(in, out); + } + } + }); + } + + private static void writeInputStreamToOutputStream(InputStream in, OutputStream out) throws IOException { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + FileUtils.copy(in, out); + } + else { + byte[] buffer = new byte[4096]; + int read; + while ((read = in.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + } + } + +} diff --git a/app/src/main/java/com/termux/api/SensorAPI.java b/app/src/main/java/com/termux/api/apis/SensorAPI.java similarity index 84% rename from app/src/main/java/com/termux/api/SensorAPI.java rename to app/src/main/java/com/termux/api/apis/SensorAPI.java index d9f2feca5..efa8fede4 100644 --- a/app/src/main/java/com/termux/api/SensorAPI.java +++ b/app/src/main/java/com/termux/api/apis/SensorAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.app.Service; import android.content.Context; @@ -12,7 +12,7 @@ import android.os.IBinder; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; import org.json.JSONArray; import org.json.JSONException; @@ -21,6 +21,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Collections; import java.util.concurrent.Semaphore; @@ -29,10 +30,14 @@ */ public class SensorAPI { + private static final String LOG_TAG = "SensorAPI"; + /** * Starts our SensorReader service */ public static void onReceive(final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + Intent serviceIntent = new Intent(context, SensorReaderService.class); serviceIntent.setAction(intent.getAction()); serviceIntent.putExtras(intent.getExtras()); @@ -44,6 +49,7 @@ public static void onReceive(final Context context, final Intent intent) { * All sensor listening functionality exists in this background service */ public static class SensorReaderService extends Service { + // indentation for JSON output protected static final int INDENTATION = 2; @@ -54,8 +60,11 @@ public static class SensorReaderService extends Service { // prevent concurrent modifications w/ sensor readout protected static Semaphore semaphore; + private static final String LOG_TAG = "SensorReaderService"; public void onCreate() { + Logger.logDebug(LOG_TAG, "onCreate"); + super.onCreate(); sensorReadout = new JSONObject(); semaphore = new Semaphore(1); @@ -63,6 +72,8 @@ public void onCreate() { @Override public int onStartCommand(Intent intent, int flags, int startId) { + Logger.logDebug(LOG_TAG, "onStartCommand"); + String command = intent.getAction(); Context context = getApplicationContext(); SensorManager sensorManager = getSensorManager(context); @@ -86,9 +97,10 @@ protected static SensorManager getSensorManager(Context context) { @Override public void onDestroy() { + Logger.logDebug(LOG_TAG, "onDestroy"); + super.onDestroy(); cleanup(); - TermuxApiLogger.info("SensorAPI SensorReaderService onDestroy()"); } protected static void cleanup() { @@ -126,7 +138,7 @@ public void onSensorChanged(SensorEvent sensorEvent) { sensorReadout.put(sensorEvent.sensor.getName(), sensorInfo); semaphore.release(); } catch (JSONException e) { - TermuxApiLogger.error("onSensorChanged error", e); + Logger.logStackTraceWithMessage(LOG_TAG, "onSensorChanged error", e); } catch (InterruptedException e) { e.printStackTrace(); } @@ -193,7 +205,7 @@ private void postSensorCommandResult(final Context context, final Intent intent, output.put("sensors", sensorArray); result.message = output.toString(INDENTATION); } catch (JSONException e) { - TermuxApiLogger.error("listHandler JSON error", e); + Logger.logStackTraceWithMessage(LOG_TAG, "listHandler JSON error", e); } return result; }; @@ -211,7 +223,7 @@ public SensorCommandResult handle(SensorManager sensorManager, Context context, outputWriter = null; sensorManager.unregisterListener(sensorEventListener); result.message = "Sensor cleanup successful!"; - TermuxApiLogger.info("Cleanup()"); + Logger.logInfo(LOG_TAG, "Cleanup()"); } else { result.message = "Sensor cleanup unnecessary"; } @@ -260,7 +272,8 @@ protected static String[] getUserRequestedSensors(Intent intent) { * Gets a list of all sensors to listen to, that were requested and are available */ protected static List getSensorsToListenTo(SensorManager sensorManager, String[] requestedSensors, Intent intent) { - List availableSensors = sensorManager.getSensorList(Sensor.TYPE_ALL); + List availableSensors = new ArrayList<>(sensorManager.getSensorList(Sensor.TYPE_ALL)); + Collections.sort(availableSensors, (s1, s2) -> s1.getName().compareTo(s2.getName())); List sensorsToListenTo = new ArrayList<>(); boolean listenToAll = intent.getBooleanExtra("all", false); @@ -270,21 +283,29 @@ protected static List getSensorsToListenTo(SensorManager sensorManager, sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_UI); } sensorsToListenTo = availableSensors; - TermuxApiLogger.info("Listening to ALL sensors"); + Logger.logInfo(LOG_TAG, "Listening to ALL sensors"); } else { // try to find matching sensors that were sent in request - for (String sensorName : requestedSensors) { + for (String requestedSensor : requestedSensors) { // ignore case - sensorName = sensorName.toUpperCase(); + requestedSensor = requestedSensor.toUpperCase(); + + Sensor shortestMatchSensor = null; + int shortestMatchSensorLength = Integer.MAX_VALUE; - for (Sensor sensor : availableSensors) { - if (sensor.getName().toUpperCase().contains(sensorName)) { - sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_UI); - sensorsToListenTo.add(sensor); - break; + for (Sensor availableSensor : availableSensors) { + String sensorName = availableSensor.getName().toUpperCase(); + if (sensorName.contains(requestedSensor) && sensorName.length() < shortestMatchSensorLength) { + shortestMatchSensor = availableSensor; + shortestMatchSensorLength = sensorName.length(); } } + + if (shortestMatchSensor != null) { + sensorManager.registerListener(sensorEventListener, shortestMatchSensor, SensorManager.SENSOR_DELAY_UI); + sensorsToListenTo.add(shortestMatchSensor); + } } } return sensorsToListenTo; @@ -311,15 +332,15 @@ protected static SensorOutputWriter createSensorOutputWriter(Intent intent) { outputWriter = new SensorOutputWriter(socketAddress); outputWriter.setOnErrorListener(e -> { outputWriter = null; - TermuxApiLogger.error("SensorOutputWriter error", e); + Logger.logStackTraceWithMessage(LOG_TAG, "SensorOutputWriter error", e); }); int delay = intent.getIntExtra("delay", SensorOutputWriter.DEFAULT_DELAY); - TermuxApiLogger.info("Delay set to: " + delay); + Logger.logInfo(LOG_TAG, "Delay set to: " + delay); outputWriter.setDelay(delay); int limit = intent.getIntExtra("limit", SensorOutputWriter.DEFAULT_LIMIT); - TermuxApiLogger.info("SensorOutput limit set to: " + limit); + Logger.logInfo(LOG_TAG, "SensorOutput limit set to: " + limit); outputWriter.setLimit(limit); return outputWriter; @@ -375,7 +396,8 @@ public void run() { try { try (LocalSocket outputSocket = new LocalSocket()) { - outputSocket.connect(new LocalSocketAddress(this.outputSocketAddress)); + outputSocket.connect(ResultReturner.getApiLocalSocketAddress( + ResultReturner.context, "output", this.outputSocketAddress)); try (PrintWriter writer = new PrintWriter(outputSocket.getOutputStream())) { @@ -383,7 +405,7 @@ public void run() { try { Thread.sleep(this.delay); } catch (InterruptedException e) { - TermuxApiLogger.info("SensorOutputWriter interrupted: " + e.getMessage()); + Logger.logInfo(LOG_TAG, "SensorOutputWriter interrupted: " + e.getMessage()); } semaphore.acquire(); writer.write(sensorReadout.toString(INDENTATION) + "\n"); @@ -391,15 +413,15 @@ public void run() { semaphore.release(); if (++counter >= limit) { - TermuxApiLogger.info("SensorOutput limit reached! Performing cleanup"); + Logger.logInfo(LOG_TAG, "SensorOutput limit reached! Performing cleanup"); cleanup(); } } - TermuxApiLogger.info("SensorOutputWriter finished"); + Logger.logInfo(LOG_TAG, "SensorOutputWriter finished"); } } } catch (Exception e) { - TermuxApiLogger.error("SensorOutputWriter error", e); + Logger.logStackTraceWithMessage(LOG_TAG, "SensorOutputWriter error", e); if (errorListener != null) { errorListener.onError(e); diff --git a/app/src/main/java/com/termux/api/ShareAPI.java b/app/src/main/java/com/termux/api/apis/ShareAPI.java similarity index 84% rename from app/src/main/java/com/termux/api/ShareAPI.java rename to app/src/main/java/com/termux/api/apis/ShareAPI.java index 407611f1c..a8eeb7655 100644 --- a/app/src/main/java/com/termux/api/ShareAPI.java +++ b/app/src/main/java/com/termux/api/apis/ShareAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.ContentValues; import android.content.Context; @@ -11,16 +11,25 @@ import android.text.TextUtils; import android.webkit.MimeTypeMap; +import com.termux.api.R; +import com.termux.api.TermuxAPIConstants; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; +import com.termux.shared.net.uri.UriUtils; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.PrintWriter; public class ShareAPI { - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + private static final String LOG_TAG = "ShareAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + final String fileExtra = intent.getStringExtra("file"); final String titleExtra = intent.getStringExtra("title"); final String contentTypeExtra = intent.getStringExtra("content-type"); @@ -42,7 +51,7 @@ static void onReceive(TermuxApiReceiver apiReceiver, final Context context, fina intentAction = Intent.ACTION_VIEW; break; default: - TermuxApiLogger.error("Invalid action '" + actionExtra + "', using 'view'"); + Logger.logError(LOG_TAG, "Invalid action '" + actionExtra + "', using 'view'"); break; } } @@ -81,7 +90,9 @@ public void writeResult(PrintWriter out) { Intent sendIntent = new Intent(); sendIntent.setAction(finalIntentAction); - Uri uriToShare = Uri.parse("content://com.termux.sharedfiles" + fileToShare.getAbsolutePath()); + + // Do not create Uri with Uri.parse() and use Uri.Builder().path(), check UriUtils.getUriFilePath(). + Uri uriToShare = UriUtils.getContentUri(TermuxAPIConstants.TERMUX_API_FILE_SHARE_URI_AUTHORITY, fileToShare.getAbsolutePath()); sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); String contentTypeToUse; @@ -116,6 +127,8 @@ public void writeResult(PrintWriter out) { public static class ContentProvider extends android.content.ContentProvider { + private static final String LOG_TAG = "ContentProvider"; + @Override public boolean onCreate() { return true; @@ -182,7 +195,17 @@ public int update(Uri uri, ContentValues values, String selection, String[] sele @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { File file = new File(uri.getPath()); + + try { + String path = file.getCanonicalPath(); + String callingPackageName = getCallingPackage(); + Logger.logDebug(LOG_TAG, "Open file request received from " + callingPackageName + " for \"" + path + "\" with mode \"" + mode + "\""); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } } + } diff --git a/app/src/main/java/com/termux/api/apis/SmsInboxAPI.java b/app/src/main/java/com/termux/api/apis/SmsInboxAPI.java new file mode 100644 index 000000000..17e5693ed --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/SmsInboxAPI.java @@ -0,0 +1,401 @@ +package com.termux.api.apis; + +import android.annotation.SuppressLint; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.provider.ContactsContract.PhoneLookup; +import android.provider.Telephony.Sms; +import android.provider.Telephony.Sms.Conversations; +import android.provider.Telephony.TextBasedSmsColumns; +import android.util.JsonWriter; + +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.ResultReturner; +import com.termux.api.util.ResultReturner.ResultJsonWriter; +import com.termux.shared.logger.Logger; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import static android.provider.Telephony.TextBasedSmsColumns.*; + +import androidx.annotation.Nullable; + +/** + * **See Also:** + * - https://developer.android.com/reference/android/provider/Telephony + * - https://developer.android.com/reference/android/provider/Telephony.Sms.Conversations + * - https://developer.android.com/reference/android/provider/Telephony.TextBasedSmsColumns + * - https://developer.android.com/reference/android/provider/BaseColumns + */ +public class SmsInboxAPI { + + private static final String[] DISPLAY_NAME_PROJECTION = {PhoneLookup.DISPLAY_NAME}; + + private static final String LOG_TAG = "SmsInboxAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + String value; + + final boolean conversationList = intent.getBooleanExtra("conversation-list", false); + + final boolean conversationReturnMultipleMessages = intent.getBooleanExtra("conversation-return-multiple-messages", false); + final boolean conversationReturnNestedView = intent.getBooleanExtra("conversation-return-nested-view", false); + final boolean conversationReturnNoOrderReverse = intent.getBooleanExtra("conversation-return-no-order-reverse", false); + + final int conversationOffset = intent.getIntExtra("conversation-offset", -1); + final int conversationLimit = intent.getIntExtra("conversation-limit", -1); + final String conversationSelection = intent.getStringExtra("conversation-selection"); + + /* + NOTE: When conversation or messages are queried from the Android database, first the + sort order is applied, and then any offset and limit values are used to filter the + entries. Since the default sort order is 'date DESC', Android returns the latest dated + conversations or messages first, but the API reverses the order by default (with + `Cursor.moveToLast()`/`Cursor.moveToPrevious()`) so that the latest entries are printed + at the end. If the order should not be reversed, then pass the respective + `*-return-no-order-reverse` extras. + */ + value = intent.getStringExtra("conversation-sort-order"); + if (value == null || value.isEmpty()) { + value = "date DESC"; + } + final String conversationSortOrder = value; + + + final int messageOffset = intent.getIntExtra("offset", 0); + final int messageLimit = intent.getIntExtra("limit", 10); + final int messageTypeColumn = intent.getIntExtra("type", TextBasedSmsColumns.MESSAGE_TYPE_INBOX); + final String messageSelection = intent.getStringExtra("message-selection"); + + value = intent.getStringExtra("from"); + if (value == null || value.isEmpty()) { + value = null; + } + final String messageAddress = value; + + value = intent.getStringExtra("message-sort-order"); + if (value == null || value.isEmpty()) { + value = "date DESC"; + } + final String messageSortOrder = value; + + final boolean messageReturnNoOrderReverse = intent.getBooleanExtra("message-return-no-order-reverse", false); + + Uri contentURI; + if (conversationList) { + contentURI = typeToContentURI(TextBasedSmsColumns.MESSAGE_TYPE_ALL); + } else { + contentURI = typeToContentURI(messageAddress == null ? + messageTypeColumn : TextBasedSmsColumns.MESSAGE_TYPE_ALL); + } + + ResultReturner.returnData(apiReceiver, intent, new ResultJsonWriter() { + @Override + public void writeJson(JsonWriter out) throws Exception { + if (conversationList) { + getConversations(context, out, + conversationOffset, conversationLimit, + conversationSelection, + conversationSortOrder, + conversationReturnMultipleMessages,conversationReturnNestedView, + conversationReturnNoOrderReverse, + messageOffset, messageLimit, + messageSelection, + messageSortOrder, + messageReturnNoOrderReverse); + } else { + getAllSms(context, out, contentURI, + messageOffset, messageLimit, + messageSelection, messageAddress, + messageSortOrder, + messageReturnNoOrderReverse); + } + } + }); + } + + @SuppressLint("SimpleDateFormat") + public static void getConversations(Context context, JsonWriter out, + int conversationOffset, int conversationLimit, + String conversationSelection, + String conversationSortOrder, + boolean conversationReturnMultipleMessages, boolean conversationReturnNestedView, + boolean conversationReturnNoOrderReverse, + int messageOffset, int messageLimit, + String messageSelection, + String messageSortOrder, + boolean messageReturnNoOrderReverse) throws IOException { + ContentResolver cr = context.getContentResolver(); + + // `THREAD_ID` is used to select messages for a conversation, so do not allow caller to pass it. + if (messageSelection != null && messageSelection.matches("^(.*[ \t\n])?" + THREAD_ID + "[ \t\n].*$")) { + throw new IllegalArgumentException( + "The 'conversation-selection' cannot contain '" + THREAD_ID + "': `" + messageSelection + "`"); + } + + conversationSortOrder = getSortOrder(conversationSortOrder, conversationOffset, conversationLimit); + messageSortOrder = getSortOrder(messageSortOrder, messageOffset, messageLimit); + + int index; + try (Cursor conversationCursor = cr.query(Conversations.CONTENT_URI, + null, conversationSelection, null , conversationSortOrder)) { + int conversationCount = conversationCursor.getCount(); + if (conversationReturnNoOrderReverse) { + conversationCursor.moveToFirst(); + } else { + conversationCursor.moveToLast(); + } + + Map nameCache = new HashMap<>(); + + if (conversationReturnNestedView) { + out.beginObject(); + } else { + out.beginArray(); + } + for (int i = 0; i < conversationCount; i++) { + index = conversationCursor.getColumnIndex(THREAD_ID); + if (index < 0) { + conversationCursor.moveToPrevious(); + continue; + } + + int id = conversationCursor.getInt(index); + + if (conversationReturnNestedView) { + out.name(String.valueOf(id)); + out.beginArray(); + } + + String[] messageSelectionArgs = null; + if (messageSelection == null || messageSelection.isEmpty()) { + messageSelection = ""; + } else { + messageSelection += " "; + } + + Cursor messageCursor = cr.query(Sms.CONTENT_URI, null, + messageSelection + THREAD_ID + " == '" + id +"'", messageSelectionArgs, + messageSortOrder); + + int messageCount = messageCursor.getCount(); + if (messageCount > 0) { + if (conversationReturnMultipleMessages) { + if (messageReturnNoOrderReverse) { + messageCursor.moveToFirst(); + } else { + messageCursor.moveToLast(); + } + + for (int j = 0; j < messageCount; j++) { + writeElement(messageCursor, out, nameCache, context); + + if (messageReturnNoOrderReverse) { + messageCursor.moveToNext(); + } else { + messageCursor.moveToPrevious(); + } + } + } else { + messageCursor.moveToFirst(); + writeElement(messageCursor, out, nameCache, context); + } + } + + messageCursor.close(); + + if (conversationReturnNestedView) { + out.endArray(); + } + + if (conversationReturnNoOrderReverse) { + conversationCursor.moveToNext(); + } else { + conversationCursor.moveToPrevious(); + } + } + if (conversationReturnNestedView) { + out.endObject(); + } else { + out.endArray(); + } + } + } + + @SuppressLint("SimpleDateFormat") + private static void writeElement(Cursor c, JsonWriter out, Map nameCache, Context context) throws IOException { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + int index; + int threadID = c.getInt(c.getColumnIndexOrThrow(THREAD_ID)); + String smsAddress = c.getString(c.getColumnIndexOrThrow(ADDRESS)); + String smsBody = c.getString(c.getColumnIndexOrThrow(BODY)); + long smsReceivedDate = c.getLong(c.getColumnIndexOrThrow(DATE)); + // long smsSentDate = c.getLong(c.getColumnIndexOrThrow(TextBasedSmsColumns.DATE_SENT)); + int smsID = c.getInt(c.getColumnIndexOrThrow("_id")); + + String smsSenderName = getContactNameFromNumber(nameCache, context, smsAddress); + String messageType = getMessageType(c.getInt(c.getColumnIndexOrThrow(TYPE))); + + out.beginObject(); + out.name("threadid").value(threadID); + out.name("type").value(messageType); + + index = c.getColumnIndex(READ); + if (index >= 0) { + out.name("read").value(c.getInt(index) != 0); + } + + if (smsSenderName != null) { + if (messageType.equals("inbox")) { + out.name("sender").value(smsSenderName); + } else { + out.name("sender").value("You"); + } + } + + out.name("address").value(smsAddress); + // Deprecated: Address can be a name like service provider instead of a number. + out.name("number").value(smsAddress); + + out.name("received").value(dateFormat.format(new Date(smsReceivedDate))); + // if (Math.abs(smsReceivedDate - smsSentDate) >= 60000) { + // out.write(" (sent "); + // out.write(dateFormat.format(new Date(smsSentDate))); + // out.write(")"); + // } + out.name("body").value(smsBody); + out.name("_id").value(smsID); + + out.endObject(); + } + + + @SuppressLint("SimpleDateFormat") + public static void getAllSms(Context context, JsonWriter out, + Uri contentURI, + int messageOffset, int messageLimit, + String messageSelection, String messageAddress, + String messageSortOrder, + boolean messageReturnNoOrderReverse) throws IOException { + ContentResolver cr = context.getContentResolver(); + + String[] messageSelectionArgs = null; + if (messageSelection == null || messageSelection.isEmpty()) { + if (messageAddress != null && !messageAddress.isEmpty()) { + messageSelection = ADDRESS + " LIKE ?"; + messageSelectionArgs = new String[]{messageAddress}; + } + } + + messageSortOrder = getSortOrder(messageSortOrder, messageOffset, messageLimit); + + try (Cursor messageCursor = cr.query(contentURI, null, + messageSelection, messageSelectionArgs, + messageSortOrder)) { + int messageCount = messageCursor.getCount(); + if (messageReturnNoOrderReverse) { + messageCursor.moveToFirst(); + } else { + messageCursor.moveToLast(); + } + + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Map nameCache = new HashMap<>(); + + out.beginArray(); + for (int i = 0; i < messageCount; i++) { + writeElement(messageCursor, out, nameCache, context); + + if (messageReturnNoOrderReverse) { + messageCursor.moveToNext(); + } else { + messageCursor.moveToPrevious(); + } + } + out.endArray(); + } + } + + private static String getContactNameFromNumber(Map cache, Context context, String number) { + if (cache.containsKey(number)) { + return cache.get(number); + } + + int index; + Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); + try (Cursor c = context.getContentResolver().query(contactUri, DISPLAY_NAME_PROJECTION, null, null, null)) { + String name = null; + if (c.moveToFirst()) { + index = c.getColumnIndex(PhoneLookup.DISPLAY_NAME); + if (index >= 0) { + name = c.getString(index); + } + } + + cache.put(number, name); + return name; + } + } + + private static String getMessageType(int type) { + switch (type) + { + case TextBasedSmsColumns.MESSAGE_TYPE_INBOX: + return "inbox"; + case TextBasedSmsColumns.MESSAGE_TYPE_SENT: + return "sent"; + case TextBasedSmsColumns.MESSAGE_TYPE_DRAFT: + return "draft"; + case TextBasedSmsColumns.MESSAGE_TYPE_FAILED: + return "failed"; + case TextBasedSmsColumns.MESSAGE_TYPE_OUTBOX: + return "outbox"; + default: + return ""; + } + } + + private static Uri typeToContentURI(int type) { + switch (type) { + case TextBasedSmsColumns.MESSAGE_TYPE_SENT: + return Sms.Sent.CONTENT_URI; + case TextBasedSmsColumns.MESSAGE_TYPE_DRAFT: + return Sms.Draft.CONTENT_URI; + case TextBasedSmsColumns.MESSAGE_TYPE_OUTBOX: + return Sms.Outbox.CONTENT_URI; + case TextBasedSmsColumns.MESSAGE_TYPE_INBOX: + return Sms.Inbox.CONTENT_URI; + case TextBasedSmsColumns.MESSAGE_TYPE_ALL: + default: + return Sms.CONTENT_URI; + } + } + + @Nullable + private static String getSortOrder(String sortOrder, int offset, int limit) { + if (sortOrder == null) { + sortOrder = ""; + } + if (limit >= 0) { + sortOrder += " LIMIT " + limit; + } + if (offset >= 0) { + sortOrder += " OFFSET " + offset; + } + if (sortOrder.isEmpty()) { + sortOrder = null; + } + return sortOrder; + } + +} diff --git a/app/src/main/java/com/termux/api/apis/SmsSendAPI.java b/app/src/main/java/com/termux/api/apis/SmsSendAPI.java new file mode 100644 index 000000000..c7d34862d --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/SmsSendAPI.java @@ -0,0 +1,74 @@ +package com.termux.api.apis; + +import android.Manifest; +import android.content.Context; +import android.content.Intent; +import android.telephony.SmsManager; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionInfo; + +import androidx.annotation.RequiresPermission; + +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; + +import java.io.PrintWriter; +import java.util.ArrayList; + +public class SmsSendAPI { + + private static final String LOG_TAG = "SmsSendAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.WithStringInput() { + @RequiresPermission(allOf = { Manifest.permission.READ_PHONE_STATE, Manifest.permission.SEND_SMS }) + @Override + public void writeResult(PrintWriter out) { + final SmsManager smsManager = getSmsManager(context,intent); + if(smsManager == null) return; + + String[] recipients = intent.getStringArrayExtra("recipients"); + + if (recipients == null) { + // Used by old versions of termux-send-sms. + String recipient = intent.getStringExtra("recipient"); + if (recipient != null) recipients = new String[]{recipient}; + } + + if (recipients == null || recipients.length == 0) { + Logger.logError(LOG_TAG, "No recipient given"); + } else { + final ArrayList messages = smsManager.divideMessage(inputString); + for (String recipient : recipients) { + smsManager.sendMultipartTextMessage(recipient, null, messages, null, null); + } + } + } + }); + } + + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + static SmsManager getSmsManager(Context context, final Intent intent) { + int slot = intent.getIntExtra("slot", -1); + if(slot == -1) { + return SmsManager.getDefault(); + } else { + SubscriptionManager sm = context.getSystemService(SubscriptionManager.class); + if(sm == null) { + Logger.logError(LOG_TAG, "SubscriptionManager not supported"); + return null; + } + for(SubscriptionInfo si: sm.getActiveSubscriptionInfoList()) { + if(si.getSimSlotIndex() == slot) { + return SmsManager.getSmsManagerForSubscriptionId(si.getSubscriptionId()); + } + } + Logger.logError(LOG_TAG, "Sim slot "+slot+" not found"); + return null; + } + } + +} diff --git a/app/src/main/java/com/termux/api/SpeechToTextAPI.java b/app/src/main/java/com/termux/api/apis/SpeechToTextAPI.java similarity index 90% rename from app/src/main/java/com/termux/api/SpeechToTextAPI.java rename to app/src/main/java/com/termux/api/apis/SpeechToTextAPI.java index 483e5c125..c33d7a31a 100644 --- a/app/src/main/java/com/termux/api/SpeechToTextAPI.java +++ b/app/src/main/java/com/termux/api/apis/SpeechToTextAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.app.Activity; import android.app.AlertDialog; @@ -14,7 +14,8 @@ import android.speech.SpeechRecognizer; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.data.IntentUtils; +import com.termux.shared.logger.Logger; import java.io.PrintWriter; import java.util.List; @@ -22,6 +23,8 @@ public class SpeechToTextAPI { + private static final String LOG_TAG = "SpeechToTextAPI"; + public static class SpeechToTextService extends IntentService { private static final String STOP_ELEMENT = ""; @@ -37,8 +40,12 @@ public SpeechToTextService(String name) { protected SpeechRecognizer mSpeechRecognizer; final LinkedBlockingQueue queueu = new LinkedBlockingQueue<>(); + private static final String LOG_TAG = "SpeechToTextService"; + @Override public void onCreate() { + Logger.logDebug(LOG_TAG, "onCreate"); + super.onCreate(); final Context context = this; @@ -53,7 +60,7 @@ public void onRmsChanged(float rmsdB) { @Override public void onResults(Bundle results) { List recognitions = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); - TermuxApiLogger.error("RecognitionListener#onResults(" + recognitions + ")"); + Logger.logError(LOG_TAG, "RecognitionListener#onResults(" + recognitions + ")"); queueu.addAll(recognitions); } @@ -66,7 +73,7 @@ public void onReadyForSpeech(Bundle params) { public void onPartialResults(Bundle partialResults) { // Do nothing. List strings = partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); - TermuxApiLogger.error("RecognitionListener#onPartialResults(" + strings + ")"); + Logger.logError(LOG_TAG, "RecognitionListener#onPartialResults(" + strings + ")"); queueu.addAll(strings); } @@ -94,13 +101,13 @@ public void onError(int error) { default: description = Integer.toString(error); } - TermuxApiLogger.error("RecognitionListener#onError(" + description + ")"); + Logger.logError(LOG_TAG, "RecognitionListener#onError(" + description + ")"); queueu.add(STOP_ELEMENT); } @Override public void onEndOfSpeech() { - TermuxApiLogger.error("RecognitionListener#onEndOfSpeech()"); + Logger.logError(LOG_TAG, "RecognitionListener#onEndOfSpeech()"); queueu.add(STOP_ELEMENT); } @@ -145,14 +152,16 @@ public void onBeginningOfSpeech() { @Override public void onDestroy() { + Logger.logDebug(LOG_TAG, "onDestroy"); + super.onDestroy(); - TermuxApiLogger.error("onDestroy"); mSpeechRecognizer.destroy(); } @Override protected void onHandleIntent(final Intent intent) { - TermuxApiLogger.error("onHandleIntent"); + Logger.logDebug(LOG_TAG, "onHandleIntent:\n" + IntentUtils.getIntentString(intent)); + ResultReturner.returnData(this, intent, new ResultReturner.WithInput() { @Override public void writeResult(PrintWriter out) throws Exception { @@ -171,6 +180,8 @@ public void writeResult(PrintWriter out) throws Exception { } public static void onReceive(final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + context.startService(new Intent(context, SpeechToTextService.class).putExtras(intent.getExtras())); } diff --git a/app/src/main/java/com/termux/api/StorageGetAPI.java b/app/src/main/java/com/termux/api/apis/StorageGetAPI.java similarity index 53% rename from app/src/main/java/com/termux/api/StorageGetAPI.java rename to app/src/main/java/com/termux/api/apis/StorageGetAPI.java index 2cd769980..2101c8cf1 100644 --- a/app/src/main/java/com/termux/api/StorageGetAPI.java +++ b/app/src/main/java/com/termux/api/apis/StorageGetAPI.java @@ -1,14 +1,22 @@ -package com.termux.api; +package com.termux.api.apis; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Bundle; +import androidx.annotation.Nullable; + +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.data.IntentUtils; +import com.termux.shared.errors.Error; +import com.termux.shared.file.FileUtils; +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.termux.file.TermuxFileUtils; -import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -16,18 +24,34 @@ public class StorageGetAPI { - private static final String FILE_EXTRA = "com.termux.api.storage.file"; + private static final String FILE_EXTRA = TermuxConstants.TERMUX_API_PACKAGE_NAME + ".storage.file"; + + private static final String LOG_TAG = "StorageGetAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); - static void onReceive(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { ResultReturner.returnData(apiReceiver, intent, out -> { final String fileExtra = intent.getStringExtra("file"); - if (fileExtra == null || !new File(fileExtra).getParentFile().canWrite()) { - out.println("ERROR: Not a writable folder: " + fileExtra); + if (fileExtra == null || fileExtra.isEmpty()) { + out.println("ERROR: " + "File path not passed"); + + return; + } + + // Get canonical path of fileExtra + String filePath = TermuxFileUtils.getCanonicalPath(fileExtra, null, true); + String fileParentDirPath = FileUtils.getFileDirname(filePath); + Logger.logVerbose(LOG_TAG, "filePath=\"" + filePath + "\", fileParentDirPath=\"" + fileParentDirPath + "\""); + + Error error = FileUtils.checkMissingFilePermissions("file parent directory", fileParentDirPath, "rw-", true); + if (error != null) { + out.println("ERROR: " + error.getErrorLogString()); return; } Intent intent1 = new Intent(context, StorageActivity.class); - intent1.putExtra(FILE_EXTRA, fileExtra); + intent1.putExtra(FILE_EXTRA, filePath); intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent1); }); @@ -37,8 +61,19 @@ public static class StorageActivity extends Activity { private String outputFile; + private static final String LOG_TAG = "StorageActivity"; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + Logger.logDebug(LOG_TAG, "onCreate"); + + super.onCreate(savedInstanceState); + } + @Override public void onResume() { + Logger.logVerbose(LOG_TAG, "onResume"); + super.onResume(); outputFile = getIntent().getStringExtra(FILE_EXTRA); @@ -56,6 +91,8 @@ public void onResume() { @Override protected void onActivityResult(int requestCode, int resultCode, Intent resultData) { + Logger.logVerbose(LOG_TAG, "onActivityResult: requestCode: " + requestCode + ", resultCode: " + resultCode + ", data: " + IntentUtils.getIntentString(resultData)); + super.onActivityResult(requestCode, resultCode, resultData); if (resultCode == RESULT_OK) { Uri data = resultData.getData(); @@ -74,7 +111,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent resultDa } } } catch (IOException e) { - TermuxApiLogger.error("Error copying " + data + " to " + outputFile); + Logger.logStackTraceWithMessage(LOG_TAG, "Error copying " + data + " to " + outputFile, e); } } finish(); diff --git a/app/src/main/java/com/termux/api/apis/TelephonyAPI.java b/app/src/main/java/com/termux/api/apis/TelephonyAPI.java new file mode 100644 index 000000000..6a751e6c8 --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/TelephonyAPI.java @@ -0,0 +1,427 @@ +package com.termux.api.apis; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.telephony.CellInfo; +import android.telephony.CellInfoCdma; +import android.telephony.CellInfoGsm; +import android.telephony.CellInfoLte; +import android.telephony.CellInfoWcdma; +import android.telephony.CellInfoNr; +import android.telephony.CellIdentityNr; +import android.telephony.CellSignalStrength; +import android.telephony.CellSignalStrengthNr; +import android.telephony.TelephonyManager; +import android.util.JsonWriter; + +import androidx.annotation.RequiresPermission; + +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; + +import java.io.IOException; + +import java.util.List; + +/** + * Exposing {@link android.telephony.TelephonyManager}. + */ +public class TelephonyAPI { + + private static final String LOG_TAG = "TelephonyAPI"; + + private static void writeIfKnown(JsonWriter out, String name, int value) throws IOException { + if (value != Integer.MAX_VALUE) out.name(name).value(value); + } + private static void writeIfKnown(JsonWriter out, String name, long value) throws IOException { + if (value != Long.MAX_VALUE) out.name(name).value(value); + } + private static void writeIfKnown(JsonWriter out, String name, int[] value) throws IOException { + if (value != null) { + out.name(name); + out.beginArray(); + for (int i = 0; i < value.length; i++) out.value(value[i]); + out.endArray(); + + } + } + + public static void onReceiveTelephonyCellInfo(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveTelephonyCellInfo"); + + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { + @Override + public void writeJson(JsonWriter out) throws Exception { + TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + out.beginArray(); + + List cellInfoData = null; + + try { + cellInfoData = manager.getAllCellInfo(); + } catch (SecurityException e) { + // Direct call of getAllCellInfo() doesn't work on Android 10 (Q). + // https://developer.android.com/reference/android/telephony/TelephonyManager#getAllCellInfo(). + } + + if (cellInfoData != null) { + for (CellInfo cellInfo : cellInfoData) { + out.beginObject(); + if (cellInfo instanceof CellInfoGsm) { + CellInfoGsm gsmInfo = (CellInfoGsm) cellInfo; + out.name("type").value("gsm"); + out.name("registered").value(cellInfo.isRegistered()); + + out.name("asu").value(gsmInfo.getCellSignalStrength().getAsuLevel()); + writeIfKnown(out, "dbm", gsmInfo.getCellSignalStrength().getDbm()); + out.name("level").value(gsmInfo.getCellSignalStrength().getLevel()); + + writeIfKnown(out, "cid", gsmInfo.getCellIdentity().getCid()); + writeIfKnown(out, "lac", gsmInfo.getCellIdentity().getLac()); + writeIfKnown(out, "mcc", gsmInfo.getCellIdentity().getMcc()); + writeIfKnown(out, "mnc", gsmInfo.getCellIdentity().getMnc()); + } else if (cellInfo instanceof CellInfoLte) { + CellInfoLte lteInfo = (CellInfoLte) cellInfo; + out.name("type").value("lte"); + out.name("registered").value(cellInfo.isRegistered()); + + out.name("asu").value(lteInfo.getCellSignalStrength().getAsuLevel()); + out.name("dbm").value(lteInfo.getCellSignalStrength().getDbm()); + writeIfKnown(out, "level", lteInfo.getCellSignalStrength().getLevel()); + writeIfKnown(out, "timing_advance", lteInfo.getCellSignalStrength().getTimingAdvance()); + + writeIfKnown(out, "ci", lteInfo.getCellIdentity().getCi()); + writeIfKnown(out, "pci", lteInfo.getCellIdentity().getPci()); + writeIfKnown(out, "tac", lteInfo.getCellIdentity().getTac()); + writeIfKnown(out, "mcc", lteInfo.getCellIdentity().getMcc()); + writeIfKnown(out, "mnc", lteInfo.getCellIdentity().getMnc()); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + writeIfKnown(out, "rsrp", lteInfo.getCellSignalStrength().getRsrp()); + writeIfKnown(out, "rsrq", lteInfo.getCellSignalStrength().getRsrq()); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + writeIfKnown(out, "rssi", lteInfo.getCellSignalStrength().getRssi()); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + writeIfKnown(out, "bands", lteInfo.getCellIdentity().getBands()); + } + } else if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) && (cellInfo instanceof CellInfoNr)) { + CellInfoNr nrInfo = (CellInfoNr) cellInfo; + CellIdentityNr nrcellIdent = (CellIdentityNr) nrInfo.getCellIdentity(); + CellSignalStrength ssInfo = nrInfo.getCellSignalStrength(); + out.name("type").value("nr"); + out.name("registered").value(cellInfo.isRegistered()); + + out.name("asu").value(ssInfo.getAsuLevel()); + out.name("dbm").value(ssInfo.getDbm()); + writeIfKnown(out, "level", ssInfo.getLevel()); + writeIfKnown(out, "nci", nrcellIdent.getNci()); + writeIfKnown(out, "pci", nrcellIdent.getPci()); + writeIfKnown(out, "tac", nrcellIdent.getTac()); + out.name("mcc").value(nrcellIdent.getMccString()); + out.name("mnc").value(nrcellIdent.getMncString()); + if (ssInfo instanceof CellSignalStrengthNr) { + CellSignalStrengthNr nrssInfo = (CellSignalStrengthNr) ssInfo; + writeIfKnown(out, "csi_rsrp", nrssInfo.getCsiRsrp()); + writeIfKnown(out, "csi_rsrq", nrssInfo.getCsiRsrq()); + writeIfKnown(out, "csi_sinr", nrssInfo.getCsiSinr()); + writeIfKnown(out, "ss_rsrp", nrssInfo.getSsRsrp()); + writeIfKnown(out, "ss_rsrq", nrssInfo.getSsRsrq()); + writeIfKnown(out, "ss_sinr", nrssInfo.getSsSinr()); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + writeIfKnown(out, "bands", nrcellIdent.getBands()); + } + } else if (cellInfo instanceof CellInfoCdma) { + CellInfoCdma cdmaInfo = (CellInfoCdma) cellInfo; + out.name("type").value("cdma"); + out.name("registered").value(cellInfo.isRegistered()); + + out.name("asu").value(cdmaInfo.getCellSignalStrength().getAsuLevel()); + out.name("dbm").value(cdmaInfo.getCellSignalStrength().getDbm()); + out.name("level").value(cdmaInfo.getCellSignalStrength().getLevel()); + out.name("cdma_dbm").value(cdmaInfo.getCellSignalStrength().getCdmaDbm()); + out.name("cdma_ecio").value(cdmaInfo.getCellSignalStrength().getCdmaEcio()); + out.name("cdma_level").value(cdmaInfo.getCellSignalStrength().getCdmaLevel()); + out.name("evdo_dbm").value(cdmaInfo.getCellSignalStrength().getEvdoDbm()); + out.name("evdo_ecio").value(cdmaInfo.getCellSignalStrength().getEvdoEcio()); + out.name("evdo_level").value(cdmaInfo.getCellSignalStrength().getEvdoLevel()); + out.name("evdo_snr").value(cdmaInfo.getCellSignalStrength().getEvdoSnr()); + + out.name("basestation").value(cdmaInfo.getCellIdentity().getBasestationId()); + out.name("latitude").value(cdmaInfo.getCellIdentity().getLatitude()); + out.name("longitude").value(cdmaInfo.getCellIdentity().getLongitude()); + out.name("network").value(cdmaInfo.getCellIdentity().getNetworkId()); + out.name("system").value(cdmaInfo.getCellIdentity().getSystemId()); + } else if (cellInfo instanceof CellInfoWcdma) { + CellInfoWcdma wcdmaInfo = (CellInfoWcdma) cellInfo; + out.name("type").value("wcdma"); + out.name("registered").value(cellInfo.isRegistered()); + + out.name("asu").value(wcdmaInfo.getCellSignalStrength().getAsuLevel()); + writeIfKnown(out, "dbm", wcdmaInfo.getCellSignalStrength().getDbm()); + out.name("level").value(wcdmaInfo.getCellSignalStrength().getLevel()); + + writeIfKnown(out, "cid", wcdmaInfo.getCellIdentity().getCid()); + writeIfKnown(out, "lac", wcdmaInfo.getCellIdentity().getLac()); + writeIfKnown(out, "mcc", wcdmaInfo.getCellIdentity().getMcc()); + writeIfKnown(out, "mnc", wcdmaInfo.getCellIdentity().getMnc()); + writeIfKnown(out, "psc", wcdmaInfo.getCellIdentity().getPsc()); + } + out.endObject(); + } + } + + out.endArray(); + } + }); + } + + public static void onReceiveTelephonyDeviceInfo(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveTelephonyDeviceInfo"); + + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + @SuppressLint("HardwareIds") + @Override + public void writeJson(JsonWriter out) throws Exception { + TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + out.beginObject(); + + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + out.name("data_enabled").value(Boolean.toString(manager.isDataEnabled())); + } + + int dataActivity = manager.getDataActivity(); + String dataActivityString; + switch (dataActivity) { + case TelephonyManager.DATA_ACTIVITY_NONE: + dataActivityString = "none"; + break; + case TelephonyManager.DATA_ACTIVITY_IN: + dataActivityString = "in"; + break; + case TelephonyManager.DATA_ACTIVITY_OUT: + dataActivityString = "out"; + break; + case TelephonyManager.DATA_ACTIVITY_INOUT: + dataActivityString = "inout"; + break; + case TelephonyManager.DATA_ACTIVITY_DORMANT: + dataActivityString = "dormant"; + break; + default: + dataActivityString = Integer.toString(dataActivity); + break; + } + out.name("data_activity").value(dataActivityString); + + int dataState = manager.getDataState(); + String dataStateString; + switch (dataState) { + case TelephonyManager.DATA_DISCONNECTED: + dataStateString = "disconnected"; + break; + case TelephonyManager.DATA_CONNECTING: + dataStateString = "connecting"; + break; + case TelephonyManager.DATA_CONNECTED: + dataStateString = "connected"; + break; + case TelephonyManager.DATA_SUSPENDED: + dataStateString = "suspended"; + break; + default: + dataStateString = Integer.toString(dataState); + break; + } + out.name("data_state").value(dataStateString); + + int phoneType = manager.getPhoneType(); + + String device_id = null; + + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + device_id = phoneType == TelephonyManager.PHONE_TYPE_GSM ? manager.getImei() : manager.getMeid(); + } + } catch (SecurityException e) { + // Failed to obtain device id. + // Android 10+ requires READ_PRIVILEGED_PHONE_STATE + // https://source.android.com/devices/tech/config/device-identifiers + } + + out.name("device_id").value(device_id); + out.name("device_software_version").value(manager.getDeviceSoftwareVersion()); + out.name("phone_count").value(manager.getPhoneCount()); + String phoneTypeString; + switch (phoneType) { + case TelephonyManager.PHONE_TYPE_CDMA: + phoneTypeString = "cdma"; + break; + case TelephonyManager.PHONE_TYPE_GSM: + phoneTypeString = "gsm"; + break; + case TelephonyManager.PHONE_TYPE_NONE: + phoneTypeString = "none"; + break; + case TelephonyManager.PHONE_TYPE_SIP: + phoneTypeString = "sip"; + break; + default: + phoneTypeString = Integer.toString(phoneType); + break; + } + out.name("phone_type").value(phoneTypeString); + + out.name("network_operator").value(manager.getNetworkOperator()); + out.name("network_operator_name").value(manager.getNetworkOperatorName()); + out.name("network_country_iso").value(manager.getNetworkCountryIso()); + int networkType = manager.getNetworkType(); + String networkTypeName; + switch (networkType) { + case TelephonyManager.NETWORK_TYPE_1xRTT: + networkTypeName = "1xrtt"; + break; + case TelephonyManager.NETWORK_TYPE_CDMA: + networkTypeName = "cdma"; + break; + case TelephonyManager.NETWORK_TYPE_EDGE: + networkTypeName = "edge"; + break; + case TelephonyManager.NETWORK_TYPE_EHRPD: + networkTypeName = "ehrpd"; + break; + case TelephonyManager.NETWORK_TYPE_EVDO_0: + networkTypeName = "evdo_0"; + break; + case TelephonyManager.NETWORK_TYPE_EVDO_A: + networkTypeName = "evdo_a"; + break; + case TelephonyManager.NETWORK_TYPE_EVDO_B: + networkTypeName = "evdo_b"; + break; + case TelephonyManager.NETWORK_TYPE_GPRS: + networkTypeName = "gprs"; + break; + case TelephonyManager.NETWORK_TYPE_HSDPA: + networkTypeName = "hdspa"; + break; + case TelephonyManager.NETWORK_TYPE_HSPA: + networkTypeName = "hspa"; + break; + case TelephonyManager.NETWORK_TYPE_HSPAP: + networkTypeName = "hspap"; + break; + case TelephonyManager.NETWORK_TYPE_HSUPA: + networkTypeName = "hsupa"; + break; + case TelephonyManager.NETWORK_TYPE_IDEN: + networkTypeName = "iden"; + break; + case TelephonyManager.NETWORK_TYPE_LTE: + networkTypeName = "lte"; + break; + case TelephonyManager.NETWORK_TYPE_UMTS: + networkTypeName = "umts"; + break; + case TelephonyManager.NETWORK_TYPE_UNKNOWN: + networkTypeName = "unknown"; + break; + default: + if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) && (networkType == TelephonyManager.NETWORK_TYPE_NR)) { + networkTypeName = "nr"; + break; + } + networkTypeName = Integer.toString(networkType); + break; + } + out.name("network_type").value(networkTypeName); + out.name("network_roaming").value(manager.isNetworkRoaming()); + out.name("sim_country_iso").value(manager.getSimCountryIso()); + out.name("sim_operator").value(manager.getSimOperator()); + out.name("sim_operator_name").value(manager.getSimOperatorName()); + + String sim_serial = null; + String subscriber_id = null; + try { + sim_serial = manager.getSimSerialNumber(); + subscriber_id = manager.getSubscriberId(); + } catch (SecurityException e) { + // Failed to obtain device id. + // Android 10+. + } + out.name("sim_serial_number").value(sim_serial); + out.name("sim_subscriber_id").value(subscriber_id); + + int simState = manager.getSimState(); + String simStateString; + switch (simState) { + case TelephonyManager.SIM_STATE_ABSENT: + simStateString = "absent"; + break; + case TelephonyManager.SIM_STATE_NETWORK_LOCKED: + simStateString = "network_locked"; + break; + case TelephonyManager.SIM_STATE_PIN_REQUIRED: + simStateString = "pin_required"; + break; + case TelephonyManager.SIM_STATE_PUK_REQUIRED: + simStateString = "puk_required"; + break; + case TelephonyManager.SIM_STATE_READY: + simStateString = "ready"; + break; + case TelephonyManager.SIM_STATE_UNKNOWN: + simStateString = "unknown"; + break; + default: + simStateString = Integer.toString(simState); + break; + } + out.name("sim_state").value(simStateString); + } + + out.endObject(); + } + }); + } + + public static void onReceiveTelephonyCall(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveTelephonyCall"); + + String numberExtra = intent.getStringExtra("number"); + if (numberExtra == null) { + Logger.logError(LOG_TAG, "No 'number' extra"); + ResultReturner.noteDone(apiReceiver, intent); + return; + } + + if(numberExtra.contains("#")) + numberExtra = numberExtra.replace("#","%23"); + + Uri data = Uri.parse("tel:" + numberExtra); + + Intent callIntent = new Intent(Intent.ACTION_CALL); + callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + callIntent.setData(data); + + try { + context.startActivity(callIntent); + } catch (SecurityException e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Exception in phone call", e); + } + + ResultReturner.noteDone(apiReceiver, intent); + } + +} diff --git a/app/src/main/java/com/termux/api/TextToSpeechAPI.java b/app/src/main/java/com/termux/api/apis/TextToSpeechAPI.java similarity index 87% rename from app/src/main/java/com/termux/api/TextToSpeechAPI.java rename to app/src/main/java/com/termux/api/apis/TextToSpeechAPI.java index 4fea86ba7..2dae2dd1c 100644 --- a/app/src/main/java/com/termux/api/TextToSpeechAPI.java +++ b/app/src/main/java/com/termux/api/apis/TextToSpeechAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.app.IntentService; import android.content.Context; @@ -12,7 +12,8 @@ import android.util.JsonWriter; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.data.IntentUtils; +import com.termux.shared.logger.Logger; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -24,7 +25,11 @@ public class TextToSpeechAPI { + private static final String LOG_TAG = "TextToSpeechAPI"; + public static void onReceive(final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + context.startService(new Intent(context, TextToSpeechService.class).putExtras(intent.getExtras())); } @@ -32,12 +37,23 @@ public static class TextToSpeechService extends IntentService { TextToSpeech mTts; final CountDownLatch mTtsLatch = new CountDownLatch(1); + private static final String LOG_TAG = "TextToSpeechService"; + public TextToSpeechService() { super(TextToSpeechService.class.getName()); } + @Override + public void onCreate() { + Logger.logDebug(LOG_TAG, "onCreate"); + + super.onCreate(); + } + @Override public void onDestroy() { + Logger.logDebug(LOG_TAG, "onDestroy"); + if (mTts != null) mTts.shutdown(); super.onDestroy(); @@ -45,6 +61,8 @@ public void onDestroy() { @Override protected void onHandleIntent(final Intent intent) { + Logger.logDebug(LOG_TAG, "onHandleIntent:\n" + IntentUtils.getIntentString(intent)); + final String speechLanguage = intent.getStringExtra("language"); final String speechRegion = intent.getStringExtra("region"); final String speechVariant = intent.getStringExtra("variant"); @@ -83,7 +101,7 @@ protected void onHandleIntent(final Intent intent) { if (status == TextToSpeech.SUCCESS) { mTtsLatch.countDown(); } else { - TermuxApiLogger.error("Failed tts initialization: status=" + status); + Logger.logError(LOG_TAG, "Failed tts initialization: status=" + status); stopSelf(); } }, speechEngine); @@ -95,11 +113,11 @@ public void writeResult(PrintWriter out) { try { try { if (!mTtsLatch.await(10, TimeUnit.SECONDS)) { - TermuxApiLogger.error("Timeout waiting for TTS initialization"); + Logger.logError(LOG_TAG, "Timeout waiting for TTS initialization"); return; } } catch (InterruptedException e) { - TermuxApiLogger.error("Interrupted awaiting TTS initialization"); + Logger.logError(LOG_TAG, "Interrupted awaiting TTS initialization"); return; } @@ -131,7 +149,7 @@ public void onStart(String utteranceId) { @Override public void onError(String utteranceId) { - TermuxApiLogger.error("UtteranceProgressListener.onError() called"); + Logger.logError(LOG_TAG, "UtteranceProgressListener.onError() called"); synchronized (ttsDoneUtterancesCount) { ttsDoneUtterancesCount.incrementAndGet(); ttsDoneUtterancesCount.notify(); @@ -150,7 +168,7 @@ public void onDone(String utteranceId) { if (speechLanguage != null) { int setLanguageResult = mTts.setLanguage(getLocale(speechLanguage, speechRegion, speechVariant)); if (setLanguageResult != TextToSpeech.LANG_AVAILABLE) { - TermuxApiLogger.error("tts.setLanguage('" + speechLanguage + "') returned " + setLanguageResult); + Logger.logError(LOG_TAG, "tts.setLanguage('" + speechLanguage + "') returned " + setLanguageResult); } } @@ -180,7 +198,7 @@ public void onDone(String utteranceId) { } } } catch (Exception e) { - TermuxApiLogger.error("TTS error", e); + Logger.logStackTraceWithMessage(LOG_TAG, "TTS error", e); } } }); diff --git a/app/src/main/java/com/termux/api/ToastAPI.java b/app/src/main/java/com/termux/api/apis/ToastAPI.java similarity index 89% rename from app/src/main/java/com/termux/api/ToastAPI.java rename to app/src/main/java/com/termux/api/apis/ToastAPI.java index 5221b3561..96ea2ea03 100644 --- a/app/src/main/java/com/termux/api/ToastAPI.java +++ b/app/src/main/java/com/termux/api/apis/ToastAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.Context; import android.content.Intent; @@ -11,13 +11,17 @@ import android.widget.Toast; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; import java.io.PrintWriter; public class ToastAPI { + private static final String LOG_TAG = "ToastAPI"; + public static void onReceive(final Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + final int durationExtra = intent.getBooleanExtra("short", false) ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG; final int backgroundColor = getColorExtra(intent, "background", Color.GRAY); final int textColor = getColorExtra(intent, "text_color", Color.WHITE); @@ -54,7 +58,7 @@ protected static int getColorExtra(Intent intent, String extra, int defaultColor try { color = Color.parseColor(colorExtra); } catch (IllegalArgumentException e) { - TermuxApiLogger.error(String.format("Failed to parse color '%s' for '%s'", colorExtra, extra)); + Logger.logError(LOG_TAG, String.format("Failed to parse color '%s' for '%s'", colorExtra, extra)); } } return color; diff --git a/app/src/main/java/com/termux/api/TorchAPI.java b/app/src/main/java/com/termux/api/apis/TorchAPI.java similarity index 79% rename from app/src/main/java/com/termux/api/TorchAPI.java rename to app/src/main/java/com/termux/api/apis/TorchAPI.java index 4f9d9b707..1e0867c50 100644 --- a/app/src/main/java/com/termux/api/TorchAPI.java +++ b/app/src/main/java/com/termux/api/apis/TorchAPI.java @@ -1,36 +1,31 @@ -package com.termux.api; +package com.termux.api.apis; -import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.hardware.Camera; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraManager; -import android.os.Build; import android.widget.Toast; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; public class TorchAPI { private static Camera legacyCamera; + private static final String LOG_TAG = "TorchAPI"; - @TargetApi(Build.VERSION_CODES.M) public static void onReceive(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + boolean enabled = intent.getBooleanExtra("enabled", false); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - toggleTorch(context, enabled); - } else { - // use legacy api for pre-marshmallow - legacyToggleTorch(enabled); - } + toggleTorch(context, enabled); ResultReturner.noteDone(apiReceiver, intent); } - @TargetApi(Build.VERSION_CODES.M) private static void toggleTorch(Context context, boolean enabled) { try { final CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); @@ -42,12 +37,12 @@ private static void toggleTorch(Context context, boolean enabled) { Toast.makeText(context, "Torch unavailable on your device", Toast.LENGTH_LONG).show(); } } catch (CameraAccessException e) { - TermuxApiLogger.error("Error toggling torch", e); + Logger.logStackTraceWithMessage(LOG_TAG, "Error toggling torch", e); } } private static void legacyToggleTorch(boolean enabled) { - TermuxApiLogger.info("Using legacy camera api to toggle torch"); + Logger.logInfo(LOG_TAG, "Using legacy camera api to toggle torch"); if (legacyCamera == null) { legacyCamera = Camera.open(); diff --git a/app/src/main/java/com/termux/api/apis/UsbAPI.java b/app/src/main/java/com/termux/api/apis/UsbAPI.java new file mode 100644 index 000000000..0d9257731 --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/UsbAPI.java @@ -0,0 +1,338 @@ +package com.termux.api.apis; + +import android.app.PendingIntent; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; +import android.hardware.usb.UsbManager; +import android.os.Build; +import android.os.Bundle; +import android.os.IBinder; +import android.util.JsonWriter; +import android.util.SparseArray; + +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.TermuxConstants; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import androidx.annotation.NonNull; + +public class UsbAPI { + + protected static final String LOG_TAG = "UsbAPI"; + + protected static SparseArray openDevices = new SparseArray<>(); + + protected static final String ACTION_USB_PERMISSION = TermuxConstants.TERMUX_API_PACKAGE_NAME + ".USB_PERMISSION"; + + public static void onReceive(final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + Intent serviceIntent = new Intent(context, UsbService.class); + serviceIntent.setAction(intent.getAction()); + Bundle extras = intent.getExtras(); + if (extras != null) + serviceIntent.putExtras(extras); + context.startService(serviceIntent); + } + + public static class UsbService extends Service { + + protected static final String LOG_TAG = "UsbService"; + + private final ThreadPoolExecutor mThreadPoolExecutor; + + public UsbService() { + super(); + mThreadPoolExecutor = new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>()); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + public void onCreate() { + Logger.logDebug(LOG_TAG, "onCreate"); + + super.onCreate(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Logger.logDebug(LOG_TAG, "onStartCommand"); + + String action = intent.getAction(); + if (action == null) { + Logger.logError(LOG_TAG, "No action passed"); + ResultReturner.returnData(this, intent, out -> out.append("Missing action\n")); + } + + if (action != null) { + switch (action) { + case "list": + runListAction(intent); + break; + case "permission": + runPermissionAction(intent); + break; + case "open": + runOpenAction(intent); + break; + default: + Logger.logError(LOG_TAG, "Invalid action: \"" + action + "\""); + ResultReturner.returnData(this, intent, out -> out.append("Invalid action: \"" + action + "\"\n")); + } + } + + return Service.START_NOT_STICKY; + } + + @Override + public void onDestroy() { + Logger.logDebug(LOG_TAG, "onDestroy"); + + super.onDestroy(); + } + + + + protected void runListAction(Intent intent) { + Logger.logVerbose(LOG_TAG,"Running 'list' usb devices action"); + + ResultReturner.returnData(this, intent, new ResultReturner.ResultJsonWriter() { + @Override + public void writeJson(JsonWriter out) throws Exception { + listDevices(out); + } + }); + } + + protected void listDevices(JsonWriter out) throws IOException { + UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); + HashMap deviceList = usbManager.getDeviceList(); + out.beginArray(); + for (String deviceName : deviceList.keySet()) { + out.value(deviceName); + } + out.endArray(); + } + + + + protected void runPermissionAction(Intent intent) { + mThreadPoolExecutor.submit(() -> { + String deviceName = intent.getStringExtra("device"); + + Logger.logVerbose(LOG_TAG,"Running 'permission' action for device \"" + deviceName + "\""); + + UsbDevice device = getDevice(intent, deviceName); + if (device == null) return; + + int status = checkAndRequestUsbDevicePermission(intent, device); + ResultReturner.returnData(this, intent, out -> { + if (status == 0) { + Logger.logVerbose(LOG_TAG, "Permission granted for device \"" + device.getDeviceName() + "\""); + out.append("Permission granted.\n" ); + } else if (status == 1) { + Logger.logVerbose(LOG_TAG, "Permission denied for device \"" + device.getDeviceName() + "\""); + out.append("Permission denied.\n" ); + } else if (status == -1) { + out.append("Permission request timeout.\n" ); + } + }); + }); + } + + + + protected void runOpenAction(Intent intent) { + mThreadPoolExecutor.submit(() -> { + String deviceName = intent.getStringExtra("device"); + + Logger.logVerbose(LOG_TAG,"Running 'open' action for device \"" + deviceName + "\""); + + UsbDevice device = getDevice(intent, deviceName); + if (device == null) return; + + int status = checkAndRequestUsbDevicePermission(intent, device); + ResultReturner.returnData(this, intent, new ResultReturner.WithAncillaryFd() { + @Override + public void writeResult(PrintWriter out) { + if (status == 0) { + int fd = open(device); + if (fd < 0) { + Logger.logVerbose(LOG_TAG, "Failed to open device \"" + device.getDeviceName() + "\": " + fd); + out.append("Open device failed.\n"); + } else { + Logger.logVerbose(LOG_TAG, "Open device \"" + device.getDeviceName() + "\" successful"); + this.sendFd(out, fd); + } + } else if (status == 1) { + Logger.logVerbose(LOG_TAG, "Permission denied to open device \"" + device.getDeviceName() + "\""); + out.append("Permission denied.\n" ); + } else if (status == -1) { + out.append("Permission request timeout.\n" ); + } + } + }); + }); + } + + protected int open(@NonNull UsbDevice device) { + UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); + + UsbDeviceConnection connection = usbManager.openDevice(device); + if (connection == null) return -2; + + int fd = connection.getFileDescriptor(); + if (fd == -1) { + connection.close(); + return -1; + } + + openDevices.put(fd, connection); + return fd; + } + + + + protected UsbDevice getDevice(Intent intent, String deviceName) { + UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); + + HashMap deviceList = usbManager.getDeviceList(); + UsbDevice device = deviceList.get(deviceName); + if (device == null) { + Logger.logVerbose(LOG_TAG, "Failed to find device \"" + deviceName + "\""); + ResultReturner.returnData(this, intent, out -> out.append("No such device.\n")); + } + + return device; + } + + + + protected boolean checkUsbDevicePermission(@NonNull UsbDevice device) { + UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); + return usbManager.hasPermission(device); + } + + protected int checkAndRequestUsbDevicePermission(Intent intent, @NonNull UsbDevice device) { + boolean checkResult = checkUsbDevicePermission(device); + Logger.logVerbose(LOG_TAG, "Permission check result for device \"" + device.getDeviceName() + "\": " + checkResult); + if (checkResult) { + return 0; + } + + if(!intent.getBooleanExtra("request", false)) { + return 1; + } + + Logger.logVerbose(LOG_TAG, "Requesting permission for device \"" + device.getDeviceName() + "\""); + + CountDownLatch latch = new CountDownLatch(1); + AtomicReference result = new AtomicReference<>(); + + BroadcastReceiver usbReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent usbIntent) { + if (ACTION_USB_PERMISSION.equals(usbIntent.getAction())) { + boolean requestResult = usbIntent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false); + Logger.logVerbose(LOG_TAG, "Permission request result for device \"" + device.getDeviceName() + "\": " + requestResult); + result.set(requestResult); + } + context.unregisterReceiver(this); + latch.countDown(); + } + }; + + UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); + + Intent usbIntent = new Intent(ACTION_USB_PERMISSION); + // Use explicit intent, otherwise permission request intent will be blocked if intent is + // mutable and app uses `targetSdkVersion` `>= 34`, or following exception will be logged + // to logcat if app uses `targetSdkVersion` `< 34`. + // > `android.app.StackTrace: New mutable implicit PendingIntent: pkg=com.termux.api, + // > action=com.termux.api.USB_PERMISSION, featureId=null. This will be blocked once the + // > app targets U+ for security reasons.` + // - https://developer.android.com/about/versions/14/behavior-changes-14#safer-intents + usbIntent.setPackage(getPackageName()); + + // Use mutable intent, otherwise permission request intent will be blocked if app + // uses `targetSdkVersion` `>= 31` and following exception may be logged to logcat. + // > java.lang.IllegalArgumentException: com.termux.api: Targeting S+ (version 31 and above) + // > requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent. + // > Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality + // > depends on the PendingIntent being mutable, e.g. if it needs to be used with inline + // > replies or bubbles. + // The intent must not be immutable as the `EXTRA_PERMISSION_GRANTED` extra needs to be + // returned by the Android framework. Otherwise, if requesting permission after + // reattaching device, and user presses `OK` to grant permission, the + // `EXTRA_PERMISSION_GRANTED` extra would not exist in the intent, and default `false` + // value would get used, and `No permission` condition of the open request would get + // triggered, even though permission was granted and it won't need to be requested for + // next open request. + // - https://developer.android.com/about/versions/12/behavior-changes-12#pending-intent-mutability + //noinspection ObsoleteSdkInt + int pendingIntentFlags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_MUTABLE : 0; + PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, usbIntent, pendingIntentFlags); + + try { + // Specify flag to not export receiver, otherwise permission request intent will be + // blocked if app uses `targetSdkVersion` `>= 34`. + // - https://developer.android.com/about/versions/14/behavior-changes-14#runtime-receivers-exported + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + registerReceiver(usbReceiver, new IntentFilter(ACTION_USB_PERMISSION), + Context.RECEIVER_NOT_EXPORTED); + } else { + //noinspection UnspecifiedRegisterReceiverFlag + registerReceiver(usbReceiver, new IntentFilter(ACTION_USB_PERMISSION)); + } + + // Request permission and wait. + usbManager.requestPermission(device, permissionIntent); + + try { + if (!latch.await(30L, TimeUnit.SECONDS)) { + Logger.logVerbose(LOG_TAG, "Permission request time out for device \"" + device.getDeviceName() + "\" after 30s"); + return -1; + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + Boolean requestResult = result.get(); + if (requestResult != null) { + usbReceiver = null; + return requestResult ? 0 : 1; + } else { + return 1; + } + } finally { + try { + if (usbReceiver != null) { + unregisterReceiver(usbReceiver); + } + } catch (Exception e) { + // Ignore + } + } + } + } + +} diff --git a/app/src/main/java/com/termux/api/apis/VibrateAPI.java b/app/src/main/java/com/termux/api/apis/VibrateAPI.java new file mode 100644 index 000000000..c2a69a51e --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/VibrateAPI.java @@ -0,0 +1,59 @@ +package com.termux.api.apis; + +import android.content.Context; +import android.content.Intent; +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.os.Build; +import android.os.VibrationEffect; +import android.os.Vibrator; + +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; + +public class VibrateAPI { + + private static final String LOG_TAG = "VibrateAPI"; + + public static void onReceive(TermuxApiReceiver apiReceiver, Context context, Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + + new Thread() { + @Override + public void run() { + Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + int milliseconds = intent.getIntExtra("duration_ms", 1000); + boolean force = intent.getBooleanExtra("force", false); + + AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + if (am == null) { + Logger.logError(LOG_TAG, "Audio service null"); + return; + } + + // Do not vibrate if "Silent" ringer mode or "Do Not Disturb" is enabled and -f/--force option is not used. + if (am.getRingerMode() != AudioManager.RINGER_MODE_SILENT || force) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + vibrator.vibrate(VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE), + new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_ALARM) + .build()); + } else { + vibrator.vibrate(milliseconds); + } + } catch (Exception e) { + // Issue on samsung devices on android 8 + // java.lang.NullPointerException: Attempt to read from field 'android.os.VibrationEffect com.android.server.VibratorService$Vibration.mEffect' on a null object reference + Logger.logStackTraceWithMessage(LOG_TAG, "Failed to run vibrator", e); + } + } + } + }.start(); + + ResultReturner.noteDone(apiReceiver, intent); + } + +} diff --git a/app/src/main/java/com/termux/api/VolumeAPI.java b/app/src/main/java/com/termux/api/apis/VolumeAPI.java similarity index 93% rename from app/src/main/java/com/termux/api/VolumeAPI.java rename to app/src/main/java/com/termux/api/apis/VolumeAPI.java index 6a7e4cbf4..6febb9d8f 100644 --- a/app/src/main/java/com/termux/api/VolumeAPI.java +++ b/app/src/main/java/com/termux/api/apis/VolumeAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.content.Context; import android.content.Intent; @@ -6,7 +6,9 @@ import android.util.JsonWriter; import android.util.SparseArray; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; import java.io.IOException; @@ -24,8 +26,11 @@ public class VolumeAPI { streamMap.append(AudioManager.STREAM_VOICE_CALL, "call"); } + private static final String LOG_TAG = "VolumeAPI"; + + public static void onReceive(final TermuxApiReceiver receiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); - static void onReceive(final TermuxApiReceiver receiver, final Context context, final Intent intent) { final AudioManager audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); String action = intent.getAction(); diff --git a/app/src/main/java/com/termux/api/WallpaperAPI.java b/app/src/main/java/com/termux/api/apis/WallpaperAPI.java similarity index 88% rename from app/src/main/java/com/termux/api/WallpaperAPI.java rename to app/src/main/java/com/termux/api/apis/WallpaperAPI.java index 0d6f960ba..3a8efe62c 100644 --- a/app/src/main/java/com/termux/api/WallpaperAPI.java +++ b/app/src/main/java/com/termux/api/apis/WallpaperAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.app.Service; import android.app.WallpaperManager; @@ -6,11 +6,10 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.os.Build; import android.os.IBinder; import com.termux.api.util.ResultReturner; -import com.termux.api.util.TermuxApiLogger; +import com.termux.shared.logger.Logger; import java.io.IOException; import java.io.InputStream; @@ -24,7 +23,11 @@ public class WallpaperAPI { - static void onReceive(final Context context, final Intent intent) { + private static final String LOG_TAG = "WallpaperAPI"; + + public static void onReceive(final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + Intent wallpaperService = new Intent(context, WallpaperService.class); wallpaperService.putExtras(intent.getExtras()); context.startService(wallpaperService); @@ -38,8 +41,11 @@ static void onReceive(final Context context, final Intent intent) { public static class WallpaperService extends Service { protected static final int DOWNLOAD_TIMEOUT = 30; + private static final String LOG_TAG = "WallpaperService"; public int onStartCommand(Intent intent, int flags, int startId) { + Logger.logDebug(LOG_TAG, "onStartCommand"); + if (intent.hasExtra("file")) { getWallpaperFromFile(intent); } else if (intent.hasExtra("url")) { @@ -72,7 +78,7 @@ protected void getWallpaperFromUrl(final Intent intent) { try { result = wallpaperDownload.get(DOWNLOAD_TIMEOUT, TimeUnit.SECONDS); } catch (InterruptedException e) { - TermuxApiLogger.info("Wallpaper download interrupted"); + Logger.logInfo(LOG_TAG, "Wallpaper download interrupted"); } catch (ExecutionException e) { result.error = "Unknown host!"; } catch (TimeoutException e) { @@ -116,13 +122,8 @@ protected void onWallpaperResult(final Intent intent, WallpaperResult result) { if (result.wallpaper != null) { try { - // allow setting of lock screen wallpaper for Nougat and later - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - int flag = intent.hasExtra("lockscreen") ? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM; - wallpaperManager.setBitmap(result.wallpaper, null, true, flag); - } else { - wallpaperManager.setBitmap(result.wallpaper); - } + int flag = intent.hasExtra("lockscreen") ? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM; + wallpaperManager.setBitmap(result.wallpaper, null, true, flag); result.message = "Wallpaper set successfully!"; } catch (IOException e) { result.error = "Error setting wallpaper: " + e.getMessage(); diff --git a/app/src/main/java/com/termux/api/WifiAPI.java b/app/src/main/java/com/termux/api/apis/WifiAPI.java similarity index 61% rename from app/src/main/java/com/termux/api/WifiAPI.java rename to app/src/main/java/com/termux/api/apis/WifiAPI.java index 8efe3dfa4..0708d9e69 100644 --- a/app/src/main/java/com/termux/api/WifiAPI.java +++ b/app/src/main/java/com/termux/api/apis/WifiAPI.java @@ -1,4 +1,4 @@ -package com.termux.api; +package com.termux.api.apis; import android.annotation.SuppressLint; import android.content.Context; @@ -7,18 +7,23 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.os.Build; import android.text.TextUtils; import android.text.format.Formatter; import android.util.JsonWriter; +import com.termux.api.TermuxApiReceiver; import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; import java.util.List; public class WifiAPI { - static void onReceiveWifiConnectionInfo(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + private static final String LOG_TAG = "WifiAPI"; + + public static void onReceiveWifiConnectionInfo(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveWifiConnectionInfo"); + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { @SuppressLint("HardwareIds") @Override @@ -51,7 +56,9 @@ static boolean isLocationEnabled(Context context) { return lm.isProviderEnabled(LocationManager.GPS_PROVIDER); } - static void onReceiveWifiScanInfo(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + public static void onReceiveWifiScanInfo(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveWifiScanInfo"); + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { @Override public void writeJson(JsonWriter out) throws Exception { @@ -74,37 +81,38 @@ public void writeJson(JsonWriter out) throws Exception { out.name("ssid").value(scan.SSID); out.name("timestamp").value(scan.timestamp); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - int channelWidth = scan.channelWidth; - String channelWidthMhz = "???"; - switch (channelWidth) { - case ScanResult.CHANNEL_WIDTH_20MHZ: - channelWidthMhz = "20"; - break; - case ScanResult.CHANNEL_WIDTH_40MHZ: - channelWidthMhz = "40"; - break; - case ScanResult.CHANNEL_WIDTH_80MHZ: - channelWidthMhz = "80"; - break; - case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: - channelWidthMhz = "80+80"; - break; - case ScanResult.CHANNEL_WIDTH_160MHZ: - channelWidthMhz = "160"; - break; - } - out.name("channel_bandwidth_mhz").value(channelWidthMhz); - if (channelWidth != ScanResult.CHANNEL_WIDTH_20MHZ) { - // centerFreq0 says "Not used if the AP bandwidth is 20 MHz". - out.name("center_frequency_mhz").value(scan.centerFreq0); - } - if (!TextUtils.isEmpty(scan.operatorFriendlyName)) { - out.name("operator_name").value(scan.operatorFriendlyName.toString()); - } - if (!TextUtils.isEmpty(scan.venueName)) { - out.name("venue_name").value(scan.venueName.toString()); - } + int channelWidth = scan.channelWidth; + String channelWidthMhz = "???"; + switch (channelWidth) { + case ScanResult.CHANNEL_WIDTH_20MHZ: + channelWidthMhz = "20"; + break; + case ScanResult.CHANNEL_WIDTH_40MHZ: + channelWidthMhz = "40"; + break; + case ScanResult.CHANNEL_WIDTH_80MHZ: + channelWidthMhz = "80"; + break; + case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: + channelWidthMhz = "80+80"; + break; + case ScanResult.CHANNEL_WIDTH_160MHZ: + channelWidthMhz = "160"; + break; + } + out.name("channel_bandwidth_mhz").value(channelWidthMhz); + if (channelWidth != ScanResult.CHANNEL_WIDTH_20MHZ) { + // centerFreq0 says "Not used if the AP bandwidth is 20 MHz". + out.name("center_frequency_mhz").value(scan.centerFreq0); + } + if (!TextUtils.isEmpty(scan.capabilities)) { + out.name("capabilities").value(scan.capabilities); + } + if (!TextUtils.isEmpty(scan.operatorFriendlyName)) { + out.name("operator_name").value(scan.operatorFriendlyName.toString()); + } + if (!TextUtils.isEmpty(scan.venueName)) { + out.name("venue_name").value(scan.venueName.toString()); } out.endObject(); } @@ -114,7 +122,9 @@ public void writeJson(JsonWriter out) throws Exception { }); } - static void onReceiveWifiEnable(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + public static void onReceiveWifiEnable(TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { + Logger.logDebug(LOG_TAG, "onReceiveWifiEnable"); + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { @Override public void writeJson(JsonWriter out) { diff --git a/app/src/main/java/com/termux/api/settings/activities/TermuxAPISettingsActivity.java b/app/src/main/java/com/termux/api/settings/activities/TermuxAPISettingsActivity.java new file mode 100644 index 000000000..80d39d194 --- /dev/null +++ b/app/src/main/java/com/termux/api/settings/activities/TermuxAPISettingsActivity.java @@ -0,0 +1,134 @@ +package com.termux.api.settings.activities; + +import android.content.Context; +import android.os.Bundle; +import android.os.Environment; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; + +import com.termux.api.R; +import com.termux.shared.activities.ReportActivity; +import com.termux.shared.file.FileUtils; +import com.termux.shared.models.ReportInfo; +import com.termux.shared.interact.ShareUtils; +import com.termux.shared.android.PackageUtils; +import com.termux.shared.termux.settings.preferences.TermuxAPIAppSharedPreferences; +import com.termux.shared.android.AndroidUtils; +import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.termux.TermuxUtils; +import com.termux.shared.activity.media.AppCompatActivityUtils; +import com.termux.shared.theme.NightMode; + +public class TermuxAPISettingsActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + AppCompatActivityUtils.setNightMode(this, NightMode.getAppNightMode().getName(), true); + + setContentView(R.layout.activity_termux_api_settings); + if (savedInstanceState == null) { + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.settings, new RootPreferencesFragment()) + .commit(); + } + + AppCompatActivityUtils.setToolbar(this, com.termux.shared.R.id.toolbar); + AppCompatActivityUtils.setShowBackButtonInActionBar(this, true); + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } + + public static class RootPreferencesFragment extends PreferenceFragmentCompat { + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + Context context = getContext(); + if (context == null) return; + + setPreferencesFromResource(R.xml.sets__termux, rootKey); + + new Thread() { + @Override + public void run() { + configureTermuxAPIPreference(context); + configureAboutPreference(context); + configureDonatePreference(context); + } + }.start(); + } + + private void configureTermuxAPIPreference(@NonNull Context context) { + Preference termuxAPIPreference = findPreference("sets__termux_api_app"); + if (termuxAPIPreference != null) { + TermuxAPIAppSharedPreferences preferences = TermuxAPIAppSharedPreferences.build(context, false); + // If failed to get app preferences, then likely app is not installed, so do not show its preference + termuxAPIPreference.setVisible(preferences != null); + } + } + + private void configureAboutPreference(@NonNull Context context) { + Preference aboutPreference = findPreference("link__termux_about"); + if (aboutPreference != null) { + aboutPreference.setOnPreferenceClickListener(preference -> { + new Thread() { + @Override + public void run() { + String title = "About"; + + StringBuilder aboutString = new StringBuilder(); + aboutString.append(TermuxUtils.getAppInfoMarkdownString(context, TermuxUtils.AppInfoMode.TERMUX_AND_PLUGIN_PACKAGE)); + aboutString.append("\n\n").append(AndroidUtils.getDeviceInfoMarkdownString(context, true)); + aboutString.append("\n\n").append(TermuxUtils.getImportantLinksMarkdownString(context)); + + ReportInfo reportInfo = new ReportInfo(title, + TermuxConstants.TERMUX_API_APP.TERMUX_API_MAIN_ACTIVITY_NAME, title); + reportInfo.setReportString(aboutString.toString()); + reportInfo.setReportSaveFileLabelAndPath(title, + Environment.getExternalStorageDirectory() + "/" + + FileUtils.sanitizeFileName(TermuxConstants.TERMUX_API_APP_NAME.replaceAll(":", "") + + "-" + title + ".log", true, true)); + + ReportActivity.startReportActivity(context, reportInfo); + } + }.start(); + + return true; + }); + } + } + + private void configureDonatePreference(@NonNull Context context) { + Preference donatePreference = findPreference("link__termux_donate"); + if (donatePreference != null) { + String signingCertificateSHA256Digest = PackageUtils.getSigningCertificateSHA256DigestForPackage(context); + if (signingCertificateSHA256Digest != null) { + // If APK is a Google Playstore release, then do not show the donation link + // since Termux isn't exempted from the playstore policy donation links restriction + // Check Fund solicitations: https://pay.google.com/intl/en_in/about/policy/ + String apkRelease = TermuxUtils.getAPKRelease(signingCertificateSHA256Digest); + if (apkRelease == null || apkRelease.equals(TermuxConstants.APK_RELEASE_GOOGLE_PLAYSTORE_SIGNING_CERTIFICATE_SHA256_DIGEST)) { + donatePreference.setVisible(false); + return; + } else { + donatePreference.setVisible(true); + } + } + + donatePreference.setOnPreferenceClickListener(preference -> { + ShareUtils.openUrl(context, TermuxConstants.TERMUX_DONATE_URL); + return true; + }); + } + } + } + +} diff --git a/app/src/main/java/com/termux/api/settings/fragments/termux_api_app/TermuxAPIPreferencesFragment.java b/app/src/main/java/com/termux/api/settings/fragments/termux_api_app/TermuxAPIPreferencesFragment.java new file mode 100644 index 000000000..8e7aebb6d --- /dev/null +++ b/app/src/main/java/com/termux/api/settings/fragments/termux_api_app/TermuxAPIPreferencesFragment.java @@ -0,0 +1,49 @@ +package com.termux.api.settings.fragments.termux_api_app; + +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.Keep; +import androidx.preference.PreferenceDataStore; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceManager; + +import com.termux.api.R; +import com.termux.shared.termux.settings.preferences.TermuxAPIAppSharedPreferences; + +@Keep +public class TermuxAPIPreferencesFragment extends PreferenceFragmentCompat { + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + Context context = getContext(); + if (context == null) return; + + PreferenceManager preferenceManager = getPreferenceManager(); + preferenceManager.setPreferenceDataStore(TermuxAPIPreferencesDataStore.getInstance(context)); + + setPreferencesFromResource(R.xml.prefs__termux_api_app___prefs__app, rootKey); + } + +} + +class TermuxAPIPreferencesDataStore extends PreferenceDataStore { + + private final Context mContext; + private final TermuxAPIAppSharedPreferences mPreferences; + + private static TermuxAPIPreferencesDataStore mInstance; + + private TermuxAPIPreferencesDataStore(Context context) { + mContext = context; + mPreferences = TermuxAPIAppSharedPreferences.build(context, true); + } + + public static synchronized TermuxAPIPreferencesDataStore getInstance(Context context) { + if (mInstance == null) { + mInstance = new TermuxAPIPreferencesDataStore(context); + } + return mInstance; + } + +} diff --git a/app/src/main/java/com/termux/api/settings/fragments/termux_api_app/debugging/DebuggingPreferencesFragment.java b/app/src/main/java/com/termux/api/settings/fragments/termux_api_app/debugging/DebuggingPreferencesFragment.java new file mode 100644 index 000000000..174be5768 --- /dev/null +++ b/app/src/main/java/com/termux/api/settings/fragments/termux_api_app/debugging/DebuggingPreferencesFragment.java @@ -0,0 +1,117 @@ +package com.termux.api.settings.fragments.termux_api_app.debugging; + +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.ListPreference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceDataStore; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceManager; + +import com.termux.api.R; +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.settings.preferences.TermuxAPIAppSharedPreferences; + +@Keep +public class DebuggingPreferencesFragment extends PreferenceFragmentCompat { + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + Context context = getContext(); + if (context == null) return; + + PreferenceManager preferenceManager = getPreferenceManager(); + preferenceManager.setPreferenceDataStore(DebuggingPreferencesDataStore.getInstance(context)); + + setPreferencesFromResource(R.xml.prefs__termux_api_app___prefs__app___prefs__debugging, rootKey); + + configureLoggingPreferences(context); + } + + private void configureLoggingPreferences(@NonNull Context context) { + PreferenceCategory loggingCategory = findPreference("logging"); + if (loggingCategory == null) return; + + ListPreference logLevelListPreference = findPreference("log_level"); + if (logLevelListPreference != null) { + TermuxAPIAppSharedPreferences preferences = TermuxAPIAppSharedPreferences.build(context, true); + if (preferences == null) return; + + setLogLevelListPreferenceData(logLevelListPreference, context, preferences.getLogLevel(true)); + loggingCategory.addPreference(logLevelListPreference); + } + } + + public static ListPreference setLogLevelListPreferenceData(ListPreference logLevelListPreference, Context context, int logLevel) { + if (logLevelListPreference == null) + logLevelListPreference = new ListPreference(context); + + CharSequence[] logLevels = Logger.getLogLevelsArray(); + CharSequence[] logLevelLabels = Logger.getLogLevelLabelsArray(context, logLevels, true); + + logLevelListPreference.setEntryValues(logLevels); + logLevelListPreference.setEntries(logLevelLabels); + + logLevelListPreference.setValue(String.valueOf(logLevel)); + logLevelListPreference.setDefaultValue(Logger.DEFAULT_LOG_LEVEL); + + return logLevelListPreference; + } +} + +class DebuggingPreferencesDataStore extends PreferenceDataStore { + + private final Context mContext; + private final TermuxAPIAppSharedPreferences mPreferences; + + private static DebuggingPreferencesDataStore mInstance; + + private DebuggingPreferencesDataStore(Context context) { + mContext = context; + mPreferences = TermuxAPIAppSharedPreferences.build(context, true); + } + + public static synchronized DebuggingPreferencesDataStore getInstance(Context context) { + if (mInstance == null) { + mInstance = new DebuggingPreferencesDataStore(context); + } + return mInstance; + } + + + + @Override + @Nullable + public String getString(String key, @Nullable String defValue) { + if (mPreferences == null) return null; + if (key == null) return null; + + switch (key) { + case "log_level": + return String.valueOf(mPreferences.getLogLevel(true)); + default: + return null; + } + } + + @Override + public void putString(String key, @Nullable String value) { + if (mPreferences == null) return; + if (key == null) return; + + switch (key) { + case "log_level": + if (value != null) { + mPreferences.setLogLevel(mContext, Integer.parseInt(value), true); + } + break; + default: + break; + } + } + +} diff --git a/app/src/main/java/com/termux/api/util/JsonUtils.java b/app/src/main/java/com/termux/api/util/JsonUtils.java new file mode 100644 index 000000000..0d0d69ef2 --- /dev/null +++ b/app/src/main/java/com/termux/api/util/JsonUtils.java @@ -0,0 +1,65 @@ +package com.termux.api.util; + +import android.util.JsonWriter; + +import com.termux.shared.logger.Logger; + +import java.io.IOException; + +public class JsonUtils { + + public static final String LOG_TAG = "JsonUtils"; + + + + public static void putBooleanValueIfSet(JsonWriter out, String key, Boolean value) { + if (out == null || key == null || key.isEmpty() || value == null) return; + + try { + out.name(key).value(value); + } catch (IOException e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Failed to put \"" + key + "\" with boolean value \"" + value + "\"", e); + } + } + + public static void putIntegerIfSet(JsonWriter out, String key, Integer value) { + if (out == null || key == null || key.isEmpty() || value == null) return; + + try { + out.name(key).value(value); + } catch (IOException e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Failed to put \"" + key + "\" with integer value \"" + value + "\"", e); + } + } + + public static void putLongIfSet(JsonWriter out, String key, Long value) { + if (out == null || key == null || key.isEmpty() || value == null) return; + + try { + out.name(key).value(value); + } catch (IOException e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Failed to put \"" + key + "\" with long value \"" + value + "\"", e); + } + } + + public static void putDoubleIfSet(JsonWriter out, String key, Double value) { + if (out == null || key == null || key.isEmpty() || value == null) return; + + try { + out.name(key).value(value); + } catch (IOException e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Failed to put \"" + key + "\" with double value \"" + value + "\"", e); + } + } + + public static void putStringIfSet(JsonWriter out, String key, String value) { + if (out == null || key == null || key.isEmpty() || value == null) return; + + try { + out.name(key).value(value); + } catch (IOException e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Failed to put \"" + key + "\" with string value \"" + value + "\"", e); + } + } + +} diff --git a/app/src/main/java/com/termux/api/util/PendingIntentUtils.java b/app/src/main/java/com/termux/api/util/PendingIntentUtils.java new file mode 100644 index 000000000..b8db213b4 --- /dev/null +++ b/app/src/main/java/com/termux/api/util/PendingIntentUtils.java @@ -0,0 +1,34 @@ +package com.termux.api.util; + +import android.app.PendingIntent; +import android.os.Build; + +public class PendingIntentUtils { + + /** + * Get {@link PendingIntent#FLAG_IMMUTABLE} flag. + * + * - https://developer.android.com/guide/components/intents-filters#DeclareMutabilityPendingIntent + * - https://developer.android.com/about/versions/12/behavior-changes-12#pending-intent-mutability + */ + public static int getPendingIntentImmutableFlag() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + return PendingIntent.FLAG_IMMUTABLE; + else + return 0; + } + + /** + * Get {@link PendingIntent#FLAG_MUTABLE} flag. + * + * - https://developer.android.com/guide/components/intents-filters#DeclareMutabilityPendingIntent + * - https://developer.android.com/about/versions/12/behavior-changes-12#pending-intent-mutability + */ + public static int getPendingIntentMutableFlag() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) + return PendingIntent.FLAG_MUTABLE; + else + return 0; + } + +} diff --git a/app/src/main/java/com/termux/api/util/PluginUtils.java b/app/src/main/java/com/termux/api/util/PluginUtils.java new file mode 100644 index 000000000..080f6a181 --- /dev/null +++ b/app/src/main/java/com/termux/api/util/PluginUtils.java @@ -0,0 +1,36 @@ +package com.termux.api.util; + +import android.app.PendingIntent; +import android.content.Context; + +import com.termux.shared.termux.settings.preferences.TermuxPreferenceConstants.TERMUX_API_APP; +import com.termux.shared.termux.settings.preferences.TermuxAPIAppSharedPreferences; + +public class PluginUtils { + + /** + * Try to get the next unique {@link PendingIntent} request code that isn't already being used by + * the app and which would create a unique {@link PendingIntent} that doesn't conflict with that + * of any other execution commands. + * + * @param context The {@link Context} for operations. + * @return Returns the request code that should be safe to use. + */ + public synchronized static int getLastPendingIntentRequestCode(final Context context) { + if (context == null) return TERMUX_API_APP.DEFAULT_VALUE_KEY_LAST_PENDING_INTENT_REQUEST_CODE; + + TermuxAPIAppSharedPreferences preferences = TermuxAPIAppSharedPreferences.build(context); + if (preferences == null) return TERMUX_API_APP.DEFAULT_VALUE_KEY_LAST_PENDING_INTENT_REQUEST_CODE; + + int lastPendingIntentRequestCode = preferences.getLastPendingIntentRequestCode(); + + int nextPendingIntentRequestCode = lastPendingIntentRequestCode + 1; + + if (nextPendingIntentRequestCode == Integer.MAX_VALUE || nextPendingIntentRequestCode < 0) + nextPendingIntentRequestCode = TERMUX_API_APP.DEFAULT_VALUE_KEY_LAST_PENDING_INTENT_REQUEST_CODE; + + preferences.setLastPendingIntentRequestCode(nextPendingIntentRequestCode); + return nextPendingIntentRequestCode; + } + +} diff --git a/app/src/main/java/com/termux/api/util/ResultReturner.java b/app/src/main/java/com/termux/api/util/ResultReturner.java index b50ca389d..279176e56 100644 --- a/app/src/main/java/com/termux/api/util/ResultReturner.java +++ b/app/src/main/java/com/termux/api/util/ResultReturner.java @@ -1,31 +1,52 @@ package com.termux.api.util; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.IntentService; import android.content.BroadcastReceiver; import android.content.BroadcastReceiver.PendingResult; +import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.net.LocalSocket; import android.net.LocalSocketAddress; +import android.net.LocalSocketAddress.Namespace; import android.os.ParcelFileDescriptor; import android.util.JsonWriter; +import androidx.annotation.NonNull; + +import com.termux.shared.android.PackageUtils; +import com.termux.shared.file.FileUtils; +import com.termux.shared.logger.Logger; +import com.termux.shared.termux.TermuxConstants; +import com.termux.shared.termux.plugins.TermuxPluginUtils; + import java.io.ByteArrayOutputStream; import java.io.FileDescriptor; +import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; public abstract class ResultReturner { + @SuppressLint("StaticFieldLeak") + public static Context context; + + private static final String LOG_TAG = "ResultReturner"; + /** - * An extra intent parameter which specifies a linux abstract namespace socket address where output from the API + * An extra intent parameter which specifies a unix socket address where output from the API * call should be written. */ private static final String SOCKET_OUTPUT_EXTRA = "socket_output"; /** - * An extra intent parameter which specifies a linux abstract namespace socket address where input to the API call + * An extra intent parameter which specifies a unix socket address where input to the API call * can be read from. */ private static final String SOCKET_INPUT_EXTRA = "socket_input"; @@ -35,7 +56,7 @@ public interface ResultWriter { } /** - * Possible subclass of {@link ResultWriter} when input is to be read from stdin. + * Possible subclass of {@link ResultWriter} when input is to be read from {@link #SOCKET_INPUT_EXTRA}. */ public static abstract class WithInput implements ResultWriter { protected InputStream in; @@ -44,9 +65,30 @@ public void setInput(InputStream inputStream) throws Exception { this.in = inputStream; } } + + /** + * Possible subclass of {@link ResultWriter} when the output is binary data instead of text. + */ + public static abstract class BinaryOutput implements ResultWriter { + private OutputStream out; + + public void setOutput(OutputStream outputStream) { + this.out = outputStream; + } + + public abstract void writeResult(OutputStream out) throws Exception; + + /** + * writeResult with a PrintWriter is marked as final and overwritten, so you don't accidentally use it + */ + public final void writeResult(PrintWriter unused) throws Exception { + writeResult(out); + out.flush(); + } + } /** - * Possible marker interface for a {@link ResultWriter} when input is to be read from stdin. + * Possible marker interface for a {@link ResultWriter} when input is to be read from {@link #SOCKET_INPUT_EXTRA}. */ public static abstract class WithStringInput extends WithInput { protected String inputString; @@ -69,14 +111,53 @@ public final void setInput(InputStream inputStream) throws Exception { } public static abstract class WithAncillaryFd implements ResultWriter { - private int fd = -1; + private LocalSocket outputSocket = null; + private final ParcelFileDescriptor[] pfds = { null }; + + public final void setOutputSocketForFds(LocalSocket outputSocket) { + this.outputSocket = outputSocket; + } + + public final void sendFd(PrintWriter out, int fd) { + // If fd already sent, then error out as we only support sending one currently. + if (this.pfds[0] != null) { + Logger.logStackTraceWithMessage(LOG_TAG, "File descriptor already sent", new Exception()); + return; + } - public final void setFd(int newFd) { - fd = newFd; + this.pfds[0] = ParcelFileDescriptor.adoptFd(fd); + FileDescriptor[] fds = { pfds[0].getFileDescriptor() }; + + // Set fd to be sent + outputSocket.setFileDescriptorsForSend(fds); + + // As per the docs: + // > The file descriptors will be sent with the next write of normal data, and will be + // delivered in a single ancillary message. + // - https://developer.android.com/reference/android/net/LocalSocket#setFileDescriptorsForSend(java.io.FileDescriptor[]) + // So we write the `@` character. It is not special, it is just the chosen character + // expected as the message by the native `termux-api` command when a fd is sent. + // - https://github.com/termux/termux-api-package/blob/e62bdadea3f26b60430bb85248f300fee68ecdcc/termux-api.c#L358 + out.print("@"); + + // Actually send the by fd by flushing the data previously written (`@`) as PrintWriter is buffered. + out.flush(); + + // Clear existing fd after it has been sent, otherwise it will get sent for every data write, + // even though we are currently not writing anything else. Android will not clear it automatically. + // - https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/net/LocalSocketImpl.java;l=523?q=setFileDescriptorsForSend + // - https://cs.android.com/android/_/android/platform/frameworks/base/+/refs/tags/android-14.0.0_r1:core/jni/android_net_LocalSocketImpl.cpp;l=194 + outputSocket.setFileDescriptorsForSend(null); } - public final int getFd() { - return fd; + public final void cleanupFds() { + if (this.pfds[0] != null) { + try { + this.pfds[0].close(); + } catch (IOException e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Failed to close file descriptor", e); + } + } } } @@ -106,73 +187,145 @@ public static void copyIntentExtras(Intent origIntent, Intent newIntent) { } + /** + * Get {@link LocalSocketAddress} for a socket address. + * + * If socket address starts with a path separator `/`, then a {@link Namespace#FILESYSTEM} + * {@link LocalSocketAddress} is returned, otherwise an {@link Namespace#ABSTRACT}. + * + * The `termux-api-package` versions `<= 0.58.0` create a abstract namespace socket and higher + * version create filesystem path socket. + * + * - https://man7.org/linux/man-pages/man7/unix.7.html + */ + @SuppressLint("SdCardPath") + public static LocalSocketAddress getApiLocalSocketAddress(@NonNull Context context, + @NonNull String socketLabel, @NonNull String socketAddress) { + if (socketAddress.startsWith("/")) { + ApplicationInfo termuxApplicationInfo = PackageUtils.getApplicationInfoForPackage(context, + TermuxConstants.TERMUX_PACKAGE_NAME); + if (termuxApplicationInfo == null) { + throw new RuntimeException("Failed to get ApplicationInfo for the Termux app package: " + + TermuxConstants.TERMUX_PACKAGE_NAME); + } + + List termuxAppDataDirectories = Arrays.asList(termuxApplicationInfo.dataDir, + "/data/data/" + TermuxConstants.TERMUX_PACKAGE_NAME); + if (!FileUtils.isPathInDirPaths(socketAddress, termuxAppDataDirectories, true)) { + throw new RuntimeException("The " + socketLabel + " socket address \"" + socketAddress + "\"" + + " is not under Termux app data directories: " + termuxAppDataDirectories); + } + + return new LocalSocketAddress(socketAddress, Namespace.FILESYSTEM); + } else { + return new LocalSocketAddress(socketAddress, Namespace.ABSTRACT); + } + } + + public static boolean shouldRunThreadForResultRunnable(Object context) { + return !(context instanceof IntentService); + } + /** * Run in a separate thread, unless the context is an IntentService. */ public static void returnData(Object context, final Intent intent, final ResultWriter resultWriter) { - final PendingResult asyncResult = (context instanceof BroadcastReceiver) ? ((BroadcastReceiver) context) - .goAsync() : null; + final BroadcastReceiver receiver = (BroadcastReceiver) ((context instanceof BroadcastReceiver) ? context : null); final Activity activity = (Activity) ((context instanceof Activity) ? context : null); + final PendingResult asyncResult = receiver != null ? receiver.goAsync() : null; + + // Store caller function stack trace to add to exception messages thrown inside `Runnable` + // lambda in case its run in a thread as it will not be included by default. + final Throwable callerStackTrace = shouldRunThreadForResultRunnable(context) ? new Exception("Called by:") : null; final Runnable runnable = () -> { + PrintWriter writer = null; + LocalSocket outputSocket = null; try { - final ParcelFileDescriptor[] pfds = { null }; - try (LocalSocket outputSocket = new LocalSocket()) { - String outputSocketAdress = intent.getStringExtra(SOCKET_OUTPUT_EXTRA); - outputSocket.connect(new LocalSocketAddress(outputSocketAdress)); - try (PrintWriter writer = new PrintWriter(outputSocket.getOutputStream())) { - if (resultWriter != null) { - if (resultWriter instanceof WithInput) { - try (LocalSocket inputSocket = new LocalSocket()) { - String inputSocketAdress = intent.getStringExtra(SOCKET_INPUT_EXTRA); - inputSocket.connect(new LocalSocketAddress(inputSocketAdress)); - ((WithInput) resultWriter).setInput(inputSocket.getInputStream()); - resultWriter.writeResult(writer); - } - } else { - resultWriter.writeResult(writer); - } - if(resultWriter instanceof WithAncillaryFd) { - int fd = ((WithAncillaryFd) resultWriter).getFd(); - if (fd >= 0) { - pfds[0] = ParcelFileDescriptor.adoptFd(fd); - FileDescriptor[] fds = { pfds[0].getFileDescriptor() }; - outputSocket.setFileDescriptorsForSend(fds); - } - } + outputSocket = new LocalSocket(); + String outputSocketAddress = intent.getStringExtra(SOCKET_OUTPUT_EXTRA); + if (outputSocketAddress == null || outputSocketAddress.isEmpty()) + throw new IOException("Missing '" + SOCKET_OUTPUT_EXTRA + "' extra"); + Logger.logDebug(LOG_TAG, "Connecting to output socket \"" + outputSocketAddress + "\""); + outputSocket.connect(getApiLocalSocketAddress(ResultReturner.context, "output", outputSocketAddress)); + writer = new PrintWriter(outputSocket.getOutputStream()); + + if (resultWriter != null) { + if(resultWriter instanceof WithAncillaryFd) { + ((WithAncillaryFd) resultWriter).setOutputSocketForFds(outputSocket); + } + if (resultWriter instanceof BinaryOutput) { + BinaryOutput bout = (BinaryOutput) resultWriter; + bout.setOutput(outputSocket.getOutputStream()); + } + if (resultWriter instanceof WithInput) { + try (LocalSocket inputSocket = new LocalSocket()) { + String inputSocketAddress = intent.getStringExtra(SOCKET_INPUT_EXTRA); + if (inputSocketAddress == null || inputSocketAddress.isEmpty()) + throw new IOException("Missing '" + SOCKET_INPUT_EXTRA + "' extra"); + inputSocket.connect(getApiLocalSocketAddress(ResultReturner.context, "input", inputSocketAddress)); + ((WithInput) resultWriter).setInput(inputSocket.getInputStream()); + resultWriter.writeResult(writer); } + } else { + resultWriter.writeResult(writer); + } + if (resultWriter instanceof WithAncillaryFd) { + ((WithAncillaryFd) resultWriter).cleanupFds(); } } - if(pfds[0] != null) { - pfds[0].close(); - } - if (asyncResult != null) { + + if (asyncResult != null && receiver.isOrderedBroadcast()) { asyncResult.setResultCode(0); } else if (activity != null) { activity.setResult(0); } - } catch (Exception e) { - TermuxApiLogger.error("Error in ResultReturner", e); - if (asyncResult != null) { + } catch (Throwable t) { + String message = "Error in " + LOG_TAG; + if (callerStackTrace != null) + t.addSuppressed(callerStackTrace); + Logger.logStackTraceWithMessage(LOG_TAG, message, t); + + TermuxPluginUtils.sendPluginCommandErrorNotification(ResultReturner.context, LOG_TAG, + TermuxConstants.TERMUX_API_APP_NAME + " Error", message, t); + + if (asyncResult != null && receiver != null && receiver.isOrderedBroadcast()) { asyncResult.setResultCode(1); } else if (activity != null) { activity.setResult(1); } } finally { - if (asyncResult != null) { - asyncResult.finish(); - } else if (activity != null) { - activity.finish(); + try { + if (writer != null) + writer.close(); + if (outputSocket != null) + outputSocket.close(); + } catch (Exception e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Failed to close", e); + } + + try { + if (asyncResult != null) { + asyncResult.finish(); + } else if (activity != null) { + activity.finish(); + } + } catch (Exception e) { + Logger.logStackTraceWithMessage(LOG_TAG, "Failed to finish", e); } } }; - if (context instanceof IntentService) { - runnable.run(); - } else { + if (shouldRunThreadForResultRunnable(context)) { new Thread(runnable).start(); - } + } else { + runnable.run(); + } + } + + public static void setContext(Context context) { + ResultReturner.context = context.getApplicationContext(); } } diff --git a/app/src/main/java/com/termux/api/util/TermuxApiLogger.java b/app/src/main/java/com/termux/api/util/TermuxApiLogger.java deleted file mode 100644 index bfd038bc6..000000000 --- a/app/src/main/java/com/termux/api/util/TermuxApiLogger.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.termux.api.util; - -import android.util.Log; - -public class TermuxApiLogger { - - private static final String TAG = "termux-api"; - - public static void info(String message) { - Log.i(TAG, message); - } - - public static void error(String message) { - Log.e(TAG, message); - } - - public static void error(String message, Exception exception) { - Log.e(TAG, message, exception); - } - -} diff --git a/app/src/main/java/com/termux/api/util/TermuxApiPermissionActivity.java b/app/src/main/java/com/termux/api/util/TermuxApiPermissionActivity.java deleted file mode 100644 index d789e415d..000000000 --- a/app/src/main/java/com/termux/api/util/TermuxApiPermissionActivity.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.termux.api.util; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.Build; -import android.text.TextUtils; -import android.util.JsonWriter; - -import java.util.ArrayList; - -public class TermuxApiPermissionActivity extends Activity { - - /** - * Intent extra containing the permissions to request. - */ - public static final String PERMISSIONS_EXTRA = "com.termux.api.permission_extra"; - - /** - * Check for and request permissions if necessary. - * - * @return if all permissions were already granted - */ - public static boolean checkAndRequestPermissions(Context context, Intent intent, String... permissions) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - final ArrayList permissionsToRequest = new ArrayList<>(); - for (String permission : permissions) { - if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_DENIED) { - permissionsToRequest.add(permission); - } - } - - if (permissionsToRequest.isEmpty()) { - return true; - } else { - ResultReturner.returnData(context, intent, new ResultReturner.ResultJsonWriter() { - @Override - public void writeJson(JsonWriter out) throws Exception { - String errorMessage = "Please grant the following permission" - + (permissionsToRequest.size() > 1 ? "s" : "") - + " to use this command: " - + TextUtils.join(" ,", permissionsToRequest); - out.beginObject().name("error").value(errorMessage).endObject(); - } - }); - - Intent startIntent = new Intent(context, TermuxApiPermissionActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putStringArrayListExtra(TermuxApiPermissionActivity.PERMISSIONS_EXTRA, permissionsToRequest); - ResultReturner.copyIntentExtras(intent, startIntent); - context.startActivity(startIntent); - return false; - } - } else { - return true; - } - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - setIntent(intent); - } - - @TargetApi(Build.VERSION_CODES.M) - @Override - protected void onResume() { - super.onResume(); - ArrayList permissionValues = getIntent().getStringArrayListExtra(PERMISSIONS_EXTRA); - requestPermissions(permissionValues.toArray(new String[0]), 123); - finish(); - } - -} diff --git a/app/src/main/java/com/termux/api/util/ViewUtils.java b/app/src/main/java/com/termux/api/util/ViewUtils.java new file mode 100644 index 000000000..6b8d22356 --- /dev/null +++ b/app/src/main/java/com/termux/api/util/ViewUtils.java @@ -0,0 +1,33 @@ +package com.termux.api.util; + +import android.content.Context; +import android.widget.Button; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import com.termux.api.R; +import com.termux.shared.theme.ThemeUtils; + +public class ViewUtils { + + public static void setWarningTextViewAndButtonState(@NonNull Context context, + @NonNull TextView textView, @NonNull Button button, + boolean warningState, String text) { + if (warningState) { + textView.setTextColor(ContextCompat.getColor(context, com.termux.shared.R.color.red_error)); + textView.setLinkTextColor(ContextCompat.getColor(context, com.termux.shared.R.color.red_error_link)); + button.setEnabled(true); + button.setAlpha(1); + } else { + textView.setTextColor(ThemeUtils.getTextColorPrimary(context)); + textView.setLinkTextColor(ThemeUtils.getTextColorLink(context)); + button.setEnabled(false); + button.setAlpha(0.5f); + } + + button.setText(text); + } + +} diff --git a/app/src/main/res/drawable-anydpi-v26/ic_launcher.xml b/app/src/main/res/drawable-anydpi-v26/ic_launcher.xml index 6192469fc..61bc6d97e 100644 --- a/app/src/main/res/drawable-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/drawable-anydpi-v26/ic_launcher.xml @@ -2,4 +2,5 @@ + diff --git a/app/src/main/res/drawable/ic_3d_rotation_black_24dp.xml b/app/src/main/res/drawable/ic_3d_rotation_black_24dp.xml new file mode 100644 index 000000000..8e0a806aa --- /dev/null +++ b/app/src/main/res/drawable/ic_3d_rotation_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_ac_unit_black_24dp.xml b/app/src/main/res/drawable/ic_ac_unit_black_24dp.xml new file mode 100644 index 000000000..a6fc395fd --- /dev/null +++ b/app/src/main/res/drawable/ic_ac_unit_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_access_alarm_black_24dp.xml b/app/src/main/res/drawable/ic_access_alarm_black_24dp.xml new file mode 100644 index 000000000..934b0675d --- /dev/null +++ b/app/src/main/res/drawable/ic_access_alarm_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_access_alarms_black_24dp.xml b/app/src/main/res/drawable/ic_access_alarms_black_24dp.xml new file mode 100644 index 000000000..5f742d33a --- /dev/null +++ b/app/src/main/res/drawable/ic_access_alarms_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_access_time_black_24dp.xml b/app/src/main/res/drawable/ic_access_time_black_24dp.xml new file mode 100644 index 000000000..2239a4f45 --- /dev/null +++ b/app/src/main/res/drawable/ic_access_time_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_accessibility_black_24dp.xml b/app/src/main/res/drawable/ic_accessibility_black_24dp.xml new file mode 100644 index 000000000..e7e53f058 --- /dev/null +++ b/app/src/main/res/drawable/ic_accessibility_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_accessible_black_24dp.xml b/app/src/main/res/drawable/ic_accessible_black_24dp.xml new file mode 100644 index 000000000..0acbacf51 --- /dev/null +++ b/app/src/main/res/drawable/ic_accessible_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_account_balance_black_24dp.xml b/app/src/main/res/drawable/ic_account_balance_black_24dp.xml new file mode 100644 index 000000000..b9d5db60b --- /dev/null +++ b/app/src/main/res/drawable/ic_account_balance_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_account_balance_wallet_black_24dp.xml b/app/src/main/res/drawable/ic_account_balance_wallet_black_24dp.xml new file mode 100644 index 000000000..326c11a31 --- /dev/null +++ b/app/src/main/res/drawable/ic_account_balance_wallet_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_account_box_black_24dp.xml b/app/src/main/res/drawable/ic_account_box_black_24dp.xml new file mode 100644 index 000000000..27ee291fc --- /dev/null +++ b/app/src/main/res/drawable/ic_account_box_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_account_circle_black_24dp.xml b/app/src/main/res/drawable/ic_account_circle_black_24dp.xml new file mode 100644 index 000000000..76785806d --- /dev/null +++ b/app/src/main/res/drawable/ic_account_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_adb_black_24dp.xml b/app/src/main/res/drawable/ic_adb_black_24dp.xml new file mode 100644 index 000000000..79ba0230a --- /dev/null +++ b/app/src/main/res/drawable/ic_adb_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_a_photo_black_24dp.xml b/app/src/main/res/drawable/ic_add_a_photo_black_24dp.xml new file mode 100644 index 000000000..3d2ba42f3 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_a_photo_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_alarm_black_24dp.xml b/app/src/main/res/drawable/ic_add_alarm_black_24dp.xml new file mode 100644 index 000000000..4c5023a07 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_alarm_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_alert_black_24dp.xml b/app/src/main/res/drawable/ic_add_alert_black_24dp.xml new file mode 100644 index 000000000..3e8e1c0ea --- /dev/null +++ b/app/src/main/res/drawable/ic_add_alert_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_black_24dp.xml b/app/src/main/res/drawable/ic_add_black_24dp.xml new file mode 100644 index 000000000..0258249cc --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_box_black_24dp.xml b/app/src/main/res/drawable/ic_add_box_black_24dp.xml new file mode 100644 index 000000000..b7e59bcf1 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_box_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_circle_black_24dp.xml b/app/src/main/res/drawable/ic_add_circle_black_24dp.xml new file mode 100644 index 000000000..db4e035b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_circle_outline_black_24dp.xml b/app/src/main/res/drawable/ic_add_circle_outline_black_24dp.xml new file mode 100644 index 000000000..900f2275e --- /dev/null +++ b/app/src/main/res/drawable/ic_add_circle_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_location_black_24dp.xml b/app/src/main/res/drawable/ic_add_location_black_24dp.xml new file mode 100644 index 000000000..c04646035 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_location_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_shopping_cart_black_24dp.xml b/app/src/main/res/drawable/ic_add_shopping_cart_black_24dp.xml new file mode 100644 index 000000000..67d7a6367 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_shopping_cart_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_to_photos_black_24dp.xml b/app/src/main/res/drawable/ic_add_to_photos_black_24dp.xml new file mode 100644 index 000000000..f704ffedf --- /dev/null +++ b/app/src/main/res/drawable/ic_add_to_photos_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_to_queue_black_24dp.xml b/app/src/main/res/drawable/ic_add_to_queue_black_24dp.xml new file mode 100644 index 000000000..c19e9aa13 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_to_queue_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_adjust_black_24dp.xml b/app/src/main/res/drawable/ic_adjust_black_24dp.xml new file mode 100644 index 000000000..eef90f79d --- /dev/null +++ b/app/src/main/res/drawable/ic_adjust_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airline_seat_flat_angled_black_24dp.xml b/app/src/main/res/drawable/ic_airline_seat_flat_angled_black_24dp.xml new file mode 100644 index 000000000..7a3d29d3a --- /dev/null +++ b/app/src/main/res/drawable/ic_airline_seat_flat_angled_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airline_seat_flat_black_24dp.xml b/app/src/main/res/drawable/ic_airline_seat_flat_black_24dp.xml new file mode 100644 index 000000000..85c009860 --- /dev/null +++ b/app/src/main/res/drawable/ic_airline_seat_flat_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airline_seat_individual_suite_black_24dp.xml b/app/src/main/res/drawable/ic_airline_seat_individual_suite_black_24dp.xml new file mode 100644 index 000000000..38a4ad508 --- /dev/null +++ b/app/src/main/res/drawable/ic_airline_seat_individual_suite_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airline_seat_legroom_extra_black_24dp.xml b/app/src/main/res/drawable/ic_airline_seat_legroom_extra_black_24dp.xml new file mode 100644 index 000000000..44b2ed2b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_airline_seat_legroom_extra_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airline_seat_legroom_normal_black_24dp.xml b/app/src/main/res/drawable/ic_airline_seat_legroom_normal_black_24dp.xml new file mode 100644 index 000000000..61c753a7b --- /dev/null +++ b/app/src/main/res/drawable/ic_airline_seat_legroom_normal_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airline_seat_legroom_reduced_black_24dp.xml b/app/src/main/res/drawable/ic_airline_seat_legroom_reduced_black_24dp.xml new file mode 100644 index 000000000..3eeb04198 --- /dev/null +++ b/app/src/main/res/drawable/ic_airline_seat_legroom_reduced_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airline_seat_recline_extra_black_24dp.xml b/app/src/main/res/drawable/ic_airline_seat_recline_extra_black_24dp.xml new file mode 100644 index 000000000..215d2db4c --- /dev/null +++ b/app/src/main/res/drawable/ic_airline_seat_recline_extra_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airline_seat_recline_normal_black_24dp.xml b/app/src/main/res/drawable/ic_airline_seat_recline_normal_black_24dp.xml new file mode 100644 index 000000000..e67a9695d --- /dev/null +++ b/app/src/main/res/drawable/ic_airline_seat_recline_normal_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airplanemode_active_black_24dp.xml b/app/src/main/res/drawable/ic_airplanemode_active_black_24dp.xml new file mode 100644 index 000000000..55a8d22a5 --- /dev/null +++ b/app/src/main/res/drawable/ic_airplanemode_active_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_airplanemode_inactive_black_24dp.xml b/app/src/main/res/drawable/ic_airplanemode_inactive_black_24dp.xml new file mode 100644 index 000000000..603130699 --- /dev/null +++ b/app/src/main/res/drawable/ic_airplanemode_inactive_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airplay_black_24dp.xml b/app/src/main/res/drawable/ic_airplay_black_24dp.xml new file mode 100644 index 000000000..18321a935 --- /dev/null +++ b/app/src/main/res/drawable/ic_airplay_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_airport_shuttle_black_24dp.xml b/app/src/main/res/drawable/ic_airport_shuttle_black_24dp.xml new file mode 100644 index 000000000..5e0d55278 --- /dev/null +++ b/app/src/main/res/drawable/ic_airport_shuttle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_alarm_add_black_24dp.xml b/app/src/main/res/drawable/ic_alarm_add_black_24dp.xml new file mode 100644 index 000000000..4c5023a07 --- /dev/null +++ b/app/src/main/res/drawable/ic_alarm_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_alarm_black_24dp.xml b/app/src/main/res/drawable/ic_alarm_black_24dp.xml new file mode 100644 index 000000000..934b0675d --- /dev/null +++ b/app/src/main/res/drawable/ic_alarm_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_alarm_off_black_24dp.xml b/app/src/main/res/drawable/ic_alarm_off_black_24dp.xml new file mode 100644 index 000000000..785e67b80 --- /dev/null +++ b/app/src/main/res/drawable/ic_alarm_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_alarm_on_black_24dp.xml b/app/src/main/res/drawable/ic_alarm_on_black_24dp.xml new file mode 100644 index 000000000..73748efd1 --- /dev/null +++ b/app/src/main/res/drawable/ic_alarm_on_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_album_black_24dp.xml b/app/src/main/res/drawable/ic_album_black_24dp.xml new file mode 100644 index 000000000..9cc85ec81 --- /dev/null +++ b/app/src/main/res/drawable/ic_album_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_all_inclusive_black_24dp.xml b/app/src/main/res/drawable/ic_all_inclusive_black_24dp.xml new file mode 100644 index 000000000..b40d240d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_all_inclusive_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_all_out_black_24dp.xml b/app/src/main/res/drawable/ic_all_out_black_24dp.xml new file mode 100644 index 000000000..11e5a11e7 --- /dev/null +++ b/app/src/main/res/drawable/ic_all_out_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_android_black_24dp.xml b/app/src/main/res/drawable/ic_android_black_24dp.xml new file mode 100644 index 000000000..401cbf63b --- /dev/null +++ b/app/src/main/res/drawable/ic_android_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_announcement_black_24dp.xml b/app/src/main/res/drawable/ic_announcement_black_24dp.xml new file mode 100644 index 000000000..3d8eee24b --- /dev/null +++ b/app/src/main/res/drawable/ic_announcement_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_apps_black_24dp.xml b/app/src/main/res/drawable/ic_apps_black_24dp.xml new file mode 100644 index 000000000..ff485cf1a --- /dev/null +++ b/app/src/main/res/drawable/ic_apps_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_archive_black_24dp.xml b/app/src/main/res/drawable/ic_archive_black_24dp.xml new file mode 100644 index 000000000..8b18a9d56 --- /dev/null +++ b/app/src/main/res/drawable/ic_archive_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_back_black_24dp.xml b/app/src/main/res/drawable/ic_arrow_back_black_24dp.xml new file mode 100644 index 000000000..beafea395 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_back_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_downward_black_24dp.xml b/app/src/main/res/drawable/ic_arrow_downward_black_24dp.xml new file mode 100644 index 000000000..23277e222 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_downward_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_drop_down_black_24dp.xml b/app/src/main/res/drawable/ic_arrow_drop_down_black_24dp.xml new file mode 100644 index 000000000..62b27ef0b --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_drop_down_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_drop_down_circle_black_24dp.xml b/app/src/main/res/drawable/ic_arrow_drop_down_circle_black_24dp.xml new file mode 100644 index 000000000..81a31397b --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_drop_down_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_drop_up_black_24dp.xml b/app/src/main/res/drawable/ic_arrow_drop_up_black_24dp.xml new file mode 100644 index 000000000..b1442ce15 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_drop_up_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_forward_black_24dp.xml b/app/src/main/res/drawable/ic_arrow_forward_black_24dp.xml new file mode 100644 index 000000000..cf9e208e6 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_forward_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_upward_black_24dp.xml b/app/src/main/res/drawable/ic_arrow_upward_black_24dp.xml new file mode 100644 index 000000000..c64ae3516 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_upward_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_art_track_black_24dp.xml b/app/src/main/res/drawable/ic_art_track_black_24dp.xml new file mode 100644 index 000000000..ecd3b054c --- /dev/null +++ b/app/src/main/res/drawable/ic_art_track_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_aspect_ratio_black_24dp.xml b/app/src/main/res/drawable/ic_aspect_ratio_black_24dp.xml new file mode 100644 index 000000000..2f3bc9163 --- /dev/null +++ b/app/src/main/res/drawable/ic_aspect_ratio_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_assessment_black_24dp.xml b/app/src/main/res/drawable/ic_assessment_black_24dp.xml new file mode 100644 index 000000000..75d0dde7b --- /dev/null +++ b/app/src/main/res/drawable/ic_assessment_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_assignment_black_24dp.xml b/app/src/main/res/drawable/ic_assignment_black_24dp.xml new file mode 100644 index 000000000..4a3eb4fe7 --- /dev/null +++ b/app/src/main/res/drawable/ic_assignment_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_assignment_ind_black_24dp.xml b/app/src/main/res/drawable/ic_assignment_ind_black_24dp.xml new file mode 100644 index 000000000..672f22839 --- /dev/null +++ b/app/src/main/res/drawable/ic_assignment_ind_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_assignment_late_black_24dp.xml b/app/src/main/res/drawable/ic_assignment_late_black_24dp.xml new file mode 100644 index 000000000..98718065e --- /dev/null +++ b/app/src/main/res/drawable/ic_assignment_late_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_assignment_return_black_24dp.xml b/app/src/main/res/drawable/ic_assignment_return_black_24dp.xml new file mode 100644 index 000000000..2c1052d0a --- /dev/null +++ b/app/src/main/res/drawable/ic_assignment_return_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_assignment_returned_black_24dp.xml b/app/src/main/res/drawable/ic_assignment_returned_black_24dp.xml new file mode 100644 index 000000000..f0e911478 --- /dev/null +++ b/app/src/main/res/drawable/ic_assignment_returned_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_assignment_turned_in_black_24dp.xml b/app/src/main/res/drawable/ic_assignment_turned_in_black_24dp.xml new file mode 100644 index 000000000..1a2ce74e3 --- /dev/null +++ b/app/src/main/res/drawable/ic_assignment_turned_in_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_assistant_black_24dp.xml b/app/src/main/res/drawable/ic_assistant_black_24dp.xml new file mode 100644 index 000000000..2430c471c --- /dev/null +++ b/app/src/main/res/drawable/ic_assistant_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_assistant_photo_black_24dp.xml b/app/src/main/res/drawable/ic_assistant_photo_black_24dp.xml new file mode 100644 index 000000000..82ef10455 --- /dev/null +++ b/app/src/main/res/drawable/ic_assistant_photo_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_attach_file_black_24dp.xml b/app/src/main/res/drawable/ic_attach_file_black_24dp.xml new file mode 100644 index 000000000..b3d7c3511 --- /dev/null +++ b/app/src/main/res/drawable/ic_attach_file_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_attach_money_black_24dp.xml b/app/src/main/res/drawable/ic_attach_money_black_24dp.xml new file mode 100644 index 000000000..b520fc98d --- /dev/null +++ b/app/src/main/res/drawable/ic_attach_money_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_attachment_black_24dp.xml b/app/src/main/res/drawable/ic_attachment_black_24dp.xml new file mode 100644 index 000000000..c18714f5c --- /dev/null +++ b/app/src/main/res/drawable/ic_attachment_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_audiotrack_black_24dp.xml b/app/src/main/res/drawable/ic_audiotrack_black_24dp.xml new file mode 100644 index 000000000..039afc511 --- /dev/null +++ b/app/src/main/res/drawable/ic_audiotrack_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_autorenew_black_24dp.xml b/app/src/main/res/drawable/ic_autorenew_black_24dp.xml new file mode 100644 index 000000000..794ca6ad3 --- /dev/null +++ b/app/src/main/res/drawable/ic_autorenew_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_av_timer_black_24dp.xml b/app/src/main/res/drawable/ic_av_timer_black_24dp.xml new file mode 100644 index 000000000..dabe56297 --- /dev/null +++ b/app/src/main/res/drawable/ic_av_timer_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_backspace_black_24dp.xml b/app/src/main/res/drawable/ic_backspace_black_24dp.xml new file mode 100644 index 000000000..35b3af305 --- /dev/null +++ b/app/src/main/res/drawable/ic_backspace_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_backup_black_24dp.xml b/app/src/main/res/drawable/ic_backup_black_24dp.xml new file mode 100644 index 000000000..086281669 --- /dev/null +++ b/app/src/main/res/drawable/ic_backup_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_battery_20_black_24dp.xml b/app/src/main/res/drawable/ic_battery_20_black_24dp.xml new file mode 100644 index 000000000..d9a1e6468 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_20_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_30_black_24dp.xml b/app/src/main/res/drawable/ic_battery_30_black_24dp.xml new file mode 100644 index 000000000..3b872eac0 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_30_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_50_black_24dp.xml b/app/src/main/res/drawable/ic_battery_50_black_24dp.xml new file mode 100644 index 000000000..8236b239c --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_50_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_60_black_24dp.xml b/app/src/main/res/drawable/ic_battery_60_black_24dp.xml new file mode 100644 index 000000000..22c91cd0c --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_60_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_80_black_24dp.xml b/app/src/main/res/drawable/ic_battery_80_black_24dp.xml new file mode 100644 index 000000000..600ad7784 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_80_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_90_black_24dp.xml b/app/src/main/res/drawable/ic_battery_90_black_24dp.xml new file mode 100644 index 000000000..fe8b8c8ca --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_90_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_alert_black_24dp.xml b/app/src/main/res/drawable/ic_battery_alert_black_24dp.xml new file mode 100644 index 000000000..4966395a9 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_alert_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_battery_charging_20_black_24dp.xml b/app/src/main/res/drawable/ic_battery_charging_20_black_24dp.xml new file mode 100644 index 000000000..c3bf3b703 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_charging_20_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_charging_30_black_24dp.xml b/app/src/main/res/drawable/ic_battery_charging_30_black_24dp.xml new file mode 100644 index 000000000..de561624f --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_charging_30_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_charging_50_black_24dp.xml b/app/src/main/res/drawable/ic_battery_charging_50_black_24dp.xml new file mode 100644 index 000000000..d794783a5 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_charging_50_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_charging_60_black_24dp.xml b/app/src/main/res/drawable/ic_battery_charging_60_black_24dp.xml new file mode 100644 index 000000000..4673e6aa0 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_charging_60_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_charging_80_black_24dp.xml b/app/src/main/res/drawable/ic_battery_charging_80_black_24dp.xml new file mode 100644 index 000000000..e004a0a61 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_charging_80_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_charging_90_black_24dp.xml b/app/src/main/res/drawable/ic_battery_charging_90_black_24dp.xml new file mode 100644 index 000000000..1b5b34d94 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_charging_90_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_battery_charging_full_black_24dp.xml b/app/src/main/res/drawable/ic_battery_charging_full_black_24dp.xml new file mode 100644 index 000000000..9389e7ce2 --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_charging_full_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_battery_full_black_24dp.xml b/app/src/main/res/drawable/ic_battery_full_black_24dp.xml new file mode 100644 index 000000000..b0e57fe2c --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_full_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_battery_std_black_24dp.xml b/app/src/main/res/drawable/ic_battery_std_black_24dp.xml new file mode 100644 index 000000000..b0e57fe2c --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_std_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_battery_unknown_black_24dp.xml b/app/src/main/res/drawable/ic_battery_unknown_black_24dp.xml new file mode 100644 index 000000000..dc6df58ad --- /dev/null +++ b/app/src/main/res/drawable/ic_battery_unknown_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_beach_access_black_24dp.xml b/app/src/main/res/drawable/ic_beach_access_black_24dp.xml new file mode 100644 index 000000000..f2fd5e702 --- /dev/null +++ b/app/src/main/res/drawable/ic_beach_access_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_beenhere_black_24dp.xml b/app/src/main/res/drawable/ic_beenhere_black_24dp.xml new file mode 100644 index 000000000..5f1c0519d --- /dev/null +++ b/app/src/main/res/drawable/ic_beenhere_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_block_black_24dp.xml b/app/src/main/res/drawable/ic_block_black_24dp.xml new file mode 100644 index 000000000..4510bf5bb --- /dev/null +++ b/app/src/main/res/drawable/ic_block_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bluetooth_audio_black_24dp.xml b/app/src/main/res/drawable/ic_bluetooth_audio_black_24dp.xml new file mode 100644 index 000000000..ece1684c6 --- /dev/null +++ b/app/src/main/res/drawable/ic_bluetooth_audio_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bluetooth_black_24dp.xml b/app/src/main/res/drawable/ic_bluetooth_black_24dp.xml new file mode 100644 index 000000000..1094756bf --- /dev/null +++ b/app/src/main/res/drawable/ic_bluetooth_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bluetooth_connected_black_24dp.xml b/app/src/main/res/drawable/ic_bluetooth_connected_black_24dp.xml new file mode 100644 index 000000000..c81c3a36a --- /dev/null +++ b/app/src/main/res/drawable/ic_bluetooth_connected_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bluetooth_disabled_black_24dp.xml b/app/src/main/res/drawable/ic_bluetooth_disabled_black_24dp.xml new file mode 100644 index 000000000..1f753a216 --- /dev/null +++ b/app/src/main/res/drawable/ic_bluetooth_disabled_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bluetooth_searching_black_24dp.xml b/app/src/main/res/drawable/ic_bluetooth_searching_black_24dp.xml new file mode 100644 index 000000000..ece1684c6 --- /dev/null +++ b/app/src/main/res/drawable/ic_bluetooth_searching_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_blur_circular_black_24dp.xml b/app/src/main/res/drawable/ic_blur_circular_black_24dp.xml new file mode 100644 index 000000000..99db60f04 --- /dev/null +++ b/app/src/main/res/drawable/ic_blur_circular_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_blur_linear_black_24dp.xml b/app/src/main/res/drawable/ic_blur_linear_black_24dp.xml new file mode 100644 index 000000000..aa6ebaf5b --- /dev/null +++ b/app/src/main/res/drawable/ic_blur_linear_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_blur_off_black_24dp.xml b/app/src/main/res/drawable/ic_blur_off_black_24dp.xml new file mode 100644 index 000000000..d342c3e50 --- /dev/null +++ b/app/src/main/res/drawable/ic_blur_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_blur_on_black_24dp.xml b/app/src/main/res/drawable/ic_blur_on_black_24dp.xml new file mode 100644 index 000000000..6bb612bb1 --- /dev/null +++ b/app/src/main/res/drawable/ic_blur_on_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_book_black_24dp.xml b/app/src/main/res/drawable/ic_book_black_24dp.xml new file mode 100644 index 000000000..811d5ac4b --- /dev/null +++ b/app/src/main/res/drawable/ic_book_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bookmark_black_24dp.xml b/app/src/main/res/drawable/ic_bookmark_black_24dp.xml new file mode 100644 index 000000000..6a6a1b39d --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bookmark_border_black_24dp.xml b/app/src/main/res/drawable/ic_bookmark_border_black_24dp.xml new file mode 100644 index 000000000..6ab9a0c6c --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_border_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_all_black_24dp.xml b/app/src/main/res/drawable/ic_border_all_black_24dp.xml new file mode 100644 index 000000000..27cb92492 --- /dev/null +++ b/app/src/main/res/drawable/ic_border_all_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_bottom_black_24dp.xml b/app/src/main/res/drawable/ic_border_bottom_black_24dp.xml new file mode 100644 index 000000000..926b6f72a --- /dev/null +++ b/app/src/main/res/drawable/ic_border_bottom_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_clear_black_24dp.xml b/app/src/main/res/drawable/ic_border_clear_black_24dp.xml new file mode 100644 index 000000000..5d7694769 --- /dev/null +++ b/app/src/main/res/drawable/ic_border_clear_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_color_black_24dp.xml b/app/src/main/res/drawable/ic_border_color_black_24dp.xml new file mode 100644 index 000000000..1889bdf65 --- /dev/null +++ b/app/src/main/res/drawable/ic_border_color_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_border_horizontal_black_24dp.xml b/app/src/main/res/drawable/ic_border_horizontal_black_24dp.xml new file mode 100644 index 000000000..987488ffb --- /dev/null +++ b/app/src/main/res/drawable/ic_border_horizontal_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_inner_black_24dp.xml b/app/src/main/res/drawable/ic_border_inner_black_24dp.xml new file mode 100644 index 000000000..477844de8 --- /dev/null +++ b/app/src/main/res/drawable/ic_border_inner_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_left_black_24dp.xml b/app/src/main/res/drawable/ic_border_left_black_24dp.xml new file mode 100644 index 000000000..5b37864de --- /dev/null +++ b/app/src/main/res/drawable/ic_border_left_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_outer_black_24dp.xml b/app/src/main/res/drawable/ic_border_outer_black_24dp.xml new file mode 100644 index 000000000..e353f680e --- /dev/null +++ b/app/src/main/res/drawable/ic_border_outer_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_right_black_24dp.xml b/app/src/main/res/drawable/ic_border_right_black_24dp.xml new file mode 100644 index 000000000..d9f5b6bf7 --- /dev/null +++ b/app/src/main/res/drawable/ic_border_right_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_style_black_24dp.xml b/app/src/main/res/drawable/ic_border_style_black_24dp.xml new file mode 100644 index 000000000..5d69a9e88 --- /dev/null +++ b/app/src/main/res/drawable/ic_border_style_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_top_black_24dp.xml b/app/src/main/res/drawable/ic_border_top_black_24dp.xml new file mode 100644 index 000000000..4de691c40 --- /dev/null +++ b/app/src/main/res/drawable/ic_border_top_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_border_vertical_black_24dp.xml b/app/src/main/res/drawable/ic_border_vertical_black_24dp.xml new file mode 100644 index 000000000..3b3655b51 --- /dev/null +++ b/app/src/main/res/drawable/ic_border_vertical_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_branding_watermark_black_24dp.xml b/app/src/main/res/drawable/ic_branding_watermark_black_24dp.xml new file mode 100644 index 000000000..e66a7afdd --- /dev/null +++ b/app/src/main/res/drawable/ic_branding_watermark_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_1_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_1_black_24dp.xml new file mode 100644 index 000000000..d92150afa --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_1_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_2_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_2_black_24dp.xml new file mode 100644 index 000000000..b5406ba11 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_2_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_3_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_3_black_24dp.xml new file mode 100644 index 000000000..8247d4ac0 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_3_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_4_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_4_black_24dp.xml new file mode 100644 index 000000000..bc3cdecc7 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_4_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_5_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_5_black_24dp.xml new file mode 100644 index 000000000..54301c0aa --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_5_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_6_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_6_black_24dp.xml new file mode 100644 index 000000000..2f9cd1e7f --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_6_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_7_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_7_black_24dp.xml new file mode 100644 index 000000000..920f615c9 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_7_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_auto_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_auto_black_24dp.xml new file mode 100644 index 000000000..8c5588140 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_auto_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_high_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_high_black_24dp.xml new file mode 100644 index 000000000..920f615c9 --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_high_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_low_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_low_black_24dp.xml new file mode 100644 index 000000000..54301c0aa --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_low_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brightness_medium_black_24dp.xml b/app/src/main/res/drawable/ic_brightness_medium_black_24dp.xml new file mode 100644 index 000000000..2f9cd1e7f --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_medium_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_broken_image_black_24dp.xml b/app/src/main/res/drawable/ic_broken_image_black_24dp.xml new file mode 100644 index 000000000..8d563a9b8 --- /dev/null +++ b/app/src/main/res/drawable/ic_broken_image_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_brush_black_24dp.xml b/app/src/main/res/drawable/ic_brush_black_24dp.xml new file mode 100644 index 000000000..54730dbe2 --- /dev/null +++ b/app/src/main/res/drawable/ic_brush_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_bubble_chart_black_24dp.xml b/app/src/main/res/drawable/ic_bubble_chart_black_24dp.xml new file mode 100644 index 000000000..188172f07 --- /dev/null +++ b/app/src/main/res/drawable/ic_bubble_chart_black_24dp.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_bug_report_black_24dp.xml b/app/src/main/res/drawable/ic_bug_report_black_24dp.xml new file mode 100644 index 000000000..4d83902b8 --- /dev/null +++ b/app/src/main/res/drawable/ic_bug_report_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_build_black_24dp.xml b/app/src/main/res/drawable/ic_build_black_24dp.xml new file mode 100644 index 000000000..18f567663 --- /dev/null +++ b/app/src/main/res/drawable/ic_build_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_burst_mode_black_24dp.xml b/app/src/main/res/drawable/ic_burst_mode_black_24dp.xml new file mode 100644 index 000000000..609cad9bd --- /dev/null +++ b/app/src/main/res/drawable/ic_burst_mode_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_business_black_24dp.xml b/app/src/main/res/drawable/ic_business_black_24dp.xml new file mode 100644 index 000000000..8924cc83f --- /dev/null +++ b/app/src/main/res/drawable/ic_business_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_business_center_black_24dp.xml b/app/src/main/res/drawable/ic_business_center_black_24dp.xml new file mode 100644 index 000000000..1bc076d5d --- /dev/null +++ b/app/src/main/res/drawable/ic_business_center_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cached_black_24dp.xml b/app/src/main/res/drawable/ic_cached_black_24dp.xml new file mode 100644 index 000000000..5e776beb1 --- /dev/null +++ b/app/src/main/res/drawable/ic_cached_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cake_black_24dp.xml b/app/src/main/res/drawable/ic_cake_black_24dp.xml new file mode 100644 index 000000000..ac0f50473 --- /dev/null +++ b/app/src/main/res/drawable/ic_cake_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_call_black_24dp.xml b/app/src/main/res/drawable/ic_call_black_24dp.xml new file mode 100644 index 000000000..ebf9de60f --- /dev/null +++ b/app/src/main/res/drawable/ic_call_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_call_end_black_24dp.xml b/app/src/main/res/drawable/ic_call_end_black_24dp.xml new file mode 100644 index 000000000..f83a53498 --- /dev/null +++ b/app/src/main/res/drawable/ic_call_end_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_call_made_black_24dp.xml b/app/src/main/res/drawable/ic_call_made_black_24dp.xml new file mode 100644 index 000000000..c5b108d4e --- /dev/null +++ b/app/src/main/res/drawable/ic_call_made_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_call_merge_black_24dp.xml b/app/src/main/res/drawable/ic_call_merge_black_24dp.xml new file mode 100644 index 000000000..40b6b383d --- /dev/null +++ b/app/src/main/res/drawable/ic_call_merge_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_call_missed_black_24dp.xml b/app/src/main/res/drawable/ic_call_missed_black_24dp.xml new file mode 100644 index 000000000..ed8ff3939 --- /dev/null +++ b/app/src/main/res/drawable/ic_call_missed_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_call_missed_outgoing_black_24dp.xml b/app/src/main/res/drawable/ic_call_missed_outgoing_black_24dp.xml new file mode 100644 index 000000000..ac0dd75e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_call_missed_outgoing_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_call_received_black_24dp.xml b/app/src/main/res/drawable/ic_call_received_black_24dp.xml new file mode 100644 index 000000000..aae066ea2 --- /dev/null +++ b/app/src/main/res/drawable/ic_call_received_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_call_split_black_24dp.xml b/app/src/main/res/drawable/ic_call_split_black_24dp.xml new file mode 100644 index 000000000..327e1d2f5 --- /dev/null +++ b/app/src/main/res/drawable/ic_call_split_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_call_to_action_black_24dp.xml b/app/src/main/res/drawable/ic_call_to_action_black_24dp.xml new file mode 100644 index 000000000..cdedeab59 --- /dev/null +++ b/app/src/main/res/drawable/ic_call_to_action_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_camera_alt_black_24dp.xml b/app/src/main/res/drawable/ic_camera_alt_black_24dp.xml new file mode 100644 index 000000000..c872f1670 --- /dev/null +++ b/app/src/main/res/drawable/ic_camera_alt_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_camera_black_24dp.xml b/app/src/main/res/drawable/ic_camera_black_24dp.xml new file mode 100644 index 000000000..9c477f895 --- /dev/null +++ b/app/src/main/res/drawable/ic_camera_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_camera_enhance_black_24dp.xml b/app/src/main/res/drawable/ic_camera_enhance_black_24dp.xml new file mode 100644 index 000000000..84a604ded --- /dev/null +++ b/app/src/main/res/drawable/ic_camera_enhance_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_camera_front_black_24dp.xml b/app/src/main/res/drawable/ic_camera_front_black_24dp.xml new file mode 100644 index 000000000..735544123 --- /dev/null +++ b/app/src/main/res/drawable/ic_camera_front_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_camera_rear_black_24dp.xml b/app/src/main/res/drawable/ic_camera_rear_black_24dp.xml new file mode 100644 index 000000000..157d4b17c --- /dev/null +++ b/app/src/main/res/drawable/ic_camera_rear_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_camera_roll_black_24dp.xml b/app/src/main/res/drawable/ic_camera_roll_black_24dp.xml new file mode 100644 index 000000000..c3f3e9555 --- /dev/null +++ b/app/src/main/res/drawable/ic_camera_roll_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cancel_black_24dp.xml b/app/src/main/res/drawable/ic_cancel_black_24dp.xml new file mode 100644 index 000000000..7d2b57eb2 --- /dev/null +++ b/app/src/main/res/drawable/ic_cancel_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_card_giftcard_black_24dp.xml b/app/src/main/res/drawable/ic_card_giftcard_black_24dp.xml new file mode 100644 index 000000000..cbb69959b --- /dev/null +++ b/app/src/main/res/drawable/ic_card_giftcard_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_card_membership_black_24dp.xml b/app/src/main/res/drawable/ic_card_membership_black_24dp.xml new file mode 100644 index 000000000..53689e261 --- /dev/null +++ b/app/src/main/res/drawable/ic_card_membership_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_card_travel_black_24dp.xml b/app/src/main/res/drawable/ic_card_travel_black_24dp.xml new file mode 100644 index 000000000..29cd27ee2 --- /dev/null +++ b/app/src/main/res/drawable/ic_card_travel_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_casino_black_24dp.xml b/app/src/main/res/drawable/ic_casino_black_24dp.xml new file mode 100644 index 000000000..2dbf3f465 --- /dev/null +++ b/app/src/main/res/drawable/ic_casino_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cast_black_24dp.xml b/app/src/main/res/drawable/ic_cast_black_24dp.xml new file mode 100644 index 000000000..7b143de9f --- /dev/null +++ b/app/src/main/res/drawable/ic_cast_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cast_connected_black_24dp.xml b/app/src/main/res/drawable/ic_cast_connected_black_24dp.xml new file mode 100644 index 000000000..7e49cf2a9 --- /dev/null +++ b/app/src/main/res/drawable/ic_cast_connected_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_center_focus_strong_black_24dp.xml b/app/src/main/res/drawable/ic_center_focus_strong_black_24dp.xml new file mode 100644 index 000000000..ab723e81f --- /dev/null +++ b/app/src/main/res/drawable/ic_center_focus_strong_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_center_focus_weak_black_24dp.xml b/app/src/main/res/drawable/ic_center_focus_weak_black_24dp.xml new file mode 100644 index 000000000..3fcca95ad --- /dev/null +++ b/app/src/main/res/drawable/ic_center_focus_weak_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_change_history_black_24dp.xml b/app/src/main/res/drawable/ic_change_history_black_24dp.xml new file mode 100644 index 000000000..b88bcb3aa --- /dev/null +++ b/app/src/main/res/drawable/ic_change_history_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_chat_black_24dp.xml b/app/src/main/res/drawable/ic_chat_black_24dp.xml new file mode 100644 index 000000000..e3489bdea --- /dev/null +++ b/app/src/main/res/drawable/ic_chat_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_chat_bubble_black_24dp.xml b/app/src/main/res/drawable/ic_chat_bubble_black_24dp.xml new file mode 100644 index 000000000..3eeab8286 --- /dev/null +++ b/app/src/main/res/drawable/ic_chat_bubble_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_chat_bubble_outline_black_24dp.xml b/app/src/main/res/drawable/ic_chat_bubble_outline_black_24dp.xml new file mode 100644 index 000000000..880a1b1a9 --- /dev/null +++ b/app/src/main/res/drawable/ic_chat_bubble_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_check_black_24dp.xml b/app/src/main/res/drawable/ic_check_black_24dp.xml new file mode 100644 index 000000000..3c728c59f --- /dev/null +++ b/app/src/main/res/drawable/ic_check_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_check_box_black_24dp.xml b/app/src/main/res/drawable/ic_check_box_black_24dp.xml new file mode 100644 index 000000000..9948171c2 --- /dev/null +++ b/app/src/main/res/drawable/ic_check_box_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_check_box_outline_blank_black_24dp.xml b/app/src/main/res/drawable/ic_check_box_outline_blank_black_24dp.xml new file mode 100644 index 000000000..cf8bfa24b --- /dev/null +++ b/app/src/main/res/drawable/ic_check_box_outline_blank_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_check_circle_black_24dp.xml b/app/src/main/res/drawable/ic_check_circle_black_24dp.xml new file mode 100644 index 000000000..1241edabd --- /dev/null +++ b/app/src/main/res/drawable/ic_check_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_chevron_left_black_24dp.xml b/app/src/main/res/drawable/ic_chevron_left_black_24dp.xml new file mode 100644 index 000000000..e6bb3ca92 --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_left_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml b/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml new file mode 100644 index 000000000..24835127d --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_child_care_black_24dp.xml b/app/src/main/res/drawable/ic_child_care_black_24dp.xml new file mode 100644 index 000000000..5af39255e --- /dev/null +++ b/app/src/main/res/drawable/ic_child_care_black_24dp.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_child_friendly_black_24dp.xml b/app/src/main/res/drawable/ic_child_friendly_black_24dp.xml new file mode 100644 index 000000000..b7384f4c9 --- /dev/null +++ b/app/src/main/res/drawable/ic_child_friendly_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_chrome_reader_mode_black_24dp.xml b/app/src/main/res/drawable/ic_chrome_reader_mode_black_24dp.xml new file mode 100644 index 000000000..99b5867b3 --- /dev/null +++ b/app/src/main/res/drawable/ic_chrome_reader_mode_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_class_black_24dp.xml b/app/src/main/res/drawable/ic_class_black_24dp.xml new file mode 100644 index 000000000..811d5ac4b --- /dev/null +++ b/app/src/main/res/drawable/ic_class_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_clear_all_black_24dp.xml b/app/src/main/res/drawable/ic_clear_all_black_24dp.xml new file mode 100644 index 000000000..1b0e565b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_clear_all_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_clear_black_24dp.xml b/app/src/main/res/drawable/ic_clear_black_24dp.xml new file mode 100644 index 000000000..ede4b7108 --- /dev/null +++ b/app/src/main/res/drawable/ic_clear_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_close_black_24dp.xml b/app/src/main/res/drawable/ic_close_black_24dp.xml new file mode 100644 index 000000000..ede4b7108 --- /dev/null +++ b/app/src/main/res/drawable/ic_close_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_closed_caption_black_24dp.xml b/app/src/main/res/drawable/ic_closed_caption_black_24dp.xml new file mode 100644 index 000000000..107771d94 --- /dev/null +++ b/app/src/main/res/drawable/ic_closed_caption_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cloud_black_24dp.xml b/app/src/main/res/drawable/ic_cloud_black_24dp.xml new file mode 100644 index 000000000..e0940ca0e --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cloud_circle_black_24dp.xml b/app/src/main/res/drawable/ic_cloud_circle_black_24dp.xml new file mode 100644 index 000000000..c0c70017d --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cloud_done_black_24dp.xml b/app/src/main/res/drawable/ic_cloud_done_black_24dp.xml new file mode 100644 index 000000000..cf7e2cc6b --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_done_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cloud_download_black_24dp.xml b/app/src/main/res/drawable/ic_cloud_download_black_24dp.xml new file mode 100644 index 000000000..261c31217 --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_download_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cloud_off_black_24dp.xml b/app/src/main/res/drawable/ic_cloud_off_black_24dp.xml new file mode 100644 index 000000000..1e753cf4c --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cloud_queue_black_24dp.xml b/app/src/main/res/drawable/ic_cloud_queue_black_24dp.xml new file mode 100644 index 000000000..0ca5119d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_queue_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_cloud_upload_black_24dp.xml b/app/src/main/res/drawable/ic_cloud_upload_black_24dp.xml new file mode 100644 index 000000000..086281669 --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud_upload_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_code_black_24dp.xml b/app/src/main/res/drawable/ic_code_black_24dp.xml new file mode 100644 index 000000000..6f1ccb6e4 --- /dev/null +++ b/app/src/main/res/drawable/ic_code_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_collections_black_24dp.xml b/app/src/main/res/drawable/ic_collections_black_24dp.xml new file mode 100644 index 000000000..68d5d0e66 --- /dev/null +++ b/app/src/main/res/drawable/ic_collections_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_collections_bookmark_black_24dp.xml b/app/src/main/res/drawable/ic_collections_bookmark_black_24dp.xml new file mode 100644 index 000000000..05f2dd410 --- /dev/null +++ b/app/src/main/res/drawable/ic_collections_bookmark_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_color_lens_black_24dp.xml b/app/src/main/res/drawable/ic_color_lens_black_24dp.xml new file mode 100644 index 000000000..f75e2fbe3 --- /dev/null +++ b/app/src/main/res/drawable/ic_color_lens_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_colorize_black_24dp.xml b/app/src/main/res/drawable/ic_colorize_black_24dp.xml new file mode 100644 index 000000000..deaae498b --- /dev/null +++ b/app/src/main/res/drawable/ic_colorize_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_comment_black_24dp.xml b/app/src/main/res/drawable/ic_comment_black_24dp.xml new file mode 100644 index 000000000..13ed321b3 --- /dev/null +++ b/app/src/main/res/drawable/ic_comment_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_compare_arrows_black_24dp.xml b/app/src/main/res/drawable/ic_compare_arrows_black_24dp.xml new file mode 100644 index 000000000..23417034d --- /dev/null +++ b/app/src/main/res/drawable/ic_compare_arrows_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_compare_black_24dp.xml b/app/src/main/res/drawable/ic_compare_black_24dp.xml new file mode 100644 index 000000000..4824f3f4c --- /dev/null +++ b/app/src/main/res/drawable/ic_compare_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_computer_black_24dp.xml b/app/src/main/res/drawable/ic_computer_black_24dp.xml new file mode 100644 index 000000000..4599f98cd --- /dev/null +++ b/app/src/main/res/drawable/ic_computer_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_confirmation_number_black_24dp.xml b/app/src/main/res/drawable/ic_confirmation_number_black_24dp.xml new file mode 100644 index 000000000..d8b22a38f --- /dev/null +++ b/app/src/main/res/drawable/ic_confirmation_number_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_contact_mail_black_24dp.xml b/app/src/main/res/drawable/ic_contact_mail_black_24dp.xml new file mode 100644 index 000000000..681947933 --- /dev/null +++ b/app/src/main/res/drawable/ic_contact_mail_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_contact_phone_black_24dp.xml b/app/src/main/res/drawable/ic_contact_phone_black_24dp.xml new file mode 100644 index 000000000..f1124cfae --- /dev/null +++ b/app/src/main/res/drawable/ic_contact_phone_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_contacts_black_24dp.xml b/app/src/main/res/drawable/ic_contacts_black_24dp.xml new file mode 100644 index 000000000..674b66b7c --- /dev/null +++ b/app/src/main/res/drawable/ic_contacts_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_content_copy_black_24dp.xml b/app/src/main/res/drawable/ic_content_copy_black_24dp.xml new file mode 100644 index 000000000..8a894a3bc --- /dev/null +++ b/app/src/main/res/drawable/ic_content_copy_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_content_cut_black_24dp.xml b/app/src/main/res/drawable/ic_content_cut_black_24dp.xml new file mode 100644 index 000000000..1c0f96a37 --- /dev/null +++ b/app/src/main/res/drawable/ic_content_cut_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_content_paste_black_24dp.xml b/app/src/main/res/drawable/ic_content_paste_black_24dp.xml new file mode 100644 index 000000000..a902d9a85 --- /dev/null +++ b/app/src/main/res/drawable/ic_content_paste_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_control_point_black_24dp.xml b/app/src/main/res/drawable/ic_control_point_black_24dp.xml new file mode 100644 index 000000000..79530889f --- /dev/null +++ b/app/src/main/res/drawable/ic_control_point_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_control_point_duplicate_black_24dp.xml b/app/src/main/res/drawable/ic_control_point_duplicate_black_24dp.xml new file mode 100644 index 000000000..472fa9c6d --- /dev/null +++ b/app/src/main/res/drawable/ic_control_point_duplicate_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_copyright_black_24dp.xml b/app/src/main/res/drawable/ic_copyright_black_24dp.xml new file mode 100644 index 000000000..fad6892cf --- /dev/null +++ b/app/src/main/res/drawable/ic_copyright_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_create_black_24dp.xml b/app/src/main/res/drawable/ic_create_black_24dp.xml new file mode 100644 index 000000000..2ab2fb753 --- /dev/null +++ b/app/src/main/res/drawable/ic_create_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_create_new_folder_black_24dp.xml b/app/src/main/res/drawable/ic_create_new_folder_black_24dp.xml new file mode 100644 index 000000000..a4dd6d23b --- /dev/null +++ b/app/src/main/res/drawable/ic_create_new_folder_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_credit_card_black_24dp.xml b/app/src/main/res/drawable/ic_credit_card_black_24dp.xml new file mode 100644 index 000000000..62a08a812 --- /dev/null +++ b/app/src/main/res/drawable/ic_credit_card_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_16_9_black_24dp.xml b/app/src/main/res/drawable/ic_crop_16_9_black_24dp.xml new file mode 100644 index 000000000..259aaefc2 --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_16_9_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_3_2_black_24dp.xml b/app/src/main/res/drawable/ic_crop_3_2_black_24dp.xml new file mode 100644 index 000000000..85777ed88 --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_3_2_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_5_4_black_24dp.xml b/app/src/main/res/drawable/ic_crop_5_4_black_24dp.xml new file mode 100644 index 000000000..625e65118 --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_5_4_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_7_5_black_24dp.xml b/app/src/main/res/drawable/ic_crop_7_5_black_24dp.xml new file mode 100644 index 000000000..9e936c789 --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_7_5_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_black_24dp.xml b/app/src/main/res/drawable/ic_crop_black_24dp.xml new file mode 100644 index 000000000..5a4749cdb --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_din_black_24dp.xml b/app/src/main/res/drawable/ic_crop_din_black_24dp.xml new file mode 100644 index 000000000..d6fd5ce05 --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_din_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_free_black_24dp.xml b/app/src/main/res/drawable/ic_crop_free_black_24dp.xml new file mode 100644 index 000000000..9b379381f --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_free_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_landscape_black_24dp.xml b/app/src/main/res/drawable/ic_crop_landscape_black_24dp.xml new file mode 100644 index 000000000..625e65118 --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_landscape_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_original_black_24dp.xml b/app/src/main/res/drawable/ic_crop_original_black_24dp.xml new file mode 100644 index 000000000..cf5d94ba4 --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_original_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_portrait_black_24dp.xml b/app/src/main/res/drawable/ic_crop_portrait_black_24dp.xml new file mode 100644 index 000000000..e8c60a1a2 --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_portrait_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_rotate_black_24dp.xml b/app/src/main/res/drawable/ic_crop_rotate_black_24dp.xml new file mode 100644 index 000000000..d3b3e9f44 --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_rotate_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_crop_square_black_24dp.xml b/app/src/main/res/drawable/ic_crop_square_black_24dp.xml new file mode 100644 index 000000000..f2357717f --- /dev/null +++ b/app/src/main/res/drawable/ic_crop_square_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_dashboard_black_24dp.xml b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml new file mode 100644 index 000000000..663d572e4 --- /dev/null +++ b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_data_usage_black_24dp.xml b/app/src/main/res/drawable/ic_data_usage_black_24dp.xml new file mode 100644 index 000000000..16b9d74ac --- /dev/null +++ b/app/src/main/res/drawable/ic_data_usage_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_date_range_black_24dp.xml b/app/src/main/res/drawable/ic_date_range_black_24dp.xml new file mode 100644 index 000000000..5ac94e0fc --- /dev/null +++ b/app/src/main/res/drawable/ic_date_range_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_dehaze_black_24dp.xml b/app/src/main/res/drawable/ic_dehaze_black_24dp.xml new file mode 100644 index 000000000..567d84160 --- /dev/null +++ b/app/src/main/res/drawable/ic_dehaze_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black_24dp.xml b/app/src/main/res/drawable/ic_delete_black_24dp.xml new file mode 100644 index 000000000..39e64d698 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_forever_black_24dp.xml b/app/src/main/res/drawable/ic_delete_forever_black_24dp.xml new file mode 100644 index 000000000..2f5557afd --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_forever_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_sweep_black_24dp.xml b/app/src/main/res/drawable/ic_delete_sweep_black_24dp.xml new file mode 100644 index 000000000..bfa31fc9d --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_sweep_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_description_black_24dp.xml b/app/src/main/res/drawable/ic_description_black_24dp.xml new file mode 100644 index 000000000..38c33351c --- /dev/null +++ b/app/src/main/res/drawable/ic_description_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_desktop_mac_black_24dp.xml b/app/src/main/res/drawable/ic_desktop_mac_black_24dp.xml new file mode 100644 index 000000000..2c873233a --- /dev/null +++ b/app/src/main/res/drawable/ic_desktop_mac_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_desktop_windows_black_24dp.xml b/app/src/main/res/drawable/ic_desktop_windows_black_24dp.xml new file mode 100644 index 000000000..bec86e7b3 --- /dev/null +++ b/app/src/main/res/drawable/ic_desktop_windows_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_details_black_24dp.xml b/app/src/main/res/drawable/ic_details_black_24dp.xml new file mode 100644 index 000000000..a30104adc --- /dev/null +++ b/app/src/main/res/drawable/ic_details_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_developer_board_black_24dp.xml b/app/src/main/res/drawable/ic_developer_board_black_24dp.xml new file mode 100644 index 000000000..27d3805f0 --- /dev/null +++ b/app/src/main/res/drawable/ic_developer_board_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_developer_mode_black_24dp.xml b/app/src/main/res/drawable/ic_developer_mode_black_24dp.xml new file mode 100644 index 000000000..538b905d9 --- /dev/null +++ b/app/src/main/res/drawable/ic_developer_mode_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_device_hub_black_24dp.xml b/app/src/main/res/drawable/ic_device_hub_black_24dp.xml new file mode 100644 index 000000000..d923eb0bc --- /dev/null +++ b/app/src/main/res/drawable/ic_device_hub_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_devices_black_24dp.xml b/app/src/main/res/drawable/ic_devices_black_24dp.xml new file mode 100644 index 000000000..150ced43d --- /dev/null +++ b/app/src/main/res/drawable/ic_devices_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_devices_other_black_24dp.xml b/app/src/main/res/drawable/ic_devices_other_black_24dp.xml new file mode 100644 index 000000000..c98c256a7 --- /dev/null +++ b/app/src/main/res/drawable/ic_devices_other_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_dialer_sip_black_24dp.xml b/app/src/main/res/drawable/ic_dialer_sip_black_24dp.xml new file mode 100644 index 000000000..244afde5b --- /dev/null +++ b/app/src/main/res/drawable/ic_dialer_sip_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_dialpad_black_24dp.xml b/app/src/main/res/drawable/ic_dialpad_black_24dp.xml new file mode 100644 index 000000000..ab1e5169b --- /dev/null +++ b/app/src/main/res/drawable/ic_dialpad_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_bike_black_24dp.xml b/app/src/main/res/drawable/ic_directions_bike_black_24dp.xml new file mode 100644 index 000000000..ded5e3359 --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_bike_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_black_24dp.xml b/app/src/main/res/drawable/ic_directions_black_24dp.xml new file mode 100644 index 000000000..739dd20ee --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_boat_black_24dp.xml b/app/src/main/res/drawable/ic_directions_boat_black_24dp.xml new file mode 100644 index 000000000..f726d87ec --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_boat_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_bus_black_24dp.xml b/app/src/main/res/drawable/ic_directions_bus_black_24dp.xml new file mode 100644 index 000000000..e16e25979 --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_bus_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_car_black_24dp.xml b/app/src/main/res/drawable/ic_directions_car_black_24dp.xml new file mode 100644 index 000000000..6d6337c3a --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_car_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_railway_black_24dp.xml b/app/src/main/res/drawable/ic_directions_railway_black_24dp.xml new file mode 100644 index 000000000..ae6f37bcc --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_railway_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_run_black_24dp.xml b/app/src/main/res/drawable/ic_directions_run_black_24dp.xml new file mode 100644 index 000000000..d18f6a17c --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_run_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_subway_black_24dp.xml b/app/src/main/res/drawable/ic_directions_subway_black_24dp.xml new file mode 100644 index 000000000..5a821964b --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_subway_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_transit_black_24dp.xml b/app/src/main/res/drawable/ic_directions_transit_black_24dp.xml new file mode 100644 index 000000000..5a821964b --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_transit_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_directions_walk_black_24dp.xml b/app/src/main/res/drawable/ic_directions_walk_black_24dp.xml new file mode 100644 index 000000000..407d67b43 --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_walk_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_disc_full_black_24dp.xml b/app/src/main/res/drawable/ic_disc_full_black_24dp.xml new file mode 100644 index 000000000..95b60042b --- /dev/null +++ b/app/src/main/res/drawable/ic_disc_full_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_dns_black_24dp.xml b/app/src/main/res/drawable/ic_dns_black_24dp.xml new file mode 100644 index 000000000..1a8528c5e --- /dev/null +++ b/app/src/main/res/drawable/ic_dns_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_do_not_disturb_alt_black_24dp.xml b/app/src/main/res/drawable/ic_do_not_disturb_alt_black_24dp.xml new file mode 100644 index 000000000..5974dd427 --- /dev/null +++ b/app/src/main/res/drawable/ic_do_not_disturb_alt_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_do_not_disturb_black_24dp.xml b/app/src/main/res/drawable/ic_do_not_disturb_black_24dp.xml new file mode 100644 index 000000000..6944a908b --- /dev/null +++ b/app/src/main/res/drawable/ic_do_not_disturb_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_do_not_disturb_off_black_24dp.xml b/app/src/main/res/drawable/ic_do_not_disturb_off_black_24dp.xml new file mode 100644 index 000000000..aa38d2dd3 --- /dev/null +++ b/app/src/main/res/drawable/ic_do_not_disturb_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_do_not_disturb_on_black_24dp.xml b/app/src/main/res/drawable/ic_do_not_disturb_on_black_24dp.xml new file mode 100644 index 000000000..099e650ce --- /dev/null +++ b/app/src/main/res/drawable/ic_do_not_disturb_on_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_dock_black_24dp.xml b/app/src/main/res/drawable/ic_dock_black_24dp.xml new file mode 100644 index 000000000..a88dd39b3 --- /dev/null +++ b/app/src/main/res/drawable/ic_dock_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_domain_black_24dp.xml b/app/src/main/res/drawable/ic_domain_black_24dp.xml new file mode 100644 index 000000000..8924cc83f --- /dev/null +++ b/app/src/main/res/drawable/ic_domain_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_done_all_black_24dp.xml b/app/src/main/res/drawable/ic_done_all_black_24dp.xml new file mode 100644 index 000000000..3148c51b9 --- /dev/null +++ b/app/src/main/res/drawable/ic_done_all_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_done_black_24dp.xml b/app/src/main/res/drawable/ic_done_black_24dp.xml new file mode 100644 index 000000000..7affe9ba9 --- /dev/null +++ b/app/src/main/res/drawable/ic_done_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_donut_large_black_24dp.xml b/app/src/main/res/drawable/ic_donut_large_black_24dp.xml new file mode 100644 index 000000000..462681de8 --- /dev/null +++ b/app/src/main/res/drawable/ic_donut_large_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_donut_small_black_24dp.xml b/app/src/main/res/drawable/ic_donut_small_black_24dp.xml new file mode 100644 index 000000000..fd50bd086 --- /dev/null +++ b/app/src/main/res/drawable/ic_donut_small_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_drafts_black_24dp.xml b/app/src/main/res/drawable/ic_drafts_black_24dp.xml new file mode 100644 index 000000000..159567e20 --- /dev/null +++ b/app/src/main/res/drawable/ic_drafts_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_drag_handle_black_24dp.xml b/app/src/main/res/drawable/ic_drag_handle_black_24dp.xml new file mode 100644 index 000000000..68a719052 --- /dev/null +++ b/app/src/main/res/drawable/ic_drag_handle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_drive_eta_black_24dp.xml b/app/src/main/res/drawable/ic_drive_eta_black_24dp.xml new file mode 100644 index 000000000..7df55f0f6 --- /dev/null +++ b/app/src/main/res/drawable/ic_drive_eta_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_dvr_black_24dp.xml b/app/src/main/res/drawable/ic_dvr_black_24dp.xml new file mode 100644 index 000000000..5b73a4e4d --- /dev/null +++ b/app/src/main/res/drawable/ic_dvr_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_edit_black_24dp.xml b/app/src/main/res/drawable/ic_edit_black_24dp.xml new file mode 100644 index 000000000..2ab2fb753 --- /dev/null +++ b/app/src/main/res/drawable/ic_edit_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_edit_location_black_24dp.xml b/app/src/main/res/drawable/ic_edit_location_black_24dp.xml new file mode 100644 index 000000000..f6c9d9b82 --- /dev/null +++ b/app/src/main/res/drawable/ic_edit_location_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_eject_black_24dp.xml b/app/src/main/res/drawable/ic_eject_black_24dp.xml new file mode 100644 index 000000000..d7b9bc9d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_eject_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_email_black_24dp.xml b/app/src/main/res/drawable/ic_email_black_24dp.xml new file mode 100644 index 000000000..ce97ab859 --- /dev/null +++ b/app/src/main/res/drawable/ic_email_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_enhanced_encryption_black_24dp.xml b/app/src/main/res/drawable/ic_enhanced_encryption_black_24dp.xml new file mode 100644 index 000000000..edba31b44 --- /dev/null +++ b/app/src/main/res/drawable/ic_enhanced_encryption_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_equalizer_black_24dp.xml b/app/src/main/res/drawable/ic_equalizer_black_24dp.xml new file mode 100644 index 000000000..5048a587e --- /dev/null +++ b/app/src/main/res/drawable/ic_equalizer_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_error_black_24dp.xml b/app/src/main/res/drawable/ic_error_black_24dp.xml new file mode 100644 index 000000000..3d98979ad --- /dev/null +++ b/app/src/main/res/drawable/ic_error_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_error_outline_black_24dp.xml b/app/src/main/res/drawable/ic_error_outline_black_24dp.xml new file mode 100644 index 000000000..a07a0f90a --- /dev/null +++ b/app/src/main/res/drawable/ic_error_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_euro_symbol_black_24dp.xml b/app/src/main/res/drawable/ic_euro_symbol_black_24dp.xml new file mode 100644 index 000000000..868381309 --- /dev/null +++ b/app/src/main/res/drawable/ic_euro_symbol_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_ev_station_black_24dp.xml b/app/src/main/res/drawable/ic_ev_station_black_24dp.xml new file mode 100644 index 000000000..67fd8a52c --- /dev/null +++ b/app/src/main/res/drawable/ic_ev_station_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_event_available_black_24dp.xml b/app/src/main/res/drawable/ic_event_available_black_24dp.xml new file mode 100644 index 000000000..a0be0d0e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_event_available_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_event_black_24dp.xml b/app/src/main/res/drawable/ic_event_black_24dp.xml new file mode 100644 index 000000000..22f1bb691 --- /dev/null +++ b/app/src/main/res/drawable/ic_event_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_event_busy_black_24dp.xml b/app/src/main/res/drawable/ic_event_busy_black_24dp.xml new file mode 100644 index 000000000..cbd8810e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_event_busy_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_event_seat_black_24dp.xml b/app/src/main/res/drawable/ic_event_seat_black_24dp.xml new file mode 100644 index 000000000..69de68cff --- /dev/null +++ b/app/src/main/res/drawable/ic_event_seat_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_exit_to_app_black_24dp.xml b/app/src/main/res/drawable/ic_exit_to_app_black_24dp.xml new file mode 100644 index 000000000..6f40d7725 --- /dev/null +++ b/app/src/main/res/drawable/ic_exit_to_app_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_expand_less_black_24dp.xml b/app/src/main/res/drawable/ic_expand_less_black_24dp.xml new file mode 100644 index 000000000..3afdf9682 --- /dev/null +++ b/app/src/main/res/drawable/ic_expand_less_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_expand_more_black_24dp.xml b/app/src/main/res/drawable/ic_expand_more_black_24dp.xml new file mode 100644 index 000000000..8d57dbc10 --- /dev/null +++ b/app/src/main/res/drawable/ic_expand_more_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_explicit_black_24dp.xml b/app/src/main/res/drawable/ic_explicit_black_24dp.xml new file mode 100644 index 000000000..003730b4f --- /dev/null +++ b/app/src/main/res/drawable/ic_explicit_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_explore_black_24dp.xml b/app/src/main/res/drawable/ic_explore_black_24dp.xml new file mode 100644 index 000000000..68aa81479 --- /dev/null +++ b/app/src/main/res/drawable/ic_explore_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_exposure_black_24dp.xml b/app/src/main/res/drawable/ic_exposure_black_24dp.xml new file mode 100644 index 000000000..23eabc358 --- /dev/null +++ b/app/src/main/res/drawable/ic_exposure_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_exposure_neg_1_black_24dp.xml b/app/src/main/res/drawable/ic_exposure_neg_1_black_24dp.xml new file mode 100644 index 000000000..94858a05a --- /dev/null +++ b/app/src/main/res/drawable/ic_exposure_neg_1_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_exposure_neg_2_black_24dp.xml b/app/src/main/res/drawable/ic_exposure_neg_2_black_24dp.xml new file mode 100644 index 000000000..c5c97cafd --- /dev/null +++ b/app/src/main/res/drawable/ic_exposure_neg_2_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_exposure_plus_1_black_24dp.xml b/app/src/main/res/drawable/ic_exposure_plus_1_black_24dp.xml new file mode 100644 index 000000000..9914313b4 --- /dev/null +++ b/app/src/main/res/drawable/ic_exposure_plus_1_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_exposure_plus_2_black_24dp.xml b/app/src/main/res/drawable/ic_exposure_plus_2_black_24dp.xml new file mode 100644 index 000000000..ad0d66fdb --- /dev/null +++ b/app/src/main/res/drawable/ic_exposure_plus_2_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_exposure_zero_black_24dp.xml b/app/src/main/res/drawable/ic_exposure_zero_black_24dp.xml new file mode 100644 index 000000000..eddfc719b --- /dev/null +++ b/app/src/main/res/drawable/ic_exposure_zero_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_extension_black_24dp.xml b/app/src/main/res/drawable/ic_extension_black_24dp.xml new file mode 100644 index 000000000..d3dd09481 --- /dev/null +++ b/app/src/main/res/drawable/ic_extension_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_face_black_24dp.xml b/app/src/main/res/drawable/ic_face_black_24dp.xml new file mode 100644 index 000000000..739bbfbca --- /dev/null +++ b/app/src/main/res/drawable/ic_face_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fast_forward_black_24dp.xml b/app/src/main/res/drawable/ic_fast_forward_black_24dp.xml new file mode 100644 index 000000000..8ef7360f0 --- /dev/null +++ b/app/src/main/res/drawable/ic_fast_forward_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fast_rewind_black_24dp.xml b/app/src/main/res/drawable/ic_fast_rewind_black_24dp.xml new file mode 100644 index 000000000..7e942d938 --- /dev/null +++ b/app/src/main/res/drawable/ic_fast_rewind_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_favorite_black_24dp.xml b/app/src/main/res/drawable/ic_favorite_black_24dp.xml new file mode 100644 index 000000000..cfba5d846 --- /dev/null +++ b/app/src/main/res/drawable/ic_favorite_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_favorite_border_black_24dp.xml b/app/src/main/res/drawable/ic_favorite_border_black_24dp.xml new file mode 100644 index 000000000..0cfbad645 --- /dev/null +++ b/app/src/main/res/drawable/ic_favorite_border_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_featured_play_list_black_24dp.xml b/app/src/main/res/drawable/ic_featured_play_list_black_24dp.xml new file mode 100644 index 000000000..800729989 --- /dev/null +++ b/app/src/main/res/drawable/ic_featured_play_list_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_featured_video_black_24dp.xml b/app/src/main/res/drawable/ic_featured_video_black_24dp.xml new file mode 100644 index 000000000..f682ebe93 --- /dev/null +++ b/app/src/main/res/drawable/ic_featured_video_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_feedback_black_24dp.xml b/app/src/main/res/drawable/ic_feedback_black_24dp.xml new file mode 100644 index 000000000..29f9baabd --- /dev/null +++ b/app/src/main/res/drawable/ic_feedback_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fiber_dvr_black_24dp.xml b/app/src/main/res/drawable/ic_fiber_dvr_black_24dp.xml new file mode 100644 index 000000000..2b1fc8292 --- /dev/null +++ b/app/src/main/res/drawable/ic_fiber_dvr_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fiber_manual_record_black_24dp.xml b/app/src/main/res/drawable/ic_fiber_manual_record_black_24dp.xml new file mode 100644 index 000000000..d0a1e7654 --- /dev/null +++ b/app/src/main/res/drawable/ic_fiber_manual_record_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fiber_new_black_24dp.xml b/app/src/main/res/drawable/ic_fiber_new_black_24dp.xml new file mode 100644 index 000000000..6097dff02 --- /dev/null +++ b/app/src/main/res/drawable/ic_fiber_new_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fiber_pin_black_24dp.xml b/app/src/main/res/drawable/ic_fiber_pin_black_24dp.xml new file mode 100644 index 000000000..a77ef951d --- /dev/null +++ b/app/src/main/res/drawable/ic_fiber_pin_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fiber_smart_record_black_24dp.xml b/app/src/main/res/drawable/ic_fiber_smart_record_black_24dp.xml new file mode 100644 index 000000000..aacb3cf4b --- /dev/null +++ b/app/src/main/res/drawable/ic_fiber_smart_record_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_file_download_black_24dp.xml b/app/src/main/res/drawable/ic_file_download_black_24dp.xml new file mode 100644 index 000000000..492b41d34 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_download_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_file_upload_black_24dp.xml b/app/src/main/res/drawable/ic_file_upload_black_24dp.xml new file mode 100644 index 000000000..d6339722a --- /dev/null +++ b/app/src/main/res/drawable/ic_file_upload_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_1_black_24dp.xml b/app/src/main/res/drawable/ic_filter_1_black_24dp.xml new file mode 100644 index 000000000..98e99212f --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_1_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_2_black_24dp.xml b/app/src/main/res/drawable/ic_filter_2_black_24dp.xml new file mode 100644 index 000000000..159b34c56 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_2_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_3_black_24dp.xml b/app/src/main/res/drawable/ic_filter_3_black_24dp.xml new file mode 100644 index 000000000..f2ec44003 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_3_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_4_black_24dp.xml b/app/src/main/res/drawable/ic_filter_4_black_24dp.xml new file mode 100644 index 000000000..c35573c63 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_4_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_5_black_24dp.xml b/app/src/main/res/drawable/ic_filter_5_black_24dp.xml new file mode 100644 index 000000000..7b2d1def1 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_5_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_6_black_24dp.xml b/app/src/main/res/drawable/ic_filter_6_black_24dp.xml new file mode 100644 index 000000000..421c5a92e --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_6_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_7_black_24dp.xml b/app/src/main/res/drawable/ic_filter_7_black_24dp.xml new file mode 100644 index 000000000..d797d2945 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_7_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_8_black_24dp.xml b/app/src/main/res/drawable/ic_filter_8_black_24dp.xml new file mode 100644 index 000000000..cab998c10 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_8_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_9_black_24dp.xml b/app/src/main/res/drawable/ic_filter_9_black_24dp.xml new file mode 100644 index 000000000..ad532962e --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_9_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_9_plus_black_24dp.xml b/app/src/main/res/drawable/ic_filter_9_plus_black_24dp.xml new file mode 100644 index 000000000..31308db3d --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_9_plus_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_b_and_w_black_24dp.xml b/app/src/main/res/drawable/ic_filter_b_and_w_black_24dp.xml new file mode 100644 index 000000000..718ce0aaf --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_b_and_w_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_black_24dp.xml b/app/src/main/res/drawable/ic_filter_black_24dp.xml new file mode 100644 index 000000000..e21abb341 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_center_focus_black_24dp.xml b/app/src/main/res/drawable/ic_filter_center_focus_black_24dp.xml new file mode 100644 index 000000000..d037f810e --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_center_focus_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_drama_black_24dp.xml b/app/src/main/res/drawable/ic_filter_drama_black_24dp.xml new file mode 100644 index 000000000..6185cf376 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_drama_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_frames_black_24dp.xml b/app/src/main/res/drawable/ic_filter_frames_black_24dp.xml new file mode 100644 index 000000000..9c6a50404 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_frames_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_hdr_black_24dp.xml b/app/src/main/res/drawable/ic_filter_hdr_black_24dp.xml new file mode 100644 index 000000000..0350ef536 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_hdr_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_list_black_24dp.xml b/app/src/main/res/drawable/ic_filter_list_black_24dp.xml new file mode 100644 index 000000000..b99b672f4 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_list_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_none_black_24dp.xml b/app/src/main/res/drawable/ic_filter_none_black_24dp.xml new file mode 100644 index 000000000..80e501d84 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_none_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_tilt_shift_black_24dp.xml b/app/src/main/res/drawable/ic_filter_tilt_shift_black_24dp.xml new file mode 100644 index 000000000..598e88721 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_tilt_shift_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_filter_vintage_black_24dp.xml b/app/src/main/res/drawable/ic_filter_vintage_black_24dp.xml new file mode 100644 index 000000000..98c733f08 --- /dev/null +++ b/app/src/main/res/drawable/ic_filter_vintage_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_find_in_page_black_24dp.xml b/app/src/main/res/drawable/ic_find_in_page_black_24dp.xml new file mode 100644 index 000000000..0e70bac9f --- /dev/null +++ b/app/src/main/res/drawable/ic_find_in_page_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_find_replace_black_24dp.xml b/app/src/main/res/drawable/ic_find_replace_black_24dp.xml new file mode 100644 index 000000000..2d2e1f3a3 --- /dev/null +++ b/app/src/main/res/drawable/ic_find_replace_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fingerprint_black_24dp.xml b/app/src/main/res/drawable/ic_fingerprint_black_24dp.xml new file mode 100644 index 000000000..f650f7445 --- /dev/null +++ b/app/src/main/res/drawable/ic_fingerprint_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_first_page_black_24dp.xml b/app/src/main/res/drawable/ic_first_page_black_24dp.xml new file mode 100644 index 000000000..483f56c7c --- /dev/null +++ b/app/src/main/res/drawable/ic_first_page_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fitness_center_black_24dp.xml b/app/src/main/res/drawable/ic_fitness_center_black_24dp.xml new file mode 100644 index 000000000..846deb431 --- /dev/null +++ b/app/src/main/res/drawable/ic_fitness_center_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flag_black_24dp.xml b/app/src/main/res/drawable/ic_flag_black_24dp.xml new file mode 100644 index 000000000..82ef10455 --- /dev/null +++ b/app/src/main/res/drawable/ic_flag_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flare_black_24dp.xml b/app/src/main/res/drawable/ic_flare_black_24dp.xml new file mode 100644 index 000000000..73565a5b1 --- /dev/null +++ b/app/src/main/res/drawable/ic_flare_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flash_auto_black_24dp.xml b/app/src/main/res/drawable/ic_flash_auto_black_24dp.xml new file mode 100644 index 000000000..f0423d559 --- /dev/null +++ b/app/src/main/res/drawable/ic_flash_auto_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flash_off_black_24dp.xml b/app/src/main/res/drawable/ic_flash_off_black_24dp.xml new file mode 100644 index 000000000..51b17693e --- /dev/null +++ b/app/src/main/res/drawable/ic_flash_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flash_on_black_24dp.xml b/app/src/main/res/drawable/ic_flash_on_black_24dp.xml new file mode 100644 index 000000000..a3c81cc38 --- /dev/null +++ b/app/src/main/res/drawable/ic_flash_on_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flight_black_24dp.xml b/app/src/main/res/drawable/ic_flight_black_24dp.xml new file mode 100644 index 000000000..55a8d22a5 --- /dev/null +++ b/app/src/main/res/drawable/ic_flight_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_flight_land_black_24dp.xml b/app/src/main/res/drawable/ic_flight_land_black_24dp.xml new file mode 100644 index 000000000..94afdf1b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_flight_land_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flight_takeoff_black_24dp.xml b/app/src/main/res/drawable/ic_flight_takeoff_black_24dp.xml new file mode 100644 index 000000000..bbc40647b --- /dev/null +++ b/app/src/main/res/drawable/ic_flight_takeoff_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flip_black_24dp.xml b/app/src/main/res/drawable/ic_flip_black_24dp.xml new file mode 100644 index 000000000..2bc2762d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_flip_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flip_to_back_black_24dp.xml b/app/src/main/res/drawable/ic_flip_to_back_black_24dp.xml new file mode 100644 index 000000000..895b4f1bc --- /dev/null +++ b/app/src/main/res/drawable/ic_flip_to_back_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_flip_to_front_black_24dp.xml b/app/src/main/res/drawable/ic_flip_to_front_black_24dp.xml new file mode 100644 index 000000000..efcf92f9b --- /dev/null +++ b/app/src/main/res/drawable/ic_flip_to_front_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_folder_black_24dp.xml b/app/src/main/res/drawable/ic_folder_black_24dp.xml new file mode 100644 index 000000000..d7c6145c6 --- /dev/null +++ b/app/src/main/res/drawable/ic_folder_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_folder_open_black_24dp.xml b/app/src/main/res/drawable/ic_folder_open_black_24dp.xml new file mode 100644 index 000000000..b71523ac0 --- /dev/null +++ b/app/src/main/res/drawable/ic_folder_open_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_folder_shared_black_24dp.xml b/app/src/main/res/drawable/ic_folder_shared_black_24dp.xml new file mode 100644 index 000000000..9ae49b673 --- /dev/null +++ b/app/src/main/res/drawable/ic_folder_shared_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_folder_special_black_24dp.xml b/app/src/main/res/drawable/ic_folder_special_black_24dp.xml new file mode 100644 index 000000000..fc94033fe --- /dev/null +++ b/app/src/main/res/drawable/ic_folder_special_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_font_download_black_24dp.xml b/app/src/main/res/drawable/ic_font_download_black_24dp.xml new file mode 100644 index 000000000..a00893d52 --- /dev/null +++ b/app/src/main/res/drawable/ic_font_download_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_align_center_black_24dp.xml b/app/src/main/res/drawable/ic_format_align_center_black_24dp.xml new file mode 100644 index 000000000..6ae79962e --- /dev/null +++ b/app/src/main/res/drawable/ic_format_align_center_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_align_justify_black_24dp.xml b/app/src/main/res/drawable/ic_format_align_justify_black_24dp.xml new file mode 100644 index 000000000..7f4e2fec4 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_align_justify_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_align_left_black_24dp.xml b/app/src/main/res/drawable/ic_format_align_left_black_24dp.xml new file mode 100644 index 000000000..28966637d --- /dev/null +++ b/app/src/main/res/drawable/ic_format_align_left_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_align_right_black_24dp.xml b/app/src/main/res/drawable/ic_format_align_right_black_24dp.xml new file mode 100644 index 000000000..c5af12b87 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_align_right_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_bold_black_24dp.xml b/app/src/main/res/drawable/ic_format_bold_black_24dp.xml new file mode 100644 index 000000000..8879506b1 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_bold_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_clear_black_24dp.xml b/app/src/main/res/drawable/ic_format_clear_black_24dp.xml new file mode 100644 index 000000000..4c903c716 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_clear_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_color_fill_black_24dp.xml b/app/src/main/res/drawable/ic_format_color_fill_black_24dp.xml new file mode 100644 index 000000000..24ddb27a5 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_color_fill_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_format_color_reset_black_24dp.xml b/app/src/main/res/drawable/ic_format_color_reset_black_24dp.xml new file mode 100644 index 000000000..0a0ecf959 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_color_reset_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_color_text_black_24dp.xml b/app/src/main/res/drawable/ic_format_color_text_black_24dp.xml new file mode 100644 index 000000000..5361c5f06 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_color_text_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_format_indent_decrease_black_24dp.xml b/app/src/main/res/drawable/ic_format_indent_decrease_black_24dp.xml new file mode 100644 index 000000000..e51124de0 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_indent_decrease_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_indent_increase_black_24dp.xml b/app/src/main/res/drawable/ic_format_indent_increase_black_24dp.xml new file mode 100644 index 000000000..d8a6b9097 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_indent_increase_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_italic_black_24dp.xml b/app/src/main/res/drawable/ic_format_italic_black_24dp.xml new file mode 100644 index 000000000..707d41074 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_italic_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_line_spacing_black_24dp.xml b/app/src/main/res/drawable/ic_format_line_spacing_black_24dp.xml new file mode 100644 index 000000000..d529661c8 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_line_spacing_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml b/app/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml new file mode 100644 index 000000000..6cb93c699 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_list_numbered_black_24dp.xml b/app/src/main/res/drawable/ic_format_list_numbered_black_24dp.xml new file mode 100644 index 000000000..0235afcdf --- /dev/null +++ b/app/src/main/res/drawable/ic_format_list_numbered_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_paint_black_24dp.xml b/app/src/main/res/drawable/ic_format_paint_black_24dp.xml new file mode 100644 index 000000000..ce8fa632d --- /dev/null +++ b/app/src/main/res/drawable/ic_format_paint_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_quote_black_24dp.xml b/app/src/main/res/drawable/ic_format_quote_black_24dp.xml new file mode 100644 index 000000000..68cda7d8c --- /dev/null +++ b/app/src/main/res/drawable/ic_format_quote_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_shapes_black_24dp.xml b/app/src/main/res/drawable/ic_format_shapes_black_24dp.xml new file mode 100644 index 000000000..431311845 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_shapes_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_size_black_24dp.xml b/app/src/main/res/drawable/ic_format_size_black_24dp.xml new file mode 100644 index 000000000..d41bb05fc --- /dev/null +++ b/app/src/main/res/drawable/ic_format_size_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_strikethrough_black_24dp.xml b/app/src/main/res/drawable/ic_format_strikethrough_black_24dp.xml new file mode 100644 index 000000000..386eb3ebe --- /dev/null +++ b/app/src/main/res/drawable/ic_format_strikethrough_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_textdirection_l_to_r_black_24dp.xml b/app/src/main/res/drawable/ic_format_textdirection_l_to_r_black_24dp.xml new file mode 100644 index 000000000..ddf3abfce --- /dev/null +++ b/app/src/main/res/drawable/ic_format_textdirection_l_to_r_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_textdirection_r_to_l_black_24dp.xml b/app/src/main/res/drawable/ic_format_textdirection_r_to_l_black_24dp.xml new file mode 100644 index 000000000..509cdaf52 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_textdirection_r_to_l_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_underlined_black_24dp.xml b/app/src/main/res/drawable/ic_format_underlined_black_24dp.xml new file mode 100644 index 000000000..948a96ca5 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_underlined_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_forum_black_24dp.xml b/app/src/main/res/drawable/ic_forum_black_24dp.xml new file mode 100644 index 000000000..26eda0900 --- /dev/null +++ b/app/src/main/res/drawable/ic_forum_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_forward_10_black_24dp.xml b/app/src/main/res/drawable/ic_forward_10_black_24dp.xml new file mode 100644 index 000000000..7b3291ad5 --- /dev/null +++ b/app/src/main/res/drawable/ic_forward_10_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_forward_30_black_24dp.xml b/app/src/main/res/drawable/ic_forward_30_black_24dp.xml new file mode 100644 index 000000000..31e37a64a --- /dev/null +++ b/app/src/main/res/drawable/ic_forward_30_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_forward_5_black_24dp.xml b/app/src/main/res/drawable/ic_forward_5_black_24dp.xml new file mode 100644 index 000000000..5259b7bcd --- /dev/null +++ b/app/src/main/res/drawable/ic_forward_5_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_forward_black_24dp.xml b/app/src/main/res/drawable/ic_forward_black_24dp.xml new file mode 100644 index 000000000..607178aec --- /dev/null +++ b/app/src/main/res/drawable/ic_forward_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_free_breakfast_black_24dp.xml b/app/src/main/res/drawable/ic_free_breakfast_black_24dp.xml new file mode 100644 index 000000000..3d0272aa2 --- /dev/null +++ b/app/src/main/res/drawable/ic_free_breakfast_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fullscreen_black_24dp.xml b/app/src/main/res/drawable/ic_fullscreen_black_24dp.xml new file mode 100644 index 000000000..8bb67b6c5 --- /dev/null +++ b/app/src/main/res/drawable/ic_fullscreen_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_fullscreen_exit_black_24dp.xml b/app/src/main/res/drawable/ic_fullscreen_exit_black_24dp.xml new file mode 100644 index 000000000..3113ce0e7 --- /dev/null +++ b/app/src/main/res/drawable/ic_fullscreen_exit_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_functions_black_24dp.xml b/app/src/main/res/drawable/ic_functions_black_24dp.xml new file mode 100644 index 000000000..9191074fd --- /dev/null +++ b/app/src/main/res/drawable/ic_functions_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_g_translate_black_24dp.xml b/app/src/main/res/drawable/ic_g_translate_black_24dp.xml new file mode 100644 index 000000000..152aff232 --- /dev/null +++ b/app/src/main/res/drawable/ic_g_translate_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_gamepad_black_24dp.xml b/app/src/main/res/drawable/ic_gamepad_black_24dp.xml new file mode 100644 index 000000000..d1f300e57 --- /dev/null +++ b/app/src/main/res/drawable/ic_gamepad_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_games_black_24dp.xml b/app/src/main/res/drawable/ic_games_black_24dp.xml new file mode 100644 index 000000000..d1f300e57 --- /dev/null +++ b/app/src/main/res/drawable/ic_games_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_gavel_black_24dp.xml b/app/src/main/res/drawable/ic_gavel_black_24dp.xml new file mode 100644 index 000000000..73a5be6ca --- /dev/null +++ b/app/src/main/res/drawable/ic_gavel_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_gesture_black_24dp.xml b/app/src/main/res/drawable/ic_gesture_black_24dp.xml new file mode 100644 index 000000000..33e253677 --- /dev/null +++ b/app/src/main/res/drawable/ic_gesture_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_get_app_black_24dp.xml b/app/src/main/res/drawable/ic_get_app_black_24dp.xml new file mode 100644 index 000000000..492b41d34 --- /dev/null +++ b/app/src/main/res/drawable/ic_get_app_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_gif_black_24dp.xml b/app/src/main/res/drawable/ic_gif_black_24dp.xml new file mode 100644 index 000000000..9e8e7de94 --- /dev/null +++ b/app/src/main/res/drawable/ic_gif_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_golf_course_black_24dp.xml b/app/src/main/res/drawable/ic_golf_course_black_24dp.xml new file mode 100644 index 000000000..4e247449e --- /dev/null +++ b/app/src/main/res/drawable/ic_golf_course_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_gps_fixed_black_24dp.xml b/app/src/main/res/drawable/ic_gps_fixed_black_24dp.xml new file mode 100644 index 000000000..07d6e4694 --- /dev/null +++ b/app/src/main/res/drawable/ic_gps_fixed_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_gps_not_fixed_black_24dp.xml b/app/src/main/res/drawable/ic_gps_not_fixed_black_24dp.xml new file mode 100644 index 000000000..a1e7c4a27 --- /dev/null +++ b/app/src/main/res/drawable/ic_gps_not_fixed_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_gps_off_black_24dp.xml b/app/src/main/res/drawable/ic_gps_off_black_24dp.xml new file mode 100644 index 000000000..dad99eb25 --- /dev/null +++ b/app/src/main/res/drawable/ic_gps_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_grade_black_24dp.xml b/app/src/main/res/drawable/ic_grade_black_24dp.xml new file mode 100644 index 000000000..a87ca098d --- /dev/null +++ b/app/src/main/res/drawable/ic_grade_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_gradient_black_24dp.xml b/app/src/main/res/drawable/ic_gradient_black_24dp.xml new file mode 100644 index 000000000..4761d5e73 --- /dev/null +++ b/app/src/main/res/drawable/ic_gradient_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_grain_black_24dp.xml b/app/src/main/res/drawable/ic_grain_black_24dp.xml new file mode 100644 index 000000000..847ad6c0b --- /dev/null +++ b/app/src/main/res/drawable/ic_grain_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_graphic_eq_black_24dp.xml b/app/src/main/res/drawable/ic_graphic_eq_black_24dp.xml new file mode 100644 index 000000000..a8eb92f2c --- /dev/null +++ b/app/src/main/res/drawable/ic_graphic_eq_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_grid_off_black_24dp.xml b/app/src/main/res/drawable/ic_grid_off_black_24dp.xml new file mode 100644 index 000000000..7cf3c950c --- /dev/null +++ b/app/src/main/res/drawable/ic_grid_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_grid_on_black_24dp.xml b/app/src/main/res/drawable/ic_grid_on_black_24dp.xml new file mode 100644 index 000000000..b2ff9e5be --- /dev/null +++ b/app/src/main/res/drawable/ic_grid_on_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_group_add_black_24dp.xml b/app/src/main/res/drawable/ic_group_add_black_24dp.xml new file mode 100644 index 000000000..b3a2fb3d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_group_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_group_black_24dp.xml b/app/src/main/res/drawable/ic_group_black_24dp.xml new file mode 100644 index 000000000..4cfd86960 --- /dev/null +++ b/app/src/main/res/drawable/ic_group_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_group_work_black_24dp.xml b/app/src/main/res/drawable/ic_group_work_black_24dp.xml new file mode 100644 index 000000000..34490ed42 --- /dev/null +++ b/app/src/main/res/drawable/ic_group_work_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_hd_black_24dp.xml b/app/src/main/res/drawable/ic_hd_black_24dp.xml new file mode 100644 index 000000000..5f8f568a1 --- /dev/null +++ b/app/src/main/res/drawable/ic_hd_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_hdr_off_black_24dp.xml b/app/src/main/res/drawable/ic_hdr_off_black_24dp.xml new file mode 100644 index 000000000..61f68fa81 --- /dev/null +++ b/app/src/main/res/drawable/ic_hdr_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_hdr_on_black_24dp.xml b/app/src/main/res/drawable/ic_hdr_on_black_24dp.xml new file mode 100644 index 000000000..fadcbd152 --- /dev/null +++ b/app/src/main/res/drawable/ic_hdr_on_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_hdr_strong_black_24dp.xml b/app/src/main/res/drawable/ic_hdr_strong_black_24dp.xml new file mode 100644 index 000000000..95dad2bf8 --- /dev/null +++ b/app/src/main/res/drawable/ic_hdr_strong_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_hdr_weak_black_24dp.xml b/app/src/main/res/drawable/ic_hdr_weak_black_24dp.xml new file mode 100644 index 000000000..f4e0300da --- /dev/null +++ b/app/src/main/res/drawable/ic_hdr_weak_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_headset_black_24dp.xml b/app/src/main/res/drawable/ic_headset_black_24dp.xml new file mode 100644 index 000000000..d4503ce60 --- /dev/null +++ b/app/src/main/res/drawable/ic_headset_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_headset_mic_black_24dp.xml b/app/src/main/res/drawable/ic_headset_mic_black_24dp.xml new file mode 100644 index 000000000..55da400c5 --- /dev/null +++ b/app/src/main/res/drawable/ic_headset_mic_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_healing_black_24dp.xml b/app/src/main/res/drawable/ic_healing_black_24dp.xml new file mode 100644 index 000000000..9a637681e --- /dev/null +++ b/app/src/main/res/drawable/ic_healing_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_hearing_black_24dp.xml b/app/src/main/res/drawable/ic_hearing_black_24dp.xml new file mode 100644 index 000000000..f456a82d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_hearing_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_help_black_24dp.xml b/app/src/main/res/drawable/ic_help_black_24dp.xml new file mode 100644 index 000000000..1517747d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_help_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_help_outline_black_24dp.xml b/app/src/main/res/drawable/ic_help_outline_black_24dp.xml new file mode 100644 index 000000000..e7cf8ea21 --- /dev/null +++ b/app/src/main/res/drawable/ic_help_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_high_quality_black_24dp.xml b/app/src/main/res/drawable/ic_high_quality_black_24dp.xml new file mode 100644 index 000000000..1d683babc --- /dev/null +++ b/app/src/main/res/drawable/ic_high_quality_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_highlight_black_24dp.xml b/app/src/main/res/drawable/ic_highlight_black_24dp.xml new file mode 100644 index 000000000..2646f5747 --- /dev/null +++ b/app/src/main/res/drawable/ic_highlight_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_highlight_off_black_24dp.xml b/app/src/main/res/drawable/ic_highlight_off_black_24dp.xml new file mode 100644 index 000000000..e368a10e8 --- /dev/null +++ b/app/src/main/res/drawable/ic_highlight_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_history_black_24dp.xml b/app/src/main/res/drawable/ic_history_black_24dp.xml new file mode 100644 index 000000000..a61de1bc9 --- /dev/null +++ b/app/src/main/res/drawable/ic_history_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_home_black_24dp.xml b/app/src/main/res/drawable/ic_home_black_24dp.xml new file mode 100644 index 000000000..70fb2910c --- /dev/null +++ b/app/src/main/res/drawable/ic_home_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_hot_tub_black_24dp.xml b/app/src/main/res/drawable/ic_hot_tub_black_24dp.xml new file mode 100644 index 000000000..ccb05e29c --- /dev/null +++ b/app/src/main/res/drawable/ic_hot_tub_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_hotel_black_24dp.xml b/app/src/main/res/drawable/ic_hotel_black_24dp.xml new file mode 100644 index 000000000..e89ead09f --- /dev/null +++ b/app/src/main/res/drawable/ic_hotel_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_hourglass_empty_black_24dp.xml b/app/src/main/res/drawable/ic_hourglass_empty_black_24dp.xml new file mode 100644 index 000000000..d55d5c821 --- /dev/null +++ b/app/src/main/res/drawable/ic_hourglass_empty_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_hourglass_full_black_24dp.xml b/app/src/main/res/drawable/ic_hourglass_full_black_24dp.xml new file mode 100644 index 000000000..e56ebd528 --- /dev/null +++ b/app/src/main/res/drawable/ic_hourglass_full_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_http_black_24dp.xml b/app/src/main/res/drawable/ic_http_black_24dp.xml new file mode 100644 index 000000000..bd4e91529 --- /dev/null +++ b/app/src/main/res/drawable/ic_http_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_https_black_24dp.xml b/app/src/main/res/drawable/ic_https_black_24dp.xml new file mode 100644 index 000000000..67a7c73ab --- /dev/null +++ b/app/src/main/res/drawable/ic_https_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_image_aspect_ratio_black_24dp.xml b/app/src/main/res/drawable/ic_image_aspect_ratio_black_24dp.xml new file mode 100644 index 000000000..1b5f83554 --- /dev/null +++ b/app/src/main/res/drawable/ic_image_aspect_ratio_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_image_black_24dp.xml b/app/src/main/res/drawable/ic_image_black_24dp.xml new file mode 100644 index 000000000..b2018595e --- /dev/null +++ b/app/src/main/res/drawable/ic_image_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_import_contacts_black_24dp.xml b/app/src/main/res/drawable/ic_import_contacts_black_24dp.xml new file mode 100644 index 000000000..9c084abb1 --- /dev/null +++ b/app/src/main/res/drawable/ic_import_contacts_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_import_export_black_24dp.xml b/app/src/main/res/drawable/ic_import_export_black_24dp.xml new file mode 100644 index 000000000..a2d1fa99f --- /dev/null +++ b/app/src/main/res/drawable/ic_import_export_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_important_devices_black_24dp.xml b/app/src/main/res/drawable/ic_important_devices_black_24dp.xml new file mode 100644 index 000000000..18e315409 --- /dev/null +++ b/app/src/main/res/drawable/ic_important_devices_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_inbox_black_24dp.xml b/app/src/main/res/drawable/ic_inbox_black_24dp.xml new file mode 100644 index 000000000..de5c746a8 --- /dev/null +++ b/app/src/main/res/drawable/ic_inbox_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_indeterminate_check_box_black_24dp.xml b/app/src/main/res/drawable/ic_indeterminate_check_box_black_24dp.xml new file mode 100644 index 000000000..77865a606 --- /dev/null +++ b/app/src/main/res/drawable/ic_indeterminate_check_box_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_info_black_24dp.xml b/app/src/main/res/drawable/ic_info_black_24dp.xml new file mode 100644 index 000000000..cc9408819 --- /dev/null +++ b/app/src/main/res/drawable/ic_info_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_info_outline_black_24dp.xml b/app/src/main/res/drawable/ic_info_outline_black_24dp.xml new file mode 100644 index 000000000..cf53e145c --- /dev/null +++ b/app/src/main/res/drawable/ic_info_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_input_black_24dp.xml b/app/src/main/res/drawable/ic_input_black_24dp.xml new file mode 100644 index 000000000..fea69dfb7 --- /dev/null +++ b/app/src/main/res/drawable/ic_input_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_insert_chart_black_24dp.xml b/app/src/main/res/drawable/ic_insert_chart_black_24dp.xml new file mode 100644 index 000000000..75d0dde7b --- /dev/null +++ b/app/src/main/res/drawable/ic_insert_chart_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_insert_comment_black_24dp.xml b/app/src/main/res/drawable/ic_insert_comment_black_24dp.xml new file mode 100644 index 000000000..dee21b533 --- /dev/null +++ b/app/src/main/res/drawable/ic_insert_comment_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_insert_drive_file_black_24dp.xml b/app/src/main/res/drawable/ic_insert_drive_file_black_24dp.xml new file mode 100644 index 000000000..7a6d09416 --- /dev/null +++ b/app/src/main/res/drawable/ic_insert_drive_file_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_insert_emoticon_black_24dp.xml b/app/src/main/res/drawable/ic_insert_emoticon_black_24dp.xml new file mode 100644 index 000000000..43d5552cd --- /dev/null +++ b/app/src/main/res/drawable/ic_insert_emoticon_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_insert_invitation_black_24dp.xml b/app/src/main/res/drawable/ic_insert_invitation_black_24dp.xml new file mode 100644 index 000000000..22f1bb691 --- /dev/null +++ b/app/src/main/res/drawable/ic_insert_invitation_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_insert_link_black_24dp.xml b/app/src/main/res/drawable/ic_insert_link_black_24dp.xml new file mode 100644 index 000000000..538c5bdfc --- /dev/null +++ b/app/src/main/res/drawable/ic_insert_link_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_insert_photo_black_24dp.xml b/app/src/main/res/drawable/ic_insert_photo_black_24dp.xml new file mode 100644 index 000000000..b2018595e --- /dev/null +++ b/app/src/main/res/drawable/ic_insert_photo_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_invert_colors_black_24dp.xml b/app/src/main/res/drawable/ic_invert_colors_black_24dp.xml new file mode 100644 index 000000000..e3f120f80 --- /dev/null +++ b/app/src/main/res/drawable/ic_invert_colors_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_invert_colors_off_black_24dp.xml b/app/src/main/res/drawable/ic_invert_colors_off_black_24dp.xml new file mode 100644 index 000000000..29ac30c6d --- /dev/null +++ b/app/src/main/res/drawable/ic_invert_colors_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_iso_black_24dp.xml b/app/src/main/res/drawable/ic_iso_black_24dp.xml new file mode 100644 index 000000000..1c4ef5f15 --- /dev/null +++ b/app/src/main/res/drawable/ic_iso_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml new file mode 100644 index 000000000..ad33063c8 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_left_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_left_black_24dp.xml new file mode 100644 index 000000000..c9f7747e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_left_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_right_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_right_black_24dp.xml new file mode 100644 index 000000000..a3d162229 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_right_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml new file mode 100644 index 000000000..57387ee4f --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_backspace_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_backspace_black_24dp.xml new file mode 100644 index 000000000..827cde005 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_backspace_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_black_24dp.xml new file mode 100644 index 000000000..f0b93ebf5 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_capslock_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_capslock_black_24dp.xml new file mode 100644 index 000000000..cc4f03853 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_capslock_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_hide_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_hide_black_24dp.xml new file mode 100644 index 000000000..e26c127d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_hide_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_return_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_return_black_24dp.xml new file mode 100644 index 000000000..83ccf2686 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_return_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_tab_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_tab_black_24dp.xml new file mode 100644 index 000000000..2f549403f --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_tab_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_voice_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_voice_black_24dp.xml new file mode 100644 index 000000000..831bb5f9e --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_voice_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_kitchen_black_24dp.xml b/app/src/main/res/drawable/ic_kitchen_black_24dp.xml new file mode 100644 index 000000000..b988eec76 --- /dev/null +++ b/app/src/main/res/drawable/ic_kitchen_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_label_black_24dp.xml b/app/src/main/res/drawable/ic_label_black_24dp.xml new file mode 100644 index 000000000..1aa8d10ab --- /dev/null +++ b/app/src/main/res/drawable/ic_label_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_label_outline_black_24dp.xml b/app/src/main/res/drawable/ic_label_outline_black_24dp.xml new file mode 100644 index 000000000..158076604 --- /dev/null +++ b/app/src/main/res/drawable/ic_label_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_landscape_black_24dp.xml b/app/src/main/res/drawable/ic_landscape_black_24dp.xml new file mode 100644 index 000000000..0350ef536 --- /dev/null +++ b/app/src/main/res/drawable/ic_landscape_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_language_black_24dp.xml b/app/src/main/res/drawable/ic_language_black_24dp.xml new file mode 100644 index 000000000..d07324c87 --- /dev/null +++ b/app/src/main/res/drawable/ic_language_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_laptop_black_24dp.xml b/app/src/main/res/drawable/ic_laptop_black_24dp.xml new file mode 100644 index 000000000..1cba86fe5 --- /dev/null +++ b/app/src/main/res/drawable/ic_laptop_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_laptop_chromebook_black_24dp.xml b/app/src/main/res/drawable/ic_laptop_chromebook_black_24dp.xml new file mode 100644 index 000000000..9cba4950c --- /dev/null +++ b/app/src/main/res/drawable/ic_laptop_chromebook_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_laptop_mac_black_24dp.xml b/app/src/main/res/drawable/ic_laptop_mac_black_24dp.xml new file mode 100644 index 000000000..7a852eced --- /dev/null +++ b/app/src/main/res/drawable/ic_laptop_mac_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_laptop_windows_black_24dp.xml b/app/src/main/res/drawable/ic_laptop_windows_black_24dp.xml new file mode 100644 index 000000000..408c4bd5a --- /dev/null +++ b/app/src/main/res/drawable/ic_laptop_windows_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_last_page_black_24dp.xml b/app/src/main/res/drawable/ic_last_page_black_24dp.xml new file mode 100644 index 000000000..0d04354c1 --- /dev/null +++ b/app/src/main/res/drawable/ic_last_page_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_launch_black_24dp.xml b/app/src/main/res/drawable/ic_launch_black_24dp.xml new file mode 100644 index 000000000..60b75a549 --- /dev/null +++ b/app/src/main/res/drawable/ic_launch_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_layers_black_24dp.xml b/app/src/main/res/drawable/ic_layers_black_24dp.xml new file mode 100644 index 000000000..84f5bb50a --- /dev/null +++ b/app/src/main/res/drawable/ic_layers_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_layers_clear_black_24dp.xml b/app/src/main/res/drawable/ic_layers_clear_black_24dp.xml new file mode 100644 index 000000000..ef2778257 --- /dev/null +++ b/app/src/main/res/drawable/ic_layers_clear_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_leak_add_black_24dp.xml b/app/src/main/res/drawable/ic_leak_add_black_24dp.xml new file mode 100644 index 000000000..41e4d0cbd --- /dev/null +++ b/app/src/main/res/drawable/ic_leak_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_leak_remove_black_24dp.xml b/app/src/main/res/drawable/ic_leak_remove_black_24dp.xml new file mode 100644 index 000000000..141dc4541 --- /dev/null +++ b/app/src/main/res/drawable/ic_leak_remove_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_lens_black_24dp.xml b/app/src/main/res/drawable/ic_lens_black_24dp.xml new file mode 100644 index 000000000..847b0a4dd --- /dev/null +++ b/app/src/main/res/drawable/ic_lens_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_library_add_black_24dp.xml b/app/src/main/res/drawable/ic_library_add_black_24dp.xml new file mode 100644 index 000000000..f704ffedf --- /dev/null +++ b/app/src/main/res/drawable/ic_library_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_library_books_black_24dp.xml b/app/src/main/res/drawable/ic_library_books_black_24dp.xml new file mode 100644 index 000000000..a51097e04 --- /dev/null +++ b/app/src/main/res/drawable/ic_library_books_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_library_music_black_24dp.xml b/app/src/main/res/drawable/ic_library_music_black_24dp.xml new file mode 100644 index 000000000..3de22fe82 --- /dev/null +++ b/app/src/main/res/drawable/ic_library_music_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_lightbulb_outline_black_24dp.xml b/app/src/main/res/drawable/ic_lightbulb_outline_black_24dp.xml new file mode 100644 index 000000000..2a8e9d74a --- /dev/null +++ b/app/src/main/res/drawable/ic_lightbulb_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_line_style_black_24dp.xml b/app/src/main/res/drawable/ic_line_style_black_24dp.xml new file mode 100644 index 000000000..b76acf40c --- /dev/null +++ b/app/src/main/res/drawable/ic_line_style_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_line_weight_black_24dp.xml b/app/src/main/res/drawable/ic_line_weight_black_24dp.xml new file mode 100644 index 000000000..9b7c374f0 --- /dev/null +++ b/app/src/main/res/drawable/ic_line_weight_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_linear_scale_black_24dp.xml b/app/src/main/res/drawable/ic_linear_scale_black_24dp.xml new file mode 100644 index 000000000..2c012d3d8 --- /dev/null +++ b/app/src/main/res/drawable/ic_linear_scale_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_link_black_24dp.xml b/app/src/main/res/drawable/ic_link_black_24dp.xml new file mode 100644 index 000000000..538c5bdfc --- /dev/null +++ b/app/src/main/res/drawable/ic_link_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_linked_camera_black_24dp.xml b/app/src/main/res/drawable/ic_linked_camera_black_24dp.xml new file mode 100644 index 000000000..201c572da --- /dev/null +++ b/app/src/main/res/drawable/ic_linked_camera_black_24dp.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_list_black_24dp.xml b/app/src/main/res/drawable/ic_list_black_24dp.xml new file mode 100644 index 000000000..4c2fb8834 --- /dev/null +++ b/app/src/main/res/drawable/ic_list_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_live_help_black_24dp.xml b/app/src/main/res/drawable/ic_live_help_black_24dp.xml new file mode 100644 index 000000000..74f549430 --- /dev/null +++ b/app/src/main/res/drawable/ic_live_help_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_live_tv_black_24dp.xml b/app/src/main/res/drawable/ic_live_tv_black_24dp.xml new file mode 100644 index 000000000..ca255f996 --- /dev/null +++ b/app/src/main/res/drawable/ic_live_tv_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_activity_black_24dp.xml b/app/src/main/res/drawable/ic_local_activity_black_24dp.xml new file mode 100644 index 000000000..49d69e0dd --- /dev/null +++ b/app/src/main/res/drawable/ic_local_activity_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_airport_black_24dp.xml b/app/src/main/res/drawable/ic_local_airport_black_24dp.xml new file mode 100644 index 000000000..eee57b401 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_airport_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_atm_black_24dp.xml b/app/src/main/res/drawable/ic_local_atm_black_24dp.xml new file mode 100644 index 000000000..1b8613806 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_atm_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_bar_black_24dp.xml b/app/src/main/res/drawable/ic_local_bar_black_24dp.xml new file mode 100644 index 000000000..c1192b41d --- /dev/null +++ b/app/src/main/res/drawable/ic_local_bar_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_cafe_black_24dp.xml b/app/src/main/res/drawable/ic_local_cafe_black_24dp.xml new file mode 100644 index 000000000..29da47203 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_cafe_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_car_wash_black_24dp.xml b/app/src/main/res/drawable/ic_local_car_wash_black_24dp.xml new file mode 100644 index 000000000..717505f8f --- /dev/null +++ b/app/src/main/res/drawable/ic_local_car_wash_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_convenience_store_black_24dp.xml b/app/src/main/res/drawable/ic_local_convenience_store_black_24dp.xml new file mode 100644 index 000000000..7d6b977b4 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_convenience_store_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_dining_black_24dp.xml b/app/src/main/res/drawable/ic_local_dining_black_24dp.xml new file mode 100644 index 000000000..7375ec304 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_dining_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_drink_black_24dp.xml b/app/src/main/res/drawable/ic_local_drink_black_24dp.xml new file mode 100644 index 000000000..d7dab58cf --- /dev/null +++ b/app/src/main/res/drawable/ic_local_drink_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_florist_black_24dp.xml b/app/src/main/res/drawable/ic_local_florist_black_24dp.xml new file mode 100644 index 000000000..a66809848 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_florist_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_gas_station_black_24dp.xml b/app/src/main/res/drawable/ic_local_gas_station_black_24dp.xml new file mode 100644 index 000000000..8a152dc0f --- /dev/null +++ b/app/src/main/res/drawable/ic_local_gas_station_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_grocery_store_black_24dp.xml b/app/src/main/res/drawable/ic_local_grocery_store_black_24dp.xml new file mode 100644 index 000000000..11887e38f --- /dev/null +++ b/app/src/main/res/drawable/ic_local_grocery_store_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_hospital_black_24dp.xml b/app/src/main/res/drawable/ic_local_hospital_black_24dp.xml new file mode 100644 index 000000000..e0f6e1450 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_hospital_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_hotel_black_24dp.xml b/app/src/main/res/drawable/ic_local_hotel_black_24dp.xml new file mode 100644 index 000000000..e89ead09f --- /dev/null +++ b/app/src/main/res/drawable/ic_local_hotel_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_laundry_service_black_24dp.xml b/app/src/main/res/drawable/ic_local_laundry_service_black_24dp.xml new file mode 100644 index 000000000..242d1fa3b --- /dev/null +++ b/app/src/main/res/drawable/ic_local_laundry_service_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_library_black_24dp.xml b/app/src/main/res/drawable/ic_local_library_black_24dp.xml new file mode 100644 index 000000000..3fd5a4f64 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_library_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_mall_black_24dp.xml b/app/src/main/res/drawable/ic_local_mall_black_24dp.xml new file mode 100644 index 000000000..206e1a0e0 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_mall_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_movies_black_24dp.xml b/app/src/main/res/drawable/ic_local_movies_black_24dp.xml new file mode 100644 index 000000000..56665e6e4 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_movies_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_offer_black_24dp.xml b/app/src/main/res/drawable/ic_local_offer_black_24dp.xml new file mode 100644 index 000000000..8b19fe422 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_offer_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_parking_black_24dp.xml b/app/src/main/res/drawable/ic_local_parking_black_24dp.xml new file mode 100644 index 000000000..a5808ce71 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_parking_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_pharmacy_black_24dp.xml b/app/src/main/res/drawable/ic_local_pharmacy_black_24dp.xml new file mode 100644 index 000000000..c313f4789 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_pharmacy_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_phone_black_24dp.xml b/app/src/main/res/drawable/ic_local_phone_black_24dp.xml new file mode 100644 index 000000000..ebf9de60f --- /dev/null +++ b/app/src/main/res/drawable/ic_local_phone_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_pizza_black_24dp.xml b/app/src/main/res/drawable/ic_local_pizza_black_24dp.xml new file mode 100644 index 000000000..7a5b03bfc --- /dev/null +++ b/app/src/main/res/drawable/ic_local_pizza_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_play_black_24dp.xml b/app/src/main/res/drawable/ic_local_play_black_24dp.xml new file mode 100644 index 000000000..49d69e0dd --- /dev/null +++ b/app/src/main/res/drawable/ic_local_play_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_post_office_black_24dp.xml b/app/src/main/res/drawable/ic_local_post_office_black_24dp.xml new file mode 100644 index 000000000..ce97ab859 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_post_office_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_printshop_black_24dp.xml b/app/src/main/res/drawable/ic_local_printshop_black_24dp.xml new file mode 100644 index 000000000..7acdb182d --- /dev/null +++ b/app/src/main/res/drawable/ic_local_printshop_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_see_black_24dp.xml b/app/src/main/res/drawable/ic_local_see_black_24dp.xml new file mode 100644 index 000000000..c872f1670 --- /dev/null +++ b/app/src/main/res/drawable/ic_local_see_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_local_shipping_black_24dp.xml b/app/src/main/res/drawable/ic_local_shipping_black_24dp.xml new file mode 100644 index 000000000..011c1e27e --- /dev/null +++ b/app/src/main/res/drawable/ic_local_shipping_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_local_taxi_black_24dp.xml b/app/src/main/res/drawable/ic_local_taxi_black_24dp.xml new file mode 100644 index 000000000..21b763e7b --- /dev/null +++ b/app/src/main/res/drawable/ic_local_taxi_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_location_city_black_24dp.xml b/app/src/main/res/drawable/ic_location_city_black_24dp.xml new file mode 100644 index 000000000..a7c688fed --- /dev/null +++ b/app/src/main/res/drawable/ic_location_city_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_location_disabled_black_24dp.xml b/app/src/main/res/drawable/ic_location_disabled_black_24dp.xml new file mode 100644 index 000000000..dad99eb25 --- /dev/null +++ b/app/src/main/res/drawable/ic_location_disabled_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_location_off_black_24dp.xml b/app/src/main/res/drawable/ic_location_off_black_24dp.xml new file mode 100644 index 000000000..56565e0f7 --- /dev/null +++ b/app/src/main/res/drawable/ic_location_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_location_on_black_24dp.xml b/app/src/main/res/drawable/ic_location_on_black_24dp.xml new file mode 100644 index 000000000..e3291a943 --- /dev/null +++ b/app/src/main/res/drawable/ic_location_on_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_location_searching_black_24dp.xml b/app/src/main/res/drawable/ic_location_searching_black_24dp.xml new file mode 100644 index 000000000..a1e7c4a27 --- /dev/null +++ b/app/src/main/res/drawable/ic_location_searching_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_lock_black_24dp.xml b/app/src/main/res/drawable/ic_lock_black_24dp.xml new file mode 100644 index 000000000..67a7c73ab --- /dev/null +++ b/app/src/main/res/drawable/ic_lock_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_lock_open_black_24dp.xml b/app/src/main/res/drawable/ic_lock_open_black_24dp.xml new file mode 100644 index 000000000..c8125981c --- /dev/null +++ b/app/src/main/res/drawable/ic_lock_open_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_lock_outline_black_24dp.xml b/app/src/main/res/drawable/ic_lock_outline_black_24dp.xml new file mode 100644 index 000000000..9a14b68f8 --- /dev/null +++ b/app/src/main/res/drawable/ic_lock_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_looks_3_black_24dp.xml b/app/src/main/res/drawable/ic_looks_3_black_24dp.xml new file mode 100644 index 000000000..418e01293 --- /dev/null +++ b/app/src/main/res/drawable/ic_looks_3_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_looks_4_black_24dp.xml b/app/src/main/res/drawable/ic_looks_4_black_24dp.xml new file mode 100644 index 000000000..4855e981a --- /dev/null +++ b/app/src/main/res/drawable/ic_looks_4_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_looks_5_black_24dp.xml b/app/src/main/res/drawable/ic_looks_5_black_24dp.xml new file mode 100644 index 000000000..45fbfab83 --- /dev/null +++ b/app/src/main/res/drawable/ic_looks_5_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_looks_6_black_24dp.xml b/app/src/main/res/drawable/ic_looks_6_black_24dp.xml new file mode 100644 index 000000000..6219b6d96 --- /dev/null +++ b/app/src/main/res/drawable/ic_looks_6_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_looks_black_24dp.xml b/app/src/main/res/drawable/ic_looks_black_24dp.xml new file mode 100644 index 000000000..dc2a0a3ce --- /dev/null +++ b/app/src/main/res/drawable/ic_looks_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_looks_one_black_24dp.xml b/app/src/main/res/drawable/ic_looks_one_black_24dp.xml new file mode 100644 index 000000000..711e01219 --- /dev/null +++ b/app/src/main/res/drawable/ic_looks_one_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_looks_two_black_24dp.xml b/app/src/main/res/drawable/ic_looks_two_black_24dp.xml new file mode 100644 index 000000000..f15dd6578 --- /dev/null +++ b/app/src/main/res/drawable/ic_looks_two_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_loop_black_24dp.xml b/app/src/main/res/drawable/ic_loop_black_24dp.xml new file mode 100644 index 000000000..ce8796cb7 --- /dev/null +++ b/app/src/main/res/drawable/ic_loop_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_loupe_black_24dp.xml b/app/src/main/res/drawable/ic_loupe_black_24dp.xml new file mode 100644 index 000000000..f55ffc686 --- /dev/null +++ b/app/src/main/res/drawable/ic_loupe_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_low_priority_black_24dp.xml b/app/src/main/res/drawable/ic_low_priority_black_24dp.xml new file mode 100644 index 000000000..c5ebe8d85 --- /dev/null +++ b/app/src/main/res/drawable/ic_low_priority_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_loyalty_black_24dp.xml b/app/src/main/res/drawable/ic_loyalty_black_24dp.xml new file mode 100644 index 000000000..af3ab2d64 --- /dev/null +++ b/app/src/main/res/drawable/ic_loyalty_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mail_black_24dp.xml b/app/src/main/res/drawable/ic_mail_black_24dp.xml new file mode 100644 index 000000000..ce97ab859 --- /dev/null +++ b/app/src/main/res/drawable/ic_mail_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mail_outline_black_24dp.xml b/app/src/main/res/drawable/ic_mail_outline_black_24dp.xml new file mode 100644 index 000000000..8ea2622e1 --- /dev/null +++ b/app/src/main/res/drawable/ic_mail_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_map_black_24dp.xml b/app/src/main/res/drawable/ic_map_black_24dp.xml new file mode 100644 index 000000000..b9bacc8a6 --- /dev/null +++ b/app/src/main/res/drawable/ic_map_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_markunread_black_24dp.xml b/app/src/main/res/drawable/ic_markunread_black_24dp.xml new file mode 100644 index 000000000..ce97ab859 --- /dev/null +++ b/app/src/main/res/drawable/ic_markunread_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_markunread_mailbox_black_24dp.xml b/app/src/main/res/drawable/ic_markunread_mailbox_black_24dp.xml new file mode 100644 index 000000000..34c9a3a09 --- /dev/null +++ b/app/src/main/res/drawable/ic_markunread_mailbox_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_memory_black_24dp.xml b/app/src/main/res/drawable/ic_memory_black_24dp.xml new file mode 100644 index 000000000..76e03b6d8 --- /dev/null +++ b/app/src/main/res/drawable/ic_memory_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_black_24dp.xml b/app/src/main/res/drawable/ic_menu_black_24dp.xml new file mode 100644 index 000000000..6d9343b31 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_merge_type_black_24dp.xml b/app/src/main/res/drawable/ic_merge_type_black_24dp.xml new file mode 100644 index 000000000..40b6b383d --- /dev/null +++ b/app/src/main/res/drawable/ic_merge_type_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_message_black_24dp.xml b/app/src/main/res/drawable/ic_message_black_24dp.xml new file mode 100644 index 000000000..d2876bfad --- /dev/null +++ b/app/src/main/res/drawable/ic_message_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mic_black_24dp.xml b/app/src/main/res/drawable/ic_mic_black_24dp.xml new file mode 100644 index 000000000..4f0dc0445 --- /dev/null +++ b/app/src/main/res/drawable/ic_mic_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mic_none_black_24dp.xml b/app/src/main/res/drawable/ic_mic_none_black_24dp.xml new file mode 100644 index 000000000..f008a4ae8 --- /dev/null +++ b/app/src/main/res/drawable/ic_mic_none_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mic_off_black_24dp.xml b/app/src/main/res/drawable/ic_mic_off_black_24dp.xml new file mode 100644 index 000000000..7b1759b34 --- /dev/null +++ b/app/src/main/res/drawable/ic_mic_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mms_black_24dp.xml b/app/src/main/res/drawable/ic_mms_black_24dp.xml new file mode 100644 index 000000000..f66e4af30 --- /dev/null +++ b/app/src/main/res/drawable/ic_mms_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mode_comment_black_24dp.xml b/app/src/main/res/drawable/ic_mode_comment_black_24dp.xml new file mode 100644 index 000000000..301e46fd1 --- /dev/null +++ b/app/src/main/res/drawable/ic_mode_comment_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mode_edit_black_24dp.xml b/app/src/main/res/drawable/ic_mode_edit_black_24dp.xml new file mode 100644 index 000000000..2ab2fb753 --- /dev/null +++ b/app/src/main/res/drawable/ic_mode_edit_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_monetization_on_black_24dp.xml b/app/src/main/res/drawable/ic_monetization_on_black_24dp.xml new file mode 100644 index 000000000..5d1dc64e0 --- /dev/null +++ b/app/src/main/res/drawable/ic_monetization_on_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_money_off_black_24dp.xml b/app/src/main/res/drawable/ic_money_off_black_24dp.xml new file mode 100644 index 000000000..32bd88158 --- /dev/null +++ b/app/src/main/res/drawable/ic_money_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_monochrome_photos_black_24dp.xml b/app/src/main/res/drawable/ic_monochrome_photos_black_24dp.xml new file mode 100644 index 000000000..5cc70220b --- /dev/null +++ b/app/src/main/res/drawable/ic_monochrome_photos_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mood_bad_black_24dp.xml b/app/src/main/res/drawable/ic_mood_bad_black_24dp.xml new file mode 100644 index 000000000..d511379df --- /dev/null +++ b/app/src/main/res/drawable/ic_mood_bad_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mood_black_24dp.xml b/app/src/main/res/drawable/ic_mood_black_24dp.xml new file mode 100644 index 000000000..43d5552cd --- /dev/null +++ b/app/src/main/res/drawable/ic_mood_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_more_black_24dp.xml b/app/src/main/res/drawable/ic_more_black_24dp.xml new file mode 100644 index 000000000..4f35646b4 --- /dev/null +++ b/app/src/main/res/drawable/ic_more_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_more_horiz_black_24dp.xml b/app/src/main/res/drawable/ic_more_horiz_black_24dp.xml new file mode 100644 index 000000000..da83afdb1 --- /dev/null +++ b/app/src/main/res/drawable/ic_more_horiz_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_more_vert_black_24dp.xml b/app/src/main/res/drawable/ic_more_vert_black_24dp.xml new file mode 100644 index 000000000..5176d8a4b --- /dev/null +++ b/app/src/main/res/drawable/ic_more_vert_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_motorcycle_black_24dp.xml b/app/src/main/res/drawable/ic_motorcycle_black_24dp.xml new file mode 100644 index 000000000..539182f83 --- /dev/null +++ b/app/src/main/res/drawable/ic_motorcycle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_mouse_black_24dp.xml b/app/src/main/res/drawable/ic_mouse_black_24dp.xml new file mode 100644 index 000000000..bec6a441f --- /dev/null +++ b/app/src/main/res/drawable/ic_mouse_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_move_to_inbox_black_24dp.xml b/app/src/main/res/drawable/ic_move_to_inbox_black_24dp.xml new file mode 100644 index 000000000..349f48fab --- /dev/null +++ b/app/src/main/res/drawable/ic_move_to_inbox_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_movie_black_24dp.xml b/app/src/main/res/drawable/ic_movie_black_24dp.xml new file mode 100644 index 000000000..a7f7b6561 --- /dev/null +++ b/app/src/main/res/drawable/ic_movie_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_movie_creation_black_24dp.xml b/app/src/main/res/drawable/ic_movie_creation_black_24dp.xml new file mode 100644 index 000000000..a7f7b6561 --- /dev/null +++ b/app/src/main/res/drawable/ic_movie_creation_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_movie_filter_black_24dp.xml b/app/src/main/res/drawable/ic_movie_filter_black_24dp.xml new file mode 100644 index 000000000..8505b79fb --- /dev/null +++ b/app/src/main/res/drawable/ic_movie_filter_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_multiline_chart_black_24dp.xml b/app/src/main/res/drawable/ic_multiline_chart_black_24dp.xml new file mode 100644 index 000000000..d521bd0ef --- /dev/null +++ b/app/src/main/res/drawable/ic_multiline_chart_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_music_note_black_24dp.xml b/app/src/main/res/drawable/ic_music_note_black_24dp.xml new file mode 100644 index 000000000..736c004ef --- /dev/null +++ b/app/src/main/res/drawable/ic_music_note_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_music_video_black_24dp.xml b/app/src/main/res/drawable/ic_music_video_black_24dp.xml new file mode 100644 index 000000000..d012978d7 --- /dev/null +++ b/app/src/main/res/drawable/ic_music_video_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_my_location_black_24dp.xml b/app/src/main/res/drawable/ic_my_location_black_24dp.xml new file mode 100644 index 000000000..07d6e4694 --- /dev/null +++ b/app/src/main/res/drawable/ic_my_location_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_nature_black_24dp.xml b/app/src/main/res/drawable/ic_nature_black_24dp.xml new file mode 100644 index 000000000..ecd6f69b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_nature_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_nature_people_black_24dp.xml b/app/src/main/res/drawable/ic_nature_people_black_24dp.xml new file mode 100644 index 000000000..592a6ecaa --- /dev/null +++ b/app/src/main/res/drawable/ic_nature_people_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_navigate_before_black_24dp.xml b/app/src/main/res/drawable/ic_navigate_before_black_24dp.xml new file mode 100644 index 000000000..e6bb3ca92 --- /dev/null +++ b/app/src/main/res/drawable/ic_navigate_before_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_navigate_next_black_24dp.xml b/app/src/main/res/drawable/ic_navigate_next_black_24dp.xml new file mode 100644 index 000000000..24835127d --- /dev/null +++ b/app/src/main/res/drawable/ic_navigate_next_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_navigation_black_24dp.xml b/app/src/main/res/drawable/ic_navigation_black_24dp.xml new file mode 100644 index 000000000..6df5ae66b --- /dev/null +++ b/app/src/main/res/drawable/ic_navigation_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_near_me_black_24dp.xml b/app/src/main/res/drawable/ic_near_me_black_24dp.xml new file mode 100644 index 000000000..fbd8e4758 --- /dev/null +++ b/app/src/main/res/drawable/ic_near_me_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_network_cell_black_24dp.xml b/app/src/main/res/drawable/ic_network_cell_black_24dp.xml new file mode 100644 index 000000000..de5804b49 --- /dev/null +++ b/app/src/main/res/drawable/ic_network_cell_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_network_check_black_24dp.xml b/app/src/main/res/drawable/ic_network_check_black_24dp.xml new file mode 100644 index 000000000..a8381d5c6 --- /dev/null +++ b/app/src/main/res/drawable/ic_network_check_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_network_locked_black_24dp.xml b/app/src/main/res/drawable/ic_network_locked_black_24dp.xml new file mode 100644 index 000000000..33bca18e6 --- /dev/null +++ b/app/src/main/res/drawable/ic_network_locked_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_network_wifi_black_24dp.xml b/app/src/main/res/drawable/ic_network_wifi_black_24dp.xml new file mode 100644 index 000000000..caac288fd --- /dev/null +++ b/app/src/main/res/drawable/ic_network_wifi_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_new_releases_black_24dp.xml b/app/src/main/res/drawable/ic_new_releases_black_24dp.xml new file mode 100644 index 000000000..ce9baf42d --- /dev/null +++ b/app/src/main/res/drawable/ic_new_releases_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_next_week_black_24dp.xml b/app/src/main/res/drawable/ic_next_week_black_24dp.xml new file mode 100644 index 000000000..9be44e3e6 --- /dev/null +++ b/app/src/main/res/drawable/ic_next_week_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_nfc_black_24dp.xml b/app/src/main/res/drawable/ic_nfc_black_24dp.xml new file mode 100644 index 000000000..81f45600a --- /dev/null +++ b/app/src/main/res/drawable/ic_nfc_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_no_encryption_black_24dp.xml b/app/src/main/res/drawable/ic_no_encryption_black_24dp.xml new file mode 100644 index 000000000..bf1acc4e9 --- /dev/null +++ b/app/src/main/res/drawable/ic_no_encryption_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_no_sim_black_24dp.xml b/app/src/main/res/drawable/ic_no_sim_black_24dp.xml new file mode 100644 index 000000000..1f82b548b --- /dev/null +++ b/app/src/main/res/drawable/ic_no_sim_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_not_interested_black_24dp.xml b/app/src/main/res/drawable/ic_not_interested_black_24dp.xml new file mode 100644 index 000000000..6944a908b --- /dev/null +++ b/app/src/main/res/drawable/ic_not_interested_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_note_add_black_24dp.xml b/app/src/main/res/drawable/ic_note_add_black_24dp.xml new file mode 100644 index 000000000..ba7153f53 --- /dev/null +++ b/app/src/main/res/drawable/ic_note_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_note_black_24dp.xml b/app/src/main/res/drawable/ic_note_black_24dp.xml new file mode 100644 index 000000000..2e8d7a517 --- /dev/null +++ b/app/src/main/res/drawable/ic_note_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_notifications_active_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_active_black_24dp.xml new file mode 100644 index 000000000..be9f8368d --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_active_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_black_24dp.xml new file mode 100644 index 000000000..7009a6763 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_notifications_none_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_none_black_24dp.xml new file mode 100644 index 000000000..a4543fd25 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_none_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_notifications_off_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_off_black_24dp.xml new file mode 100644 index 000000000..415f55811 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_notifications_paused_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_paused_black_24dp.xml new file mode 100644 index 000000000..198e53a00 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_paused_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_offline_pin_black_24dp.xml b/app/src/main/res/drawable/ic_offline_pin_black_24dp.xml new file mode 100644 index 000000000..d04f2703e --- /dev/null +++ b/app/src/main/res/drawable/ic_offline_pin_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_ondemand_video_black_24dp.xml b/app/src/main/res/drawable/ic_ondemand_video_black_24dp.xml new file mode 100644 index 000000000..b556865cc --- /dev/null +++ b/app/src/main/res/drawable/ic_ondemand_video_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_opacity_black_24dp.xml b/app/src/main/res/drawable/ic_opacity_black_24dp.xml new file mode 100644 index 000000000..c9f47f8ea --- /dev/null +++ b/app/src/main/res/drawable/ic_opacity_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_open_in_browser_black_24dp.xml b/app/src/main/res/drawable/ic_open_in_browser_black_24dp.xml new file mode 100644 index 000000000..d597c37e3 --- /dev/null +++ b/app/src/main/res/drawable/ic_open_in_browser_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_open_in_new_black_24dp.xml b/app/src/main/res/drawable/ic_open_in_new_black_24dp.xml new file mode 100644 index 000000000..60b75a549 --- /dev/null +++ b/app/src/main/res/drawable/ic_open_in_new_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_open_with_black_24dp.xml b/app/src/main/res/drawable/ic_open_with_black_24dp.xml new file mode 100644 index 000000000..c22fbd0c5 --- /dev/null +++ b/app/src/main/res/drawable/ic_open_with_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pages_black_24dp.xml b/app/src/main/res/drawable/ic_pages_black_24dp.xml new file mode 100644 index 000000000..53ac64edd --- /dev/null +++ b/app/src/main/res/drawable/ic_pages_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pageview_black_24dp.xml b/app/src/main/res/drawable/ic_pageview_black_24dp.xml new file mode 100644 index 000000000..6a990aff7 --- /dev/null +++ b/app/src/main/res/drawable/ic_pageview_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_palette_black_24dp.xml b/app/src/main/res/drawable/ic_palette_black_24dp.xml new file mode 100644 index 000000000..f75e2fbe3 --- /dev/null +++ b/app/src/main/res/drawable/ic_palette_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pan_tool_black_24dp.xml b/app/src/main/res/drawable/ic_pan_tool_black_24dp.xml new file mode 100644 index 000000000..6c09d038c --- /dev/null +++ b/app/src/main/res/drawable/ic_pan_tool_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_panorama_black_24dp.xml b/app/src/main/res/drawable/ic_panorama_black_24dp.xml new file mode 100644 index 000000000..cffa72918 --- /dev/null +++ b/app/src/main/res/drawable/ic_panorama_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_panorama_fish_eye_black_24dp.xml b/app/src/main/res/drawable/ic_panorama_fish_eye_black_24dp.xml new file mode 100644 index 000000000..ef6742b40 --- /dev/null +++ b/app/src/main/res/drawable/ic_panorama_fish_eye_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_panorama_horizontal_black_24dp.xml b/app/src/main/res/drawable/ic_panorama_horizontal_black_24dp.xml new file mode 100644 index 000000000..f0aec1e73 --- /dev/null +++ b/app/src/main/res/drawable/ic_panorama_horizontal_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_panorama_vertical_black_24dp.xml b/app/src/main/res/drawable/ic_panorama_vertical_black_24dp.xml new file mode 100644 index 000000000..22681335e --- /dev/null +++ b/app/src/main/res/drawable/ic_panorama_vertical_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_panorama_wide_angle_black_24dp.xml b/app/src/main/res/drawable/ic_panorama_wide_angle_black_24dp.xml new file mode 100644 index 000000000..900b34e58 --- /dev/null +++ b/app/src/main/res/drawable/ic_panorama_wide_angle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_party_mode_black_24dp.xml b/app/src/main/res/drawable/ic_party_mode_black_24dp.xml new file mode 100644 index 000000000..0dde9b97a --- /dev/null +++ b/app/src/main/res/drawable/ic_party_mode_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pause_black_24dp.xml b/app/src/main/res/drawable/ic_pause_black_24dp.xml new file mode 100644 index 000000000..bb28a6c41 --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pause_circle_filled_black_24dp.xml b/app/src/main/res/drawable/ic_pause_circle_filled_black_24dp.xml new file mode 100644 index 000000000..d7c2212ba --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_circle_filled_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pause_circle_outline_black_24dp.xml b/app/src/main/res/drawable/ic_pause_circle_outline_black_24dp.xml new file mode 100644 index 000000000..169c05d74 --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_circle_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_payment_black_24dp.xml b/app/src/main/res/drawable/ic_payment_black_24dp.xml new file mode 100644 index 000000000..62a08a812 --- /dev/null +++ b/app/src/main/res/drawable/ic_payment_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_people_black_24dp.xml b/app/src/main/res/drawable/ic_people_black_24dp.xml new file mode 100644 index 000000000..4cfd86960 --- /dev/null +++ b/app/src/main/res/drawable/ic_people_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_people_outline_black_24dp.xml b/app/src/main/res/drawable/ic_people_outline_black_24dp.xml new file mode 100644 index 000000000..15d27f9b8 --- /dev/null +++ b/app/src/main/res/drawable/ic_people_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_perm_camera_mic_black_24dp.xml b/app/src/main/res/drawable/ic_perm_camera_mic_black_24dp.xml new file mode 100644 index 000000000..f16141d03 --- /dev/null +++ b/app/src/main/res/drawable/ic_perm_camera_mic_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_perm_contact_calendar_black_24dp.xml b/app/src/main/res/drawable/ic_perm_contact_calendar_black_24dp.xml new file mode 100644 index 000000000..0d6b3bbdf --- /dev/null +++ b/app/src/main/res/drawable/ic_perm_contact_calendar_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_perm_data_setting_black_24dp.xml b/app/src/main/res/drawable/ic_perm_data_setting_black_24dp.xml new file mode 100644 index 000000000..2e22b3d53 --- /dev/null +++ b/app/src/main/res/drawable/ic_perm_data_setting_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_perm_device_information_black_24dp.xml b/app/src/main/res/drawable/ic_perm_device_information_black_24dp.xml new file mode 100644 index 000000000..2c4e5c7f4 --- /dev/null +++ b/app/src/main/res/drawable/ic_perm_device_information_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_perm_identity_black_24dp.xml b/app/src/main/res/drawable/ic_perm_identity_black_24dp.xml new file mode 100644 index 000000000..f182b8d4c --- /dev/null +++ b/app/src/main/res/drawable/ic_perm_identity_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_perm_media_black_24dp.xml b/app/src/main/res/drawable/ic_perm_media_black_24dp.xml new file mode 100644 index 000000000..d2bf51285 --- /dev/null +++ b/app/src/main/res/drawable/ic_perm_media_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_perm_phone_msg_black_24dp.xml b/app/src/main/res/drawable/ic_perm_phone_msg_black_24dp.xml new file mode 100644 index 000000000..60f54b140 --- /dev/null +++ b/app/src/main/res/drawable/ic_perm_phone_msg_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_perm_scan_wifi_black_24dp.xml b/app/src/main/res/drawable/ic_perm_scan_wifi_black_24dp.xml new file mode 100644 index 000000000..a71c74969 --- /dev/null +++ b/app/src/main/res/drawable/ic_perm_scan_wifi_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_person_add_black_24dp.xml b/app/src/main/res/drawable/ic_person_add_black_24dp.xml new file mode 100644 index 000000000..225ae0a86 --- /dev/null +++ b/app/src/main/res/drawable/ic_person_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_person_black_24dp.xml b/app/src/main/res/drawable/ic_person_black_24dp.xml new file mode 100644 index 000000000..b2cb337b0 --- /dev/null +++ b/app/src/main/res/drawable/ic_person_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_person_outline_black_24dp.xml b/app/src/main/res/drawable/ic_person_outline_black_24dp.xml new file mode 100644 index 000000000..f182b8d4c --- /dev/null +++ b/app/src/main/res/drawable/ic_person_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_person_pin_black_24dp.xml b/app/src/main/res/drawable/ic_person_pin_black_24dp.xml new file mode 100644 index 000000000..90ed54df7 --- /dev/null +++ b/app/src/main/res/drawable/ic_person_pin_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_person_pin_circle_black_24dp.xml b/app/src/main/res/drawable/ic_person_pin_circle_black_24dp.xml new file mode 100644 index 000000000..6fdfe7093 --- /dev/null +++ b/app/src/main/res/drawable/ic_person_pin_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_personal_video_black_24dp.xml b/app/src/main/res/drawable/ic_personal_video_black_24dp.xml new file mode 100644 index 000000000..30eef0d06 --- /dev/null +++ b/app/src/main/res/drawable/ic_personal_video_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pets_black_24dp.xml b/app/src/main/res/drawable/ic_pets_black_24dp.xml new file mode 100644 index 000000000..75874d9f6 --- /dev/null +++ b/app/src/main/res/drawable/ic_pets_black_24dp.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_phone_android_black_24dp.xml b/app/src/main/res/drawable/ic_phone_android_black_24dp.xml new file mode 100644 index 000000000..ab9b9a09e --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_android_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phone_black_24dp.xml b/app/src/main/res/drawable/ic_phone_black_24dp.xml new file mode 100644 index 000000000..ebf9de60f --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phone_bluetooth_speaker_black_24dp.xml b/app/src/main/res/drawable/ic_phone_bluetooth_speaker_black_24dp.xml new file mode 100644 index 000000000..9fb950c7d --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_bluetooth_speaker_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phone_forwarded_black_24dp.xml b/app/src/main/res/drawable/ic_phone_forwarded_black_24dp.xml new file mode 100644 index 000000000..69724527a --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_forwarded_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phone_in_talk_black_24dp.xml b/app/src/main/res/drawable/ic_phone_in_talk_black_24dp.xml new file mode 100644 index 000000000..b48b9ede7 --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_in_talk_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phone_iphone_black_24dp.xml b/app/src/main/res/drawable/ic_phone_iphone_black_24dp.xml new file mode 100644 index 000000000..2e30473f0 --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_iphone_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phone_locked_black_24dp.xml b/app/src/main/res/drawable/ic_phone_locked_black_24dp.xml new file mode 100644 index 000000000..67e7c49c0 --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_locked_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phone_missed_black_24dp.xml b/app/src/main/res/drawable/ic_phone_missed_black_24dp.xml new file mode 100644 index 000000000..b2338317a --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_missed_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phone_paused_black_24dp.xml b/app/src/main/res/drawable/ic_phone_paused_black_24dp.xml new file mode 100644 index 000000000..e5be52e5d --- /dev/null +++ b/app/src/main/res/drawable/ic_phone_paused_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phonelink_black_24dp.xml b/app/src/main/res/drawable/ic_phonelink_black_24dp.xml new file mode 100644 index 000000000..150ced43d --- /dev/null +++ b/app/src/main/res/drawable/ic_phonelink_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phonelink_erase_black_24dp.xml b/app/src/main/res/drawable/ic_phonelink_erase_black_24dp.xml new file mode 100644 index 000000000..2af6c9607 --- /dev/null +++ b/app/src/main/res/drawable/ic_phonelink_erase_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phonelink_lock_black_24dp.xml b/app/src/main/res/drawable/ic_phonelink_lock_black_24dp.xml new file mode 100644 index 000000000..bbb774aa0 --- /dev/null +++ b/app/src/main/res/drawable/ic_phonelink_lock_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phonelink_off_black_24dp.xml b/app/src/main/res/drawable/ic_phonelink_off_black_24dp.xml new file mode 100644 index 000000000..8f6376522 --- /dev/null +++ b/app/src/main/res/drawable/ic_phonelink_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phonelink_ring_black_24dp.xml b/app/src/main/res/drawable/ic_phonelink_ring_black_24dp.xml new file mode 100644 index 000000000..9c2bdec3c --- /dev/null +++ b/app/src/main/res/drawable/ic_phonelink_ring_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_phonelink_setup_black_24dp.xml b/app/src/main/res/drawable/ic_phonelink_setup_black_24dp.xml new file mode 100644 index 000000000..3a9651199 --- /dev/null +++ b/app/src/main/res/drawable/ic_phonelink_setup_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_photo_album_black_24dp.xml b/app/src/main/res/drawable/ic_photo_album_black_24dp.xml new file mode 100644 index 000000000..c39882ce3 --- /dev/null +++ b/app/src/main/res/drawable/ic_photo_album_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_photo_black_24dp.xml b/app/src/main/res/drawable/ic_photo_black_24dp.xml new file mode 100644 index 000000000..b2018595e --- /dev/null +++ b/app/src/main/res/drawable/ic_photo_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_photo_camera_black_24dp.xml b/app/src/main/res/drawable/ic_photo_camera_black_24dp.xml new file mode 100644 index 000000000..c872f1670 --- /dev/null +++ b/app/src/main/res/drawable/ic_photo_camera_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_photo_filter_black_24dp.xml b/app/src/main/res/drawable/ic_photo_filter_black_24dp.xml new file mode 100644 index 000000000..c96ab1ade --- /dev/null +++ b/app/src/main/res/drawable/ic_photo_filter_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_photo_library_black_24dp.xml b/app/src/main/res/drawable/ic_photo_library_black_24dp.xml new file mode 100644 index 000000000..68d5d0e66 --- /dev/null +++ b/app/src/main/res/drawable/ic_photo_library_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_photo_size_select_actual_black_24dp.xml b/app/src/main/res/drawable/ic_photo_size_select_actual_black_24dp.xml new file mode 100644 index 000000000..d1c310417 --- /dev/null +++ b/app/src/main/res/drawable/ic_photo_size_select_actual_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_photo_size_select_large_black_24dp.xml b/app/src/main/res/drawable/ic_photo_size_select_large_black_24dp.xml new file mode 100644 index 000000000..9095333a0 --- /dev/null +++ b/app/src/main/res/drawable/ic_photo_size_select_large_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_photo_size_select_small_black_24dp.xml b/app/src/main/res/drawable/ic_photo_size_select_small_black_24dp.xml new file mode 100644 index 000000000..380e4b35f --- /dev/null +++ b/app/src/main/res/drawable/ic_photo_size_select_small_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_picture_as_pdf_black_24dp.xml b/app/src/main/res/drawable/ic_picture_as_pdf_black_24dp.xml new file mode 100644 index 000000000..1308ca32e --- /dev/null +++ b/app/src/main/res/drawable/ic_picture_as_pdf_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_picture_in_picture_alt_black_24dp.xml b/app/src/main/res/drawable/ic_picture_in_picture_alt_black_24dp.xml new file mode 100644 index 000000000..e7d980a7b --- /dev/null +++ b/app/src/main/res/drawable/ic_picture_in_picture_alt_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_picture_in_picture_black_24dp.xml b/app/src/main/res/drawable/ic_picture_in_picture_black_24dp.xml new file mode 100644 index 000000000..b61c5218b --- /dev/null +++ b/app/src/main/res/drawable/ic_picture_in_picture_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pie_chart_black_24dp.xml b/app/src/main/res/drawable/ic_pie_chart_black_24dp.xml new file mode 100644 index 000000000..ffcd8f3c0 --- /dev/null +++ b/app/src/main/res/drawable/ic_pie_chart_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pie_chart_outlined_black_24dp.xml b/app/src/main/res/drawable/ic_pie_chart_outlined_black_24dp.xml new file mode 100644 index 000000000..baf9b1085 --- /dev/null +++ b/app/src/main/res/drawable/ic_pie_chart_outlined_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pin_drop_black_24dp.xml b/app/src/main/res/drawable/ic_pin_drop_black_24dp.xml new file mode 100644 index 000000000..49a331741 --- /dev/null +++ b/app/src/main/res/drawable/ic_pin_drop_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_place_black_24dp.xml b/app/src/main/res/drawable/ic_place_black_24dp.xml new file mode 100644 index 000000000..e3291a943 --- /dev/null +++ b/app/src/main/res/drawable/ic_place_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_play_arrow_black_24dp.xml b/app/src/main/res/drawable/ic_play_arrow_black_24dp.xml new file mode 100644 index 000000000..bf9b895ac --- /dev/null +++ b/app/src/main/res/drawable/ic_play_arrow_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_play_circle_filled_black_24dp.xml b/app/src/main/res/drawable/ic_play_circle_filled_black_24dp.xml new file mode 100644 index 000000000..85ee3ba97 --- /dev/null +++ b/app/src/main/res/drawable/ic_play_circle_filled_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_play_circle_outline_black_24dp.xml b/app/src/main/res/drawable/ic_play_circle_outline_black_24dp.xml new file mode 100644 index 000000000..f7a497a60 --- /dev/null +++ b/app/src/main/res/drawable/ic_play_circle_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_play_for_work_black_24dp.xml b/app/src/main/res/drawable/ic_play_for_work_black_24dp.xml new file mode 100644 index 000000000..c05df0252 --- /dev/null +++ b/app/src/main/res/drawable/ic_play_for_work_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_playlist_add_black_24dp.xml b/app/src/main/res/drawable/ic_playlist_add_black_24dp.xml new file mode 100644 index 000000000..905d86e64 --- /dev/null +++ b/app/src/main/res/drawable/ic_playlist_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_playlist_add_check_black_24dp.xml b/app/src/main/res/drawable/ic_playlist_add_check_black_24dp.xml new file mode 100644 index 000000000..4f7a1c13f --- /dev/null +++ b/app/src/main/res/drawable/ic_playlist_add_check_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_playlist_play_black_24dp.xml b/app/src/main/res/drawable/ic_playlist_play_black_24dp.xml new file mode 100644 index 000000000..f20557cb2 --- /dev/null +++ b/app/src/main/res/drawable/ic_playlist_play_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_plus_one_black_24dp.xml b/app/src/main/res/drawable/ic_plus_one_black_24dp.xml new file mode 100644 index 000000000..3bd2f2bc6 --- /dev/null +++ b/app/src/main/res/drawable/ic_plus_one_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_poll_black_24dp.xml b/app/src/main/res/drawable/ic_poll_black_24dp.xml new file mode 100644 index 000000000..75d0dde7b --- /dev/null +++ b/app/src/main/res/drawable/ic_poll_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_polymer_black_24dp.xml b/app/src/main/res/drawable/ic_polymer_black_24dp.xml new file mode 100644 index 000000000..c2c9b5d85 --- /dev/null +++ b/app/src/main/res/drawable/ic_polymer_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pool_black_24dp.xml b/app/src/main/res/drawable/ic_pool_black_24dp.xml new file mode 100644 index 000000000..e5a4635d9 --- /dev/null +++ b/app/src/main/res/drawable/ic_pool_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_portable_wifi_off_black_24dp.xml b/app/src/main/res/drawable/ic_portable_wifi_off_black_24dp.xml new file mode 100644 index 000000000..6a3e06fd4 --- /dev/null +++ b/app/src/main/res/drawable/ic_portable_wifi_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_portrait_black_24dp.xml b/app/src/main/res/drawable/ic_portrait_black_24dp.xml new file mode 100644 index 000000000..ae8878b75 --- /dev/null +++ b/app/src/main/res/drawable/ic_portrait_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_power_black_24dp.xml b/app/src/main/res/drawable/ic_power_black_24dp.xml new file mode 100644 index 000000000..51b929f94 --- /dev/null +++ b/app/src/main/res/drawable/ic_power_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_power_input_black_24dp.xml b/app/src/main/res/drawable/ic_power_input_black_24dp.xml new file mode 100644 index 000000000..cfa62a288 --- /dev/null +++ b/app/src/main/res/drawable/ic_power_input_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_power_settings_new_black_24dp.xml b/app/src/main/res/drawable/ic_power_settings_new_black_24dp.xml new file mode 100644 index 000000000..26272ab8d --- /dev/null +++ b/app/src/main/res/drawable/ic_power_settings_new_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pregnant_woman_black_24dp.xml b/app/src/main/res/drawable/ic_pregnant_woman_black_24dp.xml new file mode 100644 index 000000000..f6e0151e0 --- /dev/null +++ b/app/src/main/res/drawable/ic_pregnant_woman_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_present_to_all_black_24dp.xml b/app/src/main/res/drawable/ic_present_to_all_black_24dp.xml new file mode 100644 index 000000000..56c63ce18 --- /dev/null +++ b/app/src/main/res/drawable/ic_present_to_all_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_print_black_24dp.xml b/app/src/main/res/drawable/ic_print_black_24dp.xml new file mode 100644 index 000000000..7acdb182d --- /dev/null +++ b/app/src/main/res/drawable/ic_print_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_priority_high_black_24dp.xml b/app/src/main/res/drawable/ic_priority_high_black_24dp.xml new file mode 100644 index 000000000..66799d862 --- /dev/null +++ b/app/src/main/res/drawable/ic_priority_high_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_public_black_24dp.xml b/app/src/main/res/drawable/ic_public_black_24dp.xml new file mode 100644 index 000000000..d976b4244 --- /dev/null +++ b/app/src/main/res/drawable/ic_public_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_publish_black_24dp.xml b/app/src/main/res/drawable/ic_publish_black_24dp.xml new file mode 100644 index 000000000..512134054 --- /dev/null +++ b/app/src/main/res/drawable/ic_publish_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_query_builder_black_24dp.xml b/app/src/main/res/drawable/ic_query_builder_black_24dp.xml new file mode 100644 index 000000000..fdcce49cb --- /dev/null +++ b/app/src/main/res/drawable/ic_query_builder_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_question_answer_black_24dp.xml b/app/src/main/res/drawable/ic_question_answer_black_24dp.xml new file mode 100644 index 000000000..26eda0900 --- /dev/null +++ b/app/src/main/res/drawable/ic_question_answer_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_queue_black_24dp.xml b/app/src/main/res/drawable/ic_queue_black_24dp.xml new file mode 100644 index 000000000..f704ffedf --- /dev/null +++ b/app/src/main/res/drawable/ic_queue_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_queue_music_black_24dp.xml b/app/src/main/res/drawable/ic_queue_music_black_24dp.xml new file mode 100644 index 000000000..848a8600c --- /dev/null +++ b/app/src/main/res/drawable/ic_queue_music_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_queue_play_next_black_24dp.xml b/app/src/main/res/drawable/ic_queue_play_next_black_24dp.xml new file mode 100644 index 000000000..dab15898b --- /dev/null +++ b/app/src/main/res/drawable/ic_queue_play_next_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_radio_black_24dp.xml b/app/src/main/res/drawable/ic_radio_black_24dp.xml new file mode 100644 index 000000000..42bc4f384 --- /dev/null +++ b/app/src/main/res/drawable/ic_radio_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_radio_button_checked_black_24dp.xml b/app/src/main/res/drawable/ic_radio_button_checked_black_24dp.xml new file mode 100644 index 000000000..a5025aea6 --- /dev/null +++ b/app/src/main/res/drawable/ic_radio_button_checked_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_radio_button_unchecked_black_24dp.xml b/app/src/main/res/drawable/ic_radio_button_unchecked_black_24dp.xml new file mode 100644 index 000000000..f61549b90 --- /dev/null +++ b/app/src/main/res/drawable/ic_radio_button_unchecked_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_rate_review_black_24dp.xml b/app/src/main/res/drawable/ic_rate_review_black_24dp.xml new file mode 100644 index 000000000..df82c525d --- /dev/null +++ b/app/src/main/res/drawable/ic_rate_review_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_receipt_black_24dp.xml b/app/src/main/res/drawable/ic_receipt_black_24dp.xml new file mode 100644 index 000000000..4714dde6d --- /dev/null +++ b/app/src/main/res/drawable/ic_receipt_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_recent_actors_black_24dp.xml b/app/src/main/res/drawable/ic_recent_actors_black_24dp.xml new file mode 100644 index 000000000..31589a141 --- /dev/null +++ b/app/src/main/res/drawable/ic_recent_actors_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_record_voice_over_black_24dp.xml b/app/src/main/res/drawable/ic_record_voice_over_black_24dp.xml new file mode 100644 index 000000000..3337021c9 --- /dev/null +++ b/app/src/main/res/drawable/ic_record_voice_over_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_redeem_black_24dp.xml b/app/src/main/res/drawable/ic_redeem_black_24dp.xml new file mode 100644 index 000000000..cbb69959b --- /dev/null +++ b/app/src/main/res/drawable/ic_redeem_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_redo_black_24dp.xml b/app/src/main/res/drawable/ic_redo_black_24dp.xml new file mode 100644 index 000000000..424e788f5 --- /dev/null +++ b/app/src/main/res/drawable/ic_redo_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_refresh_black_24dp.xml b/app/src/main/res/drawable/ic_refresh_black_24dp.xml new file mode 100644 index 000000000..8229a9a64 --- /dev/null +++ b/app/src/main/res/drawable/ic_refresh_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_remove_black_24dp.xml b/app/src/main/res/drawable/ic_remove_black_24dp.xml new file mode 100644 index 000000000..a5411774f --- /dev/null +++ b/app/src/main/res/drawable/ic_remove_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_remove_circle_black_24dp.xml b/app/src/main/res/drawable/ic_remove_circle_black_24dp.xml new file mode 100644 index 000000000..099e650ce --- /dev/null +++ b/app/src/main/res/drawable/ic_remove_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_remove_circle_outline_black_24dp.xml b/app/src/main/res/drawable/ic_remove_circle_outline_black_24dp.xml new file mode 100644 index 000000000..9af945673 --- /dev/null +++ b/app/src/main/res/drawable/ic_remove_circle_outline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_remove_from_queue_black_24dp.xml b/app/src/main/res/drawable/ic_remove_from_queue_black_24dp.xml new file mode 100644 index 000000000..4ccb896f4 --- /dev/null +++ b/app/src/main/res/drawable/ic_remove_from_queue_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_remove_red_eye_black_24dp.xml b/app/src/main/res/drawable/ic_remove_red_eye_black_24dp.xml new file mode 100644 index 000000000..e02f1d191 --- /dev/null +++ b/app/src/main/res/drawable/ic_remove_red_eye_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_remove_shopping_cart_black_24dp.xml b/app/src/main/res/drawable/ic_remove_shopping_cart_black_24dp.xml new file mode 100644 index 000000000..614229224 --- /dev/null +++ b/app/src/main/res/drawable/ic_remove_shopping_cart_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_reorder_black_24dp.xml b/app/src/main/res/drawable/ic_reorder_black_24dp.xml new file mode 100644 index 000000000..2b87cd840 --- /dev/null +++ b/app/src/main/res/drawable/ic_reorder_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_repeat_black_24dp.xml b/app/src/main/res/drawable/ic_repeat_black_24dp.xml new file mode 100644 index 000000000..e7c67d710 --- /dev/null +++ b/app/src/main/res/drawable/ic_repeat_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_repeat_one_black_24dp.xml b/app/src/main/res/drawable/ic_repeat_one_black_24dp.xml new file mode 100644 index 000000000..fc8c83ad7 --- /dev/null +++ b/app/src/main/res/drawable/ic_repeat_one_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_replay_10_black_24dp.xml b/app/src/main/res/drawable/ic_replay_10_black_24dp.xml new file mode 100644 index 000000000..14702647a --- /dev/null +++ b/app/src/main/res/drawable/ic_replay_10_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_replay_30_black_24dp.xml b/app/src/main/res/drawable/ic_replay_30_black_24dp.xml new file mode 100644 index 000000000..cccac86ae --- /dev/null +++ b/app/src/main/res/drawable/ic_replay_30_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_replay_5_black_24dp.xml b/app/src/main/res/drawable/ic_replay_5_black_24dp.xml new file mode 100644 index 000000000..4cb5bf0b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_replay_5_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_replay_black_24dp.xml b/app/src/main/res/drawable/ic_replay_black_24dp.xml new file mode 100644 index 000000000..0ff0a64d7 --- /dev/null +++ b/app/src/main/res/drawable/ic_replay_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_reply_all_black_24dp.xml b/app/src/main/res/drawable/ic_reply_all_black_24dp.xml new file mode 100644 index 000000000..d43e0b2b7 --- /dev/null +++ b/app/src/main/res/drawable/ic_reply_all_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_reply_black_24dp.xml b/app/src/main/res/drawable/ic_reply_black_24dp.xml new file mode 100644 index 000000000..46b19a0d3 --- /dev/null +++ b/app/src/main/res/drawable/ic_reply_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_report_black_24dp.xml b/app/src/main/res/drawable/ic_report_black_24dp.xml new file mode 100644 index 000000000..e20d8899c --- /dev/null +++ b/app/src/main/res/drawable/ic_report_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_report_problem_black_24dp.xml b/app/src/main/res/drawable/ic_report_problem_black_24dp.xml new file mode 100644 index 000000000..b3a9e036b --- /dev/null +++ b/app/src/main/res/drawable/ic_report_problem_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_restaurant_black_24dp.xml b/app/src/main/res/drawable/ic_restaurant_black_24dp.xml new file mode 100644 index 000000000..e14429d09 --- /dev/null +++ b/app/src/main/res/drawable/ic_restaurant_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_restaurant_menu_black_24dp.xml b/app/src/main/res/drawable/ic_restaurant_menu_black_24dp.xml new file mode 100644 index 000000000..7375ec304 --- /dev/null +++ b/app/src/main/res/drawable/ic_restaurant_menu_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_restore_black_24dp.xml b/app/src/main/res/drawable/ic_restore_black_24dp.xml new file mode 100644 index 000000000..a61de1bc9 --- /dev/null +++ b/app/src/main/res/drawable/ic_restore_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_restore_page_black_24dp.xml b/app/src/main/res/drawable/ic_restore_page_black_24dp.xml new file mode 100644 index 000000000..53bde6253 --- /dev/null +++ b/app/src/main/res/drawable/ic_restore_page_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_ring_volume_black_24dp.xml b/app/src/main/res/drawable/ic_ring_volume_black_24dp.xml new file mode 100644 index 000000000..18d9921b9 --- /dev/null +++ b/app/src/main/res/drawable/ic_ring_volume_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_room_black_24dp.xml b/app/src/main/res/drawable/ic_room_black_24dp.xml new file mode 100644 index 000000000..e3291a943 --- /dev/null +++ b/app/src/main/res/drawable/ic_room_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_room_service_black_24dp.xml b/app/src/main/res/drawable/ic_room_service_black_24dp.xml new file mode 100644 index 000000000..295bd491c --- /dev/null +++ b/app/src/main/res/drawable/ic_room_service_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_rotate_90_degrees_ccw_black_24dp.xml b/app/src/main/res/drawable/ic_rotate_90_degrees_ccw_black_24dp.xml new file mode 100644 index 000000000..9a3f09493 --- /dev/null +++ b/app/src/main/res/drawable/ic_rotate_90_degrees_ccw_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_rotate_left_black_24dp.xml b/app/src/main/res/drawable/ic_rotate_left_black_24dp.xml new file mode 100644 index 000000000..2fd476dcd --- /dev/null +++ b/app/src/main/res/drawable/ic_rotate_left_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_rotate_right_black_24dp.xml b/app/src/main/res/drawable/ic_rotate_right_black_24dp.xml new file mode 100644 index 000000000..a98657481 --- /dev/null +++ b/app/src/main/res/drawable/ic_rotate_right_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_rounded_corner_black_24dp.xml b/app/src/main/res/drawable/ic_rounded_corner_black_24dp.xml new file mode 100644 index 000000000..929f7cf4a --- /dev/null +++ b/app/src/main/res/drawable/ic_rounded_corner_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_router_black_24dp.xml b/app/src/main/res/drawable/ic_router_black_24dp.xml new file mode 100644 index 000000000..fa79931d3 --- /dev/null +++ b/app/src/main/res/drawable/ic_router_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_rowing_black_24dp.xml b/app/src/main/res/drawable/ic_rowing_black_24dp.xml new file mode 100644 index 000000000..a81e4b115 --- /dev/null +++ b/app/src/main/res/drawable/ic_rowing_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_rss_feed_black_24dp.xml b/app/src/main/res/drawable/ic_rss_feed_black_24dp.xml new file mode 100644 index 000000000..4da9b623b --- /dev/null +++ b/app/src/main/res/drawable/ic_rss_feed_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_rv_hookup_black_24dp.xml b/app/src/main/res/drawable/ic_rv_hookup_black_24dp.xml new file mode 100644 index 000000000..4c9eeac67 --- /dev/null +++ b/app/src/main/res/drawable/ic_rv_hookup_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_satellite_black_24dp.xml b/app/src/main/res/drawable/ic_satellite_black_24dp.xml new file mode 100644 index 000000000..82862f07f --- /dev/null +++ b/app/src/main/res/drawable/ic_satellite_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_save_black_24dp.xml b/app/src/main/res/drawable/ic_save_black_24dp.xml new file mode 100644 index 000000000..a561d632a --- /dev/null +++ b/app/src/main/res/drawable/ic_save_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_scanner_black_24dp.xml b/app/src/main/res/drawable/ic_scanner_black_24dp.xml new file mode 100644 index 000000000..1c5477662 --- /dev/null +++ b/app/src/main/res/drawable/ic_scanner_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_schedule_black_24dp.xml b/app/src/main/res/drawable/ic_schedule_black_24dp.xml new file mode 100644 index 000000000..fdcce49cb --- /dev/null +++ b/app/src/main/res/drawable/ic_schedule_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_school_black_24dp.xml b/app/src/main/res/drawable/ic_school_black_24dp.xml new file mode 100644 index 000000000..30d83f840 --- /dev/null +++ b/app/src/main/res/drawable/ic_school_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_screen_lock_landscape_black_24dp.xml b/app/src/main/res/drawable/ic_screen_lock_landscape_black_24dp.xml new file mode 100644 index 000000000..329c92a0d --- /dev/null +++ b/app/src/main/res/drawable/ic_screen_lock_landscape_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_screen_lock_portrait_black_24dp.xml b/app/src/main/res/drawable/ic_screen_lock_portrait_black_24dp.xml new file mode 100644 index 000000000..0769a31b4 --- /dev/null +++ b/app/src/main/res/drawable/ic_screen_lock_portrait_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_screen_lock_rotation_black_24dp.xml b/app/src/main/res/drawable/ic_screen_lock_rotation_black_24dp.xml new file mode 100644 index 000000000..f427d32e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_screen_lock_rotation_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_screen_rotation_black_24dp.xml b/app/src/main/res/drawable/ic_screen_rotation_black_24dp.xml new file mode 100644 index 000000000..230dc6855 --- /dev/null +++ b/app/src/main/res/drawable/ic_screen_rotation_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_screen_share_black_24dp.xml b/app/src/main/res/drawable/ic_screen_share_black_24dp.xml new file mode 100644 index 000000000..612f18565 --- /dev/null +++ b/app/src/main/res/drawable/ic_screen_share_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sd_card_black_24dp.xml b/app/src/main/res/drawable/ic_sd_card_black_24dp.xml new file mode 100644 index 000000000..f9ad72d48 --- /dev/null +++ b/app/src/main/res/drawable/ic_sd_card_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sd_storage_black_24dp.xml b/app/src/main/res/drawable/ic_sd_storage_black_24dp.xml new file mode 100644 index 000000000..f9ad72d48 --- /dev/null +++ b/app/src/main/res/drawable/ic_sd_storage_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_search_black_24dp.xml b/app/src/main/res/drawable/ic_search_black_24dp.xml new file mode 100644 index 000000000..affc7ba26 --- /dev/null +++ b/app/src/main/res/drawable/ic_search_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_security_black_24dp.xml b/app/src/main/res/drawable/ic_security_black_24dp.xml new file mode 100644 index 000000000..918642399 --- /dev/null +++ b/app/src/main/res/drawable/ic_security_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_select_all_black_24dp.xml b/app/src/main/res/drawable/ic_select_all_black_24dp.xml new file mode 100644 index 000000000..68702c1fe --- /dev/null +++ b/app/src/main/res/drawable/ic_select_all_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_send_black_24dp.xml b/app/src/main/res/drawable/ic_send_black_24dp.xml new file mode 100644 index 000000000..e145ca83c --- /dev/null +++ b/app/src/main/res/drawable/ic_send_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sentiment_dissatisfied_black_24dp.xml b/app/src/main/res/drawable/ic_sentiment_dissatisfied_black_24dp.xml new file mode 100644 index 000000000..a04b621d2 --- /dev/null +++ b/app/src/main/res/drawable/ic_sentiment_dissatisfied_black_24dp.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_sentiment_neutral_black_24dp.xml b/app/src/main/res/drawable/ic_sentiment_neutral_black_24dp.xml new file mode 100644 index 000000000..355c93eb8 --- /dev/null +++ b/app/src/main/res/drawable/ic_sentiment_neutral_black_24dp.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_sentiment_satisfied_black_24dp.xml b/app/src/main/res/drawable/ic_sentiment_satisfied_black_24dp.xml new file mode 100644 index 000000000..7b9624e1f --- /dev/null +++ b/app/src/main/res/drawable/ic_sentiment_satisfied_black_24dp.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_sentiment_very_dissatisfied_black_24dp.xml b/app/src/main/res/drawable/ic_sentiment_very_dissatisfied_black_24dp.xml new file mode 100644 index 000000000..ab7d04228 --- /dev/null +++ b/app/src/main/res/drawable/ic_sentiment_very_dissatisfied_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sentiment_very_satisfied_black_24dp.xml b/app/src/main/res/drawable/ic_sentiment_very_satisfied_black_24dp.xml new file mode 100644 index 000000000..3ee1f32fc --- /dev/null +++ b/app/src/main/res/drawable/ic_sentiment_very_satisfied_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_applications_black_24dp.xml b/app/src/main/res/drawable/ic_settings_applications_black_24dp.xml new file mode 100644 index 000000000..968166e5f --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_applications_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_backup_restore_black_24dp.xml b/app/src/main/res/drawable/ic_settings_backup_restore_black_24dp.xml new file mode 100644 index 000000000..aa424c0d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_backup_restore_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_black_24dp.xml b/app/src/main/res/drawable/ic_settings_black_24dp.xml new file mode 100644 index 000000000..ace746c40 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_bluetooth_black_24dp.xml b/app/src/main/res/drawable/ic_settings_bluetooth_black_24dp.xml new file mode 100644 index 000000000..da624c49d --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_bluetooth_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_brightness_black_24dp.xml b/app/src/main/res/drawable/ic_settings_brightness_black_24dp.xml new file mode 100644 index 000000000..26f971e33 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_brightness_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_cell_black_24dp.xml b/app/src/main/res/drawable/ic_settings_cell_black_24dp.xml new file mode 100644 index 000000000..76c94be59 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_cell_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_ethernet_black_24dp.xml b/app/src/main/res/drawable/ic_settings_ethernet_black_24dp.xml new file mode 100644 index 000000000..d60cda4fa --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_ethernet_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_input_antenna_black_24dp.xml b/app/src/main/res/drawable/ic_settings_input_antenna_black_24dp.xml new file mode 100644 index 000000000..0da55e23b --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_input_antenna_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_input_component_black_24dp.xml b/app/src/main/res/drawable/ic_settings_input_component_black_24dp.xml new file mode 100644 index 000000000..389fe7e14 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_input_component_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_input_composite_black_24dp.xml b/app/src/main/res/drawable/ic_settings_input_composite_black_24dp.xml new file mode 100644 index 000000000..389fe7e14 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_input_composite_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_input_hdmi_black_24dp.xml b/app/src/main/res/drawable/ic_settings_input_hdmi_black_24dp.xml new file mode 100644 index 000000000..c565522da --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_input_hdmi_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_input_svideo_black_24dp.xml b/app/src/main/res/drawable/ic_settings_input_svideo_black_24dp.xml new file mode 100644 index 000000000..ca1872942 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_input_svideo_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_overscan_black_24dp.xml b/app/src/main/res/drawable/ic_settings_overscan_black_24dp.xml new file mode 100644 index 000000000..b37284ae0 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_overscan_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_phone_black_24dp.xml b/app/src/main/res/drawable/ic_settings_phone_black_24dp.xml new file mode 100644 index 000000000..e15d7ff9d --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_phone_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_power_black_24dp.xml b/app/src/main/res/drawable/ic_settings_power_black_24dp.xml new file mode 100644 index 000000000..931de8686 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_power_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_remote_black_24dp.xml b/app/src/main/res/drawable/ic_settings_remote_black_24dp.xml new file mode 100644 index 000000000..73dd42c74 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_remote_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_system_daydream_black_24dp.xml b/app/src/main/res/drawable/ic_settings_system_daydream_black_24dp.xml new file mode 100644 index 000000000..c6982761b --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_system_daydream_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_voice_black_24dp.xml b/app/src/main/res/drawable/ic_settings_voice_black_24dp.xml new file mode 100644 index 000000000..08c1a40c3 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_voice_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_share_black_24dp.xml b/app/src/main/res/drawable/ic_share_black_24dp.xml new file mode 100644 index 000000000..e3fe874d6 --- /dev/null +++ b/app/src/main/res/drawable/ic_share_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_shop_black_24dp.xml b/app/src/main/res/drawable/ic_shop_black_24dp.xml new file mode 100644 index 000000000..50e643077 --- /dev/null +++ b/app/src/main/res/drawable/ic_shop_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_shop_two_black_24dp.xml b/app/src/main/res/drawable/ic_shop_two_black_24dp.xml new file mode 100644 index 000000000..4f27a6db2 --- /dev/null +++ b/app/src/main/res/drawable/ic_shop_two_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_shopping_basket_black_24dp.xml b/app/src/main/res/drawable/ic_shopping_basket_black_24dp.xml new file mode 100644 index 000000000..0f128b2af --- /dev/null +++ b/app/src/main/res/drawable/ic_shopping_basket_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_shopping_cart_black_24dp.xml b/app/src/main/res/drawable/ic_shopping_cart_black_24dp.xml new file mode 100644 index 000000000..11887e38f --- /dev/null +++ b/app/src/main/res/drawable/ic_shopping_cart_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_short_text_black_24dp.xml b/app/src/main/res/drawable/ic_short_text_black_24dp.xml new file mode 100644 index 000000000..11c24c5a3 --- /dev/null +++ b/app/src/main/res/drawable/ic_short_text_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_show_chart_black_24dp.xml b/app/src/main/res/drawable/ic_show_chart_black_24dp.xml new file mode 100644 index 000000000..550bdf1e6 --- /dev/null +++ b/app/src/main/res/drawable/ic_show_chart_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_shuffle_black_24dp.xml b/app/src/main/res/drawable/ic_shuffle_black_24dp.xml new file mode 100644 index 000000000..ec80046cb --- /dev/null +++ b/app/src/main/res/drawable/ic_shuffle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_0_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_0_bar_black_24dp.xml new file mode 100644 index 000000000..61f01c4c9 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_0_bar_black_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_1_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_1_bar_black_24dp.xml new file mode 100644 index 000000000..b54b810e3 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_1_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_2_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_2_bar_black_24dp.xml new file mode 100644 index 000000000..dc509708e --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_2_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_3_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_3_bar_black_24dp.xml new file mode 100644 index 000000000..de5804b49 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_3_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_4_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_4_bar_black_24dp.xml new file mode 100644 index 000000000..fa5880f1d --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_4_bar_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_0_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_0_bar_black_24dp.xml new file mode 100644 index 000000000..aaf772e49 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_0_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_1_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_1_bar_black_24dp.xml new file mode 100644 index 000000000..ef569e3e3 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_1_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_2_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_2_bar_black_24dp.xml new file mode 100644 index 000000000..43d0b014f --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_2_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_3_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_3_bar_black_24dp.xml new file mode 100644 index 000000000..33e31e5db --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_3_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_4_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_4_bar_black_24dp.xml new file mode 100644 index 000000000..3966b97f8 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_connected_no_internet_4_bar_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_no_sim_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_no_sim_black_24dp.xml new file mode 100644 index 000000000..1f82b548b --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_no_sim_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_null_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_null_black_24dp.xml new file mode 100644 index 000000000..047dec422 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_null_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_cellular_off_black_24dp.xml b/app/src/main/res/drawable/ic_signal_cellular_off_black_24dp.xml new file mode 100644 index 000000000..57d9df1d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_cellular_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_0_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_0_bar_black_24dp.xml new file mode 100644 index 000000000..5807bc6ee --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_0_bar_black_24dp.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_1_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_1_bar_black_24dp.xml new file mode 100644 index 000000000..f3a728c93 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_1_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_1_bar_lock_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_1_bar_lock_black_24dp.xml new file mode 100644 index 000000000..22ebc37b7 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_1_bar_lock_black_24dp.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_2_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_2_bar_black_24dp.xml new file mode 100644 index 000000000..33d8e47d3 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_2_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_2_bar_lock_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_2_bar_lock_black_24dp.xml new file mode 100644 index 000000000..460a290df --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_2_bar_lock_black_24dp.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_3_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_3_bar_black_24dp.xml new file mode 100644 index 000000000..caac288fd --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_3_bar_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_3_bar_lock_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_3_bar_lock_black_24dp.xml new file mode 100644 index 000000000..fa4cf9c99 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_3_bar_lock_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_4_bar_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_4_bar_black_24dp.xml new file mode 100644 index 000000000..d0ccd71e0 --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_4_bar_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_4_bar_lock_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_4_bar_lock_black_24dp.xml new file mode 100644 index 000000000..320914d7c --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_4_bar_lock_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_signal_wifi_off_black_24dp.xml b/app/src/main/res/drawable/ic_signal_wifi_off_black_24dp.xml new file mode 100644 index 000000000..8339d792b --- /dev/null +++ b/app/src/main/res/drawable/ic_signal_wifi_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sim_card_alert_black_24dp.xml b/app/src/main/res/drawable/ic_sim_card_alert_black_24dp.xml new file mode 100644 index 000000000..39654879e --- /dev/null +++ b/app/src/main/res/drawable/ic_sim_card_alert_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sim_card_black_24dp.xml b/app/src/main/res/drawable/ic_sim_card_black_24dp.xml new file mode 100644 index 000000000..6e659a8ad --- /dev/null +++ b/app/src/main/res/drawable/ic_sim_card_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_skip_next_black_24dp.xml b/app/src/main/res/drawable/ic_skip_next_black_24dp.xml new file mode 100644 index 000000000..1253ff063 --- /dev/null +++ b/app/src/main/res/drawable/ic_skip_next_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_skip_previous_black_24dp.xml b/app/src/main/res/drawable/ic_skip_previous_black_24dp.xml new file mode 100644 index 000000000..cd05efeb6 --- /dev/null +++ b/app/src/main/res/drawable/ic_skip_previous_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_slideshow_black_24dp.xml b/app/src/main/res/drawable/ic_slideshow_black_24dp.xml new file mode 100644 index 000000000..de38db853 --- /dev/null +++ b/app/src/main/res/drawable/ic_slideshow_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_slow_motion_video_black_24dp.xml b/app/src/main/res/drawable/ic_slow_motion_video_black_24dp.xml new file mode 100644 index 000000000..fe1d2d9cf --- /dev/null +++ b/app/src/main/res/drawable/ic_slow_motion_video_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_smartphone_black_24dp.xml b/app/src/main/res/drawable/ic_smartphone_black_24dp.xml new file mode 100644 index 000000000..0f291f1cb --- /dev/null +++ b/app/src/main/res/drawable/ic_smartphone_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_smoke_free_black_24dp.xml b/app/src/main/res/drawable/ic_smoke_free_black_24dp.xml new file mode 100644 index 000000000..f764d2e70 --- /dev/null +++ b/app/src/main/res/drawable/ic_smoke_free_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_smoking_rooms_black_24dp.xml b/app/src/main/res/drawable/ic_smoking_rooms_black_24dp.xml new file mode 100644 index 000000000..9a32e8872 --- /dev/null +++ b/app/src/main/res/drawable/ic_smoking_rooms_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sms_black_24dp.xml b/app/src/main/res/drawable/ic_sms_black_24dp.xml new file mode 100644 index 000000000..8b8ead2f6 --- /dev/null +++ b/app/src/main/res/drawable/ic_sms_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sms_failed_black_24dp.xml b/app/src/main/res/drawable/ic_sms_failed_black_24dp.xml new file mode 100644 index 000000000..29f9baabd --- /dev/null +++ b/app/src/main/res/drawable/ic_sms_failed_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_snooze_black_24dp.xml b/app/src/main/res/drawable/ic_snooze_black_24dp.xml new file mode 100644 index 000000000..6d88f7dbc --- /dev/null +++ b/app/src/main/res/drawable/ic_snooze_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sort_black_24dp.xml b/app/src/main/res/drawable/ic_sort_black_24dp.xml new file mode 100644 index 000000000..fd4c56f0e --- /dev/null +++ b/app/src/main/res/drawable/ic_sort_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sort_by_alpha_black_24dp.xml b/app/src/main/res/drawable/ic_sort_by_alpha_black_24dp.xml new file mode 100644 index 000000000..97bf945e8 --- /dev/null +++ b/app/src/main/res/drawable/ic_sort_by_alpha_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_spa_black_24dp.xml b/app/src/main/res/drawable/ic_spa_black_24dp.xml new file mode 100644 index 000000000..cff1f2d8b --- /dev/null +++ b/app/src/main/res/drawable/ic_spa_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_space_bar_black_24dp.xml b/app/src/main/res/drawable/ic_space_bar_black_24dp.xml new file mode 100644 index 000000000..2ca50dbb5 --- /dev/null +++ b/app/src/main/res/drawable/ic_space_bar_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_speaker_black_24dp.xml b/app/src/main/res/drawable/ic_speaker_black_24dp.xml new file mode 100644 index 000000000..cc84a59a7 --- /dev/null +++ b/app/src/main/res/drawable/ic_speaker_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_speaker_group_black_24dp.xml b/app/src/main/res/drawable/ic_speaker_group_black_24dp.xml new file mode 100644 index 000000000..85236e7c6 --- /dev/null +++ b/app/src/main/res/drawable/ic_speaker_group_black_24dp.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_speaker_notes_black_24dp.xml b/app/src/main/res/drawable/ic_speaker_notes_black_24dp.xml new file mode 100644 index 000000000..c95ec5ab0 --- /dev/null +++ b/app/src/main/res/drawable/ic_speaker_notes_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_speaker_notes_off_black_24dp.xml b/app/src/main/res/drawable/ic_speaker_notes_off_black_24dp.xml new file mode 100644 index 000000000..11a404a20 --- /dev/null +++ b/app/src/main/res/drawable/ic_speaker_notes_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_speaker_phone_black_24dp.xml b/app/src/main/res/drawable/ic_speaker_phone_black_24dp.xml new file mode 100644 index 000000000..5e9c5809e --- /dev/null +++ b/app/src/main/res/drawable/ic_speaker_phone_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_spellcheck_black_24dp.xml b/app/src/main/res/drawable/ic_spellcheck_black_24dp.xml new file mode 100644 index 000000000..f4a1b5096 --- /dev/null +++ b/app/src/main/res/drawable/ic_spellcheck_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_star_black_24dp.xml b/app/src/main/res/drawable/ic_star_black_24dp.xml new file mode 100644 index 000000000..a87ca098d --- /dev/null +++ b/app/src/main/res/drawable/ic_star_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_star_border_black_24dp.xml b/app/src/main/res/drawable/ic_star_border_black_24dp.xml new file mode 100644 index 000000000..b36536b99 --- /dev/null +++ b/app/src/main/res/drawable/ic_star_border_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_star_half_black_24dp.xml b/app/src/main/res/drawable/ic_star_half_black_24dp.xml new file mode 100644 index 000000000..8274dc054 --- /dev/null +++ b/app/src/main/res/drawable/ic_star_half_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stars_black_24dp.xml b/app/src/main/res/drawable/ic_stars_black_24dp.xml new file mode 100644 index 000000000..61c5d7ace --- /dev/null +++ b/app/src/main/res/drawable/ic_stars_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stay_current_landscape_black_24dp.xml b/app/src/main/res/drawable/ic_stay_current_landscape_black_24dp.xml new file mode 100644 index 000000000..931407919 --- /dev/null +++ b/app/src/main/res/drawable/ic_stay_current_landscape_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stay_current_portrait_black_24dp.xml b/app/src/main/res/drawable/ic_stay_current_portrait_black_24dp.xml new file mode 100644 index 000000000..50c70b3e5 --- /dev/null +++ b/app/src/main/res/drawable/ic_stay_current_portrait_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stay_primary_landscape_black_24dp.xml b/app/src/main/res/drawable/ic_stay_primary_landscape_black_24dp.xml new file mode 100644 index 000000000..931407919 --- /dev/null +++ b/app/src/main/res/drawable/ic_stay_primary_landscape_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stay_primary_portrait_black_24dp.xml b/app/src/main/res/drawable/ic_stay_primary_portrait_black_24dp.xml new file mode 100644 index 000000000..50c70b3e5 --- /dev/null +++ b/app/src/main/res/drawable/ic_stay_primary_portrait_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stop_black_24dp.xml b/app/src/main/res/drawable/ic_stop_black_24dp.xml new file mode 100644 index 000000000..c428d728d --- /dev/null +++ b/app/src/main/res/drawable/ic_stop_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stop_screen_share_black_24dp.xml b/app/src/main/res/drawable/ic_stop_screen_share_black_24dp.xml new file mode 100644 index 000000000..353164041 --- /dev/null +++ b/app/src/main/res/drawable/ic_stop_screen_share_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_storage_black_24dp.xml b/app/src/main/res/drawable/ic_storage_black_24dp.xml new file mode 100644 index 000000000..53c595cd7 --- /dev/null +++ b/app/src/main/res/drawable/ic_storage_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_store_black_24dp.xml b/app/src/main/res/drawable/ic_store_black_24dp.xml new file mode 100644 index 000000000..806e675b0 --- /dev/null +++ b/app/src/main/res/drawable/ic_store_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_store_mall_directory_black_24dp.xml b/app/src/main/res/drawable/ic_store_mall_directory_black_24dp.xml new file mode 100644 index 000000000..806e675b0 --- /dev/null +++ b/app/src/main/res/drawable/ic_store_mall_directory_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_straighten_black_24dp.xml b/app/src/main/res/drawable/ic_straighten_black_24dp.xml new file mode 100644 index 000000000..dfcddfb2d --- /dev/null +++ b/app/src/main/res/drawable/ic_straighten_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_streetview_black_24dp.xml b/app/src/main/res/drawable/ic_streetview_black_24dp.xml new file mode 100644 index 000000000..dace89ab7 --- /dev/null +++ b/app/src/main/res/drawable/ic_streetview_black_24dp.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_strikethrough_s_black_24dp.xml b/app/src/main/res/drawable/ic_strikethrough_s_black_24dp.xml new file mode 100644 index 000000000..c3dd1d927 --- /dev/null +++ b/app/src/main/res/drawable/ic_strikethrough_s_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_style_black_24dp.xml b/app/src/main/res/drawable/ic_style_black_24dp.xml new file mode 100644 index 000000000..ab2c20afa --- /dev/null +++ b/app/src/main/res/drawable/ic_style_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_subdirectory_arrow_left_black_24dp.xml b/app/src/main/res/drawable/ic_subdirectory_arrow_left_black_24dp.xml new file mode 100644 index 000000000..c3b6c6d4e --- /dev/null +++ b/app/src/main/res/drawable/ic_subdirectory_arrow_left_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_subdirectory_arrow_right_black_24dp.xml b/app/src/main/res/drawable/ic_subdirectory_arrow_right_black_24dp.xml new file mode 100644 index 000000000..65acc6989 --- /dev/null +++ b/app/src/main/res/drawable/ic_subdirectory_arrow_right_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_subject_black_24dp.xml b/app/src/main/res/drawable/ic_subject_black_24dp.xml new file mode 100644 index 000000000..0fcd6f4a7 --- /dev/null +++ b/app/src/main/res/drawable/ic_subject_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_subscriptions_black_24dp.xml b/app/src/main/res/drawable/ic_subscriptions_black_24dp.xml new file mode 100644 index 000000000..6f0ed4551 --- /dev/null +++ b/app/src/main/res/drawable/ic_subscriptions_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_subtitles_black_24dp.xml b/app/src/main/res/drawable/ic_subtitles_black_24dp.xml new file mode 100644 index 000000000..4a6c02822 --- /dev/null +++ b/app/src/main/res/drawable/ic_subtitles_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_subway_black_24dp.xml b/app/src/main/res/drawable/ic_subway_black_24dp.xml new file mode 100644 index 000000000..6baec2689 --- /dev/null +++ b/app/src/main/res/drawable/ic_subway_black_24dp.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_supervisor_account_black_24dp.xml b/app/src/main/res/drawable/ic_supervisor_account_black_24dp.xml new file mode 100644 index 000000000..8aa9c18a7 --- /dev/null +++ b/app/src/main/res/drawable/ic_supervisor_account_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_surround_sound_black_24dp.xml b/app/src/main/res/drawable/ic_surround_sound_black_24dp.xml new file mode 100644 index 000000000..6c155d3f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_surround_sound_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_swap_calls_black_24dp.xml b/app/src/main/res/drawable/ic_swap_calls_black_24dp.xml new file mode 100644 index 000000000..1ae514a4c --- /dev/null +++ b/app/src/main/res/drawable/ic_swap_calls_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_swap_horiz_black_24dp.xml b/app/src/main/res/drawable/ic_swap_horiz_black_24dp.xml new file mode 100644 index 000000000..d571dc318 --- /dev/null +++ b/app/src/main/res/drawable/ic_swap_horiz_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_swap_vert_black_24dp.xml b/app/src/main/res/drawable/ic_swap_vert_black_24dp.xml new file mode 100644 index 000000000..1c9a30b75 --- /dev/null +++ b/app/src/main/res/drawable/ic_swap_vert_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_swap_vertical_circle_black_24dp.xml b/app/src/main/res/drawable/ic_swap_vertical_circle_black_24dp.xml new file mode 100644 index 000000000..81a9bb797 --- /dev/null +++ b/app/src/main/res/drawable/ic_swap_vertical_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_switch_camera_black_24dp.xml b/app/src/main/res/drawable/ic_switch_camera_black_24dp.xml new file mode 100644 index 000000000..d49ce20ee --- /dev/null +++ b/app/src/main/res/drawable/ic_switch_camera_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_switch_video_black_24dp.xml b/app/src/main/res/drawable/ic_switch_video_black_24dp.xml new file mode 100644 index 000000000..e0d3730bb --- /dev/null +++ b/app/src/main/res/drawable/ic_switch_video_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sync_black_24dp.xml b/app/src/main/res/drawable/ic_sync_black_24dp.xml new file mode 100644 index 000000000..ce8796cb7 --- /dev/null +++ b/app/src/main/res/drawable/ic_sync_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sync_disabled_black_24dp.xml b/app/src/main/res/drawable/ic_sync_disabled_black_24dp.xml new file mode 100644 index 000000000..a2a1db39d --- /dev/null +++ b/app/src/main/res/drawable/ic_sync_disabled_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sync_problem_black_24dp.xml b/app/src/main/res/drawable/ic_sync_problem_black_24dp.xml new file mode 100644 index 000000000..e361fb9b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_sync_problem_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_system_update_alt_black_24dp.xml b/app/src/main/res/drawable/ic_system_update_alt_black_24dp.xml new file mode 100644 index 000000000..25b07b5b4 --- /dev/null +++ b/app/src/main/res/drawable/ic_system_update_alt_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_system_update_black_24dp.xml b/app/src/main/res/drawable/ic_system_update_black_24dp.xml new file mode 100644 index 000000000..94605e06d --- /dev/null +++ b/app/src/main/res/drawable/ic_system_update_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tab_black_24dp.xml b/app/src/main/res/drawable/ic_tab_black_24dp.xml new file mode 100644 index 000000000..2b7d5e91b --- /dev/null +++ b/app/src/main/res/drawable/ic_tab_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tab_unselected_black_24dp.xml b/app/src/main/res/drawable/ic_tab_unselected_black_24dp.xml new file mode 100644 index 000000000..4d4ad637a --- /dev/null +++ b/app/src/main/res/drawable/ic_tab_unselected_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tablet_android_black_24dp.xml b/app/src/main/res/drawable/ic_tablet_android_black_24dp.xml new file mode 100644 index 000000000..d81be40d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_tablet_android_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tablet_black_24dp.xml b/app/src/main/res/drawable/ic_tablet_black_24dp.xml new file mode 100644 index 000000000..901ead299 --- /dev/null +++ b/app/src/main/res/drawable/ic_tablet_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tablet_mac_black_24dp.xml b/app/src/main/res/drawable/ic_tablet_mac_black_24dp.xml new file mode 100644 index 000000000..394d05fde --- /dev/null +++ b/app/src/main/res/drawable/ic_tablet_mac_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tag_faces_black_24dp.xml b/app/src/main/res/drawable/ic_tag_faces_black_24dp.xml new file mode 100644 index 000000000..43d5552cd --- /dev/null +++ b/app/src/main/res/drawable/ic_tag_faces_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tap_and_play_black_24dp.xml b/app/src/main/res/drawable/ic_tap_and_play_black_24dp.xml new file mode 100644 index 000000000..267ab9e9a --- /dev/null +++ b/app/src/main/res/drawable/ic_tap_and_play_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_terrain_black_24dp.xml b/app/src/main/res/drawable/ic_terrain_black_24dp.xml new file mode 100644 index 000000000..0350ef536 --- /dev/null +++ b/app/src/main/res/drawable/ic_terrain_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_text_fields_black_24dp.xml b/app/src/main/res/drawable/ic_text_fields_black_24dp.xml new file mode 100644 index 000000000..dd81ddfd3 --- /dev/null +++ b/app/src/main/res/drawable/ic_text_fields_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_text_format_black_24dp.xml b/app/src/main/res/drawable/ic_text_format_black_24dp.xml new file mode 100644 index 000000000..147d71c4f --- /dev/null +++ b/app/src/main/res/drawable/ic_text_format_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_textsms_black_24dp.xml b/app/src/main/res/drawable/ic_textsms_black_24dp.xml new file mode 100644 index 000000000..8b8ead2f6 --- /dev/null +++ b/app/src/main/res/drawable/ic_textsms_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_texture_black_24dp.xml b/app/src/main/res/drawable/ic_texture_black_24dp.xml new file mode 100644 index 000000000..4adbbba5a --- /dev/null +++ b/app/src/main/res/drawable/ic_texture_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_theaters_black_24dp.xml b/app/src/main/res/drawable/ic_theaters_black_24dp.xml new file mode 100644 index 000000000..56665e6e4 --- /dev/null +++ b/app/src/main/res/drawable/ic_theaters_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_thumb_down_black_24dp.xml b/app/src/main/res/drawable/ic_thumb_down_black_24dp.xml new file mode 100644 index 000000000..26ba95c85 --- /dev/null +++ b/app/src/main/res/drawable/ic_thumb_down_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_thumb_up_black_24dp.xml b/app/src/main/res/drawable/ic_thumb_up_black_24dp.xml new file mode 100644 index 000000000..34fb51ab3 --- /dev/null +++ b/app/src/main/res/drawable/ic_thumb_up_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_thumbs_up_down_black_24dp.xml b/app/src/main/res/drawable/ic_thumbs_up_down_black_24dp.xml new file mode 100644 index 000000000..4679d8b03 --- /dev/null +++ b/app/src/main/res/drawable/ic_thumbs_up_down_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_time_to_leave_black_24dp.xml b/app/src/main/res/drawable/ic_time_to_leave_black_24dp.xml new file mode 100644 index 000000000..7df55f0f6 --- /dev/null +++ b/app/src/main/res/drawable/ic_time_to_leave_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_timelapse_black_24dp.xml b/app/src/main/res/drawable/ic_timelapse_black_24dp.xml new file mode 100644 index 000000000..6e1ad6926 --- /dev/null +++ b/app/src/main/res/drawable/ic_timelapse_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_timeline_black_24dp.xml b/app/src/main/res/drawable/ic_timeline_black_24dp.xml new file mode 100644 index 000000000..29ea1c529 --- /dev/null +++ b/app/src/main/res/drawable/ic_timeline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_timer_10_black_24dp.xml b/app/src/main/res/drawable/ic_timer_10_black_24dp.xml new file mode 100644 index 000000000..1e1384df2 --- /dev/null +++ b/app/src/main/res/drawable/ic_timer_10_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_timer_3_black_24dp.xml b/app/src/main/res/drawable/ic_timer_3_black_24dp.xml new file mode 100644 index 000000000..d72bd6c8d --- /dev/null +++ b/app/src/main/res/drawable/ic_timer_3_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_timer_black_24dp.xml b/app/src/main/res/drawable/ic_timer_black_24dp.xml new file mode 100644 index 000000000..f41be8005 --- /dev/null +++ b/app/src/main/res/drawable/ic_timer_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_timer_off_black_24dp.xml b/app/src/main/res/drawable/ic_timer_off_black_24dp.xml new file mode 100644 index 000000000..d9cfc9450 --- /dev/null +++ b/app/src/main/res/drawable/ic_timer_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_title_black_24dp.xml b/app/src/main/res/drawable/ic_title_black_24dp.xml new file mode 100644 index 000000000..fc5ddab28 --- /dev/null +++ b/app/src/main/res/drawable/ic_title_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_toc_black_24dp.xml b/app/src/main/res/drawable/ic_toc_black_24dp.xml new file mode 100644 index 000000000..f3194970c --- /dev/null +++ b/app/src/main/res/drawable/ic_toc_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_today_black_24dp.xml b/app/src/main/res/drawable/ic_today_black_24dp.xml new file mode 100644 index 000000000..77fd98c78 --- /dev/null +++ b/app/src/main/res/drawable/ic_today_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_toll_black_24dp.xml b/app/src/main/res/drawable/ic_toll_black_24dp.xml new file mode 100644 index 000000000..d406ad1d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_toll_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tonality_black_24dp.xml b/app/src/main/res/drawable/ic_tonality_black_24dp.xml new file mode 100644 index 000000000..870da4784 --- /dev/null +++ b/app/src/main/res/drawable/ic_tonality_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_touch_app_black_24dp.xml b/app/src/main/res/drawable/ic_touch_app_black_24dp.xml new file mode 100644 index 000000000..dda5c85cc --- /dev/null +++ b/app/src/main/res/drawable/ic_touch_app_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_toys_black_24dp.xml b/app/src/main/res/drawable/ic_toys_black_24dp.xml new file mode 100644 index 000000000..d56ddfcf2 --- /dev/null +++ b/app/src/main/res/drawable/ic_toys_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_track_changes_black_24dp.xml b/app/src/main/res/drawable/ic_track_changes_black_24dp.xml new file mode 100644 index 000000000..a2c58e313 --- /dev/null +++ b/app/src/main/res/drawable/ic_track_changes_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_traffic_black_24dp.xml b/app/src/main/res/drawable/ic_traffic_black_24dp.xml new file mode 100644 index 000000000..db5f0688c --- /dev/null +++ b/app/src/main/res/drawable/ic_traffic_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_train_black_24dp.xml b/app/src/main/res/drawable/ic_train_black_24dp.xml new file mode 100644 index 000000000..d5183ac1c --- /dev/null +++ b/app/src/main/res/drawable/ic_train_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tram_black_24dp.xml b/app/src/main/res/drawable/ic_tram_black_24dp.xml new file mode 100644 index 000000000..ecef58960 --- /dev/null +++ b/app/src/main/res/drawable/ic_tram_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_transfer_within_a_station_black_24dp.xml b/app/src/main/res/drawable/ic_transfer_within_a_station_black_24dp.xml new file mode 100644 index 000000000..0ecbf6838 --- /dev/null +++ b/app/src/main/res/drawable/ic_transfer_within_a_station_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_transform_black_24dp.xml b/app/src/main/res/drawable/ic_transform_black_24dp.xml new file mode 100644 index 000000000..782817ae4 --- /dev/null +++ b/app/src/main/res/drawable/ic_transform_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_translate_black_24dp.xml b/app/src/main/res/drawable/ic_translate_black_24dp.xml new file mode 100644 index 000000000..108415117 --- /dev/null +++ b/app/src/main/res/drawable/ic_translate_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_trending_down_black_24dp.xml b/app/src/main/res/drawable/ic_trending_down_black_24dp.xml new file mode 100644 index 000000000..121978a0e --- /dev/null +++ b/app/src/main/res/drawable/ic_trending_down_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_trending_flat_black_24dp.xml b/app/src/main/res/drawable/ic_trending_flat_black_24dp.xml new file mode 100644 index 000000000..087199682 --- /dev/null +++ b/app/src/main/res/drawable/ic_trending_flat_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_trending_up_black_24dp.xml b/app/src/main/res/drawable/ic_trending_up_black_24dp.xml new file mode 100644 index 000000000..4c9da94b9 --- /dev/null +++ b/app/src/main/res/drawable/ic_trending_up_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tune_black_24dp.xml b/app/src/main/res/drawable/ic_tune_black_24dp.xml new file mode 100644 index 000000000..a15149da2 --- /dev/null +++ b/app/src/main/res/drawable/ic_tune_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_turned_in_black_24dp.xml b/app/src/main/res/drawable/ic_turned_in_black_24dp.xml new file mode 100644 index 000000000..6a6a1b39d --- /dev/null +++ b/app/src/main/res/drawable/ic_turned_in_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_turned_in_not_black_24dp.xml b/app/src/main/res/drawable/ic_turned_in_not_black_24dp.xml new file mode 100644 index 000000000..6ab9a0c6c --- /dev/null +++ b/app/src/main/res/drawable/ic_turned_in_not_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_tv_black_24dp.xml b/app/src/main/res/drawable/ic_tv_black_24dp.xml new file mode 100644 index 000000000..36269ad06 --- /dev/null +++ b/app/src/main/res/drawable/ic_tv_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_unarchive_black_24dp.xml b/app/src/main/res/drawable/ic_unarchive_black_24dp.xml new file mode 100644 index 000000000..9dd011610 --- /dev/null +++ b/app/src/main/res/drawable/ic_unarchive_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_undo_black_24dp.xml b/app/src/main/res/drawable/ic_undo_black_24dp.xml new file mode 100644 index 000000000..5558e37d7 --- /dev/null +++ b/app/src/main/res/drawable/ic_undo_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_unfold_less_black_24dp.xml b/app/src/main/res/drawable/ic_unfold_less_black_24dp.xml new file mode 100644 index 000000000..7282a9755 --- /dev/null +++ b/app/src/main/res/drawable/ic_unfold_less_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_unfold_more_black_24dp.xml b/app/src/main/res/drawable/ic_unfold_more_black_24dp.xml new file mode 100644 index 000000000..e9ba75409 --- /dev/null +++ b/app/src/main/res/drawable/ic_unfold_more_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_update_black_24dp.xml b/app/src/main/res/drawable/ic_update_black_24dp.xml new file mode 100644 index 000000000..a1a7cbdfd --- /dev/null +++ b/app/src/main/res/drawable/ic_update_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_usb_black_24dp.xml b/app/src/main/res/drawable/ic_usb_black_24dp.xml new file mode 100644 index 000000000..2e7e0dc81 --- /dev/null +++ b/app/src/main/res/drawable/ic_usb_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_verified_user_black_24dp.xml b/app/src/main/res/drawable/ic_verified_user_black_24dp.xml new file mode 100644 index 000000000..e0615e96c --- /dev/null +++ b/app/src/main/res/drawable/ic_verified_user_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_vertical_align_bottom_black_24dp.xml b/app/src/main/res/drawable/ic_vertical_align_bottom_black_24dp.xml new file mode 100644 index 000000000..78c391924 --- /dev/null +++ b/app/src/main/res/drawable/ic_vertical_align_bottom_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_vertical_align_center_black_24dp.xml b/app/src/main/res/drawable/ic_vertical_align_center_black_24dp.xml new file mode 100644 index 000000000..f8d0ee3da --- /dev/null +++ b/app/src/main/res/drawable/ic_vertical_align_center_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_vertical_align_top_black_24dp.xml b/app/src/main/res/drawable/ic_vertical_align_top_black_24dp.xml new file mode 100644 index 000000000..1312b6c98 --- /dev/null +++ b/app/src/main/res/drawable/ic_vertical_align_top_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_vibration_black_24dp.xml b/app/src/main/res/drawable/ic_vibration_black_24dp.xml new file mode 100644 index 000000000..669d5e30f --- /dev/null +++ b/app/src/main/res/drawable/ic_vibration_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_video_call_black_24dp.xml b/app/src/main/res/drawable/ic_video_call_black_24dp.xml new file mode 100644 index 000000000..d242ad8bb --- /dev/null +++ b/app/src/main/res/drawable/ic_video_call_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_video_label_black_24dp.xml b/app/src/main/res/drawable/ic_video_label_black_24dp.xml new file mode 100644 index 000000000..a1bbc57fa --- /dev/null +++ b/app/src/main/res/drawable/ic_video_label_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_video_library_black_24dp.xml b/app/src/main/res/drawable/ic_video_library_black_24dp.xml new file mode 100644 index 000000000..f808aee58 --- /dev/null +++ b/app/src/main/res/drawable/ic_video_library_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_videocam_black_24dp.xml b/app/src/main/res/drawable/ic_videocam_black_24dp.xml new file mode 100644 index 000000000..e23eac818 --- /dev/null +++ b/app/src/main/res/drawable/ic_videocam_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_videocam_off_black_24dp.xml b/app/src/main/res/drawable/ic_videocam_off_black_24dp.xml new file mode 100644 index 000000000..b7d0b1bb8 --- /dev/null +++ b/app/src/main/res/drawable/ic_videocam_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_videogame_asset_black_24dp.xml b/app/src/main/res/drawable/ic_videogame_asset_black_24dp.xml new file mode 100644 index 000000000..52658f650 --- /dev/null +++ b/app/src/main/res/drawable/ic_videogame_asset_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_agenda_black_24dp.xml b/app/src/main/res/drawable/ic_view_agenda_black_24dp.xml new file mode 100644 index 000000000..3528f04fa --- /dev/null +++ b/app/src/main/res/drawable/ic_view_agenda_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_array_black_24dp.xml b/app/src/main/res/drawable/ic_view_array_black_24dp.xml new file mode 100644 index 000000000..65f37a4cd --- /dev/null +++ b/app/src/main/res/drawable/ic_view_array_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_carousel_black_24dp.xml b/app/src/main/res/drawable/ic_view_carousel_black_24dp.xml new file mode 100644 index 000000000..d7067815f --- /dev/null +++ b/app/src/main/res/drawable/ic_view_carousel_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_column_black_24dp.xml b/app/src/main/res/drawable/ic_view_column_black_24dp.xml new file mode 100644 index 000000000..06694b8e8 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_column_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_comfy_black_24dp.xml b/app/src/main/res/drawable/ic_view_comfy_black_24dp.xml new file mode 100644 index 000000000..b9d4c744f --- /dev/null +++ b/app/src/main/res/drawable/ic_view_comfy_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_compact_black_24dp.xml b/app/src/main/res/drawable/ic_view_compact_black_24dp.xml new file mode 100644 index 000000000..f41bd67cb --- /dev/null +++ b/app/src/main/res/drawable/ic_view_compact_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_day_black_24dp.xml b/app/src/main/res/drawable/ic_view_day_black_24dp.xml new file mode 100644 index 000000000..ee43f6846 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_day_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_headline_black_24dp.xml b/app/src/main/res/drawable/ic_view_headline_black_24dp.xml new file mode 100644 index 000000000..7bee91b66 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_headline_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_list_black_24dp.xml b/app/src/main/res/drawable/ic_view_list_black_24dp.xml new file mode 100644 index 000000000..78118c161 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_list_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_module_black_24dp.xml b/app/src/main/res/drawable/ic_view_module_black_24dp.xml new file mode 100644 index 000000000..ab36b0766 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_module_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_quilt_black_24dp.xml b/app/src/main/res/drawable/ic_view_quilt_black_24dp.xml new file mode 100644 index 000000000..a2e78f72c --- /dev/null +++ b/app/src/main/res/drawable/ic_view_quilt_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_stream_black_24dp.xml b/app/src/main/res/drawable/ic_view_stream_black_24dp.xml new file mode 100644 index 000000000..fea83133a --- /dev/null +++ b/app/src/main/res/drawable/ic_view_stream_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_view_week_black_24dp.xml b/app/src/main/res/drawable/ic_view_week_black_24dp.xml new file mode 100644 index 000000000..a92c91ca1 --- /dev/null +++ b/app/src/main/res/drawable/ic_view_week_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_vignette_black_24dp.xml b/app/src/main/res/drawable/ic_vignette_black_24dp.xml new file mode 100644 index 000000000..0dec207b4 --- /dev/null +++ b/app/src/main/res/drawable/ic_vignette_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_visibility_black_24dp.xml b/app/src/main/res/drawable/ic_visibility_black_24dp.xml new file mode 100644 index 000000000..e02f1d191 --- /dev/null +++ b/app/src/main/res/drawable/ic_visibility_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_visibility_off_black_24dp.xml b/app/src/main/res/drawable/ic_visibility_off_black_24dp.xml new file mode 100644 index 000000000..689f3f47c --- /dev/null +++ b/app/src/main/res/drawable/ic_visibility_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_voice_chat_black_24dp.xml b/app/src/main/res/drawable/ic_voice_chat_black_24dp.xml new file mode 100644 index 000000000..df35c271a --- /dev/null +++ b/app/src/main/res/drawable/ic_voice_chat_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_voicemail_black_24dp.xml b/app/src/main/res/drawable/ic_voicemail_black_24dp.xml new file mode 100644 index 000000000..c3119987a --- /dev/null +++ b/app/src/main/res/drawable/ic_voicemail_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_volume_down_black_24dp.xml b/app/src/main/res/drawable/ic_volume_down_black_24dp.xml new file mode 100644 index 000000000..06d03cc80 --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_down_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_volume_mute_black_24dp.xml b/app/src/main/res/drawable/ic_volume_mute_black_24dp.xml new file mode 100644 index 000000000..b6c24e30e --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_mute_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_volume_off_black_24dp.xml b/app/src/main/res/drawable/ic_volume_off_black_24dp.xml new file mode 100644 index 000000000..3aed66ddc --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_off_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_volume_up_black_24dp.xml b/app/src/main/res/drawable/ic_volume_up_black_24dp.xml new file mode 100644 index 000000000..bb0c74ba1 --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_up_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_vpn_key_black_24dp.xml b/app/src/main/res/drawable/ic_vpn_key_black_24dp.xml new file mode 100644 index 000000000..2eddd16f6 --- /dev/null +++ b/app/src/main/res/drawable/ic_vpn_key_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_vpn_lock_black_24dp.xml b/app/src/main/res/drawable/ic_vpn_lock_black_24dp.xml new file mode 100644 index 000000000..7ecdb914a --- /dev/null +++ b/app/src/main/res/drawable/ic_vpn_lock_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wallpaper_black_24dp.xml b/app/src/main/res/drawable/ic_wallpaper_black_24dp.xml new file mode 100644 index 000000000..9e2340bd2 --- /dev/null +++ b/app/src/main/res/drawable/ic_wallpaper_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_warning_black_24dp.xml b/app/src/main/res/drawable/ic_warning_black_24dp.xml new file mode 100644 index 000000000..b3a9e036b --- /dev/null +++ b/app/src/main/res/drawable/ic_warning_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_watch_black_24dp.xml b/app/src/main/res/drawable/ic_watch_black_24dp.xml new file mode 100644 index 000000000..b658387ec --- /dev/null +++ b/app/src/main/res/drawable/ic_watch_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_watch_later_black_24dp.xml b/app/src/main/res/drawable/ic_watch_later_black_24dp.xml new file mode 100644 index 000000000..e9f85c873 --- /dev/null +++ b/app/src/main/res/drawable/ic_watch_later_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wb_auto_black_24dp.xml b/app/src/main/res/drawable/ic_wb_auto_black_24dp.xml new file mode 100644 index 000000000..ba2d39b79 --- /dev/null +++ b/app/src/main/res/drawable/ic_wb_auto_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wb_cloudy_black_24dp.xml b/app/src/main/res/drawable/ic_wb_cloudy_black_24dp.xml new file mode 100644 index 000000000..b1c638a91 --- /dev/null +++ b/app/src/main/res/drawable/ic_wb_cloudy_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wb_incandescent_black_24dp.xml b/app/src/main/res/drawable/ic_wb_incandescent_black_24dp.xml new file mode 100644 index 000000000..f15dac43c --- /dev/null +++ b/app/src/main/res/drawable/ic_wb_incandescent_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wb_iridescent_black_24dp.xml b/app/src/main/res/drawable/ic_wb_iridescent_black_24dp.xml new file mode 100644 index 000000000..7a218b32c --- /dev/null +++ b/app/src/main/res/drawable/ic_wb_iridescent_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wb_sunny_black_24dp.xml b/app/src/main/res/drawable/ic_wb_sunny_black_24dp.xml new file mode 100644 index 000000000..a56fb5049 --- /dev/null +++ b/app/src/main/res/drawable/ic_wb_sunny_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wc_black_24dp.xml b/app/src/main/res/drawable/ic_wc_black_24dp.xml new file mode 100644 index 000000000..67dcddf03 --- /dev/null +++ b/app/src/main/res/drawable/ic_wc_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_web_asset_black_24dp.xml b/app/src/main/res/drawable/ic_web_asset_black_24dp.xml new file mode 100644 index 000000000..e38da9921 --- /dev/null +++ b/app/src/main/res/drawable/ic_web_asset_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_web_black_24dp.xml b/app/src/main/res/drawable/ic_web_black_24dp.xml new file mode 100644 index 000000000..107f01042 --- /dev/null +++ b/app/src/main/res/drawable/ic_web_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_weekend_black_24dp.xml b/app/src/main/res/drawable/ic_weekend_black_24dp.xml new file mode 100644 index 000000000..20befd9ab --- /dev/null +++ b/app/src/main/res/drawable/ic_weekend_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_whatshot_black_24dp.xml b/app/src/main/res/drawable/ic_whatshot_black_24dp.xml new file mode 100644 index 000000000..1cbc037f7 --- /dev/null +++ b/app/src/main/res/drawable/ic_whatshot_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_widgets_black_24dp.xml b/app/src/main/res/drawable/ic_widgets_black_24dp.xml new file mode 100644 index 000000000..4abb823f8 --- /dev/null +++ b/app/src/main/res/drawable/ic_widgets_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wifi_black_24dp.xml b/app/src/main/res/drawable/ic_wifi_black_24dp.xml new file mode 100644 index 000000000..69c81f1d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_wifi_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wifi_lock_black_24dp.xml b/app/src/main/res/drawable/ic_wifi_lock_black_24dp.xml new file mode 100644 index 000000000..8eba49d04 --- /dev/null +++ b/app/src/main/res/drawable/ic_wifi_lock_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wifi_tethering_black_24dp.xml b/app/src/main/res/drawable/ic_wifi_tethering_black_24dp.xml new file mode 100644 index 000000000..4e021adaa --- /dev/null +++ b/app/src/main/res/drawable/ic_wifi_tethering_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_work_black_24dp.xml b/app/src/main/res/drawable/ic_work_black_24dp.xml new file mode 100644 index 000000000..4a0748d94 --- /dev/null +++ b/app/src/main/res/drawable/ic_work_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wrap_text_black_24dp.xml b/app/src/main/res/drawable/ic_wrap_text_black_24dp.xml new file mode 100644 index 000000000..8b2b24a84 --- /dev/null +++ b/app/src/main/res/drawable/ic_wrap_text_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_youtube_searched_for_black_24dp.xml b/app/src/main/res/drawable/ic_youtube_searched_for_black_24dp.xml new file mode 100644 index 000000000..ff5b0b0a1 --- /dev/null +++ b/app/src/main/res/drawable/ic_youtube_searched_for_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_zoom_in_black_24dp.xml b/app/src/main/res/drawable/ic_zoom_in_black_24dp.xml new file mode 100644 index 000000000..4ab846567 --- /dev/null +++ b/app/src/main/res/drawable/ic_zoom_in_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_zoom_out_black_24dp.xml b/app/src/main/res/drawable/ic_zoom_out_black_24dp.xml new file mode 100644 index 000000000..baaef6a32 --- /dev/null +++ b/app/src/main/res/drawable/ic_zoom_out_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_zoom_out_map_black_24dp.xml b/app/src/main/res/drawable/ic_zoom_out_map_black_24dp.xml new file mode 100644 index 000000000..ff394c007 --- /dev/null +++ b/app/src/main/res/drawable/ic_zoom_out_map_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_permission.xml b/app/src/main/res/layout/activity_permission.xml deleted file mode 100644 index d532cc300..000000000 --- a/app/src/main/res/layout/activity_permission.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - -