From 6213b7f7828b41ad2036431d53bf1994c770750c Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 01:49:11 +0500 Subject: [PATCH 01/19] Changed: Use double quotes instead of single quotes for all gradle dependencies --- build.gradle | 2 +- terminal-emulator/build.gradle | 4 ++-- terminal-view/build.gradle | 2 +- termux-shared/build.gradle | 10 +++++----- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index aa0981015d..80ddd4bde1 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' + classpath "com.android.tools.build:gradle:4.2.2" } } diff --git a/terminal-emulator/build.gradle b/terminal-emulator/build.gradle index f3d567b3dc..afc57e9f7e 100644 --- a/terminal-emulator/build.gradle +++ b/terminal-emulator/build.gradle @@ -50,8 +50,8 @@ tasks.withType(Test) { } dependencies { - implementation 'androidx.annotation:annotation:1.3.0' - testImplementation 'junit:junit:4.13.2' + implementation "androidx.annotation:annotation:1.3.0" + testImplementation "junit:junit:4.13.2" } task sourceJar(type: Jar) { diff --git a/terminal-view/build.gradle b/terminal-view/build.gradle index 1504f68856..d603da2880 100644 --- a/terminal-view/build.gradle +++ b/terminal-view/build.gradle @@ -29,7 +29,7 @@ android { } dependencies { - testImplementation 'junit:junit:4.13.2' + testImplementation "junit:junit:4.13.2" } task sourceJar(type: Jar) { diff --git a/termux-shared/build.gradle b/termux-shared/build.gradle index 0f3f6cf99a..6284782019 100644 --- a/termux-shared/build.gradle +++ b/termux-shared/build.gradle @@ -5,16 +5,16 @@ android { compileSdkVersion project.properties.compileSdkVersion.toInteger() dependencies { - implementation 'androidx.appcompat:appcompat:1.3.1' + 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 "com.google.android.material:material:1.4.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:2.0' + implementation "org.lsposed.hiddenapibypass:hiddenapibypass:2.0" // Do not increment version higher than 1.0.0-alpha09 since it will break ViewUtils and needs to be looked into // noinspection GradleDependency @@ -61,8 +61,8 @@ 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' + androidTestImplementation "androidx.test.ext:junit:1.1.3" + androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0" } task sourceJar(type: Jar) { From 623aaebb4a730289d61c02c8898d24e839427138 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:00:26 +0500 Subject: [PATCH 02/19] Changed: Bump down `minSdkVersion` from `24` to `21` to restart supporting android 5/6 for the time being Compatibility fixes will come in later commits. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index c8f9ae0514..fc751ab345 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ org.gradle.jvmargs=-Xmx2048M android.useAndroidX=true -minSdkVersion=24 +minSdkVersion=21 targetSdkVersion=28 ndkVersion=22.1.7171670 compileSdkVersion=30 From 9143ebdc22752c8a3ea79503a3b76f603c8f8812 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:02:26 +0500 Subject: [PATCH 03/19] Changed: Enable desugaring support to enable support for new language APIs like Java 8 on old android versions https://developer.android.com/studio/write/java8-support --- app/build.gradle | 4 ++++ termux-shared/build.gradle | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 628dae01f5..e613395c02 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -97,6 +97,9 @@ android { } compileOptions { + // Flag to enable support for the new language APIs + coreLibraryDesugaringEnabled true + sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } @@ -140,6 +143,7 @@ android { dependencies { testImplementation "junit:junit:4.13.2" testImplementation "org.robolectric:robolectric:4.4" + coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5" } task versionName { diff --git a/termux-shared/build.gradle b/termux-shared/build.gradle index 6284782019..573f547cd7 100644 --- a/termux-shared/build.gradle +++ b/termux-shared/build.gradle @@ -49,6 +49,9 @@ android { } compileOptions { + // Flag to enable support for the new language APIs + coreLibraryDesugaringEnabled true + sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } @@ -63,6 +66,7 @@ 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" } task sourceJar(type: Jar) { From a1719d91b3ef32218a0ac6553c659f3e1baab4da Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:03:14 +0500 Subject: [PATCH 04/19] Changed: Bump `termux-am-library` to 2.0.0 that uses `minSdkVersion` `21` --- termux-shared/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/termux-shared/build.gradle b/termux-shared/build.gradle index 573f547cd7..d44a8e4573 100644 --- a/termux-shared/build.gradle +++ b/termux-shared/build.gradle @@ -27,7 +27,7 @@ android { implementation project(":terminal-view") - implementation 'com.github.termux:termux-am-library:1.0' + implementation "com.termux:termux-am-library:v2.0.0" } defaultConfig { From 14e9a8b6fc10379819f7e3406692151dc8759e59 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:04:49 +0500 Subject: [PATCH 05/19] Changed: Use float dp parameter instead of int for `ViewUtils.dpToPx()` to not lose precision --- .../src/main/java/com/termux/shared/view/ViewUtils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java b/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java index e0d87345c4..d7b521981e 100644 --- a/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java @@ -216,15 +216,18 @@ public static Activity getActivity(Context context) { return null; } + /** Convert value in device independent pixels (dp) to pixels (px) units. */ - public static int dpToPx(Context context, int dp) { - return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); + public static float dpToPx(Context context, float dp) { + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); + } } public static void setLayoutMarginsInDp(@NonNull View view, int left, int top, int right, int bottom) { Context context = view.getContext(); - setLayoutMarginsInPixels(view, dpToPx(context, left), dpToPx(context, top), dpToPx(context, right), dpToPx(context, bottom)); + setLayoutMarginsInPixels(view, (int) dpToPx(context, left), (int) dpToPx(context, top), + (int) dpToPx(context, right), (int) dpToPx(context, bottom)); } public static void setLayoutMarginsInPixels(@NonNull View view, int left, int top, int right, int bottom) { From fa829623a886319b8b8aa360efde6c348279d02e Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:05:22 +0500 Subject: [PATCH 06/19] Added: Add `ViewUtils.pxToDp()` --- .../src/main/java/com/termux/shared/view/ViewUtils.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java b/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java index d7b521981e..d85b82909b 100644 --- a/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java @@ -221,6 +221,10 @@ public static Activity getActivity(Context context) { public static float dpToPx(Context context, float dp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); } + + /** Convert value in pixels (px) to device independent pixels (dp) units. */ + public static float pxToDp(Context context, float px) { + return px / context.getResources().getDisplayMetrics().density; } From 677a5800424be462a369622b823e75a88b35a40d Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:31:21 +0500 Subject: [PATCH 07/19] Changed: Add general compatibility fixes for `minSdkVerion` `21` --- app/src/main/AndroidManifest.xml | 12 ++- .../java/com/termux/app/TermuxInstaller.java | 3 +- .../java/com/termux/view/TerminalView.java | 5 +- .../support/PopupWindowCompatGingerbread.java | 75 +++++++++++++++++++ .../TextSelectionCursorController.java | 7 ++ .../TextSelectionHandleView.java | 13 +++- .../termux/shared/android/AndroidUtils.java | 9 ++- .../termux/shared/android/PackageUtils.java | 4 + .../shared/android/PermissionUtils.java | 24 +++++- .../shared/file/filesystem/UnixConstants.java | 9 ++- .../termux/shared/interact/ShareUtils.java | 3 +- .../termux/extrakeys/SpecialButtonState.java | 4 +- .../termux/terminal/io/TerminalExtraKeys.java | 14 +++- .../com/termux/shared/view/KeyboardUtils.java | 3 + .../com/termux/shared/view/ViewUtils.java | 8 +- 15 files changed, 168 insertions(+), 25 deletions(-) create mode 100644 terminal-view/src/main/java/com/termux/view/support/PopupWindowCompatGingerbread.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ca1b1e9941..4a2bc2f895 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,7 +46,8 @@ android:requestLegacyExternalStorage="true" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="false" - android:theme="@style/Theme.TermuxApp.DayNight.DarkActionBar"> + android:theme="@style/Theme.TermuxApp.DayNight.DarkActionBar" + tools:targetApi="m"> + android:theme="@style/Theme.TermuxActivity.DayNight.NoActionBar" + tools:targetApi="n"> @@ -91,7 +93,8 @@ android:exported="false" android:label="@string/application_name" android:parentActivityName=".app.TermuxActivity" - android:resizeableActivity="true" /> + android:resizeableActivity="true" + tools:targetApi="n" /> + android:taskAffinity="${TERMUX_PACKAGE_NAME}.filereceiver" + tools:targetApi="n"> diff --git a/app/src/main/java/com/termux/app/TermuxInstaller.java b/app/src/main/java/com/termux/app/TermuxInstaller.java index c3d112adb2..15f48bfd80 100644 --- a/app/src/main/java/com/termux/app/TermuxInstaller.java +++ b/app/src/main/java/com/termux/app/TermuxInstaller.java @@ -4,6 +4,7 @@ import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; +import android.os.Build; import android.os.Environment; import android.system.Os; import android.util.Pair; @@ -71,7 +72,7 @@ static void setupBootstrapIfNeeded(final Activity activity, final Runnable whenD // Termux can only be run as the primary user (device owner) since only that // account has the expected file system paths. Verify that: - if (!PackageUtils.isCurrentUserThePrimaryUser(activity)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !PackageUtils.isCurrentUserThePrimaryUser(activity)) { bootstrapErrorMessage = activity.getString(R.string.bootstrap_error_not_primary_user_message, MarkdownUtils.getMarkdownCodeForString(TERMUX_PREFIX_DIR_PATH, false)); Logger.logError(LOG_TAG, "isFilesDirectoryAccessible: " + isFilesDirectoryAccessible); Logger.logError(LOG_TAG, bootstrapErrorMessage); diff --git a/terminal-view/src/main/java/com/termux/view/TerminalView.java b/terminal-view/src/main/java/com/termux/view/TerminalView.java index 2b56d66ea6..b76ea85844 100644 --- a/terminal-view/src/main/java/com/termux/view/TerminalView.java +++ b/terminal-view/src/main/java/com/termux/view/TerminalView.java @@ -1245,6 +1245,7 @@ protected void onDetachedFromWindow() { * Define functions required for long hold toolbar. */ private final Runnable mShowFloatingToolbar = new Runnable() { + @RequiresApi(api = Build.VERSION_CODES.M) @Override public void run() { if (getTextSelectionActionMode() != null) { @@ -1253,6 +1254,7 @@ public void run() { } }; + @RequiresApi(api = Build.VERSION_CODES.M) private void showFloatingToolbar() { if (getTextSelectionActionMode() != null) { int delay = ViewConfiguration.getDoubleTapTimeout(); @@ -1260,6 +1262,7 @@ private void showFloatingToolbar() { } } + @RequiresApi(api = Build.VERSION_CODES.M) void hideFloatingToolbar() { if (getTextSelectionActionMode() != null) { removeCallbacks(mShowFloatingToolbar); @@ -1268,7 +1271,7 @@ void hideFloatingToolbar() { } public void updateFloatingToolbarVisibility(MotionEvent event) { - if (getTextSelectionActionMode() != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && getTextSelectionActionMode() != null) { switch (event.getActionMasked()) { case MotionEvent.ACTION_MOVE: hideFloatingToolbar(); diff --git a/terminal-view/src/main/java/com/termux/view/support/PopupWindowCompatGingerbread.java b/terminal-view/src/main/java/com/termux/view/support/PopupWindowCompatGingerbread.java new file mode 100644 index 0000000000..24a1797c5e --- /dev/null +++ b/terminal-view/src/main/java/com/termux/view/support/PopupWindowCompatGingerbread.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.termux.view.support; + +import android.util.Log; +import android.widget.PopupWindow; + +import java.lang.reflect.Method; + +/** + * Implementation of PopupWindow compatibility that can call Gingerbread APIs. + * https://chromium.googlesource.com/android_tools/+/HEAD/sdk/extras/android/support/v4/src/gingerbread/android/support/v4/widget/PopupWindowCompatGingerbread.java + */ +public class PopupWindowCompatGingerbread { + + private static Method sSetWindowLayoutTypeMethod; + private static boolean sSetWindowLayoutTypeMethodAttempted; + private static Method sGetWindowLayoutTypeMethod; + private static boolean sGetWindowLayoutTypeMethodAttempted; + + public static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) { + if (!sSetWindowLayoutTypeMethodAttempted) { + try { + sSetWindowLayoutTypeMethod = PopupWindow.class.getDeclaredMethod( + "setWindowLayoutType", int.class); + sSetWindowLayoutTypeMethod.setAccessible(true); + } catch (Exception e) { + // Reflection method fetch failed. Oh well. + } + sSetWindowLayoutTypeMethodAttempted = true; + } + if (sSetWindowLayoutTypeMethod != null) { + try { + sSetWindowLayoutTypeMethod.invoke(popupWindow, layoutType); + } catch (Exception e) { + // Reflection call failed. Oh well. + } + } + } + + public static int getWindowLayoutType(PopupWindow popupWindow) { + if (!sGetWindowLayoutTypeMethodAttempted) { + try { + sGetWindowLayoutTypeMethod = PopupWindow.class.getDeclaredMethod( + "getWindowLayoutType"); + sGetWindowLayoutTypeMethod.setAccessible(true); + } catch (Exception e) { + // Reflection method fetch failed. Oh well. + } + sGetWindowLayoutTypeMethodAttempted = true; + } + if (sGetWindowLayoutTypeMethod != null) { + try { + return (Integer) sGetWindowLayoutTypeMethod.invoke(popupWindow); + } catch (Exception e) { + // Reflection call failed. Oh well. + } + } + return 0; + } + +} diff --git a/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionCursorController.java b/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionCursorController.java index 2f64793a07..c08dca4470 100644 --- a/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionCursorController.java +++ b/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionCursorController.java @@ -3,6 +3,7 @@ import android.content.ClipboardManager; import android.content.Context; import android.graphics.Rect; +import android.os.Build; import android.text.TextUtils; import android.view.ActionMode; import android.view.Menu; @@ -153,6 +154,12 @@ public void onDestroyActionMode(ActionMode mode) { }; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + mActionMode = terminalView.startActionMode(callback); + return; + } + + //noinspection NewApi mActionMode = terminalView.startActionMode(new ActionMode.Callback2() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { diff --git a/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionHandleView.java b/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionHandleView.java index 4f39e723ba..b3caca6720 100644 --- a/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionHandleView.java +++ b/terminal-view/src/main/java/com/termux/view/textselection/TextSelectionHandleView.java @@ -4,6 +4,7 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.SystemClock; import android.view.MotionEvent; import android.view.View; @@ -14,6 +15,7 @@ import com.termux.view.R; import com.termux.view.TerminalView; +import com.termux.view.support.PopupWindowCompatGingerbread; @SuppressLint("ViewConstructor") public class TextSelectionHandleView extends View { @@ -68,13 +70,18 @@ private void initHandle() { android.R.attr.textSelectHandleWindowStyle); mHandle.setSplitTouchEnabled(true); mHandle.setClippingEnabled(false); - mHandle.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL); mHandle.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); mHandle.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); mHandle.setBackgroundDrawable(null); mHandle.setAnimationStyle(0); - mHandle.setEnterTransition(null); - mHandle.setExitTransition(null); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + mHandle.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL); + mHandle.setEnterTransition(null); + mHandle.setExitTransition(null); + } else { + PopupWindowCompatGingerbread.setWindowLayoutType(mHandle, WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL); + } mHandle.setContentView(this); } diff --git a/termux-shared/src/main/java/com/termux/shared/android/AndroidUtils.java b/termux-shared/src/main/java/com/termux/shared/android/AndroidUtils.java index 766ea34ef9..4ddcc3fbbc 100644 --- a/termux-shared/src/main/java/com/termux/shared/android/AndroidUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/android/AndroidUtils.java @@ -48,9 +48,12 @@ public static String getAppInfoMarkdownString(@NonNull final Context context) { !filesDir.equals("/data/data/" + context.getPackageName() + "/files")) AndroidUtils.appendPropertyToMarkdown(markdownString,"FILES_DIR", filesDir); - Long userId = PackageUtils.getUserIdForPackage(context); - if (userId == null || userId != 0) - AndroidUtils.appendPropertyToMarkdown(markdownString,"USER_ID", userId); + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ) { + Long userId = PackageUtils.getUserIdForPackage(context); + if (userId == null || userId != 0) + AndroidUtils.appendPropertyToMarkdown(markdownString, "USER_ID", userId); + } AndroidUtils.appendPropertyToMarkdownIfSet(markdownString,"PROFILE_OWNER", PackageUtils.getProfileOwnerPackageNameForUser(context)); diff --git a/termux-shared/src/main/java/com/termux/shared/android/PackageUtils.java b/termux-shared/src/main/java/com/termux/shared/android/PackageUtils.java index dae7b42b55..4447a9218b 100644 --- a/termux-shared/src/main/java/com/termux/shared/android/PackageUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/android/PackageUtils.java @@ -8,11 +8,13 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.os.Build; import android.os.UserHandle; import android.os.UserManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import com.termux.shared.R; import com.termux.shared.data.DataUtils; @@ -507,6 +509,7 @@ public static String getSigningCertificateSHA256DigestForPackage(@NonNull final * @param context The {@link Context} for the package. * @return Returns the serial number. This will be {@code null} if failed to get it. */ + @RequiresApi(api = Build.VERSION_CODES.N) @Nullable public static Long getUserIdForPackage(@NonNull Context context) { UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); @@ -521,6 +524,7 @@ public static Long getUserIdForPackage(@NonNull Context context) { * @param context The {@link Context} for operations. * @return Returns {@code true} if the current user is the primary user, otherwise [@code false}. */ + @RequiresApi(api = Build.VERSION_CODES.N) public static boolean isCurrentUserThePrimaryUser(@NonNull Context context) { Long userId = getUserIdForPackage(context); return userId != null && userId == 0; diff --git a/termux-shared/src/main/java/com/termux/shared/android/PermissionUtils.java b/termux-shared/src/main/java/com/termux/shared/android/PermissionUtils.java index ff19a1512a..60aeed077f 100644 --- a/termux-shared/src/main/java/com/termux/shared/android/PermissionUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/android/PermissionUtils.java @@ -93,6 +93,7 @@ public static boolean checkPermissions(@NonNull Context context, @NonNull String * will fail silently and will log an exception. * @return Returns {@code true} if requesting the permission was successful, otherwise {@code false}. */ + @RequiresApi(api = Build.VERSION_CODES.M) public static boolean requestPermission(@NonNull Context context, @NonNull String permission, int requestCode) { return requestPermissions(context, new String[]{permission}, requestCode); @@ -116,6 +117,7 @@ public static boolean requestPermission(@NonNull Context context, @NonNull Strin * will fail silently and will log an exception. * @return Returns {@code true} if requesting the permissions was successful, otherwise {@code false}. */ + @RequiresApi(api = Build.VERSION_CODES.M) public static boolean requestPermissions(@NonNull Context context, @NonNull String[] permissions, int requestCode) { List permissionsNotRequested = getPermissionsNotRequested(context, permissions); @@ -274,12 +276,13 @@ public static boolean checkAndRequestLegacyOrManageExternalStoragePermission(@No return true; } + errmsg = context.getString(R.string.msg_storage_permission_not_granted); Logger.logError(LOG_TAG, errmsg); if (showErrorMessage) Logger.showToast(context, errmsg, false); - if (requestCode < 0) + if (requestCode < 0 || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false; if (requestLegacyStoragePermission || Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { @@ -323,6 +326,7 @@ public static boolean checkStoragePermission(@NonNull Context context, boolean c * will fail silently and will log an exception. * @return Returns {@code true} if requesting the permission was successful, otherwise {@code false}. */ + @RequiresApi(api = Build.VERSION_CODES.M) public static boolean requestLegacyStorageExternalPermission(@NonNull Context context, int requestCode) { Logger.logInfo(LOG_TAG, "Requesting legacy external storage permission"); return requestPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE, requestCode); @@ -439,7 +443,10 @@ public static boolean hasRequestedLegacyExternalStorage(@NonNull Context context * @return Returns {@code true} if permission is granted, otherwise {@code false}. */ public static boolean checkDisplayOverOtherAppsPermission(@NonNull Context context) { - return Settings.canDrawOverlays(context); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) + return Settings.canDrawOverlays(context); + else + return true; } /** Wrapper for {@link #requestDisplayOverOtherAppsPermission(Context, int)}. */ @@ -461,6 +468,9 @@ public static Error requestDisplayOverOtherAppsPermission(@NonNull Context conte public static Error requestDisplayOverOtherAppsPermission(@NonNull Context context, int requestCode) { Logger.logInfo(LOG_TAG, "Requesting display over apps permission"); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) + return null; + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); intent.setData(Uri.parse("package:" + context.getPackageName())); @@ -505,8 +515,11 @@ public static boolean validateDisplayOverOtherAppsPermissionForPostAndroid10(@No * @return Returns {@code true} if permission is granted, otherwise {@code false}. */ public static boolean checkIfBatteryOptimizationsDisabled(@NonNull Context context) { - PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - return powerManager.isIgnoringBatteryOptimizations(context.getPackageName()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + return powerManager.isIgnoringBatteryOptimizations(context.getPackageName()); + } else + return true; } /** Wrapper for {@link #requestDisableBatteryOptimizations(Context, int)}. */ @@ -530,6 +543,9 @@ public static Error requestDisableBatteryOptimizations(@NonNull Context context) public static Error requestDisableBatteryOptimizations(@NonNull Context context, int requestCode) { Logger.logInfo(LOG_TAG, "Requesting to disable battery optimizations"); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) + return null; + Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + context.getPackageName())); diff --git a/termux-shared/src/main/java/com/termux/shared/file/filesystem/UnixConstants.java b/termux-shared/src/main/java/com/termux/shared/file/filesystem/UnixConstants.java index 72e7dc2ae9..9659be7e7b 100644 --- a/termux-shared/src/main/java/com/termux/shared/file/filesystem/UnixConstants.java +++ b/termux-shared/src/main/java/com/termux/shared/file/filesystem/UnixConstants.java @@ -32,8 +32,11 @@ // Those constants are initialized by native code to ensure correctness on different architectures. // AT_SYMLINK_NOFOLLOW (used by fstatat) and AT_REMOVEDIR (used by unlinkat) as of July 2018 do not // have equivalents in android.system.OsConstants so left unchanged. +import android.os.Build; import android.system.OsConstants; +import androidx.annotation.RequiresApi; + /** * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:libcore/ojluni/src/main/java/sun/nio/fs/UnixConstants.java */ @@ -56,7 +59,11 @@ private UnixConstants() { } static final int O_SYNC = OsConstants.O_SYNC; - static final int O_DSYNC = OsConstants.O_DSYNC; + // Crash on Android 5. + // No static field O_DSYNC of type I in class Landroid/system/OsConstants; or its superclasses + // (declaration of 'android.system.OsConstants' appears in /system/framework/core-libart.jar) + //@RequiresApi(Build.VERSION_CODES.O_MR1) + //static final int O_DSYNC = OsConstants.O_DSYNC; static final int O_NOFOLLOW = OsConstants.O_NOFOLLOW; diff --git a/termux-shared/src/main/java/com/termux/shared/interact/ShareUtils.java b/termux-shared/src/main/java/com/termux/shared/interact/ShareUtils.java index c7793f75fb..4d17af86f6 100644 --- a/termux-shared/src/main/java/com/termux/shared/interact/ShareUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/interact/ShareUtils.java @@ -8,6 +8,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Environment; import androidx.appcompat.app.AppCompatActivity; @@ -145,7 +146,7 @@ public static void saveTextToFile(final Context context, final String label, fin !PermissionUtils.checkPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { Logger.logErrorAndShowToast(context, LOG_TAG, context.getString(R.string.msg_storage_permission_not_granted)); - if (storagePermissionRequestCode >= 0) { + if (storagePermissionRequestCode >= 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (context instanceof AppCompatActivity) PermissionUtils.requestPermission(((AppCompatActivity) context), Manifest.permission.WRITE_EXTERNAL_STORAGE, storagePermissionRequestCode); else if (context instanceof Activity) diff --git a/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/SpecialButtonState.java b/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/SpecialButtonState.java index 3b68952966..606dcc4f5e 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/SpecialButtonState.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/SpecialButtonState.java @@ -38,7 +38,9 @@ public void setIsCreated(boolean value) { /** Set {@link #isActive}. */ public void setIsActive(boolean value) { isActive = value; - buttons.forEach(button -> button.setTextColor(value ? mExtraKeysView.getButtonActiveTextColor() : mExtraKeysView.getButtonTextColor())); + for (MaterialButton button : buttons) { + button.setTextColor(value ? mExtraKeysView.getButtonActiveTextColor() : mExtraKeysView.getButtonTextColor()); + } } /** Set {@link #isLocked}. */ diff --git a/termux-shared/src/main/java/com/termux/shared/termux/terminal/io/TerminalExtraKeys.java b/termux-shared/src/main/java/com/termux/shared/termux/terminal/io/TerminalExtraKeys.java index 05571f7a7d..44eb5b02f0 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/terminal/io/TerminalExtraKeys.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/terminal/io/TerminalExtraKeys.java @@ -1,5 +1,6 @@ package com.termux.shared.termux.terminal.io; +import android.os.Build; import android.view.KeyEvent; import android.view.View; @@ -9,6 +10,7 @@ import com.termux.shared.termux.extrakeys.ExtraKeyButton; import com.termux.shared.termux.extrakeys.ExtraKeysView; import com.termux.shared.termux.extrakeys.SpecialButton; +import com.termux.terminal.TerminalSession; import com.termux.view.TerminalView; import static com.termux.shared.termux.extrakeys.ExtraKeysConstants.PRIMARY_KEY_CODES_FOR_STRINGS; @@ -63,9 +65,15 @@ protected void onTerminalExtraKeyButtonClick(View view, String key, boolean ctrl mTerminalView.onKeyDown(keyCode, keyEvent); } else { // not a control char - key.codePoints().forEach(codePoint -> { - mTerminalView.inputCodePoint(codePoint, ctrlDown, altDown); - }); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + key.codePoints().forEach(codePoint -> { + mTerminalView.inputCodePoint(codePoint, ctrlDown, altDown); + }); + } else { + TerminalSession session = mTerminalView.getCurrentSession(); + if (session != null && key.length() > 0) + session.write(key); + } } } diff --git a/termux-shared/src/main/java/com/termux/shared/view/KeyboardUtils.java b/termux-shared/src/main/java/com/termux/shared/view/KeyboardUtils.java index eee44ec23d..5df35d2b09 100644 --- a/termux-shared/src/main/java/com/termux/shared/view/KeyboardUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/view/KeyboardUtils.java @@ -4,12 +4,14 @@ import android.content.Context; import android.content.res.Configuration; import android.inputmethodservice.InputMethodService; +import android.os.Build; import android.view.View; import android.view.WindowInsets; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.core.view.WindowInsetsCompat; import com.termux.shared.logger.Logger; @@ -118,6 +120,7 @@ public static void setSoftInputModeAdjustResize(final Activity activity) { * @param activity The Activity of the root view for which the visibility should be checked. * @return Returns {@code true} if soft keyboard is visible, otherwise {@code false}. */ + @RequiresApi(api = Build.VERSION_CODES.M) public static boolean isSoftKeyboardVisible(final Activity activity) { if (activity != null && activity.getWindow() != null) { WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets(); diff --git a/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java b/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java index d85b82909b..2f62d74d3c 100644 --- a/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/view/ViewUtils.java @@ -6,12 +6,14 @@ import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; +import android.os.Build; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import com.termux.shared.logger.Logger; @@ -77,13 +79,13 @@ public static Rect[] getWindowAndViewRects(View view, int statusBarHeight) { boolean isInMultiWindowMode = false; Context context = view.getContext(); if (context instanceof AppCompatActivity) { - androidx.appcompat.app.ActionBar actionBar = ((AppCompatActivity) context).getSupportActionBar(); + ActionBar actionBar = ((AppCompatActivity) context).getSupportActionBar(); if (actionBar != null) actionBarHeight = actionBar.getHeight(); - isInMultiWindowMode = ((AppCompatActivity) context).isInMultiWindowMode(); + isInMultiWindowMode = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) && ((AppCompatActivity) context).isInMultiWindowMode(); } else if (context instanceof Activity) { android.app.ActionBar actionBar = ((Activity) context).getActionBar(); if (actionBar != null) actionBarHeight = actionBar.getHeight(); - isInMultiWindowMode = ((Activity) context).isInMultiWindowMode(); + isInMultiWindowMode = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) && ((Activity) context).isInMultiWindowMode(); } int displayOrientation = getDisplayOrientation(context); From 55dcd09a096931833337336355e38da053442524 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:33:21 +0500 Subject: [PATCH 08/19] Fixed: Fixed extra keys not showing properly on Android 5 Related issue #739 --- app/src/main/java/com/termux/app/TermuxActivity.java | 10 +++++++--- .../app/terminal/io/TerminalToolbarViewPager.java | 3 ++- .../shared/termux/extrakeys/ExtraKeysView.java | 12 +++++++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java index 548566e269..47fe2363f6 100644 --- a/app/src/main/java/com/termux/app/TermuxActivity.java +++ b/app/src/main/java/com/termux/app/TermuxActivity.java @@ -173,7 +173,7 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo private int mNavBarHeight; - private int mTerminalToolbarDefaultHeight; + private float mTerminalToolbarDefaultHeight; private static final int CONTEXT_MENU_SELECT_URL_ID = 0; @@ -528,7 +528,7 @@ private void setTerminalToolbarHeight() { if (terminalToolbarViewPager == null) return; ViewGroup.LayoutParams layoutParams = terminalToolbarViewPager.getLayoutParams(); - layoutParams.height = (int) Math.round(mTerminalToolbarDefaultHeight * + layoutParams.height = Math.round(mTerminalToolbarDefaultHeight * (mTermuxTerminalExtraKeys.getExtraKeysInfo() == null ? 0 : mTermuxTerminalExtraKeys.getExtraKeysInfo().getMatrix().length) * mProperties.getTerminalToolbarHeightScaleFactor()); terminalToolbarViewPager.setLayoutParams(layoutParams); @@ -835,6 +835,10 @@ public ViewPager getTerminalToolbarViewPager() { return (ViewPager) findViewById(R.id.terminal_toolbar_view_pager); } + public float getTerminalToolbarDefaultHeight() { + return mTerminalToolbarDefaultHeight; + } + public boolean isTerminalViewSelected() { return getTerminalToolbarViewPager().getCurrentItem() == 0; } @@ -960,7 +964,7 @@ private void reloadActivityStyling(boolean recreateActivity) { if (mExtraKeysView != null) { mExtraKeysView.setButtonTextAllCaps(mProperties.shouldExtraKeysTextBeAllCaps()); - mExtraKeysView.reload(mTermuxTerminalExtraKeys.getExtraKeysInfo()); + mExtraKeysView.reload(mTermuxTerminalExtraKeys.getExtraKeysInfo(), mTerminalToolbarDefaultHeight); } // Update NightMode.APP_NIGHT_MODE diff --git a/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java b/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java index ac1e2e4def..a526570b09 100644 --- a/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java +++ b/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java @@ -47,7 +47,8 @@ public Object instantiateItem(@NonNull ViewGroup collection, int position) { extraKeysView.setExtraKeysViewClient(mActivity.getTermuxTerminalExtraKeys()); extraKeysView.setButtonTextAllCaps(mActivity.getProperties().shouldExtraKeysTextBeAllCaps()); mActivity.setExtraKeysView(extraKeysView); - extraKeysView.reload(mActivity.getTermuxTerminalExtraKeys().getExtraKeysInfo()); + extraKeysView.reload(mActivity.getTermuxTerminalExtraKeys().getExtraKeysInfo(), + mActivity.getTerminalToolbarDefaultHeight()); // apply extra keys fix if enabled in prefs if (mActivity.getProperties().isUsingFullScreen() && mActivity.getProperties().isUsingFullScreenWorkAround()) { diff --git a/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/ExtraKeysView.java b/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/ExtraKeysView.java index cbd59b74f9..4fbbf1e171 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/ExtraKeysView.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/ExtraKeysView.java @@ -60,7 +60,7 @@ * in {@link ExtraKeysView#ExtraKeysView(Context, AttributeSet)} by calling the respective functions. * If you extend {@link ExtraKeysView}, you can also set them in the constructor, but do call super(). * - * After this you will have to make a call to {@link ExtraKeysView#reload(ExtraKeysInfo) and pass + * After this you will have to make a call to {@link ExtraKeysView#reload(ExtraKeysInfo, float) and pass * it the {@link ExtraKeysInfo} to load and display the extra keys. Read its class javadocs for more * info on how to create it. * @@ -379,9 +379,11 @@ public Map getDefaultSpecialButtons(ExtraKeys * Reload this instance of {@link ExtraKeysView} with the info passed in {@code extraKeysInfo}. * * @param extraKeysInfo The {@link ExtraKeysInfo} that defines the necessary info for the extra keys. + * @param heightPx The height in pixels of the parent surrounding the {@link ExtraKeysView}. It must + * be a single child. */ @SuppressLint("ClickableViewAccessibility") - public void reload(ExtraKeysInfo extraKeysInfo) { + public void reload(ExtraKeysInfo extraKeysInfo, float heightPx) { if (extraKeysInfo == null) return; @@ -469,7 +471,11 @@ public void reload(ExtraKeysInfo extraKeysInfo) { LayoutParams param = new GridLayout.LayoutParams(); param.width = 0; - param.height = 0; + if(Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) { + param.height = (int)(heightPx + 0.5); + } else { + param.height = 0; + } param.setMargins(0, 0, 0, 0); param.columnSpec = GridLayout.spec(col, GridLayout.FILL, 1.f); param.rowSpec = GridLayout.spec(row, GridLayout.FILL, 1.f); From c549988434d532caf2e3f471fb783cd48bc1b730 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:33:51 +0500 Subject: [PATCH 09/19] Fixed: Fix broken javadocs links --- .../com/termux/shared/termux/extrakeys/ExtraKeysInfo.java | 3 ++- .../termux/shell/command/runner/terminal/TermuxSession.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/ExtraKeysInfo.java b/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/ExtraKeysInfo.java index 9140c13edd..2f5bb4a7b0 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/ExtraKeysInfo.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/extrakeys/ExtraKeysInfo.java @@ -5,6 +5,7 @@ import androidx.annotation.NonNull; +import com.google.android.material.button.MaterialButton; import com.termux.shared.termux.extrakeys.ExtraKeysConstants.EXTRA_KEY_DISPLAY_MAPS; import com.termux.shared.termux.terminal.io.TerminalExtraKeys; @@ -68,7 +69,7 @@ * * Its up to the {@link ExtraKeysView.IExtraKeysView} client on how to handle individual key values * of an {@link ExtraKeyButton}. They are sent as is via - * {@link ExtraKeysView.IExtraKeysView#onExtraKeyButtonClick(View, ExtraKeyButton, Button)}. The + * {@link ExtraKeysView.IExtraKeysView#onExtraKeyButtonClick(View, ExtraKeyButton, MaterialButton)}. The * {@link TerminalExtraKeys} which is an implementation of the interface, * checks if the key is one of {@link ExtraKeysConstants#PRIMARY_KEY_CODES_FOR_STRINGS} and generates * a {@link android.view.KeyEvent} for it, and if its not, then converts the key to code points by diff --git a/termux-shared/src/main/java/com/termux/shared/termux/shell/command/runner/terminal/TermuxSession.java b/termux-shared/src/main/java/com/termux/shared/termux/shell/command/runner/terminal/TermuxSession.java index 2cfeb45d58..7f365c9968 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/shell/command/runner/terminal/TermuxSession.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/shell/command/runner/terminal/TermuxSession.java @@ -217,10 +217,10 @@ public void killIfExecuting(@NonNull final Context context, boolean processResul * callback will be called. * * @param termuxSession The {@link TermuxSession}, which should be set if - * {@link #execute(Context, ExecutionCommand, TerminalSessionClient, TermuxSessionClient, ShellEnvironmentClient, String, boolean)} + * {@link #execute(Context, ExecutionCommand, TerminalSessionClient, TermuxSessionClient, ShellEnvironmentClient, boolean)} * successfully started the process. * @param executionCommand The {@link ExecutionCommand}, which should be set if - * {@link #execute(Context, ExecutionCommand, TerminalSessionClient, TermuxSessionClient, ShellEnvironmentClient, String, boolean)} + * {@link #execute(Context, ExecutionCommand, TerminalSessionClient, TermuxSessionClient, ShellEnvironmentClient, boolean)} * failed to start the process. */ private static void processTermuxSessionResult(final TermuxSession termuxSession, ExecutionCommand executionCommand) { From 4e08f76fd20a9d514c41e1888525b0ef661765fa Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:35:43 +0500 Subject: [PATCH 10/19] Changed: Export correct PATH and also export LD_LIBRARY_PATH for Android 5/6 since packages won't use DT_RUNPATH --- .../com/termux/shared/termux/shell/TermuxShellUtils.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java index d20208b54f..dde43e9581 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java @@ -1,9 +1,11 @@ package com.termux.shared.termux.shell; import android.content.Context; +import android.os.Build; import androidx.annotation.NonNull; +import com.termux.shared.BuildConfig; import com.termux.shared.errors.Error; import com.termux.shared.file.filesystem.FileTypes; import com.termux.shared.termux.TermuxBootstrap; @@ -95,9 +97,14 @@ public static String[] buildEnvironment(Context currentPackageContext, boolean i environment.add("PATH= " + System.getenv("PATH")); } else { environment.add("LANG=en_US.UTF-8"); - environment.add("PATH=" + TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH); environment.add("PWD=" + workingDirectory); environment.add("TMPDIR=" + TermuxConstants.TERMUX_TMP_PREFIX_DIR_PATH); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + environment.add("PATH=" + TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH + ":" + TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH + "/applets"); + environment.add("LD_LIBRARY_PATH=" + TermuxConstants.TERMUX_LIB_PREFIX_DIR_PATH); + } else { + environment.add("PATH=" + TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH); + } } return environment.toArray(new String[0]); From ab9b620c880f362fe27bcfb611d5eb929be4e635 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:36:45 +0500 Subject: [PATCH 11/19] Added: Add ResourceUtils to get resource ids from names This will mainly be used later when MediaViewer gets added. --- .../android/resource/ResourceUtils.java | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 termux-shared/src/main/java/com/termux/shared/android/resource/ResourceUtils.java diff --git a/termux-shared/src/main/java/com/termux/shared/android/resource/ResourceUtils.java b/termux-shared/src/main/java/com/termux/shared/android/resource/ResourceUtils.java new file mode 100644 index 0000000000..67cfb662de --- /dev/null +++ b/termux-shared/src/main/java/com/termux/shared/android/resource/ResourceUtils.java @@ -0,0 +1,136 @@ +package com.termux.shared.android.resource; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.termux.shared.data.DataUtils; +import com.termux.shared.logger.Logger; + +public class ResourceUtils { + + public static final String RES_TYPE_COLOR = "color"; + public static final String RES_TYPE_DRAWABLE = "drawable"; + public static final String RES_TYPE_ID = "id"; + public static final String RES_TYPE_LAYOUT = "layout"; + public static final String RES_TYPE_STRING = "string"; + public static final String RES_TYPE_STYLE = "style"; + + + private static final String LOG_TAG = "ResourceUtils"; + + + /** Wrapper for {@link #getResourceId(Context, String, String, String, boolean)} without {@code defPackage}. */ + @Nullable + public static Integer getResourceId(@NonNull Context context, String name, + @Nullable String defType, + boolean logErrorMessage) { + return getResourceId(context, name, defType, null, logErrorMessage); + } + + /** + * Get resource identifier for the given resource name. A fully qualified resource name is of + * the form "package:type/entry". The first two components (package and type) are optional if + * defType and defPackage, respectively, are specified here. + * + * @param context The {@link Context} for operations. + * @param name The name of the desired resource. + * @param defType Optional default resource type to find, if "type/" is not included in the name. + * Can be null to require an explicit type. + * @param defPackage Optional default package to find, if "package:" is not included in the name. + * Can be null to require an explicit package. + * @param logErrorMessage If an error message should be logged if failed to find resource. + * @return Returns the resource identifier if found. Otherwise {@code null} if an exception was + * raised or resource was not found. + */ + @Nullable + public static Integer getResourceId(@NonNull Context context, String name, + @Nullable String defType, @Nullable String defPackage, + boolean logErrorMessage) { + if (DataUtils.isNullOrEmpty(name)) return null; + + Integer resourceId = null; + try { + resourceId = context.getResources().getIdentifier(name, defType, defPackage); + if (resourceId == 0) resourceId = null; + } catch (Exception e) { + // Ignore + } + + if (resourceId == null && logErrorMessage) { + Logger.logError(LOG_TAG, "Resource id not found. name: \"" + name + "\", type: \"" + defType+ "\", package: \"" + defPackage + "\", component \"" + context.getClass().getName() + "\""); + } + + return resourceId; + } + + + + /** + * Get resource identifier for the given {@link #RES_TYPE_COLOR} resource name. + * + * This is a wrapper for {@link #getResourceId(Context, String, String, String, boolean)}. + */ + @Nullable + public static Integer getColorResourceId(@NonNull Context context, String name, + @Nullable String defPackage, boolean logErrorMessage) { + return getResourceId(context, name, RES_TYPE_COLOR, defPackage, logErrorMessage); + } + + /** + * Get resource identifier for the given {@link #RES_TYPE_DRAWABLE} resource name. + * + * This is a wrapper for {@link #getResourceId(Context, String, String, String, boolean)}. + */ + @Nullable + public static Integer getDrawableResourceId(@NonNull Context context, String name, + @Nullable String defPackage, boolean logErrorMessage) { + return getResourceId(context, name, RES_TYPE_DRAWABLE, defPackage, logErrorMessage); + } + + /** + * Get resource identifier for the given {@link #RES_TYPE_ID} resource name. + * + * This is a wrapper for {@link #getResourceId(Context, String, String, String, boolean)}. + */ + @Nullable + public static Integer getIdResourceId(@NonNull Context context, String name, + @Nullable String defPackage, boolean logErrorMessage) { + return getResourceId(context, name, RES_TYPE_ID, defPackage, logErrorMessage); + } + + /** + * Get resource identifier for the given {@link #RES_TYPE_LAYOUT} resource name. + * + * This is a wrapper for {@link #getResourceId(Context, String, String, String, boolean)}. + */ + @Nullable + public static Integer getLayoutResourceId(@NonNull Context context, String name, + @Nullable String defPackage, boolean logErrorMessage) { + return getResourceId(context, name, RES_TYPE_LAYOUT, defPackage, logErrorMessage); + } + + /** + * Get resource identifier for the given {@link #RES_TYPE_STRING} resource name. + * + * This is a wrapper for {@link #getResourceId(Context, String, String, String, boolean)}. + */ + @Nullable + public static Integer getStringResourceId(@NonNull Context context, String name, + @Nullable String defPackage, boolean logErrorMessage) { + return getResourceId(context, name, RES_TYPE_STRING, defPackage, logErrorMessage); + } + + /** + * Get resource identifier for the given {@link #RES_TYPE_STYLE} resource name. + * + * This is a wrapper for {@link #getResourceId(Context, String, String, String, boolean)}. + */ + @Nullable + public static Integer getStyleResourceId(@NonNull Context context, String name, + @Nullable String defPackage, boolean logErrorMessage) { + return getResourceId(context, name, RES_TYPE_STYLE, defPackage, logErrorMessage); + } + +} From 5290ce1f7745a4c47f88f22b4fb19de2acc10988 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 02:40:12 +0500 Subject: [PATCH 12/19] Added|Fixed: Add `TermuxNotificationUtils.getTermuxOrPluginAppNotificationBuilder()` helper function and fix notification icon drawable resource id issue on Android 5 --- .../notification/NotificationUtils.java | 2 + .../shared/termux/crash/TermuxCrashUtils.java | 22 +----- .../notification/TermuxNotificationUtils.java | 71 +++++++++++++++++++ .../termux/plugins/TermuxPluginUtils.java | 20 +----- 4 files changed, 77 insertions(+), 38 deletions(-) diff --git a/termux-shared/src/main/java/com/termux/shared/notification/NotificationUtils.java b/termux-shared/src/main/java/com/termux/shared/notification/NotificationUtils.java index 25597a2037..e21a83f401 100644 --- a/termux-shared/src/main/java/com/termux/shared/notification/NotificationUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/notification/NotificationUtils.java @@ -51,6 +51,8 @@ public static NotificationManager getNotificationManager(final Context context) * * @param context The {@link Context} for operations. * @param title The title for the notification. + * @param channelId The channel id for the notification. + * @param priority The priority for the notification. * @param notificationText The second line text of the notification. * @param notificationBigText The full text of the notification that may optionally be styled. * @param contentIntent The {@link PendingIntent} which should be sent when notification is clicked. diff --git a/termux-shared/src/main/java/com/termux/shared/termux/crash/TermuxCrashUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/crash/TermuxCrashUtils.java index 5d551a9715..a34557077a 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/crash/TermuxCrashUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/crash/TermuxCrashUtils.java @@ -5,13 +5,11 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.graphics.drawable.Icon; import android.os.Environment; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.termux.shared.R; import com.termux.shared.activities.ReportActivity; import com.termux.shared.android.AndroidUtils; import com.termux.shared.crash.CrashHandler; @@ -391,26 +389,10 @@ public static Notification.Builder getCrashReportsNotificationBuilder(final Cont final PendingIntent contentIntent, final PendingIntent deleteIntent, final int notificationMode) { - - Notification.Builder builder = NotificationUtils.geNotificationBuilder(termuxPackageContext, + return TermuxNotificationUtils.getTermuxOrPluginAppNotificationBuilder( + currentPackageContext, termuxPackageContext, TermuxConstants.TERMUX_CRASH_REPORTS_NOTIFICATION_CHANNEL_ID, Notification.PRIORITY_HIGH, title, notificationText, notificationBigText, contentIntent, deleteIntent, notificationMode); - - if (builder == null) return null; - - // Enable timestamp - builder.setShowWhen(true); - - // Set notification icon - builder.setSmallIcon(Icon.createWithResource(currentPackageContext, R.drawable.ic_error_notification)); - - // Set background color for small notification icon - builder.setColor(0xFF607D8B); - - // Dismiss on click - builder.setAutoCancel(true); - - return builder; } /** diff --git a/termux-shared/src/main/java/com/termux/shared/termux/notification/TermuxNotificationUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/notification/TermuxNotificationUtils.java index eb0b50626d..19c7c02b7d 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/notification/TermuxNotificationUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/notification/TermuxNotificationUtils.java @@ -1,7 +1,16 @@ package com.termux.shared.termux.notification; +import android.app.Notification; +import android.app.PendingIntent; import android.content.Context; +import android.graphics.drawable.Icon; +import android.os.Build; +import androidx.annotation.Nullable; + +import com.termux.shared.R; +import com.termux.shared.android.resource.ResourceUtils; +import com.termux.shared.notification.NotificationUtils; import com.termux.shared.termux.settings.preferences.TermuxAppSharedPreferences; import com.termux.shared.termux.settings.preferences.TermuxPreferenceConstants; import com.termux.shared.termux.TermuxConstants; @@ -35,4 +44,66 @@ public synchronized static int getNextNotificationId(final Context context) { preferences.setLastNotificationId(nextNotificationId); return nextNotificationId; } + + /** + * Get {@link Notification.Builder} for termux app or its plugin. + * + * @param currentPackageContext The {@link Context} of current package. + * @param termuxPackageContext The {@link Context} of termux package. + * @param channelId The channel id for the notification. + * @param priority The priority for the notification. + * @param title The title for the notification. + * @param notificationText The second line text of the notification. + * @param notificationBigText The full text of the notification that may optionally be styled. + * @param contentIntent The {@link PendingIntent} which should be sent when notification is clicked. + * @param deleteIntent The {@link PendingIntent} which should be sent when notification is deleted. + * @param notificationMode The notification mode. It must be one of {@code NotificationUtils.NOTIFICATION_MODE_*}. + * @return Returns the {@link Notification.Builder}. + */ + @Nullable + public static Notification.Builder getTermuxOrPluginAppNotificationBuilder(final Context currentPackageContext, + final Context termuxPackageContext, + final String channelId, + final int priority, + final CharSequence title, + final CharSequence notificationText, + final CharSequence notificationBigText, + final PendingIntent contentIntent, + final PendingIntent deleteIntent, + final int notificationMode) { + Notification.Builder builder = NotificationUtils.geNotificationBuilder(termuxPackageContext, + channelId, priority, + title, notificationText, notificationBigText, contentIntent, deleteIntent, notificationMode); + + if (builder == null) return null; + + // Enable timestamp + builder.setShowWhen(true); + + // Set notification icon + // If a notification is to be shown by a termux plugin app, then we can't use the drawable + // resource id for the plugin app with setSmallIcon(@DrawableRes int icon) since notification + // is shown with termuxPackageContext and termux-app package would have a different id and + // when android tries to load the drawable an exception would be thrown and notification will + // not be thrown. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + // Set Icon instead of drawable resource id + builder.setSmallIcon(Icon.createWithResource(currentPackageContext, R.drawable.ic_error_notification)); + } else { + // Set drawable resource id used by termux-app package + Integer iconResId = ResourceUtils.getDrawableResourceId(termuxPackageContext, "ic_error_notification", + termuxPackageContext.getPackageName(), true); + if (iconResId != null) + builder.setSmallIcon(iconResId); + } + + // Set background color for small notification icon + builder.setColor(0xFF607D8B); + + // Dismiss on click + builder.setAutoCancel(true); + + return builder; + } + } diff --git a/termux-shared/src/main/java/com/termux/shared/termux/plugins/TermuxPluginUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/plugins/TermuxPluginUtils.java index ed2d9a2016..1ab482e521 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/plugins/TermuxPluginUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/plugins/TermuxPluginUtils.java @@ -4,7 +4,6 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; -import android.graphics.drawable.Icon; import android.os.Environment; import androidx.annotation.Nullable; @@ -403,25 +402,10 @@ public static Notification.Builder getPluginCommandErrorsNotificationBuilder(fin final PendingIntent contentIntent, final PendingIntent deleteIntent, final int notificationMode) { - Notification.Builder builder = NotificationUtils.geNotificationBuilder(termuxPackageContext, + return TermuxNotificationUtils.getTermuxOrPluginAppNotificationBuilder( + currentPackageContext, termuxPackageContext, TermuxConstants.TERMUX_PLUGIN_COMMAND_ERRORS_NOTIFICATION_CHANNEL_ID, Notification.PRIORITY_HIGH, title, notificationText, notificationBigText, contentIntent, deleteIntent, notificationMode); - - if (builder == null) return null; - - // Enable timestamp - builder.setShowWhen(true); - - // Set notification icon - builder.setSmallIcon(Icon.createWithResource(currentPackageContext, R.drawable.ic_error_notification)); - - // Set background color for small notification icon - builder.setColor(0xFF607D8B); - - // Dismiss on click - builder.setAutoCancel(true); - - return builder; } /** From 007bef81321fd9659b816fe674166f1a9ffd5f12 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Tue, 26 Apr 2022 03:28:20 +0500 Subject: [PATCH 13/19] Added: Add message to bootstrap error if user installed termux on portable/external/removable sd card since its not supported on some devices --- .../main/java/com/termux/app/TermuxInstaller.java | 12 ++++++++++-- app/src/main/res/values/strings.xml | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/termux/app/TermuxInstaller.java b/app/src/main/java/com/termux/app/TermuxInstaller.java index 15f48bfd80..504b515f77 100644 --- a/app/src/main/java/com/termux/app/TermuxInstaller.java +++ b/app/src/main/java/com/termux/app/TermuxInstaller.java @@ -73,7 +73,8 @@ static void setupBootstrapIfNeeded(final Activity activity, final Runnable whenD // Termux can only be run as the primary user (device owner) since only that // account has the expected file system paths. Verify that: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !PackageUtils.isCurrentUserThePrimaryUser(activity)) { - bootstrapErrorMessage = activity.getString(R.string.bootstrap_error_not_primary_user_message, MarkdownUtils.getMarkdownCodeForString(TERMUX_PREFIX_DIR_PATH, false)); + bootstrapErrorMessage = activity.getString(R.string.bootstrap_error_not_primary_user_message, + MarkdownUtils.getMarkdownCodeForString(TERMUX_PREFIX_DIR_PATH, false)); Logger.logError(LOG_TAG, "isFilesDirectoryAccessible: " + isFilesDirectoryAccessible); Logger.logError(LOG_TAG, bootstrapErrorMessage); sendBootstrapCrashReportNotification(activity, bootstrapErrorMessage); @@ -84,7 +85,14 @@ static void setupBootstrapIfNeeded(final Activity activity, final Runnable whenD } if (!isFilesDirectoryAccessible) { - bootstrapErrorMessage = Error.getMinimalErrorString(filesDirectoryAccessibleError) + "\nTERMUX_FILES_DIR: " + MarkdownUtils.getMarkdownCodeForString(TermuxConstants.TERMUX_FILES_DIR_PATH, false); + bootstrapErrorMessage = Error.getMinimalErrorString(filesDirectoryAccessibleError); + //noinspection SdCardPath + if (PackageUtils.isAppInstalledOnExternalStorage(activity) && + !TermuxConstants.TERMUX_FILES_DIR_PATH.equals(activity.getFilesDir().getAbsolutePath().replaceAll("^/data/user/0/", "/data/data/"))) { + bootstrapErrorMessage += "\n\n" + activity.getString(R.string.bootstrap_error_installed_on_portable_sd, + MarkdownUtils.getMarkdownCodeForString(TERMUX_PREFIX_DIR_PATH, false)); + } + Logger.logError(LOG_TAG, bootstrapErrorMessage); sendBootstrapCrashReportNotification(activity, bootstrapErrorMessage); MessageDialogUtils.showMessage(activity, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index acc0f44b0d..e7e0da60e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,7 +33,11 @@ Try again &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 %1$s. + under any path other than:\n%1$s. + &TERMUX_APP_NAME; cannot be installed on + portable/external/removable sd card on your device. + \nBootstrap binaries compiled for &TERMUX_APP_NAME; have hardcoded $PREFIX path and cannot be installed + under any path other than:\n%1$s. From 7677633e8f5b7845fced2831144a733b43f4ff0b Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Thu, 28 Apr 2022 10:21:59 +0500 Subject: [PATCH 14/19] Fixed: Catch `UnsatisfiedLinkError` for `local-socket` library --- .../termux/shared/net/socket/local/LocalSocketManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/termux-shared/src/main/java/com/termux/shared/net/socket/local/LocalSocketManager.java b/termux-shared/src/main/java/com/termux/shared/net/socket/local/LocalSocketManager.java index 0b7c3dc936..3cd959c34c 100644 --- a/termux-shared/src/main/java/com/termux/shared/net/socket/local/LocalSocketManager.java +++ b/termux-shared/src/main/java/com/termux/shared/net/socket/local/LocalSocketManager.java @@ -75,8 +75,10 @@ public synchronized Error start() { Logger.logDebug(LOG_TAG, "Loading \"" + LOCAL_SOCKET_LIBRARY + "\" library"); System.loadLibrary(LOCAL_SOCKET_LIBRARY); localSocketLibraryLoaded = true; - } catch (Exception e) { - return LocalSocketErrno.ERRNO_START_LOCAL_SOCKET_LIB_LOAD_FAILED_WITH_EXCEPTION.getError(e, LOCAL_SOCKET_LIBRARY, e.getMessage()); + } catch (Throwable t) { + Error error = LocalSocketErrno.ERRNO_START_LOCAL_SOCKET_LIB_LOAD_FAILED_WITH_EXCEPTION.getError(t, LOCAL_SOCKET_LIBRARY, t.getMessage()); + Logger.logErrorExtended(LOG_TAG, error.getErrorLogString()); + return error; } } From 18a1a33e83f637a091e32275d83a558fd0c39468 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Thu, 28 Apr 2022 10:22:38 +0500 Subject: [PATCH 15/19] Added: Enable `TERMUX_PACKAGE_VARIANT` `apt-android-5` builds --- app/build.gradle | 8 +++++++- .../com/termux/shared/termux/TermuxBootstrap.java | 14 +++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e613395c02..62a3c7e550 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ ext { // crash at startup. // Bootstrap of a different variant must not be manually installed by the user after app installation // by replacing $PREFIX since app code is dependant on the variant used to build the APK. - // Currently supported values are: [ "apt-android-7" ] + // Currently supported values are: [ "apt-android-7" "apt-android-5" ] packageVariant = System.getenv("TERMUX_PACKAGE_VARIANT") ?: "apt-android-7" // Default: "apt-android-7" } @@ -219,6 +219,12 @@ task downloadBootstraps() { downloadBootstrap("arm", "f8ec9505081b81da0ee66413762c52e6cb4a6ebd7be1a2a5ddee8953e0795dc9", version) downloadBootstrap("i686", "0491f12ed84a5ef3c28bd742311fed9f176e32100a2c6bbdb017df8f48044484", version) downloadBootstrap("x86_64", "94073a0e136bf5a9c05c1997a55dc261248f4ccb8bffaa9a950a132529cd1529", version) + } else if (packageVariant == "apt-android-5") { + def version = "2022.04.25-r1" + "+" + packageVariant + downloadBootstrap("aarch64", "66eac22c1626cfa8c37f0d30e5cc987bf5e01356ef8c883a12d9b65c93b60e64", version) + downloadBootstrap("arm", "84637d87f176bd647c9e05b161ae4de3611773871727b11405076a54cbf43467", version) + downloadBootstrap("i686", "20d7c399bfba5de95309838effb782a2b16e9eff4f72a55150617ee513e25fea", version) + downloadBootstrap("x86_64", "ae35f4d17027df562e241835299d7e711944825f10c1c2d9c5eb91d5e247daba", version) } else { throw new GradleException("Unsupported TERMUX_PACKAGE_VARIANT \"" + packageVariant + "\"") } diff --git a/termux-shared/src/main/java/com/termux/shared/termux/TermuxBootstrap.java b/termux-shared/src/main/java/com/termux/shared/termux/TermuxBootstrap.java index 7480dcff85..50ccef15d1 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/TermuxBootstrap.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/TermuxBootstrap.java @@ -58,10 +58,10 @@ public static boolean isAppPackageVariantAPTAndroid7() { return PackageVariant.APT_ANDROID_7.equals(TERMUX_APP_PACKAGE_VARIANT); } - ///** Is {@link PackageVariant#APT_ANDROID_5} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */ - //public static boolean isAppPackageVariantAPTAndroid5() { - // return PackageVariant.APT_ANDROID_5.equals(TERMUX_APP_PACKAGE_VARIANT); - //} + /** Is {@link PackageVariant#APT_ANDROID_5} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */ + public static boolean isAppPackageVariantAPTAndroid5() { + return PackageVariant.APT_ANDROID_5.equals(TERMUX_APP_PACKAGE_VARIANT); + } ///** Is {@link PackageVariant#TAPM_ANDROID_7} set as {@link #TERMUX_APP_PACKAGE_VARIANT}. */ //public static boolean isAppPackageVariantTAPMAndroid7() { @@ -132,10 +132,10 @@ public static PackageManager managerOf(String name) { public enum PackageVariant { /** {@link PackageManager#APT} variant for Android 7+. */ - APT_ANDROID_7("apt-android-7"); + APT_ANDROID_7("apt-android-7"), - ///** {@link PackageManager#APT} variant for Android 5+. */ - //APT_ANDROID_5("apt-android-5"); + /** {@link PackageManager#APT} variant for Android 5+. */ + APT_ANDROID_5("apt-android-5"); ///** {@link PackageManager#TAPM} variant for Android 7+. */ //TAPM_ANDROID_7("tapm-android-7"); From 4d084c02e7d889f8bc8678c5b7439e0a037de02b Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Thu, 28 Apr 2022 21:54:18 +0200 Subject: [PATCH 16/19] Changed: Bump android-5 bootstraps to v2022.04.28-r6 --- app/build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 62a3c7e550..5b21def075 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -220,11 +220,11 @@ task downloadBootstraps() { downloadBootstrap("i686", "0491f12ed84a5ef3c28bd742311fed9f176e32100a2c6bbdb017df8f48044484", version) downloadBootstrap("x86_64", "94073a0e136bf5a9c05c1997a55dc261248f4ccb8bffaa9a950a132529cd1529", version) } else if (packageVariant == "apt-android-5") { - def version = "2022.04.25-r1" + "+" + packageVariant - downloadBootstrap("aarch64", "66eac22c1626cfa8c37f0d30e5cc987bf5e01356ef8c883a12d9b65c93b60e64", version) - downloadBootstrap("arm", "84637d87f176bd647c9e05b161ae4de3611773871727b11405076a54cbf43467", version) - downloadBootstrap("i686", "20d7c399bfba5de95309838effb782a2b16e9eff4f72a55150617ee513e25fea", version) - downloadBootstrap("x86_64", "ae35f4d17027df562e241835299d7e711944825f10c1c2d9c5eb91d5e247daba", 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 + "\"") } From 899ef71e17f496fffb680d51ed5834ff0c1157f5 Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Thu, 28 Apr 2022 22:44:07 +0200 Subject: [PATCH 17/19] Changed: Bump android-7 bootstraps to v2022.04.28-r5 --- app/build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5b21def075..1071633d04 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -214,11 +214,11 @@ task downloadBootstraps() { doLast { def packageVariant = project.ext.packageVariant if (packageVariant == "apt-android-7") { - def version = "2022.04.22-r1" + "+" + packageVariant - downloadBootstrap("aarch64", "ec8a6043644594fc24681cffaf9c7b32f5bc68df7491c5df9a060e40e1934c70", version) - downloadBootstrap("arm", "f8ec9505081b81da0ee66413762c52e6cb4a6ebd7be1a2a5ddee8953e0795dc9", version) - downloadBootstrap("i686", "0491f12ed84a5ef3c28bd742311fed9f176e32100a2c6bbdb017df8f48044484", version) - downloadBootstrap("x86_64", "94073a0e136bf5a9c05c1997a55dc261248f4ccb8bffaa9a950a132529cd1529", 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 = "2022.04.28-r6" + "+" + packageVariant downloadBootstrap("aarch64", "913609d439415c828c5640be1b0561467e539cb1c7080662decaaca2fb4820e7", version) From 7b222ba3921faaecd315955883b9634c9893c543 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Fri, 29 Apr 2022 04:26:17 +0500 Subject: [PATCH 18/19] Changed: Export correct PATH and also export LD_LIBRARY_PATH for `apt-android-5` variant instead of on Android 5/6 Overrides 4e08f76f --- .../java/com/termux/shared/termux/shell/TermuxShellUtils.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java index dde43e9581..35a0be275d 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/shell/TermuxShellUtils.java @@ -1,11 +1,9 @@ package com.termux.shared.termux.shell; import android.content.Context; -import android.os.Build; import androidx.annotation.NonNull; -import com.termux.shared.BuildConfig; import com.termux.shared.errors.Error; import com.termux.shared.file.filesystem.FileTypes; import com.termux.shared.termux.TermuxBootstrap; @@ -99,7 +97,7 @@ public static String[] buildEnvironment(Context currentPackageContext, boolean i environment.add("LANG=en_US.UTF-8"); environment.add("PWD=" + workingDirectory); environment.add("TMPDIR=" + TermuxConstants.TERMUX_TMP_PREFIX_DIR_PATH); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + if (TermuxBootstrap.isAppPackageVariantAPTAndroid5()) { environment.add("PATH=" + TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH + ":" + TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH + "/applets"); environment.add("LD_LIBRARY_PATH=" + TermuxConstants.TERMUX_LIB_PREFIX_DIR_PATH); } else { From b04f209f17403b5764cbbba246bdea9a6de09efe Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Fri, 29 Apr 2022 18:07:57 +0500 Subject: [PATCH 19/19] Added: Add TERMUX_DEVS key SHA-256 digest to official signing keys list --- .../com/termux/shared/termux/TermuxConstants.java | 11 ++++++++++- .../java/com/termux/shared/termux/TermuxUtils.java | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/termux-shared/src/main/java/com/termux/shared/termux/TermuxConstants.java b/termux-shared/src/main/java/com/termux/shared/termux/TermuxConstants.java index 3a33eb52ea..c6d1ad807b 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/TermuxConstants.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/TermuxConstants.java @@ -11,7 +11,7 @@ import java.util.List; /* - * Version: v0.41.0 + * Version: v0.42.0 * SPDX-License-Identifier: MIT * * Changelog @@ -239,6 +239,9 @@ * * - 0.41.0 (2022-04-17) * - Added `TERMUX_APP.TERMUX_AM_SOCKET_FILE_PATH`. + * + * - 0.42.0 (2022-04-29) + * - Added `APK_RELEASE_TERMUX_DEVS` and `APK_RELEASE_TERMUX_DEVS_SIGNING_CERTIFICATE_SHA256_DIGEST`. */ /** @@ -450,6 +453,12 @@ public final class TermuxConstants { /** Google Play Store APK release signing certificate SHA-256 digest */ public static final String APK_RELEASE_GOOGLE_PLAYSTORE_SIGNING_CERTIFICATE_SHA256_DIGEST = "738F0A30A04D3C8A1BE304AF18D0779BCF3EA88FB60808F657A3521861C2EBF9"; // Default: "738F0A30A04D3C8A1BE304AF18D0779BCF3EA88FB60808F657A3521861C2EBF9" + /** Termux Devs APK release */ + public static final String APK_RELEASE_TERMUX_DEVS = "Termux Devs"; // Default: "Termux Devs" + + /** Termux Devs APK release signing certificate SHA-256 digest */ + public static final String APK_RELEASE_TERMUX_DEVS_SIGNING_CERTIFICATE_SHA256_DIGEST = "F7A038EB551F1BE8FDF388686B784ABAB4552A5D82DF423E3D8F1B5CBE1C69AE"; // Default: "F7A038EB551F1BE8FDF388686B784ABAB4552A5D82DF423E3D8F1B5CBE1C69AE" + diff --git a/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java index b5fdf91217..cd6bb8d30e 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java @@ -634,6 +634,8 @@ public static String getAPKRelease(String signingCertificateSHA256Digest) { return TermuxConstants.APK_RELEASE_GITHUB; case TermuxConstants.APK_RELEASE_GOOGLE_PLAYSTORE_SIGNING_CERTIFICATE_SHA256_DIGEST: return TermuxConstants.APK_RELEASE_GOOGLE_PLAYSTORE; + case TermuxConstants.APK_RELEASE_TERMUX_DEVS_SIGNING_CERTIFICATE_SHA256_DIGEST: + return TermuxConstants.APK_RELEASE_TERMUX_DEVS; default: return "Unknown"; }