Compare commits

..

40 Commits

Author SHA1 Message Date
Fredrik Fornwall 53f75a8da3 Changed: Update gradle, android gradle plugin and dependencies 2026-01-04 03:16:28 +01:00
dependabot[bot] bcb61c387c Changed: Bump actions/upload-artifact from 4 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-04 03:08:14 +01:00
dependabot[bot] c6ec1cb64f
Changed: Bump actions/checkout from 4 to 6 (#4859)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Fredrik Fornwall <fredrik@fornwall.net>
2026-01-04 03:06:03 +01:00
Fredrik Fornwall 382c9708b3 Fixed: Update gradle wrapper validation in CI
Replace `gradle/wrapper-validation-action@v3` with
`gradle/actions/wrapper-validation@5` which should fix the error seen
e.g. [here](https://github.com/termux/termux-app/actions/runs/20685857619/job/59386383274):

> Error: The action gradle/actions/wrapper-validation@v3.5.0 is not allowed in termux/termux-app because all actions must be from a repository owned by termux, created by GitHub, or match one of the patterns: gradle/actions/dependency-submission@*, gradle/wrapper-validation-action@v*.
2026-01-04 02:55:26 +01:00
dependabot[bot] edd44d2ce9 Changed: Bump actions/setup-java from 4 to 5
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4 to 5.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-04 02:42:55 +01:00
dependabot[bot] 4183ffa122 Changed: Bump gradle/actions from 4 to 5
Bumps [gradle/actions](https://github.com/gradle/actions) from 4 to 5.
- [Release notes](https://github.com/gradle/actions/releases)
- [Commits](https://github.com/gradle/actions/compare/v4...v5)

---
updated-dependencies:
- dependency-name: gradle/actions
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-04 02:42:31 +01:00
agnostic-apollo 8aca6dbbf4
Added: Add Warp sponsors logo
- https://www.warp.dev

The logo is sourced from 640dffd347/Github/Sponsor/Warp-Github-LG-03.png
2025-09-26 23:04:22 +05:00
agnostic-apollo 1812a405ee
Added: Add Clouflare funders logo
- https://www.cloudflare.com
- https://packages-cf.termux.dev

Clouflare has served around 36TB (32TB cached) data, 39M requests, 1M unique visitors in last 30 days for our https://termux.dev domain, and has potentially served 100s to 1000s of TBs of data over the years for free for Termux, primarily from the https://packages-cf.termux.dev `apt` packages repo, which is a cloudflare backed variant of our primary repo https://packages.termux.dev.

The `cloudflare.png` logo is sourced from www.cloudflare.com/press-kit
2025-09-26 23:04:22 +05:00
agnostic-apollo 338fb66e5c
Added: Add NLnet NGI Mobifree sponsors logo
- https://nlnet.nl/mobifree
- https://nlnet.nl/news/2024/20241111-NGI-Mobifree-grants.html
- https://termux.dev/en/posts/general/2024/11/11/termux-selected-for-nlnet-ngi-mobifree-grant.html

The `nlnet-ngi-mobifree.png` logo is sourced from https://nlnet.nl/logo
2025-09-25 00:56:11 +05:00
agnostic-apollo f852dca0ef
Added: Add GitHub Secure Open Source Fund sponsors logo
- https://resources.github.com/github-secure-open-source-fund
- https://github.blog/open-source/maintainers/securing-the-supply-chain-at-scale-starting-with-71-important-open-source-projects
- https://termux.dev/en/posts/general/2025/08/11/termux-selected-for-github-secure-open-source-fund-session-2.html

The `github.png` logo is sourced from https://github.com/logos
2025-09-25 00:56:05 +05:00
agnostic-apollo 8174a995ae
Added: Add GitHub Accelerator sponsors logo
- https://github.com/accelerator
- https://github.blog/2023-04-12-github-accelerator-our-first-cohort-and-whats-next

The `github.png` logo is sourced from https://github.com/logos
2025-09-25 00:56:05 +05:00
agnostic-apollo 7bceab88e2
Added: Add `SECURITY.md` 2025-06-25 21:10:52 +05:00
agnostic-apollo 2c1bd650b0
Added: Enable workflow dispatch trigger for Automatic Dependency Submission workflow 2025-06-20 13:30:51 +05:00
agnostic-apollo 4a9ad910dd
Added: Add Automatic Dependency Submission for SBOM
- https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/configuring-automatic-dependency-submission-for-your-repository#gradle-projects
- https://github.com/actions/gradle-build-tools-actions#the-dependency-submission-action
2025-06-17 10:17:44 +05:00
agnostic-apollo 9d2ac14557
Fixed: Use `ndkVersion` specified in project properties or `$JITPACK_NDK_VERSION` env variable for `termux-shared` library 2025-05-30 12:06:45 +05:00
agnostic-apollo c6e2ca7fde
Changed(README): Set latest version to 0.118.3 2025-05-23 15:01:53 +05:00
agnostic-apollo da3a0ac4e2
Fixed: Add explicit `serialVersionUID` to `Serializable` classes like `ReportInfo` and `TextIOInfo`
Reading `ReportInfo` with `Bundle.getSerializable()` by `ReportActivity` is triggering exception when default algorithm is used for `serialVersionUID` in Termux:API plugin app when error notification created in `ResultReturner.returnData()` by `TermuxPluginUtils.sendPluginCommandErrorNotification()` is clicked.

```
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.termux/com.termux.shared.activities.ReportActivity}: android.os.BadParcelableException: Parcelable encountered IOException reading a Serializable object (name = com.termux.shared.models.ReportInfo)
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4280)
	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4467)
	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:222)
	at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:133)
	at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:103)
	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:80)
	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2823)
	at android.os.Handler.dispatchMessage(Handler.java:110)
	at android.os.Looper.loopOnce(Looper.java:248)
	at android.os.Looper.loop(Looper.java:338)
	at android.app.ActivityThread.main(ActivityThread.java:9067)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)
Caused by: android.os.BadParcelableException: Parcelable encountered IOException reading a Serializable object (name = com.termux.shared.models.ReportInfo)
	at android.os.Parcel.readSerializableInternal(Parcel.java:5520)
	at android.os.Parcel.readValue(Parcel.java:5038)
	at android.os.Parcel.readValue(Parcel.java:4702)
	at android.os.Parcel.-$$Nest$mreadValue(Unknown Source:0)
	at android.os.Parcel$LazyValue.apply(Parcel.java:4811)
	at android.os.Parcel$LazyValue.apply(Parcel.java:4764)
	at android.os.BaseBundle.unwrapLazyValueFromMapLocked(BaseBundle.java:446)
	at android.os.BaseBundle.getValueAt(BaseBundle.java:426)
	at android.os.BaseBundle.getValue(BaseBundle.java:397)
	at android.os.BaseBundle.getValue(BaseBundle.java:380)
	at android.os.BaseBundle.getValue(BaseBundle.java:373)
	at android.os.BaseBundle.getSerializable(BaseBundle.java:1522)
	at android.os.Bundle.getSerializable(Bundle.java:1339)
	at com.termux.shared.activities.ReportActivity.updateUI(ReportActivity.java:140)
	at com.termux.shared.activities.ReportActivity.onCreate(ReportActivity.java:93)
	at android.app.Activity.performCreate(Activity.java:9155)
	at android.app.Activity.performCreate(Activity.java:9133)
	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1521)
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4262)
	... 13 more
Caused by: java.io.InvalidClassException: com.termux.shared.models.ReportInfo; local class incompatible: stream classdesc serialVersionUID = -5165426368218339031, local class serialVersionUID = 1
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:652)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1743)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1624)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1902)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1442)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
	at android.os.Parcel.readSerializableInternal(Parcel.java:5507)
	... 31 more

```

If using release APK with obfuscation enabled, then following exception will be triggered.

```
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.termux/com.termux.shared.activities.ReportActivity}: android.os.BadParcelableException: Parcelable encountered ClassNotFoundException reading a Serializable object (name = I0.a)
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3864)
	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4006)
	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:111)
	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2462)
	at android.os.Handler.dispatchMessage(Handler.java:106)
	at android.os.Looper.loopOnce(Looper.java:240)
	at android.os.Looper.loop(Looper.java:351)
	at android.app.ActivityThread.main(ActivityThread.java:8377)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
Caused by: android.os.BadParcelableException: Parcelable encountered ClassNotFoundException reading a Serializable object (name = I0.a)
	at android.os.Parcel.readSerializableInternal(Parcel.java:5113)
	at android.os.Parcel.readValue(Parcel.java:4655)
	at android.os.Parcel.readValue(Parcel.java:4363)
	at android.os.Parcel.-$$Nest$mreadValue(Unknown Source:0)
	at android.os.Parcel$LazyValue.apply(Parcel.java:4461)
	at android.os.Parcel$LazyValue.apply(Parcel.java:4420)
	at android.os.BaseBundle.getValueAt(BaseBundle.java:394)
	at android.os.BaseBundle.getValue(BaseBundle.java:374)
	at android.os.BaseBundle.getValue(BaseBundle.java:357)
	at android.os.BaseBundle.getValue(BaseBundle.java:350)
	at android.os.BaseBundle.getSerializable(BaseBundle.java:1451)
	at android.os.Bundle.getSerializable(Bundle.java:1144)
	at com.termux.shared.activities.ReportActivity.updateUI(ReportActivity.java:136)
	at com.termux.shared.activities.ReportActivity.onCreate(ReportActivity.java:89)
	at android.app.Activity.performCreate(Activity.java:8397)
	at android.app.Activity.performCreate(Activity.java:8370)
	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1403)
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3837)
	... 12 more
Caused by: java.lang.ClassNotFoundException: I0.a
	at java.lang.Class.classForName(Native Method)
	at java.lang.Class.forName(Class.java:536)
	at android.os.Parcel$2.resolveClass(Parcel.java:5090)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1733)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1624)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1902)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1442)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
	at android.os.Parcel.readSerializableInternal(Parcel.java:5096)
	... 29 more
Caused by: java.lang.ClassNotFoundException: I0.a
	... 38 more
```

Related issue https://github.com/termux/termux-api/issues/762
2025-05-23 02:27:29 +05:00
Wang Han 4de0caac5b Changed|Fixed: Bump `org.lsposed.hiddenapibypass:hiddenapibypass` to `6.1` to fix crash on Android 16 QPR1
```
Build fingerprint: 'google/shiba_beta/shiba:16/BP31.250502.008/13497110:user/release-keys'
Revision: 'MP1.0'
ABI: 'arm64'
Executable: /system/bin/app_process64
Cmdline: com.termux
pid: 22617, tid: 22617, name: com.termux  >>> com.termux <<<
uid: 10323
tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
esr: 0000000092000006 (Data Abort Exception 0x24)
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x000000000000000c
Cause: null pointer dereference
    x0  0000000070b6f798  x1  0000000002159228  x2  000000000000000c  x3  00000000ebad6073
    x4  00000000ebad6074  x5  00000000ebad6075  x6  00000000ebad6076  x7  00000000ebad6077
    x8  00000000ebad6078  x9  00000000ebad6079  x10 00000000ebad607a  x11 00000000ebad607b
    x12 00000000ebad607c  x13 00000000ebad607d  x14 00000000ebad607e  x15 00000000ebad607f
    x16 0000007feda203f0  x17 0000007976776a9c  x18 0000007cd0e44000  x19 b400007b850b8be0
    x20 0000000000000000  x21 b400007b850b8ca0  x22 0000000000000000  x23 00000000021592b8
    x24 000000006413b378  x25 0000000070b99ee0  x26 0000000070b9fc78  x27 0000000000000000
    x28 0000000000000053  x29 0000000070b99ee0
    lr  0000007976776a98  sp  0000007feda203f0  pc  0000007976776b0c  pst 0000000080001000
    esr 0000000092000006
26 total frames
backtrace:
      #00 pc 00000000000c8b0c  /data/app/~~p_sHRwZKj3QVf_xeRMrR3g==/com.termux-rodTRD4IY6G2qtCPCrHfhw==/oat/arm64/base.odex (org.lsposed.hiddenapibypass.HiddenApiBypass.getDeclaredMethods+780)
      #01 pc 00000000000c8dc4  /data/app/~~p_sHRwZKj3QVf_xeRMrR3g==/com.termux-rodTRD4IY6G2qtCPCrHfhw==/oat/arm64/base.odex (org.lsposed.hiddenapibypass.HiddenApiBypass.setHiddenApiExemptions+68)
      #02 pc 00000000000ae560  /data/app/~~p_sHRwZKj3QVf_xeRMrR3g==/com.termux-rodTRD4IY6G2qtCPCrHfhw==/oat/arm64/base.odex (com.termux.shared.reflection.ReflectionUtils.bypassHiddenAPIReflectionRestrictions+448)
      #03 pc 00000000000a342c  /data/app/~~p_sHRwZKj3QVf_xeRMrR3g==/com.termux-rodTRD4IY6G2qtCPCrHfhw==/oat/arm64/base.odex (com.termux.shared.android.SELinuxUtils.getContext+108)
      #04 pc 00000000000c0b60  /data/app/~~p_sHRwZKj3QVf_xeRMrR3g==/com.termux-rodTRD4IY6G2qtCPCrHfhw==/oat/arm64/base.odex (com.termux.shared.termux.shell.command.environment.TermuxAppShellEnvironment.setTermuxAppEnvironment+3216)
      #05 pc 000000000009eafc  /data/app/~~p_sHRwZKj3QVf_xeRMrR3g==/com.termux-rodTRD4IY6G2qtCPCrHfhw==/oat/arm64/base.odex (com.termux.app.TermuxApplication.onCreate+1596)
      ...
      #22 pc 0000000000105c98  /system/lib64/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+104) (BuildId: ea93df5e792bbd2e0cbb71b2a7599aaa)
      #23 pc 000000000013121c  /system/lib64/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+908) (BuildId: ea93df5e792bbd2e0cbb71b2a7599aaa)
      #24 pc 000000000000459c  /system/bin/app_process64 (main+1212) (BuildId: a237cfae6965d7f0b950e5955c73432c)
      #25 pc 000000000006bb88  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+120) (BuildId: eecb0fc2ec8128ec92c091c0160586d1)
```

Related commit https://github.com/LSPosed/AndroidHiddenApiBypass/commit/9efadf06
Related commit https://android-review.googlesource.com/c/platform/libcore/+/3380841
Related commit https://cs.android.com/android/_/android/platform/libcore/+/0dc31afe

Closes #4556
2025-05-23 02:26:47 +05:00
agnostic-apollo bc321d0a7c
Changed(README): Set latest version to 0.118.2 2025-03-29 12:15:10 +05:00
agnostic-apollo 9ee1c9d5ad
Fixed: Use `openjdk11` for jitpack builds of termux libraries
`Unrecognized option: --add-exports=java.base/sun.nio.ch=ALL-UNNAMED`

Related commit 52da00e5
2025-03-29 10:34:17 +05:00
Johannes Altmanninger a988383e01 Fixed: Fully consume unknown CSI sequences containing unsupported parameter and intermediate bytes
Standard ECMA-48: Control Functions for Coded Character Sets specifies the format of CSI commands.
- https://en.wikipedia.org/wiki/ANSI_escape_code#Control_Sequence_Introducer_commands
- https://invisible-island.net/xterm/ecma-48-parameter-format.html#section5.4

Previously unsupported bytes would be echoed to the terminal.

```shell
$ printf '\x1b[=u' # PF
u
$ printf '\x1b[=5u' # PPF
5u
$ printf '\x1b[=5!u' # PPIF
5!u
$ printf '\x1b[=5!%u' # PPIIF
5!0
$ printf '\x1b[=?5!%u' # PPPIIF
?5!0
```

This fixes a problem with fish shell 4.0.0 which uses that sequence.

Closes #4338

Co-authored-by: @krobelus <aclopte@gmail.com>
Co-authored-by: @agnostic-apollo  <agnosticapollo@gmail.com>
2025-03-15 11:26:11 +05:00
agnostic-apollo d2cd6ac2e5
Changed|Fixed: Bump `org.lsposed.hiddenapibypass:hiddenapibypass` to `5.0` to fix crash on Android 16
```
Build fingerprint: 'google/sdk_gphone64_x86_64/emu64xa:Baklava/BP22.250103.008/12932282:userdebug/dev-keys'
Revision: '0'
ABI: 'x86_64'
Timestamp: 2025-01-25
Process uptime: 1s
Cmdline: com.termux
pid: 4700, tid: 4700, name: com.termux  >>> com.termux <<<
uid: 10212
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x000000000000000c
Cause: null pointer dereference
    rax 0000000000000000  rbx 000071ad67c247b0  rcx 000000000000000c  rdx 000071abc520c888
    r8  00005f2000006018  r9  0000607c00006004  r10 000071abc423d68c  r11 000071abc4cca7c0
    r12 00007ffc65da8240  r13 000071ad67c24858  r14 00007ffc65da85d8  r15 000071ad67c247b0
    rdi 000071ad87c26110  rsi 00007ffc65da8148
    rbp 00007ffc65da8050  rsp 00007ffc65da8040  rip 000071abc4cca817
124 total frames
backtrace:
      #00 pc 00000000008ca817  /apex/com.android.art/lib64/libart.so (art::Unsafe_getObject(_JNIEnv*, _jobject*, _jobject*, long) (.__uniq.306581074569039686346581217366878976736)+87) (BuildId: 99c067c739342eb9769974bbb229d3b3)
      #01 pc 000000000022c80b  /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+219) (BuildId: 99c067c739342eb9769974bbb229d3b3)
      #02 pc 0000000000211dd4  /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+756) (BuildId: 99c067c739342eb9769974bbb229d3b3)
      #03 pc 0000000000556155  /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+181) (BuildId: 99c067c739342eb9769974bbb229d3b3)
      #04 pc 00000000006dd182  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+2434) (BuildId: 99c067c739342eb9769974bbb229d3b3)
      #05 pc 0000000000233564  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+10804) (BuildId: 99c067c739342eb9769974bbb229d3b3)
      #06 pc 000000000022eb25  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+5) (BuildId: 99c067c739342eb9769974bbb229d3b3)
      #07 pc 0000000000080eb4  <anonymous:71ab3d335000> (org.lsposed.hiddenapibypass.HiddenApiBypass.getDeclaredMethods+0)
      ...
      #13 pc 0000000000080dd0  <anonymous:71ab3d335000> (org.lsposed.hiddenapibypass.HiddenApiBypass.setHiddenApiExemptions+0)
      ...
      #19 pc 0000000000080cf8  <anonymous:71ab3d335000> (org.lsposed.hiddenapibypass.HiddenApiBypass.addHiddenApiExemptions+0)
      ...
      #25 pc 0000000000005ab4  <anonymous:71ae82992000> (com.termux.shared.reflection.ReflectionUtils.bypassHiddenAPIReflectionRestrictions+0)
      ...
      #31 pc 0000000000004738  <anonymous:71ae86607000> (com.termux.shared.android.SELinuxUtils.getContext+0)
      ...
      #37 pc 0000000000005b48  <anonymous:71ae825d8000> (com.termux.shared.termux.shell.command.environment.TermuxAppShellEnvironment.setTermuxAppEnvironment+0)
      ...
      #43 pc 000000000000603c  <anonymous:71ae825d8000> (com.termux.shared.termux.shell.command.environment.TermuxShellEnvironment.init+0)
      ...
      #49 pc 0000000000006a68  <anonymous:71ae7e1c2000> (com.termux.app.TermuxApplication.onCreate+0)
```

Related commit 40b4cafa47
Related issue https://github.com/LSPosed/AndroidHiddenApiBypass/issues/52

Closes #4368
2025-01-25 02:30:20 +05:00
agnostic-apollo 52da00e5c2
Fixed: Fix gradle build error if using jdk `17`
`Unable to make field private final java.lang.String java.io.File.path accessible: module java.base does not "opens java.io" to unnamed module`
2025-01-13 03:41:34 +05:00
agnostic-apollo b0e1dbc3da
Fixed: Use `TERMUX_STYLING_APP` for `TERMUX_STYLING_ACTIVITY_NAME` as per 078eea2b 2025-01-13 01:50:45 +05:00
agnostic-apollo 078eea2b74
Added: Rename app classes in `TermuxConstants` with `_APP` suffix added and add `TERMUX_*_MAIN_ACTIVITY_NAME` and `TERMUX_*_LAUNCHER_ACTIVITY_NAME` constants to each app class 2025-01-13 01:30:06 +05:00
agnostic-apollo fb01127ff2
Fixed: Fix tests added in b84dc703 2024-10-28 12:45:39 +05:00
Jason Yu b84dc703e8 Added: Add empty and null strings tests for invalid urls to `FileReceiverActivityTest` 2024-10-28 12:34:31 +05:00
Fredrik Fornwall 8be53336c3 Fixed: Implement colon separated CSI parameters 2024-10-02 17:27:08 +02:00
Evgeny Zhabotinsky d90e3fbca1 Fixed: Make ScrollDown escape respect margins
SD sequence (`${CSI}${N}T`) was scrolling the whole width
 of the terminal instead of just between the margins.
RI sequence (`${ESC}M`, move cursor up 1 line) was doing the same.
Fixed that.

Fixes #2576 where in tmux scrolling one of several
 side-by-side panels down resulted in all visually scrolling.
2024-09-29 23:37:28 +02:00
Tom Kranz 245158ceb9 Added: Basic MIME type recognition in ContentProvider 2024-09-28 01:19:50 +02:00
Matan Ziv-Av 6c00f1fc61 Fixed: Use Canvas.drawTextRun instead of drawText
drawText does (very) basic BiDi, which causes inconsistent behaviour.
This ensures everything is LtR.
2024-09-27 11:27:38 +02:00
Fredrik Fornwall 03142590ff Added: Terminal CSI reporting of window and cell pixel size
Implement the following CSI escape sequences from
https://invisible-island.net/xterm/ctlseqs/ctlseqs.html:

> CSI Ps ; Ps ; Ps t
> [..]
>    Ps = 1 4  ⇒  Report xterm text area size in pixels.
>    Result is CSI  4 ;  height ;  width t
> [..]
>    Ps = 1 6  ⇒  Report xterm character cell size in pixels.
>    Result is CSI  6 ;  height ;  width t

Extracted from changes in https://github.com/termux/termux-app/pull/2973
by @MatanZ and adopted to play well with the just merged #3098 (.ws_xpixel
and .ws_ypixel values in winsize).
2024-09-26 21:53:52 +02:00
Artem Chepurnyi 4443b657bf Fixed: Mark view as important for AutoFill before requesting an AutoFill
Co-authored-by: @AChep <mail@artemchep.com>
Co-authored-by: @agnostic-apollo  <agnosticapollo@gmail.com>
2024-09-26 20:34:18 +05:00
Dvd-Znf a8a69c6d80 Update latest version in README.md to v0.118.1 2024-09-26 16:55:56 +02:00
Krunal Patel 438cd73fff Added|Changed: Fill `.ws_xpixel` and `.ws_ypixel` in `winsize`
This allows to get terminal size in pixel using `TIOCGWINSZ` ioctl.
Set `.ws_xpixel` using `columns * cell_width` and set `.ws_ypixel` using `rows * cell_height`.
Cell width and height is font width and line spacing, respectively.
2024-09-26 15:09:09 +02:00
Fredrik Fornwall 36d811ea7d Fixed: Parse (but ignore for now) terminal APC sequences 2024-09-18 22:28:16 +02:00
agnostic-apollo c2d57f2ed8
Added|Fixed: Do not show AutoFill UI on Termux start and add support for usernames
- The AutoFill type and hints are no longer hardcoded in `TerminalView` class and `TermuxActivity` layout xml. They are dynamically set to required values before making a manual AutoFill request and reverted back afterwards to default values. The hardcoded value `AUTOFILL_TYPE_TEXT` returned by `getAutofillType()` was causing the AutoFill UI to show on Activity starts, this will return `AUTOFILL_TYPE_NONE` by default now so that AutoFill UI isn't shown automatically.
- The AutoFill importance is no longer hardcoded in `TermuxActivity` layout xml and is returned by `TerminalView` class itself by `getImportantForAutofill()`.
- The AutoFill function in `TermuxActivity` for making a manual AutoFill request is moved to `TerminalView` class. This and moving of hardcoded values to `TerminalView` class mentioned above is done as complete logic of AutoFill should be handled by `TerminalView` class itself and not scattered in various places.
- The Terminal context menu now supports AutoFilling a username. Note that GBoard/Google Password Manager seems to have a bug where it will still show `Pick a saved password` instead of username, even though `AUTOFILL_HINT_USERNAME` is being requested, however it will still AutoFill a username of selected entry correctly.
- Pressing the back button to close the keyboard will also cancel the current manually requested AutoFill request and UI will not show when keyboard is opened again.

Closes #3909
2024-08-27 20:44:05 +05:00
Josh Triplett 661c37501f Make Shift-PgUp and Shift-PgDn scroll by pages rather than lines
In other terminals, such as gnome-terminal, Shift-PgUp and Shift-PgDn
scroll the screen by a full page, rather than a single line. Adjust
termux to match.
2024-08-16 12:18:54 +02:00
Fredrik Fornwall f80b46487d Fixed: Improve handling of empty ';' SGR sequences
Currently the Termux terminal emulator prints "HI" in red with:

```sh
printf "\e[31;m HI \e[0m"
```

This is not how other terminals (tested on xterm, gnome-terminal,
alacritty and the mac built in terminal) handle it, since they parse
""\e[31;m" as "\e[31;0m", where the "0" resets the colors.

This change aligns with other terminals, as well as improves performance
by avoiding allocating a new int[] array for each byte processed by
`parseArg()`, and most importantly simplifies things by removing the
`mIsCSIStart` and `mLastCSIArg` state, preparing for supporting ':'
separated sub parameters such as used in
https://sw.kovidgoyal.net/kitty/underlines/
2024-08-13 19:20:38 +02:00
Fredrik Fornwall a5de3d3a2b Fixed: Use current bg color when scrolling with horizontal margins
Fixes https://github.com/termux/termux-packages/issues/12556

Issue was also reported here:
https://www.reddit.com/r/termux/comments/1df1dii/how_can_i_fix_this_annoying_screenfilling_thing/
2024-08-13 19:14:53 +02:00
45 changed files with 437 additions and 451 deletions

View File

@ -17,7 +17,7 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ env.GITHUB_REF }}
@ -71,13 +71,14 @@ jobs:
fi
echo "Attaching APKs to github release"
if ! gh release upload "$RELEASE_VERSION_NAME" \
"$APK_DIR_PATH/${APK_BASENAME_PREFIX}_universal.apk" \
"$APK_DIR_PATH/${APK_BASENAME_PREFIX}_arm64-v8a.apk" \
"$APK_DIR_PATH/${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \
"$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86_64.apk" \
"$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86.apk" \
"$APK_DIR_PATH/${APK_BASENAME_PREFIX}_sha256sums" \
; then
if ! hub release edit \
-m "" \
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_universal.apk" \
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_arm64-v8a.apk" \
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_armeabi-v7a.apk" \
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86_64.apk" \
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_x86.apk" \
-a "$APK_DIR_PATH/${APK_BASENAME_PREFIX}_sha256sums" \
"$RELEASE_VERSION_NAME"; then
exit_on_error "Attach APKs to release failed for '$APK_VERSION_TAG' release."
fi

View File

@ -19,7 +19,13 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup java 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Build APKs
shell: bash {0}
@ -79,7 +85,7 @@ jobs:
fi
- name: Attach universal APK file
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: ${{ env.APK_BASENAME_PREFIX }}_universal
path: |
@ -87,7 +93,7 @@ jobs:
${{ env.APK_DIR_PATH }}/output-metadata.json
- name: Attach arm64-v8a APK file
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: ${{ env.APK_BASENAME_PREFIX }}_arm64-v8a
path: |
@ -95,7 +101,7 @@ jobs:
${{ env.APK_DIR_PATH }}/output-metadata.json
- name: Attach armeabi-v7a APK file
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: ${{ env.APK_BASENAME_PREFIX }}_armeabi-v7a
path: |
@ -103,7 +109,7 @@ jobs:
${{ env.APK_DIR_PATH }}/output-metadata.json
- name: Attach x86_64 APK file
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: ${{ env.APK_BASENAME_PREFIX }}_x86_64
path: |
@ -111,7 +117,7 @@ jobs:
${{ env.APK_DIR_PATH }}/output-metadata.json
- name: Attach x86 APK file
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: ${{ env.APK_BASENAME_PREFIX }}_x86
path: |
@ -119,7 +125,7 @@ jobs:
${{ env.APK_DIR_PATH }}/output-metadata.json
- name: Attach sha256sums file
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: ${{ env.APK_BASENAME_PREFIX }}_sha256sums
path: |

View File

@ -0,0 +1,23 @@
name: Automatic Dependency Submission
on:
push:
branches: [ 'master' ]
workflow_dispatch:
permissions:
contents: write
jobs:
dependency-submission:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 17
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v5

View File

@ -15,5 +15,5 @@ jobs:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v3
- uses: actions/checkout@v6
- uses: gradle/actions/wrapper-validation@5

View File

@ -15,7 +15,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup java 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Execute tests
run: |
./gradlew test

View File

@ -29,6 +29,7 @@ Quick how-to about Termux package management is available at [Package Management
- [Debugging](#debugging)
- [For Maintainers and Contributors](#for-maintainers-and-contributors)
- [Forking](#forking)
- [Sponsors and Funders](#sponsors-and-funders)
##
@ -49,7 +50,7 @@ The core [Termux](https://github.com/termux/termux-app) app comes with the follo
## Installation
Latest version is `v0.118.1`.
Latest version is `v0.118.3`.
**NOTICE: It is highly recommended that you update to `v0.118.0` or higher ASAP for various bug fixes, including a critical world-readable vulnerability reported [here](https://termux.github.io/general/2022/02/15/termux-apps-vulnerability-disclosures.html). See [below](#google-play-store-experimental-branch) for information regarding Termux on Google Play.**
@ -264,3 +265,31 @@ Commit messages **must** use the [Conventional Commits](https://www.conventional
- You also need to recompile bootstrap zip for the new package name. Check [building bootstrap](https://github.com/termux/termux-packages/wiki/For-maintainers#build-bootstrap-archives), [here](https://github.com/termux/termux-app/issues/1983) and [here](https://github.com/termux/termux-app/issues/2081#issuecomment-865280111).
- Currently, not all plugins use `TermuxConstants` from `termux-shared` library and have hardcoded `com.termux` values and will need to be manually patched.
- If forking termux plugins, check [Forking and Local Development](https://github.com/termux/termux-app/wiki/Termux-Libraries#forking-and-local-development) for info on how to use termux libraries for plugins.
##
## Sponsors and Funders
[<img alt="GitHub Accelerator" width="25%" src="site/assets/sponsors/github.png" />](https://github.com)
*[GitHub Accelerator](https://github.com/accelerator) ([1](https://github.blog/2023-04-12-github-accelerator-our-first-cohort-and-whats-next))*
&nbsp;
[<img alt="GitHub Secure Open Source Fund" width="25%" src="site/assets/sponsors/github.png" />](https://github.com)
*[GitHub Secure Open Source Fund](https://resources.github.com/github-secure-open-source-fund) ([1](https://github.blog/open-source/maintainers/securing-the-supply-chain-at-scale-starting-with-71-important-open-source-projects), [2](https://termux.dev/en/posts/general/2025/08/11/termux-selected-for-github-secure-open-source-fund-session-2.html))*
&nbsp;
[<img alt="NLnet NGI Mobifree" width="25%" src="site/assets/sponsors/nlnet-ngi-mobifree.png" />](https://nlnet.nl/mobifree)
*[NLnet NGI Mobifree](https://nlnet.nl/mobifree) ([1](https://nlnet.nl/news/2024/20241111-NGI-Mobifree-grants.html), [2](https://termux.dev/en/posts/general/2024/11/11/termux-selected-for-nlnet-ngi-mobifree-grant.html))*
&nbsp;
[<img alt="Cloudflare" width="25%" src="site/assets/sponsors/cloudflare.png" />](https://www.cloudflare.com)
*[Cloudflare](https://www.cloudflare.com) ([1](https://packages-cf.termux.dev))*
&nbsp;
[<img alt="Warp" width="25%" src="https://github.com/warpdotdev/brand-assets/blob/640dffd347439bbcb535321ab36b7281cf4446c0/Github/Sponsor/Warp-Github-LG-03.png" />](https://www.warp.dev/?utm_source=github&utm_medium=readme&utm_campaign=termux)
[*Warp, built for coding with multiple AI agents*](https://www.warp.dev/?utm_source=github&utm_medium=readme&utm_campaign=termux)

1
SECURITY.md Normal file
View File

@ -0,0 +1 @@
Check https://termux.dev/security for info on Termux security policies and how to report vulnerabilities.

View File

@ -10,16 +10,11 @@ ext {
// by replacing $PREFIX since app code is dependant on the variant used to build the APK.
// Currently supported values are: [ "apt-android-7" "apt-android-5" ]
packageVariant = System.getenv("TERMUX_PACKAGE_VARIANT") ?: "apt-android-7" // Default: "apt-android-7"
bootstrapMinSdk = packageVariant == "apt-android-5" ? 21 : 24
bootstrapMinRelease = packageVariant == "apt-android-5" ? "5.0" : "7.0"
bootstrapMaxSdk = packageVariant == "apt-android-5" ? 23 : null
bootstrapMaxRelease = packageVariant == "apt-android-5" ? "6.0" : null
buildMinSdk = bootstrapMinSdk
buildTargetSdk = project.properties.targetSdkVersion.toInteger()
}
android {
namespace "com.termux"
compileSdkVersion project.properties.compileSdkVersion.toInteger()
ndkVersion = System.getenv("JITPACK_NDK_VERSION") ?: project.properties.ndkVersion
def appVersionName = System.getenv("TERMUX_APP_VERSION_NAME") ?: ""
@ -28,38 +23,32 @@ android {
def splitAPKsForReleaseBuilds = System.getenv("TERMUX_SPLIT_APKS_FOR_RELEASE_BUILDS") ?: "0" // F-Droid does not support split APKs #1904
dependencies {
implementation "androidx.annotation:annotation:1.3.0"
implementation "androidx.core:core:1.6.0"
implementation "androidx.drawerlayout:drawerlayout:1.1.1"
implementation "androidx.preference:preference:1.1.1"
implementation "androidx.annotation:annotation:1.9.0"
implementation "androidx.core:core:1.13.1"
implementation "androidx.drawerlayout:drawerlayout:1.2.0"
implementation "androidx.preference:preference:1.2.1"
implementation "androidx.viewpager:viewpager:1.0.0"
implementation "com.google.android.material:material:1.4.0"
implementation "com.google.android.material:material:1.12.0"
implementation "com.google.guava:guava:24.1-jre"
implementation "io.noties.markwon:core:$markwonVersion"
implementation "io.noties.markwon:ext-strikethrough:$markwonVersion"
implementation "io.noties.markwon:linkify:$markwonVersion"
implementation "io.noties.markwon:recycler:$markwonVersion"
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
implementation project(":terminal-view")
implementation project(":termux-shared")
}
defaultConfig {
applicationId "com.termux"
minSdk buildMinSdk
targetSdk buildTargetSdk
versionCode 1021
versionName "0.119.0-beta.2"
minSdkVersion project.properties.minSdkVersion.toInteger()
targetSdkVersion project.properties.targetSdkVersion.toInteger()
versionCode 118
versionName "0.118.0"
if (appVersionName) versionName = appVersionName
validateVersionName(versionName)
buildConfigField "Integer", "TERMUX_APP__BOOTSTRAP_MIN_SDK", project.ext.bootstrapMinSdk.toString()
buildConfigField "String", "TERMUX_APP__BOOTSTRAP_MIN_RELEASE",
project.ext.bootstrapMinRelease ? "\"" + project.ext.bootstrapMinRelease + "\"" : "null"
buildConfigField "Integer", "TERMUX_APP__BOOTSTRAP_MAX_SDK", project.ext.bootstrapMaxSdk.toString()
buildConfigField "String", "TERMUX_APP__BOOTSTRAP_MAX_RELEASE",
project.ext.bootstrapMaxRelease ? "\"" + project.ext.bootstrapMaxRelease + "\"" : "null"
buildConfigField "String", "TERMUX_PACKAGE_VARIANT", "\"" + project.ext.packageVariant + "\"" // Used by TermuxApplication class
manifestPlaceholders.TERMUX_PACKAGE_NAME = "com.termux"
@ -123,7 +112,7 @@ android {
}
}
lintOptions {
lint {
disable 'ProtectedPermissions'
}
@ -151,12 +140,15 @@ android {
}
}
buildFeatures {
buildConfig true
}
}
dependencies {
testImplementation "junit:junit:4.13.2"
testImplementation "org.robolectric:robolectric:4.10"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.2"
}
task versionName {
@ -227,17 +219,17 @@ task downloadBootstraps() {
doLast {
def packageVariant = project.ext.packageVariant
if (packageVariant == "apt-android-7") {
def version = "2025.03.28-r1" + "+" + packageVariant
downloadBootstrap("aarch64", "c8d702b6f742935001c37cda81b8ac69504a95d5cf28f2899532dd8cd4b057eb", version)
downloadBootstrap("arm", "f3bb9d1b32552b34fff41861dbf193ec5ba2848d67d779ac1c7256da6640f85d", version)
downloadBootstrap("i686", "36db3e1ac3547f9a174fd763bd9a484fa1a3449cdd81e1cf2408ff0454f839c6", version)
downloadBootstrap("x86_64", "1c124ec2396ee70a51b0b0a574f29aa659526aa2b9f558f993b2fb05d1e51855", version)
def version = "2022.04.28-r5" + "+" + packageVariant
downloadBootstrap("aarch64", "4a51a7eb209fe82efc24d52e3cccc13165f27377290687cb82038cbd8e948430", version)
downloadBootstrap("arm", "6459a786acbae50d4c8a36fa1c3de6a4dd2d482572f6d54f73274709bd627325", version)
downloadBootstrap("i686", "919d212b2f19e08600938db4079e794e947365022dbfd50ac342c50fcedcd7be", version)
downloadBootstrap("x86_64", "61b02fdc03ea4f5d9da8d8cf018013fdc6659e6da6cbf44e9b24d1c623580b89", version)
} else if (packageVariant == "apt-android-5") {
def version = "2025.03.28-r3" + "+" + packageVariant
downloadBootstrap("aarch64", "147c98e610a30588665a89776314833c293006b12c70e65dcde6eb54c2344113", version)
downloadBootstrap("arm", "363c28dd4b70c995302498beae79fb5917af7d3b0ca9fbd9da7de96ab64c6122", version)
downloadBootstrap("i686", "a2e742381ab24cf8c9a78ae4e2425ee44d8fb9625a2b0ef63e4cd32e292f7186", version)
downloadBootstrap("x86_64", "4f6866c222b0f1ae1b180220ffc6e8e1afbc10b9cbb7a462c062c490eda90044", version)
def version = "2022.04.28-r6" + "+" + packageVariant
downloadBootstrap("aarch64", "913609d439415c828c5640be1b0561467e539cb1c7080662decaaca2fb4820e7", version)
downloadBootstrap("arm", "26bfb45304c946170db69108e5eb6e3641aad751406ce106c80df80cad2eccf8", version)
downloadBootstrap("i686", "46dcfeb5eef67ba765498db9fe4c50dc4690805139aa0dd141a9d8ee0693cd27", version)
downloadBootstrap("x86_64", "615b590679ee6cd885b7fd2ff9473c845e920f9b422f790bb158c63fe42b8481", version)
} else {
throw new GradleException("Unsupported TERMUX_PACKAGE_VARIANT \"" + packageVariant + "\"")
}

View File

@ -10,8 +10,3 @@
-dontobfuscate
#-renamesourcefileattribute SourceFile
#-keepattributes SourceFile,LineNumberTable
# Temp fix for androidx.window:window:1.0.0-alpha09 imported by termux-shared
# https://issuetracker.google.com/issues/189001730
# https://android-review.googlesource.com/c/platform/frameworks/support/+/1757630
-keep class androidx.window.** { *; }

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.termux"
android:installLocation="internalOnly"
android:sharedUserId="${TERMUX_PACKAGE_NAME}"
android:sharedUserLabel="@string/shared_user_label">

View File

@ -774,7 +774,7 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
// If permission is granted, then also setup storage symlinks.
if(PermissionUtils.checkAndRequestLegacyOrManageExternalStoragePermission(
TermuxActivity.this, requestCode, true, !isPermissionCallback)) {
TermuxActivity.this, requestCode, !isPermissionCallback)) {
if (isPermissionCallback)
Logger.logInfoAndShowToast(TermuxActivity.this, LOG_TAG,
getString(com.termux.shared.R.string.msg_storage_permission_granted_on_request));

View File

@ -52,7 +52,7 @@ public class TermuxApplication extends Application {
boolean isTermuxFilesDirectoryAccessible = error == null;
if (isTermuxFilesDirectoryAccessible) {
Logger.logInfo(LOG_TAG, "Termux files directory is accessible");
/*
error = TermuxFileUtils.isAppsTermuxAppDirectoryAccessible(true, true);
if (error != null) {
Logger.logErrorExtended(LOG_TAG, "Create apps/termux-app directory failed\n" + error);
@ -61,7 +61,6 @@ public class TermuxApplication extends Application {
// Setup termux-am-socket server
TermuxAmSocketServer.setupTermuxAmSocketServer(context);
*/
} else {
Logger.logErrorExtended(LOG_TAG, "Termux files directory is not accessible\n" + error);
}

View File

@ -10,12 +10,8 @@ import android.system.Os;
import android.util.Pair;
import android.view.WindowManager;
import com.termux.BuildConfig;
import com.termux.R;
import com.termux.shared.file.FileUtils;
import com.termux.shared.shell.command.ExecutionCommand;
import com.termux.shared.shell.command.runner.app.AppShell;
import com.termux.shared.termux.TermuxBootstrap;
import com.termux.shared.termux.crash.TermuxCrashUtils;
import com.termux.shared.termux.file.TermuxFileUtils;
import com.termux.shared.interact.MessageDialogUtils;
@ -106,12 +102,6 @@ final class TermuxInstaller {
return;
}
if (!checkIfMinOrMaxSdkVersionIsIncompatible(activity,
BuildConfig.TERMUX_APP__BOOTSTRAP_MIN_SDK, BuildConfig.TERMUX_APP__BOOTSTRAP_MIN_RELEASE,
BuildConfig.TERMUX_APP__BOOTSTRAP_MAX_SDK, BuildConfig.TERMUX_APP__BOOTSTRAP_MAX_RELEASE)) {
return;
}
// If prefix directory exists, even if its a symlink to a valid directory and symlink is not broken/dangling
if (FileUtils.directoryFileExists(TERMUX_PREFIX_DIR_PATH, true)) {
if (TermuxFileUtils.isTermuxPrefixDirectoryEmpty()) {
@ -205,8 +195,7 @@ final class TermuxInstaller {
outStream.write(buffer, 0, readBytes);
}
if (zipEntryName.startsWith("bin/") || zipEntryName.startsWith("libexec") ||
zipEntryName.startsWith("lib/apt/apt-helper") || zipEntryName.startsWith("lib/apt/methods") ||
zipEntryName.equals("etc/termux/bootstrap/termux-bootstrap-second-stage.sh")) {
zipEntryName.startsWith("lib/apt/apt-helper") || zipEntryName.startsWith("lib/apt/methods")) {
//noinspection OctalInteger
Os.chmod(targetFile.getAbsolutePath(), 0700);
}
@ -227,35 +216,6 @@ final class TermuxInstaller {
throw new RuntimeException("Moving termux prefix staging to prefix directory failed");
}
// Run Termux bootstrap second stage.
String termuxBootstrapSecondStageFile = TERMUX_PREFIX_DIR_PATH + "/etc/termux/bootstrap/termux-bootstrap-second-stage.sh";
if (!FileUtils.fileExists(termuxBootstrapSecondStageFile, false)) {
Logger.logInfo(LOG_TAG, "Not running Termux bootstrap second stage since script not found at \"" + termuxBootstrapSecondStageFile + "\" path.");
} else {
if (!FileUtils.fileExists(TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH + "/bash", true)) {
Logger.logInfo(LOG_TAG, "Not running Termux bootstrap second stage since bash not found.");
}
Logger.logInfo(LOG_TAG, "Running Termux bootstrap second stage.");
ExecutionCommand executionCommand = new ExecutionCommand(-1,
termuxBootstrapSecondStageFile, null, null,
null, ExecutionCommand.Runner.APP_SHELL.getName(), false);
executionCommand.commandLabel = "Termux Bootstrap Second Stage Command";
executionCommand.backgroundCustomLogLevel = Logger.LOG_LEVEL_NORMAL;
AppShell appShell = AppShell.execute(activity, executionCommand, null, new TermuxShellEnvironment(), null, true);
if (appShell == null || !executionCommand.isSuccessful() || executionCommand.resultData.exitCode != 0) {
// Generate debug report before deleting broken prefix directory to get `stat` info at time of failure.
showBootstrapErrorDialog(activity, whenDone, MarkdownUtils.getMarkdownCodeForString(executionCommand.toString(), true));
// Delete prefix directory as otherwise when app is restarted, the broken prefix directory would be used and logged into.
Logger.logInfo(LOG_TAG, "Deleting broken termux prefix.");
error = FileUtils.deleteFile("termux prefix directory", TERMUX_PREFIX_DIR_PATH, true);
if (error != null)
Logger.logErrorExtended(LOG_TAG, error.toString());
return;
}
}
Logger.logInfo(LOG_TAG, "Bootstrap packages installed successfully.");
// Recreate env file since termux prefix was wiped earlier
@ -279,42 +239,6 @@ final class TermuxInstaller {
}.start();
}
public static boolean checkIfMinOrMaxSdkVersionIsIncompatible(Activity activity,
Integer minSdk, String minRelease,
Integer maxSdk, String maxRelease) {
if (minSdk != null && Build.VERSION.SDK_INT < minSdk) {
String bootstrapErrorMessage = activity.getString(R.string.bootstrap_error_apk_bootstrap_variant_min_sdk_incompatible,
MarkdownUtils.getMarkdownCodeForString(TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT.getName(), false),
MarkdownUtils.getMarkdownCodeForString(Build.VERSION.RELEASE, false),
Build.VERSION.SDK_INT,
MarkdownUtils.getMarkdownCodeForString(minRelease, false),
minSdk);
Logger.logError(LOG_TAG, bootstrapErrorMessage);
sendBootstrapCrashReportNotification(activity, bootstrapErrorMessage);
MessageDialogUtils.exitAppWithErrorMessage(activity,
activity.getString(R.string.bootstrap_error_title),
bootstrapErrorMessage);
return false;
}
if (maxSdk != null && Build.VERSION.SDK_INT > maxSdk) {
String bootstrapErrorMessage = activity.getString(R.string.bootstrap_error_apk_bootstrap_variant_max_sdk_incompatible,
MarkdownUtils.getMarkdownCodeForString(TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT.getName(), false),
MarkdownUtils.getMarkdownCodeForString(Build.VERSION.RELEASE, false),
Build.VERSION.SDK_INT,
MarkdownUtils.getMarkdownCodeForString(maxRelease, false),
maxSdk);
Logger.logError(LOG_TAG, bootstrapErrorMessage);
sendBootstrapCrashReportNotification(activity, bootstrapErrorMessage);
MessageDialogUtils.exitAppWithErrorMessage(activity,
activity.getString(R.string.bootstrap_error_title),
bootstrapErrorMessage);
return false;
}
return true;
}
public static void showBootstrapErrorDialog(Activity activity, Runnable whenDone, String message) {
Logger.logErrorExtended(LOG_TAG, "Bootstrap Error:\n" + message);

View File

@ -35,7 +35,6 @@ public final class HelpActivity extends AppCompatActivity {
mWebView = new WebView(this);
WebSettings settings = mWebView.getSettings();
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setAppCacheEnabled(false);
setContentView(progressLayout);
mWebView.clearCache(true);

View File

@ -271,7 +271,7 @@ public class TermuxTerminalSessionActivityClient extends TermuxTerminalSessionCl
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).build()).build();
try {
mBellSoundId = mBellSoundPool.load(mActivity, R.raw.bell, 1);
mBellSoundId = mBellSoundPool.load(mActivity, com.termux.shared.R.raw.bell, 1);
} catch (Exception e){
// Catch java.lang.RuntimeException: Unable to resume activity {com.termux/com.termux.app.TermuxActivity}: android.content.res.Resources$NotFoundException: File res/raw/bell.ogg from drawable resource ID
Logger.logStackTraceWithMessage(LOG_TAG, "Failed to load bell sound pool", e);

View File

@ -735,8 +735,8 @@ public class TermuxTerminalViewClient extends TermuxTerminalViewClientBase {
MessageDialogUtils.showMessage(mActivity, TermuxConstants.TERMUX_APP_NAME + " Report Issue",
mActivity.getString(R.string.msg_add_termux_debug_info),
mActivity.getString(R.string.action_yes), (dialog, which) -> reportIssueFromTranscript(transcriptText, true),
mActivity.getString(R.string.action_no), (dialog, which) -> reportIssueFromTranscript(transcriptText, false),
mActivity.getString(com.termux.shared.R.string.action_yes), (dialog, which) -> reportIssueFromTranscript(transcriptText, true),
mActivity.getString(com.termux.shared.R.string.action_no), (dialog, which) -> reportIssueFromTranscript(transcriptText, false),
null);
}

View File

@ -27,18 +27,10 @@
<!-- Termux Bootstrap Packages Installation -->
<string name="bootstrap_installer_body">Installing bootstrap packages…</string>
<string name="bootstrap_error_title">&TERMUX_APP_NAME; Bootstrap Error</string>
<string name="bootstrap_error_title">Unable to install bootstrap</string>
<string name="bootstrap_error_body">&TERMUX_APP_NAME; was unable to install the bootstrap packages.</string>
<string name="bootstrap_error_abort">Abort</string>
<string name="bootstrap_error_try_again">Try again</string>
<string name="bootstrap_error_apk_bootstrap_variant_min_sdk_incompatible">The APK bootstrap variant %1$s
of currently installed &TERMUX_APP_NAME; app is not compatible with the Android version %2$s
(sdk `%3$d`) of the device and it requires minimum Android version %4$s (sdk `%5$d`).
\n\nUninstall the &TERMUX_APP_NAME; app and reinstall the correct APK build variant.</string>
<string name="bootstrap_error_apk_bootstrap_variant_max_sdk_incompatible">The APK bootstrap variant %1$s
of currently installed &TERMUX_APP_NAME; app is not compatible with the Android version %2$s
(sdk `%3$d`) of the device and it requires maximum Android version %4$s (sdk `%5$d`).
\n\nUninstall the &TERMUX_APP_NAME; app and reinstall the correct APK build variant.</string>
<string name="bootstrap_error_not_primary_user_message">&TERMUX_APP_NAME; can only be run as the primary user.
\nBootstrap binaries compiled for &TERMUX_APP_NAME; have hardcoded $PREFIX path and cannot be installed
under any path other than:\n%1$s.</string>

View File

@ -4,7 +4,7 @@ buildscript {
google()
}
dependencies {
classpath "com.android.tools.build:gradle:4.2.2"
classpath "com.android.tools.build:gradle:8.13.2"
}
}
@ -15,7 +15,3 @@ allprojects {
maven { url "https://jitpack.io" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -22,8 +22,7 @@ android.useAndroidX=true
minSdkVersion=21
targetSdkVersion=28
ndkVersion=22.1.7171670
compileSdkVersion=30
ndkVersion=29.0.14206865
compileSdkVersion=36
markwonVersion=4.6.2

Binary file not shown.

View File

@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

295
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -15,81 +15,114 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -98,88 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

40
gradlew.bat vendored
View File

@ -13,8 +13,10 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@ -25,7 +27,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -56,32 +59,33 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@ -1,2 +1,4 @@
jdk:
- openjdk17
env:
JITPACK_NDK_VERSION: "21.1.6352462"
JITPACK_NDK_VERSION: "29.0.14206865"

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -2,6 +2,8 @@ apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
android {
namespace "com.termux.emulator"
compileSdkVersion project.properties.compileSdkVersion.toInteger()
ndkVersion = System.getenv("JITPACK_NDK_VERSION") ?: project.properties.ndkVersion
@ -50,13 +52,13 @@ tasks.withType(Test) {
}
dependencies {
implementation "androidx.annotation:annotation:1.3.0"
implementation "androidx.annotation:annotation:1.9.0"
testImplementation "junit:junit:4.13.2"
}
task sourceJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier "sources"
archiveClassifier = "sources"
}
afterEvaluate {
@ -64,7 +66,7 @@ afterEvaluate {
publications {
// Creates a Maven publication called "release".
release(MavenPublication) {
from components.release
from components.findByName('release')
groupId = 'com.termux'
artifactId = 'terminal-emulator'
version = '0.118.0'

View File

@ -1,2 +1,2 @@
<manifest package="com.termux.terminal">
<manifest>
</manifest>

View File

@ -2,10 +2,11 @@ apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
android {
namespace "com.termux.view"
compileSdkVersion project.properties.compileSdkVersion.toInteger()
dependencies {
implementation "androidx.annotation:annotation:1.3.0"
implementation "androidx.annotation:annotation:1.9.0"
api project(":terminal-emulator")
}
@ -34,7 +35,7 @@ dependencies {
task sourceJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier "sources"
archiveClassifier = "sources"
}
afterEvaluate {
@ -42,7 +43,7 @@ afterEvaluate {
publications {
// Creates a Maven publication called "release".
release(MavenPublication) {
from components.release
from components.findByName('release')
groupId = 'com.termux'
artifactId = 'terminal-view'
version = '0.118.0'
@ -51,3 +52,4 @@ afterEvaluate {
}
}
}

View File

@ -1,2 +1,2 @@
<manifest package="com.termux.view">
<manifest>
</manifest>

View File

@ -2,23 +2,24 @@ apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
android {
namespace = "com.termux.shared"
compileSdkVersion project.properties.compileSdkVersion.toInteger()
ndkVersion = System.getenv("JITPACK_NDK_VERSION") ?: project.properties.ndkVersion
dependencies {
implementation "androidx.appcompat:appcompat:1.3.1"
implementation "androidx.annotation:annotation:1.3.0"
implementation "androidx.core:core:1.6.0"
implementation "com.google.android.material:material:1.4.0"
implementation "androidx.appcompat:appcompat:1.6.1"
implementation "androidx.annotation:annotation:1.9.0"
implementation "androidx.core:core:1.13.1"
implementation "com.google.android.material:material:1.12.0"
implementation "com.google.guava:guava:24.1-jre"
implementation "io.noties.markwon:core:$markwonVersion"
implementation "io.noties.markwon:ext-strikethrough:$markwonVersion"
implementation "io.noties.markwon:linkify:$markwonVersion"
implementation "io.noties.markwon:recycler:$markwonVersion"
implementation "org.lsposed.hiddenapibypass:hiddenapibypass:5.0"
implementation "org.lsposed.hiddenapibypass:hiddenapibypass:6.1"
// Do not increment version higher than 1.0.0-alpha09 since it will break ViewUtils and needs to be looked into
// noinspection GradleDependency
implementation "androidx.window:window:1.0.0-alpha09"
implementation "androidx.window:window:1.1.0"
// Do not increment version higher than 2.5 or there
// will be runtime exceptions on android < 8
@ -31,6 +32,7 @@ android {
}
defaultConfig {
compileSdkVersion project.properties.compileSdkVersion.toInteger()
minSdkVersion project.properties.minSdkVersion.toInteger()
targetSdkVersion project.properties.targetSdkVersion.toInteger()
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -55,6 +57,7 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
externalNativeBuild {
ndkBuild {
path file('src/main/cpp/Android.mk')
@ -64,14 +67,13 @@ android {
dependencies {
testImplementation "junit:junit:4.13.2"
androidTestImplementation "androidx.test.ext:junit:1.1.3"
androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
androidTestImplementation "androidx.test.ext:junit:1.1.5"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.2"
}
task sourceJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier "sources"
archiveClassifier = "sources"
}
afterEvaluate {
@ -79,7 +81,7 @@ afterEvaluate {
publications {
// Creates a Maven publication called "release".
release(MavenPublication) {
from components.release
from components.findByName('release')
groupId = 'com.termux'
artifactId = 'termux-shared'
version = '0.118.0'

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.termux.shared">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.VIBRATE" />
</manifest>

View File

@ -5,8 +5,6 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.system.Os;
import android.system.OsConstants;
import androidx.annotation.NonNull;
@ -160,19 +158,7 @@ public class AndroidUtils {
appendPropertyToMarkdown(markdownString, "BOARD", Build.BOARD);
appendPropertyToMarkdown(markdownString, "HARDWARE", Build.HARDWARE);
appendPropertyToMarkdown(markdownString, "DEVICE", Build.DEVICE);
appendPropertyToMarkdown(markdownString, "SUPPORTED_ABIS", Joiner.on(", ").skipNulls().join(Build.SUPPORTED_ABIS));
appendPropertyToMarkdown(markdownString, "SUPPORTED_32_BIT_ABIS", Joiner.on(", ").skipNulls().join(Build.SUPPORTED_32_BIT_ABIS));
appendPropertyToMarkdown(markdownString, "SUPPORTED_64_BIT_ABIS", Joiner.on(", ").skipNulls().join(Build.SUPPORTED_64_BIT_ABIS));
// If on Android >= 15
if (Build.VERSION.SDK_INT >= 35) {
try {
appendPropertyToMarkdownIfSet(markdownString, "PAGE_SIZE", Os.sysconf(OsConstants._SC_PAGESIZE));
} catch (Throwable t) {
// Ignore
}
}
markdownString.append("\n##\n");

View File

@ -209,44 +209,31 @@ public class PermissionUtils {
/** If path is under primary external storage directory and storage permission is missing,
* then legacy or manage external storage permission will be requested from the user via a call
* to {@link #checkAndRequestLegacyOrManageExternalStoragePermission(Context, int, boolean, boolean)}.
* to {@link #checkAndRequestLegacyOrManageExternalStoragePermission(Context, int, boolean)}.
*
* @param context The context for operations.
* @param filePath The path to check.
* @param requestCode The request code to use while asking for permission.
* @param prioritizeManageExternalStoragePermission If {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* permission should be requested if on
* Android `>= 11` instead of getting legacy
* storage permission.
* @param showErrorMessage If an error message toast should be shown if permission is not granted.
* @return Returns {@code true} if permission is granted, otherwise {@code false}.
*/
@SuppressLint("SdCardPath")
public static boolean checkAndRequestLegacyOrManageExternalStoragePermissionIfPathOnPrimaryExternalStorage(
@NonNull Context context, String filePath, int requestCode,
boolean prioritizeManageExternalStoragePermission, boolean showErrorMessage) {
@NonNull Context context, String filePath, int requestCode, boolean showErrorMessage) {
// If path is under primary external storage directory, then check for missing permissions.
if (!FileUtils.isPathInDirPaths(filePath,
Arrays.asList(Environment.getExternalStorageDirectory().getAbsolutePath(), "/sdcard"), true))
return true;
return checkAndRequestLegacyOrManageExternalStoragePermission(context, requestCode, prioritizeManageExternalStoragePermission, showErrorMessage);
return checkAndRequestLegacyOrManageExternalStoragePermission(context, requestCode, showErrorMessage);
}
/**
* Check if legacy or manage external storage permissions has been granted.
*
* - If `prioritizeManageExternalStoragePermission` is `true and running on Android `>= 11`, then
* it will be checked if app has been granted the
* {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE}.
* - If `prioritizeManageExternalStoragePermission` is `false` and running on Android `>= 11`, then
* if {@link #isLegacyExternalStoragePossible(Context)} returns `true`, them it will be
* checked if app has has been granted {@link Manifest.permission#READ_EXTERNAL_STORAGE} and
* {@link Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions, otherwise it will be checked
* if app has been granted the {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission.
* - If running on Android `< 11`, then it will only be checked if app has been granted
* {@link Manifest.permission#READ_EXTERNAL_STORAGE} and
* {@link Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions.
* Check if legacy or manage external storage permissions has been granted. If
* {@link #isLegacyExternalStoragePossible(Context)} returns {@code true}, them it will be
* checked if app has has been granted {@link Manifest.permission#READ_EXTERNAL_STORAGE} and
* {@link Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions, otherwise it will be checked
* if app has been granted the {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission.
*
* If storage permission is missing, it will be requested from the user if {@code context} is an
* instance of {@link Activity} or {@link AppCompatActivity} and {@code requestCode}
@ -269,34 +256,16 @@ public class PermissionUtils {
*}
* @param context The context for operations.
* @param requestCode The request code to use while asking for permission.
* @param prioritizeManageExternalStoragePermission If {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* permission should be requested if on
* Android `>= 11` instead of getting legacy
* storage permission.
* @param showErrorMessage If an error message toast should be shown if permission is not granted.
* @return Returns {@code true} if permission is granted, otherwise {@code false}.
*/
public static boolean checkAndRequestLegacyOrManageExternalStoragePermission(@NonNull Context context,
int requestCode,
boolean prioritizeManageExternalStoragePermission,
boolean showErrorMessage) {
Logger.logVerbose(LOG_TAG, "Checking storage permission");
String errmsg;
Boolean requestLegacyStoragePermission = null;
if (prioritizeManageExternalStoragePermission && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
requestLegacyStoragePermission = false;
if (requestLegacyStoragePermission == null)
requestLegacyStoragePermission = isLegacyExternalStoragePossible(context);
boolean requestLegacyStoragePermission = isLegacyExternalStoragePossible(context);
boolean checkIfHasRequestedLegacyExternalStorage = checkIfHasRequestedLegacyExternalStorage(context);
Logger.logVerbose(LOG_TAG, "prioritizeManageExternalStoragePermission=" + prioritizeManageExternalStoragePermission +
", requestLegacyStoragePermission=" + requestLegacyStoragePermission +
", checkIfHasRequestedLegacyExternalStorage=" + checkIfHasRequestedLegacyExternalStorage);
if (requestLegacyStoragePermission && checkIfHasRequestedLegacyExternalStorage) {
// Check if requestLegacyExternalStorage is set to true in app manifest
if (!hasRequestedLegacyExternalStorage(context, showErrorMessage))

View File

@ -51,7 +51,7 @@ public class MessageDialogUtils {
final DialogInterface.OnClickListener onNegativeButton,
final DialogInterface.OnDismissListener onDismiss) {
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.Theme_AppCompat_Light_Dialog);
AlertDialog.Builder builder = new AlertDialog.Builder(context, androidx.appcompat.R.style.Theme_AppCompat_Light_Dialog);
LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View view = inflater.inflate(R.layout.dialog_show_message, null);

View File

@ -1,5 +1,7 @@
package com.termux.shared.models;
import androidx.annotation.Keep;
import com.termux.shared.markdown.MarkdownUtils;
import com.termux.shared.android.AndroidUtils;
@ -10,6 +12,25 @@ import java.io.Serializable;
*/
public class ReportInfo implements Serializable {
/**
* Explicitly define `serialVersionUID` to prevent exceptions on deserialization.
*
* Like when calling `Bundle.getSerializable()` on Android.
* `android.os.BadParcelableException: Parcelable encountered IOException reading a Serializable object` (name = <class_name>)
* `java.io.InvalidClassException: <class_name>; local class incompatible`
*
* The `@Keep` annotation is necessary to prevent the field from being removed by proguard when
* app is compiled, even if its kept during library compilation.
*
* **See Also:**
* - https://docs.oracle.com/javase/8/docs/platform/serialization/spec/version.html#a6678
* - https://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100
*/
@Keep
private static final long serialVersionUID = 1L;
/** The user action that was being processed for which the report was generated. */
public final String userAction;
/** The internal app component that sent the report. */

View File

@ -3,6 +3,7 @@ package com.termux.shared.models;
import android.graphics.Color;
import android.graphics.Typeface;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import com.termux.shared.activities.TextIOActivity;
@ -19,6 +20,25 @@ import java.io.Serializable;
*/
public class TextIOInfo implements Serializable {
/**
* Explicitly define `serialVersionUID` to prevent exceptions on deserialization.
*
* Like when calling `Bundle.getSerializable()` on Android.
* `android.os.BadParcelableException: Parcelable encountered IOException reading a Serializable object` (name = <class_name>)
* `java.io.InvalidClassException: <class_name>; local class incompatible`
*
* The `@Keep` annotation is necessary to prevent the field from being removed by proguard when
* app is compiled, even if its kept during library compilation.
*
* **See Also:**
* - https://docs.oracle.com/javase/8/docs/platform/serialization/spec/version.html#a6678
* - https://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100
*/
@Keep
private static final long serialVersionUID = 1L;
public static final int GENERAL_DATA_SIZE_LIMIT_IN_BYTES = 1000;
public static final int LABEL_SIZE_LIMIT_IN_BYTES = 4000;
public static final int TEXT_SIZE_LIMIT_IN_BYTES = 100000 - GENERAL_DATA_SIZE_LIMIT_IN_BYTES - LABEL_SIZE_LIMIT_IN_BYTES; // < 100KB

View File

@ -1,7 +1,6 @@
package com.termux.shared.shell.command.environment;
import android.content.Context;
import android.os.Build;
import androidx.annotation.NonNull;
@ -21,20 +20,6 @@ import java.util.HashMap;
*/
public class AndroidShellEnvironment extends UnixShellEnvironment {
/** Environment variable scope for Android. */
public static final String ANDROID_ENV_SCOPE = "ANDROID__"; // Default: "ANDROID__"
/**
* Environment variable for the Android build SDK version currently running on the device that
* is defined by {@link Build.VERSION#SDK_INT} and `ro.build.version.sdk` system property.
*
* - https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT
* - https://developer.android.com/reference/android/os/Build.VERSION_CODES
*
* Default value: `ANDROID__BUILD_VERSION_SDK`
*/
public static final String ENV_ANDROID__BUILD_VERSION_SDK = ANDROID_ENV_SCOPE + "BUILD_VERSION_SDK";
protected ShellCommandShellEnvironment shellCommandShellEnvironment;
public AndroidShellEnvironment() {
@ -76,8 +61,6 @@ public class AndroidShellEnvironment extends UnixShellEnvironment {
ShellEnvironmentUtils.putToEnvIfInSystemEnv(environment, "DEX2OATBOOTCLASSPATH");
ShellEnvironmentUtils.putToEnvIfInSystemEnv(environment, "SYSTEMSERVERCLASSPATH");
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_ANDROID__BUILD_VERSION_SDK, String.valueOf(Build.VERSION.SDK_INT));
return environment;
}

View File

@ -33,13 +33,13 @@ public class ShellCommandShellEnvironment {
public static final String ENV_SHELL_CMD__APP_SHELL_NUMBER_SINCE_BOOT = SHELL_CMD_ENV_PREFIX + "APP_SHELL_NUMBER_SINCE_BOOT";
/** Environment variable for the {{@link ExecutionCommand.Runner#TERMINAL_SESSION} number since boot. */
public static final String ENV_SHELL_CMD__APP_TERMINAL_SESSION_NUMBER_SINCE_BOOT = SHELL_CMD_ENV_PREFIX + "APP_TERMINAL_SESSION_NUMBER_SINCE_BOOT";
public static final String ENV_SHELL_CMD__TERMINAL_SESSION_NUMBER_SINCE_BOOT = SHELL_CMD_ENV_PREFIX + "TERMINAL_SESSION_NUMBER_SINCE_BOOT";
/** Environment variable for the {@link ExecutionCommand.Runner#APP_SHELL} number since app start. */
public static final String ENV_SHELL_CMD__APP_SHELL_NUMBER_SINCE_APP_START = SHELL_CMD_ENV_PREFIX + "APP_SHELL_NUMBER_SINCE_APP_START";
/** Environment variable for the {@link ExecutionCommand.Runner#TERMINAL_SESSION} number since app start. */
public static final String ENV_SHELL_CMD__APP_TERMINAL_SESSION_NUMBER_SINCE_APP_START = SHELL_CMD_ENV_PREFIX + "APP_TERMINAL_SESSION_NUMBER_SINCE_APP_START";
public static final String ENV_SHELL_CMD__TERMINAL_SESSION_NUMBER_SINCE_APP_START = SHELL_CMD_ENV_PREFIX + "TERMINAL_SESSION_NUMBER_SINCE_APP_START";
/** Get shell environment containing info for {@link ExecutionCommand}. */

View File

@ -326,7 +326,7 @@ public final class TermuxPropertyConstants {
/** Defines the key for extra keys */
public static final String KEY_EXTRA_KEYS = "extra-keys"; // Default: "extra-keys"
//public static final String DEFAULT_IVALUE_EXTRA_KEYS = "[[ESC, TAB, CTRL, ALT, {key: '-', popup: '|'}, DOWN, UP]]"; // Single row
public static final String DEFAULT_IVALUE_EXTRA_KEYS = "[['ESC',{key: 'DRAWER', popup: 'PASTE'},'SCROLL','HOME','UP','END','PGUP'], ['TAB','CTRL','ALT','LEFT','DOWN','RIGHT','PGDN']]"; // Double row
public static final String DEFAULT_IVALUE_EXTRA_KEYS = "[['ESC','/',{key: '-', popup: '|'},'HOME','UP','END','PGUP'], ['TAB','CTRL','ALT','LEFT','DOWN','RIGHT','PGDN']]"; // Double row
/** Defines the key for extra keys style */
public static final String KEY_EXTRA_KEYS_STYLE = "extra-keys-style"; // Default: "extra-keys-style"

View File

@ -27,12 +27,6 @@ public class TermuxAppShellEnvironment {
/** Termux app environment variables. */
public static HashMap<String, String> termuxAppEnvironment;
/** Environment variable root scope. */
public static final String TERMUX_ENV__S_ROOT = "TERMUX_"; // Default: "TERMUX_"
/** Environment variable scope for Termux. */
public static final String TERMUX_ENV__S_TERMUX = TERMUX_ENV__S_ROOT + "_"; // Default: "TERMUX__"
/** Environment variable for the Termux app version. */
public static final String ENV_TERMUX_VERSION = TermuxConstants.TERMUX_ENV_PREFIX_ROOT + "_VERSION";
@ -40,15 +34,15 @@ public class TermuxAppShellEnvironment {
public static final String TERMUX_APP_ENV_PREFIX = TermuxConstants.TERMUX_ENV_PREFIX_ROOT + "_APP__";
/** Environment variable for the Termux app version name. */
public static final String ENV_TERMUX_APP__APP_VERSION_NAME = TERMUX_APP_ENV_PREFIX + "APP_VERSION_NAME";
public static final String ENV_TERMUX_APP__VERSION_NAME = TERMUX_APP_ENV_PREFIX + "VERSION_NAME";
/** Environment variable for the Termux app version code. */
public static final String ENV_TERMUX_APP__APP_VERSION_CODE = TERMUX_APP_ENV_PREFIX + "APP_VERSION_CODE";
public static final String ENV_TERMUX_APP__VERSION_CODE = TERMUX_APP_ENV_PREFIX + "VERSION_CODE";
/** Environment variable for the Termux app package name. */
public static final String ENV_TERMUX_APP__PACKAGE_NAME = TERMUX_APP_ENV_PREFIX + "PACKAGE_NAME";
/** Environment variable for the Termux app process id. */
public static final String ENV_TERMUX_APP__PID = TERMUX_APP_ENV_PREFIX + "PID";
/** Environment variable for the Termux app uid. */
public static final String ENV_TERMUX__UID = TERMUX_ENV__S_TERMUX + "UID";
public static final String ENV_TERMUX_APP__UID = TERMUX_APP_ENV_PREFIX + "UID";
/** Environment variable for the Termux app targetSdkVersion. */
public static final String ENV_TERMUX_APP__TARGET_SDK = TERMUX_APP_ENV_PREFIX + "TARGET_SDK";
/** Environment variable for the Termux app is debuggable apk build. */
@ -56,29 +50,28 @@ public class TermuxAppShellEnvironment {
/** Environment variable for the Termux app {@link TermuxConstants} APK_RELEASE_*. */
public static final String ENV_TERMUX_APP__APK_RELEASE = TERMUX_APP_ENV_PREFIX + "APK_RELEASE";
/** Environment variable for the Termux app install path. */
public static final String ENV_TERMUX_APP__APK_FILE = TERMUX_APP_ENV_PREFIX + "APK_FILE";
public static final String ENV_TERMUX_APP__APK_PATH = TERMUX_APP_ENV_PREFIX + "APK_PATH";
/** Environment variable for the Termux app is installed on external/portable storage. */
public static final String ENV_TERMUX_APP__IS_INSTALLED_ON_EXTERNAL_STORAGE = TERMUX_APP_ENV_PREFIX + "IS_INSTALLED_ON_EXTERNAL_STORAGE";
/** Environment variable for the Termux app process selinux context. */
public static final String ENV_TERMUX_APP__SE_PROCESS_CONTEXT = TERMUX_APP_ENV_PREFIX + "SE_PROCESS_CONTEXT";
/** Environment variable for the Termux app data files selinux context. */
public static final String ENV_TERMUX_APP__SE_FILE_CONTEXT = TERMUX_APP_ENV_PREFIX + "SE_FILE_CONTEXT";
/** Environment variable for the Termux app seInfo tag found in selinux policy used to set app process and app data files selinux context. */
public static final String ENV_TERMUX_APP__SE_INFO = TERMUX_APP_ENV_PREFIX + "SE_INFO";
/** Environment variable for the current Termux process selinux context. */
public static final String ENV_TERMUX__SE_PROCESS_CONTEXT = TERMUX_ENV__S_TERMUX + "SE_PROCESS_CONTEXT";
/** Environment variable for the Termux app user id. */
public static final String ENV_TERMUX__USER_ID = TERMUX_ENV__S_TERMUX + "USER_ID";
public static final String ENV_TERMUX_APP__USER_ID = TERMUX_APP_ENV_PREFIX + "USER_ID";
/** Environment variable for the Termux app profile owner. */
public static final String ENV_TERMUX__PROFILE_OWNER = TERMUX_ENV__S_TERMUX + "PROFILE_OWNER";
public static final String ENV_TERMUX_APP__PROFILE_OWNER = TERMUX_APP_ENV_PREFIX + "PROFILE_OWNER";
/** Environment variable for the Termux app {@link TermuxBootstrap#TERMUX_APP_PACKAGE_MANAGER}. */
public static final String ENV_TERMUX_APP__PACKAGE_MANAGER = TERMUX_APP_ENV_PREFIX + "PACKAGE_MANAGER";
/** Environment variable for the Termux app {@link TermuxBootstrap#TERMUX_APP_PACKAGE_VARIANT}. */
public static final String ENV_TERMUX_APP__PACKAGE_VARIANT = TERMUX_APP_ENV_PREFIX + "PACKAGE_VARIANT";
/** Environment variable for the Termux app files directory. */
public static final String ENV_TERMUX_APP__DATA_DIR = TERMUX_APP_ENV_PREFIX + "DATA_DIR";
public static final String ENV_TERMUX_APP__LEGACY_DATA_DIR = TERMUX_APP_ENV_PREFIX + "LEGACY_DATA_DIR";
public static final String ENV_TERMUX_APP__BUILD_DATA_DIR = TERMUX_APP_ENV_PREFIX + "BUILD_DATA_DIR";
public static final String ENV_TERMUX_APP__FILES_DIR = TERMUX_APP_ENV_PREFIX + "FILES_DIR";
/** Environment variable for the Termux app {@link TermuxAmSocketServer#getTermuxAppAMSocketServerEnabled(Context)}. */
public static final String ENV_TERMUX_APP__AM_SOCKET_SERVER_ENABLED = TERMUX_APP_ENV_PREFIX + "AM_SOCKET_SERVER_ENABLED";
@ -112,22 +105,21 @@ public class TermuxAppShellEnvironment {
HashMap<String, String> environment = new HashMap<>();
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_VERSION, PackageUtils.getVersionNameForPackage(packageInfo));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__APP_VERSION_NAME, PackageUtils.getVersionNameForPackage(packageInfo));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__APP_VERSION_CODE, String.valueOf(PackageUtils.getVersionCodeForPackage(packageInfo)));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__VERSION_NAME, PackageUtils.getVersionNameForPackage(packageInfo));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__VERSION_CODE, String.valueOf(PackageUtils.getVersionCodeForPackage(packageInfo)));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__PACKAGE_NAME, packageName);
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__PID, TermuxUtils.getTermuxAppPID(currentPackageContext));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX__UID, String.valueOf(PackageUtils.getUidForPackage(applicationInfo)));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__UID, String.valueOf(PackageUtils.getUidForPackage(applicationInfo)));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__TARGET_SDK, String.valueOf(PackageUtils.getTargetSDKForPackage(applicationInfo)));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__IS_DEBUGGABLE_BUILD, PackageUtils.isAppForPackageADebuggableBuild(applicationInfo));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__APK_FILE, PackageUtils.getBaseAPKPathForPackage(applicationInfo));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__APK_PATH, PackageUtils.getBaseAPKPathForPackage(applicationInfo));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__IS_INSTALLED_ON_EXTERNAL_STORAGE, PackageUtils.isAppInstalledOnExternalStorage(applicationInfo));
putTermuxAPKSignature(currentPackageContext, environment);
Context termuxPackageContext = TermuxUtils.getTermuxPackageContext(currentPackageContext);
if (termuxPackageContext != null) {
/*
// An app that does not have the same sharedUserId as termux app will not be able to get
// get termux context's classloader to get BuildConfig.TERMUX_PACKAGE_VARIANT via reflection.
// Check TermuxBootstrap.setTermuxPackageManagerAndVariantFromTermuxApp()
@ -135,28 +127,24 @@ public class TermuxAppShellEnvironment {
environment.put(ENV_TERMUX_APP__PACKAGE_MANAGER, TermuxBootstrap.TERMUX_APP_PACKAGE_MANAGER.getName());
if (TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT != null)
environment.put(ENV_TERMUX_APP__PACKAGE_VARIANT, TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT.getName());
*/
/*
// Will not be set for plugins
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__AM_SOCKET_SERVER_ENABLED,
TermuxAmSocketServer.getTermuxAppAMSocketServerEnabled(currentPackageContext));
*/
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__DATA_DIR, applicationInfo.dataDir);
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__LEGACY_DATA_DIR, "/data/data/" + applicationInfo.packageName);
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__BUILD_DATA_DIR, TermuxConstants.TERMUX_INTERNAL_PRIVATE_APP_DATA_DIR_PATH);
String filesDirPath = currentPackageContext.getFilesDir().getAbsolutePath();
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__FILES_DIR, filesDirPath);
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX__SE_PROCESS_CONTEXT, SELinuxUtils.getContext());
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__SE_FILE_CONTEXT, SELinuxUtils.getFileContext(applicationInfo.dataDir));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__SE_PROCESS_CONTEXT, SELinuxUtils.getContext());
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__SE_FILE_CONTEXT, SELinuxUtils.getFileContext(filesDirPath));
String seInfoUser = PackageUtils.getApplicationInfoSeInfoUserForPackage(applicationInfo);
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__SE_INFO, PackageUtils.getApplicationInfoSeInfoForPackage(applicationInfo) +
(DataUtils.isNullOrEmpty(seInfoUser) ? "" : seInfoUser));
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX__USER_ID, String.valueOf(PackageUtils.getUserIdForPackage(currentPackageContext)));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX__PROFILE_OWNER, PackageUtils.getProfileOwnerPackageNameForUser(currentPackageContext));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__USER_ID, String.valueOf(PackageUtils.getUserIdForPackage(currentPackageContext)));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_TERMUX_APP__PROFILE_OWNER, PackageUtils.getProfileOwnerPackageNameForUser(currentPackageContext));
}
termuxAppEnvironment = environment;

View File

@ -34,9 +34,9 @@ public class TermuxShellCommandShellEnvironment extends ShellCommandShellEnviron
String.valueOf(TermuxShellManager.getAndIncrementAppShellNumberSinceAppStart()));
} else if (ExecutionCommand.Runner.TERMINAL_SESSION.equalsRunner(executionCommand.runner)) {
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_SHELL_CMD__APP_TERMINAL_SESSION_NUMBER_SINCE_BOOT,
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_SHELL_CMD__TERMINAL_SESSION_NUMBER_SINCE_BOOT,
String.valueOf(preferences.getAndIncrementTerminalSessionNumberSinceBoot()));
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_SHELL_CMD__APP_TERMINAL_SESSION_NUMBER_SINCE_APP_START,
ShellEnvironmentUtils.putToEnvIfSet(environment, ENV_SHELL_CMD__TERMINAL_SESSION_NUMBER_SINCE_APP_START,
String.valueOf(TermuxShellManager.getAndIncrementTerminalSessionNumberSinceAppStart()));
} else {
return environment;

View File

@ -1,12 +1,9 @@
package com.termux.shared.termux.shell.command.environment;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import androidx.annotation.NonNull;
import com.termux.shared.android.PackageUtils;
import com.termux.shared.errors.Error;
import com.termux.shared.file.FileUtils;
import com.termux.shared.logger.Logger;
@ -74,25 +71,12 @@ public class TermuxShellEnvironment extends AndroidShellEnvironment {
if (termuxAppEnvironment != null)
environment.putAll(termuxAppEnvironment);
/*
HashMap<String, String> termuxApiAppEnvironment = TermuxAPIShellEnvironment.getEnvironment(currentPackageContext);
if (termuxApiAppEnvironment != null)
environment.putAll(termuxApiAppEnvironment);
*/
ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoForPackage(currentPackageContext, TermuxConstants.TERMUX_PACKAGE_NAME);
if (applicationInfo != null && !applicationInfo.enabled) {
applicationInfo = null;
}
if (applicationInfo != null) {
environment.put("TERMUX__APPS_DIR", applicationInfo.dataDir + "/termux/apps");
}
environment.put("TERMUX__ROOTFS", TermuxConstants.TERMUX_FILES_DIR_PATH);
environment.put(ENV_HOME, TermuxConstants.TERMUX_HOME_DIR_PATH);
environment.put("TERMUX__HOME", TermuxConstants.TERMUX_HOME_DIR_PATH);
environment.put(ENV_PREFIX, TermuxConstants.TERMUX_PREFIX_DIR_PATH);
environment.put("TERMUX__PREFIX", TermuxConstants.TERMUX_PREFIX_DIR_PATH);
// If failsafe is not enabled, then we keep default PATH and TMPDIR so that system binaries can be used
if (!isFailSafe) {

View File

@ -185,12 +185,11 @@ public class ViewUtils {
public static Point getDisplaySize( @NonNull Context context, boolean activitySize) {
// android.view.WindowManager.getDefaultDisplay() and Display.getSize() are deprecated in
// API 30 and give wrong values in API 30 for activitySize=false in multi-window
androidx.window.WindowManager windowManager = new androidx.window.WindowManager(context);
androidx.window.WindowMetrics windowMetrics;
androidx.window.layout.WindowMetrics windowMetrics;
if (activitySize)
windowMetrics = windowManager.getCurrentWindowMetrics();
windowMetrics = androidx.window.layout.WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context);
else
windowMetrics = windowManager.getMaximumWindowMetrics();
windowMetrics = androidx.window.layout.WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(context);
return new Point(windowMetrics.getBounds().width(), windowMetrics.getBounds().height());
}