Merge branch '2023.4-dev' into '2023.4'
Big list of bugfixes and features See merge request kalilinux/nethunter/apps/kali-nethunter-term!29
@ -4,6 +4,8 @@ stages:
|
||||
- build
|
||||
|
||||
before_script:
|
||||
- apt update && apt -y install openjdk-17-jdk
|
||||
- JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
|
||||
- export GRADLE_USER_HOME=$(pwd)/.gradle
|
||||
- export PACKAGE=`egrep '^[[:blank:]]+package' ./nhterm/src/main/AndroidManifest.xml | awk -F'[=>]' '{print $2}' | sed s/\"//g`
|
||||
- export VERSION_NAME=`egrep '^[[:blank:]]+versionName=' ./build.gradle | awk -F '"' '{print $2}'`
|
||||
|
@ -32,6 +32,6 @@ dependencies {
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
@ -30,6 +30,6 @@ dependencies {
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
@ -35,6 +35,6 @@ dependencies {
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
12
build.gradle
@ -1,12 +1,12 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.30'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.android = [
|
||||
KOTLIN_VERSION : '1.5.30',
|
||||
KOTLIN_VERSION : '1.6.10',
|
||||
MIN_SDK_VERSION : 21,
|
||||
COMPILE_SDK_VERSION: 31,
|
||||
TARGET_SDK_VERSION : 32,
|
||||
TARGET_SDK_VERSION : 28,
|
||||
JUNIT_VERSION : "4.12"
|
||||
]
|
||||
|
||||
@ -14,8 +14,8 @@ buildscript {
|
||||
ext {
|
||||
//version=YYYYMMVVRR (Either "VV" for stable version OR "RR" for pre-release candidate (e.g. 0001 for rc1))
|
||||
//noinspection HighAppVersionCode
|
||||
versionCode=2023030200
|
||||
versionName="2023.3"
|
||||
versionCode=2023040100
|
||||
versionName="2023.4"
|
||||
}
|
||||
|
||||
ext.deps = [
|
||||
@ -35,7 +35,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.3.1'
|
||||
classpath 'com.android.tools.build:gradle:8.0.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath rootProject.ext.deps["kotlin-gradle-plugin"]
|
||||
|
||||
|
@ -25,6 +25,6 @@ dependencies {
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
@ -41,13 +41,13 @@ public class TabSwitcherButton extends AppCompatImageButton implements TabSwitch
|
||||
private TabSwitcherDrawable drawable;
|
||||
|
||||
/**
|
||||
* Initializes the view.
|
||||
* Initializes the view. // selectableItemBackgroundBorderless
|
||||
*/
|
||||
private void initialize() {
|
||||
drawable = new TabSwitcherDrawable(getContext());
|
||||
setImageDrawable(drawable);
|
||||
ViewUtil.setBackground(this,
|
||||
ThemeUtil.getDrawable(getContext(), R.attr.selectableItemBackgroundBorderless));
|
||||
ThemeUtil.getDrawable(getContext(), androidx.appcompat.R.attr.selectableItemBackgroundBorderless));
|
||||
setContentDescription(null);
|
||||
setClickable(true);
|
||||
setFocusable(true);
|
||||
@ -144,4 +144,4 @@ public class TabSwitcherButton extends AppCompatImageButton implements TabSwitch
|
||||
drawable.onAllTabsRemoved(tabSwitcher, tabs, animation);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -15,20 +15,63 @@ License.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<declare-styleable name="TabSwitcher">
|
||||
<attr name="android:background"/>
|
||||
<attr name="layoutPolicy" format="enum">
|
||||
<enum name="auto" value="0"/>
|
||||
<enum name="phone" value="1"/>
|
||||
<enum name="tablet" value="2"/>
|
||||
<attr name="tabSwitcherThemeGlobal" format="reference"/>
|
||||
<attr name="tabSwitcherThemePhone" format="reference"/>
|
||||
<attr name="tabSwitcherThemeTablet" format="reference"/>
|
||||
<attr name="tabSwitcherBackground" format="reference|color"/>
|
||||
<attr name="tabSwitcherLayoutPolicy" format="enum">
|
||||
<enum name="auto" value="1"/>
|
||||
<enum name="phone" value="2"/>
|
||||
<enum name="tablet" value="3"/>
|
||||
</attr>
|
||||
<attr name="tabIcon" format="reference"/>
|
||||
<attr name="tabBackgroundColor" format="color"/>
|
||||
<attr name="tabTitleTextColor" format="color"/>
|
||||
<attr name="tabCloseButtonIcon" format="reference"/>
|
||||
<attr name="toolbarTitle" format="string"/>
|
||||
<attr name="toolbarMenu" format="reference"/>
|
||||
<attr name="toolbarNavigationIcon" format="reference"/>
|
||||
</declare-styleable>
|
||||
<attr name="tabSwitcherTabIcon" format="reference"/>
|
||||
<attr name="tabSwitcherTabIconTint" format="color"/>
|
||||
<attr name="tabSwitcherTabBackgroundColor" format="color"/>
|
||||
<attr name="tabSwitcherTabContentBackgroundColor" format="color"/>
|
||||
<attr name="tabSwitcherAddTabButtonColor" format="color"/>
|
||||
<attr name="tabSwitcherTabTitleTextColor" format="color"/>
|
||||
<attr name="tabSwitcherTabCloseButtonIcon" format="reference"/>
|
||||
<attr name="tabSwitcherTabCloseButtonIconTint" format="color"/>
|
||||
<attr name="tabSwitcherTabProgressBarColor" format="color"/>
|
||||
<attr name="tabSwitcherToolbarTitle" format="string"/>
|
||||
<attr name="tabSwitcherToolbarMenu" format="reference"/>
|
||||
<attr name="tabSwitcherToolbarNavigationIcon" format="reference"/>
|
||||
<attr name="tabSwitcherToolbarNavigationIconTint" format="color"/>
|
||||
<attr name="tabSwitcherTabToolbarPreviewFadeThreshold" format="integer"/>
|
||||
<attr name="tabSwitcherTabToolbarPreviewFadeDuration" format="integer"/>
|
||||
<attr name="tabSwitcherEmptyView" format="reference"/>
|
||||
<attr name="tabSwitcherEmptyViewAnimationDuration" format="integer"/>
|
||||
<attr name="tabSwitcherToolbarPopupTheme" format="reference"/>
|
||||
|
||||
</resources>
|
||||
<declare-styleable name="TabSwitcher">
|
||||
<attr name="android:background"/>
|
||||
<attr name="preserveState" format="boolean"/>
|
||||
<attr name="layoutPolicy" format="enum">
|
||||
<enum name="auto" value="0"/>
|
||||
<enum name="phone" value="1"/>
|
||||
<enum name="tablet" value="2"/>
|
||||
<enum name="tablet_landscape" value="3"/>
|
||||
</attr>
|
||||
<attr name="tabIcon" format="reference"/>
|
||||
<attr name="tabIconTint" format="color"/>
|
||||
<attr name="tabBackgroundColor" format="color"/>
|
||||
<attr name="tabContentBackgroundColor" format="color"/>
|
||||
<attr name="addTabButtonColor" format="color"/>
|
||||
<attr name="tabTitleTextColor" format="color"/>
|
||||
<attr name="tabCloseButtonIcon" format="reference"/>
|
||||
<attr name="tabCloseButtonIconTint" format="color"/>
|
||||
<attr name="showToolbars" format="boolean"/>
|
||||
<attr name="toolbarTitle" format="string"/>
|
||||
<attr name="toolbarMenu" format="reference"/>
|
||||
<attr name="toolbarNavigationIcon" format="reference"/>
|
||||
<attr name="toolbarNavigationIconTint" format="color"/>
|
||||
<attr name="tabPreviewFadeThreshold" format="integer"/>
|
||||
<attr name="tabPreviewFadeDuration" format="integer"/>
|
||||
<attr name="emptyView" format="reference"/>
|
||||
<attr name="emptyViewAnimationDuration" format="integer"/>
|
||||
<attr name="themeGlobal" format="reference"/>
|
||||
<attr name="themePhone" format="reference"/>
|
||||
<attr name="themeTablet" format="reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
@ -14,3 +14,5 @@ org.gradle.jvmargs=-Xmx1536m
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
ndkVersion=25.1.8937393
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
|
||||
|
@ -15,7 +15,7 @@ android {
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++11"
|
||||
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
|
||||
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
@ -63,18 +63,26 @@ dependencies {
|
||||
|
||||
implementation rootProject.ext.deps["kotlin-stdlib"]
|
||||
|
||||
implementation 'org.greenrobot:eventbus:3.0.0'
|
||||
implementation 'com.github.wrdlbrnft:modular-adapter:0.2.0.6'
|
||||
implementation 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.19'
|
||||
implementation 'org.greenrobot:eventbus:3.3.1'
|
||||
implementation 'com.github.wrdlbrnft:modular-adapter:0.3.0.22'
|
||||
implementation 'com.github.wrdlbrnft:sorted-list-adapter:0.3.0.27'
|
||||
implementation 'com.simplecityapps:recyclerview-fastscroll:1.0.16'
|
||||
implementation 'de.psdev.licensesdialog:licensesdialog:1.8.3'
|
||||
implementation 'de.psdev.licensesdialog:licensesdialog:1.9.0'
|
||||
implementation 'com.github.GrenderG:Color-O-Matic:1.1.5'
|
||||
implementation 'com.github.topjohnwu.libsu:core:5.2.1'
|
||||
|
||||
implementation 'androidx.annotation:annotation:1.2.0'
|
||||
implementation 'androidx.annotation:annotation:1.3.0'
|
||||
implementation "androidx.core:core:1.6.0"
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.appcompat:appcompat-resources:1.2.0'
|
||||
implementation 'androidx.preference:preference:1.0.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||
implementation 'androidx.appcompat:appcompat-resources:1.3.0'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
implementation 'androidx.preference:preference:1.1.0'
|
||||
implementation "androidx.compose.material:material:1.0.0"
|
||||
|
||||
// Backports for lower api levels
|
||||
implementation 'com.llamalab.safs:safs-core:0.2.0'
|
||||
implementation 'me.zhanghai.android.retrofile:library:1.1.1'
|
||||
|
||||
implementation project(':chrome-tabs')
|
||||
implementation project(':NeoLang')
|
||||
@ -83,6 +91,6 @@ dependencies {
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
@ -38,6 +38,8 @@
|
||||
android:label="@string/app_name"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:resizeableActivity="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:largeHeap="true"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="false"
|
||||
tools:replace="android:supportsRtl"
|
||||
@ -46,7 +48,7 @@
|
||||
android:name=".ui.term.NeoTermActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="adjustResize|stateHidden"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
@ -79,7 +81,7 @@
|
||||
android:name=".ui.term.NeoTermRemoteInterface"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.Dark"
|
||||
android:theme="@style/AppTheme"
|
||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
@ -141,12 +143,12 @@
|
||||
android:name=".ui.other.AboutActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/about"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".ui.other.CrashActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/error"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".ui.other.SetupActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
@ -156,34 +158,34 @@
|
||||
android:name=".ui.other.BonusActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".ui.pm.PackageManagerActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/package_settings"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".ui.customize.CustomizeActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/customization_settings"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".ui.customize.ColorSchemeActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/pref_customization_color_scheme"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".ui.settings.SettingActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme.Dark"/>
|
||||
android:theme="@style/AppTheme"/>
|
||||
<activity
|
||||
android:name=".ui.settings.GeneralSettingsActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme.Dark"/>
|
||||
android:theme="@style/AppTheme"/>
|
||||
<activity
|
||||
android:name=".ui.settings.UISettingsActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme.Dark"/>
|
||||
android:theme="@style/AppTheme"/>
|
||||
|
||||
<service
|
||||
android:name=".services.NeoTermService"
|
||||
|
@ -2,14 +2,14 @@
|
||||
# Version: 1.0.3
|
||||
|
||||
# export path for android bins/tools
|
||||
export PATH=/data/data/com.offsec.nhterm/files/home/.nhterm/script:/data/data/com.offsec.nhterm/files/usr/bin:/data/data/com.offsec.nhterm/files/usr/sbin:/sbin:/system/bin:/system/xbin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/odm/bin:/vendor/bin:.
|
||||
export PATH="/data/data/com.offsec.nethunter/files/scripts:/data/data/com.offsec.nethunter/files/scripts/bin:/data/data/com.offsec.nhterm/files/home/.nhterm/script:/data/data/com.offsec.nhterm/files/usr/bin:/data/data/com.offsec.nhterm/files/usr/sbin:/sbin:/system/bin:/system/xbin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/odm/bin:/vendor/bin:."
|
||||
# Remove some exports that break default android binaries from running
|
||||
unset LD_LIBRARY_PATH
|
||||
unset LD_PRELOAD
|
||||
|
||||
export PS1="\\[\\e[1;32m\\]\\u [ \\[\\e[0m\\]\\w\\[\\e[1;32m\\] ]\$ \\[\\e[0m\\]"
|
||||
# Find and remember su location
|
||||
SU1=$(which su)
|
||||
SU2="$SU1 -mm -c $@"
|
||||
SU2="$SU1 -mm -s $@"
|
||||
|
||||
# clear out old view
|
||||
clear
|
||||
|
3
nhterm/src/main/assets/eks/README.txt
Normal file
@ -0,0 +1,3 @@
|
||||
// Switching eks profiles
|
||||
* rename current default to something else
|
||||
* and now rename the chosen profile to default.nm ( to apply restart the terminal )
|
@ -1,57 +0,0 @@
|
||||
#!/data/data/io.neoterm/files/usr/bin/bash
|
||||
|
||||
function file_suffix() {
|
||||
echo "${1##*.}"
|
||||
}
|
||||
|
||||
function detect_program() {
|
||||
case "$1" in
|
||||
*.tar.* | *.tar ) echo "tar xvf %s" ;;
|
||||
*.7z ) echo "7za x %s" ;;
|
||||
*.rar ) echo "unrar x %s" ;;
|
||||
*.zip ) echo "unzip %s" ;;
|
||||
* ) echo "" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
function do_extract() {
|
||||
local file="$1"
|
||||
local dir="$(dirname $file)"
|
||||
|
||||
if [[ ! -f "$file" ]]; then
|
||||
echo "$file: no such file or directory"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local program="$(detect_program $file)"
|
||||
|
||||
if [[ "$program" == "" ]]; then
|
||||
echo "Unsupported format: $(file_suffix $file)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local command="$(printf "$program" "$file")"
|
||||
|
||||
if [[ ! -w "$dir" || ! -r "$file" ]]; then
|
||||
command="sudo $command"
|
||||
fi
|
||||
|
||||
cd "$dir" || {
|
||||
echo "Failed to cd: $dir"
|
||||
return 1
|
||||
}
|
||||
|
||||
eval "$command"
|
||||
}
|
||||
|
||||
if [[ "$#" == 0 ]]; then
|
||||
echo "You must specific at least a file to extract."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
clear
|
||||
while [[ "$#" != 0 ]]; do
|
||||
file="$1"; shift
|
||||
echo "[Extracting] $(basename $file)"
|
||||
do_extract "$file"
|
||||
done
|
5
nhterm/src/main/assets/scripts/open-bash
Normal file
@ -0,0 +1,5 @@
|
||||
#!/data/data/io.neoterm/files/usr/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
bash
|
@ -1,12 +0,0 @@
|
||||
#!/data/data/io.neoterm/files/usr/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
VIM="$(which vim)"
|
||||
|
||||
if [[ "$VIM"x == ""x ]]; then
|
||||
echo "Vim is not installed, now installing..."
|
||||
apt update && apt install -y vim
|
||||
fi
|
||||
|
||||
$VIM "$@"
|
@ -7,11 +7,13 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.view.Gravity
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.offsec.nhterm.component.NeoInitializer
|
||||
import com.offsec.nhterm.component.config.NeoPreference
|
||||
import com.offsec.nhterm.ui.other.BonusActivity
|
||||
import com.offsec.nhterm.utils.CrashHandler
|
||||
import com.offsec.nhterm.utils.NeoPermission
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -21,6 +23,8 @@ class App : Application() {
|
||||
super.onCreate()
|
||||
app = this
|
||||
|
||||
Shell.cmd("setenforce 0").exec()
|
||||
|
||||
NeoPreference.init(this)
|
||||
CrashHandler.init()
|
||||
NeoInitializer.init(this)
|
||||
@ -31,7 +35,7 @@ class App : Application() {
|
||||
}
|
||||
|
||||
fun errorDialog(context: Context, message: String, dismissCallback: (() -> Unit)?) {
|
||||
AlertDialog.Builder(context)
|
||||
MaterialAlertDialogBuilder(context, R.style.DialogStyle)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(message)
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
|
@ -10,6 +10,7 @@ public final class KeyHandler {
|
||||
public static final int KEYMOD_ALT = 0x80000000;
|
||||
public static final int KEYMOD_CTRL = 0x40000000;
|
||||
public static final int KEYMOD_SHIFT = 0x20000000;
|
||||
public static final int KEYMOD_NUM_LOCK = 0x10000000;
|
||||
|
||||
private static final Map<String, Integer> TERMCAP_TO_KEYCODE = new HashMap<>();
|
||||
|
||||
@ -96,10 +97,16 @@ public final class KeyHandler {
|
||||
keyMod |= KEYMOD_ALT;
|
||||
keyCode &= ~KEYMOD_ALT;
|
||||
}
|
||||
if ((keyCode & KEYMOD_NUM_LOCK) != 0) {
|
||||
keyMod |= KEYMOD_NUM_LOCK;
|
||||
keyCode &= ~KEYMOD_NUM_LOCK;
|
||||
}
|
||||
return getCode(keyCode, keyMod, cursorKeysApplication, keypadApplication);
|
||||
}
|
||||
|
||||
public static String getCode(int keyCode, int keyMode, boolean cursorApp, boolean keypadApplication) {
|
||||
boolean numLockOn = (keyMode & KEYMOD_NUM_LOCK) != 0;
|
||||
keyMode &= ~KEYMOD_NUM_LOCK;
|
||||
switch (keyCode) {
|
||||
case KEYCODE_DPAD_CENTER:
|
||||
return "\015";
|
||||
@ -179,7 +186,11 @@ public final class KeyHandler {
|
||||
// Just do what xterm and gnome-terminal does:
|
||||
return prefix + (((keyMode & KEYMOD_CTRL) == 0) ? "\u007F" : "\u0008");
|
||||
case KEYCODE_NUM_LOCK:
|
||||
return "\033OP";
|
||||
if (keypadApplication) {
|
||||
return "\033OP";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
case KEYCODE_SPACE:
|
||||
// If ctrl is not down, return null so that it goes through normal input processing (which may e.g. cause a
|
||||
@ -200,31 +211,81 @@ public final class KeyHandler {
|
||||
case KEYCODE_NUMPAD_COMMA:
|
||||
return ",";
|
||||
case KEYCODE_NUMPAD_DOT:
|
||||
return keypadApplication ? "\033On" : ".";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? "\033On" : ".";
|
||||
} else {
|
||||
// DELETE
|
||||
return transformForModifiers("\033[3", keyMode, '~');
|
||||
}
|
||||
case KEYCODE_NUMPAD_SUBTRACT:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'm') : "-";
|
||||
case KEYCODE_NUMPAD_DIVIDE:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'o') : "/";
|
||||
case KEYCODE_NUMPAD_0:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'p') : "0";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'p') : "0";
|
||||
} else {
|
||||
// INSERT
|
||||
return transformForModifiers("\033[2", keyMode, '~');
|
||||
}
|
||||
case KEYCODE_NUMPAD_1:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'q') : "1";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'q') : "1";
|
||||
} else {
|
||||
// END
|
||||
return (keyMode == 0) ? (cursorApp ? "\033OF" : "\033[F") : transformForModifiers("\033[1", keyMode, 'F');
|
||||
}
|
||||
case KEYCODE_NUMPAD_2:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'r') : "2";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'r') : "2";
|
||||
} else {
|
||||
// DOWN
|
||||
return (keyMode == 0) ? (cursorApp ? "\033OB" : "\033[B") : transformForModifiers("\033[1", keyMode, 'B');
|
||||
}
|
||||
case KEYCODE_NUMPAD_3:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 's') : "3";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 's') : "3";
|
||||
} else {
|
||||
// PGDN
|
||||
return "\033[6~";
|
||||
}
|
||||
case KEYCODE_NUMPAD_4:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 't') : "4";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 't') : "4";
|
||||
} else {
|
||||
// LEFT
|
||||
return (keyMode == 0) ? (cursorApp ? "\033OD" : "\033[D") : transformForModifiers("\033[1", keyMode, 'D');
|
||||
}
|
||||
case KEYCODE_NUMPAD_5:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'u') : "5";
|
||||
case KEYCODE_NUMPAD_6:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'v') : "6";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'v') : "6";
|
||||
} else {
|
||||
// RIGHT
|
||||
return (keyMode == 0) ? (cursorApp ? "\033OC" : "\033[C") : transformForModifiers("\033[1", keyMode, 'C');
|
||||
}
|
||||
case KEYCODE_NUMPAD_7:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'w') : "7";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'w') : "7";
|
||||
} else {
|
||||
// HOME
|
||||
return (keyMode == 0) ? (cursorApp ? "\033OH" : "\033[H") : transformForModifiers("\033[1", keyMode, 'H');
|
||||
}
|
||||
case KEYCODE_NUMPAD_8:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'x') : "8";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'x') : "8";
|
||||
} else {
|
||||
// UP
|
||||
return (keyMode == 0) ? (cursorApp ? "\033OA" : "\033[A") : transformForModifiers("\033[1", keyMode, 'A');
|
||||
}
|
||||
case KEYCODE_NUMPAD_9:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'y') : "9";
|
||||
if (numLockOn) {
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'y') : "9";
|
||||
} else {
|
||||
// PGUP
|
||||
return "\033[5~";
|
||||
}
|
||||
case KEYCODE_NUMPAD_EQUALS:
|
||||
return keypadApplication ? transformForModifiers("\033O", keyMode, 'X') : "=";
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.offsec.nhterm.component.colorscheme
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import io.neolang.frontend.ConfigVisitor
|
||||
import com.offsec.nhterm.App
|
||||
import com.offsec.nhterm.R
|
||||
@ -18,7 +19,7 @@ import java.nio.file.Files
|
||||
class ColorSchemeComponent : ConfigFileBasedComponent<NeoColorScheme>(NeoTermPath.COLORS_PATH) {
|
||||
companion object {
|
||||
fun colorFile(colorName: String): File {
|
||||
return File("${NeoTermPath.COLORS_PATH}/$colorName.nl")
|
||||
return File("${NeoTermPath.COLORS_PATH}/$colorName.nl")
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,18 +50,22 @@ class ColorSchemeComponent : ConfigFileBasedComponent<NeoColorScheme>(NeoTermPat
|
||||
fun reloadColorSchemes(): Boolean {
|
||||
colors.clear()
|
||||
|
||||
File(baseDir)
|
||||
.listFiles(NEOLANG_FILTER)
|
||||
.mapNotNull { this.loadConfigure(it) }
|
||||
.forEach {
|
||||
colors.put(it.colorName, it)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
File(baseDir)
|
||||
.listFiles(NEOLANG_FILTER)
|
||||
.mapNotNull { this.loadConfigure(it) }
|
||||
.forEach {
|
||||
colors.put(it.colorName, it)
|
||||
}
|
||||
|
||||
if (colors.containsKey(DefaultColorScheme.colorName)) {
|
||||
DEFAULT_COLOR = colors[DefaultColorScheme.colorName]!!
|
||||
return true
|
||||
if (colors.containsKey(DefaultColorScheme.colorName)) {
|
||||
DEFAULT_COLOR = colors[DefaultColorScheme.colorName]!!
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun applyColorScheme(view: TerminalView?, extraKeysView: ExtraKeysView?, colorScheme: NeoColorScheme?) {
|
||||
@ -112,7 +117,11 @@ class ColorSchemeComponent : ConfigFileBasedComponent<NeoColorScheme>(NeoTermPat
|
||||
val content = component.newGenerator(colorScheme).generateCode(colorScheme)
|
||||
|
||||
kotlin.runCatching {
|
||||
Files.write(colorFile.toPath(), content.toByteArray())
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Files.write(colorFile.toPath(), content.toByteArray())
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}.onFailure {
|
||||
throw RuntimeException("Failed to save file ${colorFile.absolutePath}")
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.offsec.nhterm.component.colorscheme
|
||||
|
||||
import android.os.Build
|
||||
import com.offsec.nhterm.R
|
||||
import io.neolang.frontend.ConfigVisitor
|
||||
import com.offsec.nhterm.backend.TerminalColorScheme
|
||||
import com.offsec.nhterm.backend.TerminalColors
|
||||
@ -139,12 +141,16 @@ open class NeoColorScheme : CodeGenObject, ConfigFileBasedObject {
|
||||
if (session != null && session.emulator != null) {
|
||||
session.emulator.setColorScheme(scheme)
|
||||
}
|
||||
view.setBackgroundColor(TerminalColors.parse(backgroundColor))
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
view.setBackgroundColor(TerminalColors.parse(backgroundColor))
|
||||
}
|
||||
}
|
||||
|
||||
if (extraKeysView != null) {
|
||||
extraKeysView.setBackgroundColor(TerminalColors.parse(backgroundColor))
|
||||
extraKeysView.setTextColor(TerminalColors.parse(foregroundColor))
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
extraKeysView.setBackgroundColor(TerminalColors.parse(backgroundColor))
|
||||
extraKeysView.setTextColor(TerminalColors.parse(foregroundColor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package com.offsec.nhterm.component.config
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.preference.PreferenceManager
|
||||
import android.system.ErrnoException
|
||||
import android.system.Os
|
||||
@ -49,14 +50,17 @@ open class NeoConfigureFile(val configureFile: File) {
|
||||
|
||||
fun getVisitor() = configVisitor ?: throw IllegalStateException("Configure file not loaded or parse failed.")
|
||||
|
||||
open fun parseConfigure() = kotlin.runCatching {
|
||||
val programCode = String(Files.readAllBytes(configureFile.toPath()))
|
||||
configParser.setInputSource(programCode)
|
||||
|
||||
val ast = configParser.parse()
|
||||
val astVisitor = ast.visit().getVisitor(ConfigVisitor::class.java) ?: return false
|
||||
astVisitor.start()
|
||||
configVisitor = astVisitor.getCallback()
|
||||
open fun parseConfigure() = kotlin.runCatching {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val programCode = String(Files.readAllBytes(configureFile.toPath()))
|
||||
configParser.setInputSource(programCode)
|
||||
|
||||
val ast = configParser.parse()
|
||||
val astVisitor = ast.visit().getVisitor(ConfigVisitor::class.java) ?: return false
|
||||
astVisitor.start()
|
||||
configVisitor = astVisitor.getCallback()
|
||||
}
|
||||
}.isSuccess
|
||||
}
|
||||
|
||||
@ -85,14 +89,16 @@ object NeoPreference {
|
||||
MIN_FONT_SIZE = (4f * dipInPixels).toInt()
|
||||
MAX_FONT_SIZE = 256
|
||||
|
||||
// load apt source
|
||||
val sourceFile = File(NeoTermPath.SOURCE_FILE)
|
||||
kotlin.runCatching {
|
||||
Files.readAllBytes(sourceFile.toPath())?.let {
|
||||
val source = String(it).trim().trimEnd()
|
||||
val array = source.split(" ")
|
||||
if (array.size >= 2 && array[0] == "deb") {
|
||||
store(R.string.key_package_source, array[1])
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// load apt source
|
||||
val sourceFile = File(NeoTermPath.SOURCE_FILE)
|
||||
kotlin.runCatching {
|
||||
Files.readAllBytes(sourceFile.toPath())?.let {
|
||||
val source = String(it).trim().trimEnd()
|
||||
val array = source.split(" ")
|
||||
if (array.size >= 2 && array[0] == "deb") {
|
||||
store(R.string.key_package_source, array[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -226,13 +232,6 @@ object NeoPreference {
|
||||
)
|
||||
}
|
||||
|
||||
fun isVibrateEnabled(): Boolean {
|
||||
return loadBoolean(
|
||||
R.string.key_general_vibrate,
|
||||
DefaultValues.enableVibrate
|
||||
)
|
||||
}
|
||||
|
||||
fun isExecveWrapperEnabled(): Boolean {
|
||||
return loadBoolean(
|
||||
R.string.key_general_use_execve_wrapper,
|
||||
|
@ -3,10 +3,10 @@ package com.offsec.nhterm.component.config
|
||||
import android.annotation.SuppressLint
|
||||
|
||||
object DefaultValues {
|
||||
const val fontSize = 30
|
||||
const val fontSize = 18
|
||||
|
||||
const val enableBell = false
|
||||
const val enableVibrate = true
|
||||
const val enableVibrate = false
|
||||
const val enableExecveWrapper = true
|
||||
const val enableAutoCompletion = false
|
||||
const val enableFullScreen = false
|
||||
@ -27,6 +27,7 @@ object NeoTermPath {
|
||||
@SuppressLint("SdCardPath")
|
||||
const val ROOT_PATH = "/data/data/com.offsec.nhterm/files"
|
||||
const val USR_PATH = "$ROOT_PATH/usr"
|
||||
const val BIN_PATH = "$USR_PATH/bin"
|
||||
const val HOME_PATH = "/"
|
||||
const val APT_BIN_PATH = "$USR_PATH/bin/apt"
|
||||
const val LIB_PATH = "$USR_PATH/lib"
|
||||
@ -43,7 +44,7 @@ object NeoTermPath {
|
||||
const val SOURCE_FILE = "$USR_PATH/etc/apt/sources.list"
|
||||
const val PACKAGE_LIST_DIR = "$USR_PATH/var/lib/apt/lists"
|
||||
|
||||
private const val SOURCE = "https://example.com/nhterm"
|
||||
private const val SOURCE = "http://http.kali.org/kali"
|
||||
|
||||
val DEFAULT_MAIN_PACKAGE_SOURCE: String
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.offsec.nhterm.component.extrakey
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import io.neolang.frontend.ConfigVisitor
|
||||
import com.offsec.nhterm.App
|
||||
import com.offsec.nhterm.component.ConfigFileBasedComponent
|
||||
@ -57,12 +58,14 @@ class ExtraKeyComponent : ConfigFileBasedComponent<NeoExtraKey>(NeoTermPath.EKS_
|
||||
|
||||
private fun reloadExtraKeyConfig() {
|
||||
extraKeys.clear()
|
||||
File(baseDir)
|
||||
.listFiles(NEOLANG_FILTER)
|
||||
.filter { it.absolutePath != NeoTermPath.EKS_DEFAULT_FILE }
|
||||
.mapNotNull { this.loadConfigure(it) }
|
||||
.forEach {
|
||||
registerShortcutKeys(it)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
File(baseDir)
|
||||
.listFiles(NEOLANG_FILTER)
|
||||
.filter { it.absolutePath != NeoTermPath.EKS_DEFAULT_FILE }
|
||||
.mapNotNull { this.loadConfigure(it) }
|
||||
.forEach {
|
||||
registerShortcutKeys(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -38,7 +39,7 @@ public class NeoPackageParser {
|
||||
KEY_HOMEPAGE = "Homepage",
|
||||
KEY_DESC = "Description";
|
||||
|
||||
private BufferedReader reader;
|
||||
private final BufferedReader reader;
|
||||
private ParseStateListener stateListener;
|
||||
|
||||
NeoPackageParser(InputStream inputStream) {
|
||||
@ -100,6 +101,9 @@ public class NeoPackageParser {
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case KEY_PACKAGE_NAME:
|
||||
packageInfo.setPackageName(value);
|
||||
break;
|
||||
case KEY_ARCH:
|
||||
packageInfo.setArchitecture(Architecture.Companion.parse(value));
|
||||
break;
|
||||
@ -149,16 +153,14 @@ public class NeoPackageParser {
|
||||
|
||||
private String appendToLastValue(NeoPackageInfo packageInfo, String key, String value) {
|
||||
// Currently, only descriptions can be multiline
|
||||
switch (key) {
|
||||
case KEY_DESC:
|
||||
return packageInfo.getDescription() + " " + value;
|
||||
default:
|
||||
return value;
|
||||
if (KEY_DESC.equals(key)) {
|
||||
return packageInfo.getDescription() + " " + value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean splitKeyAndValue(String line, String[] splits) {
|
||||
int valueIndex = line.indexOf(':');
|
||||
int valueIndex = line.indexOf(": ");
|
||||
if (valueIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import com.offsec.nhterm.component.NeoComponent;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@ -56,7 +57,7 @@ public class PackageComponent implements NeoComponent {
|
||||
}
|
||||
|
||||
private void tryParsePackages(File packageListFile, final boolean clearPrevious) throws IOException {
|
||||
NeoPackageParser packageParser = new NeoPackageParser(new FileInputStream(packageListFile));
|
||||
NeoPackageParser packageParser = new NeoPackageParser(Files.newInputStream(packageListFile.toPath()));
|
||||
packageParser.setStateListener(new NeoPackageParser.ParseStateListener() {
|
||||
@Override
|
||||
public void onStartState() {
|
||||
@ -88,6 +89,7 @@ public class PackageComponent implements NeoComponent {
|
||||
neoPackages.put(packageInfo.getPackageName(), packageInfo);
|
||||
}
|
||||
});
|
||||
|
||||
packageParser.parse();
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,13 @@ enum class Architecture {
|
||||
}
|
||||
|
||||
class NeoPackageInfo {
|
||||
var packageName: String? = null
|
||||
var packageName: String = "dummy"
|
||||
var isEssential: Boolean = false
|
||||
var version: String? = null
|
||||
var architecture: Architecture = Architecture.ALL
|
||||
var maintainer: String? = null
|
||||
var installedSizeInBytes: Long = 0L
|
||||
var fileName: String? = null
|
||||
var fileName: String = "null"
|
||||
var dependenciesString: String? = null
|
||||
var dependencies: Array<NeoPackageInfo>? = null
|
||||
var sizeInBytes: Long = 0L
|
||||
@ -31,5 +31,5 @@ class NeoPackageInfo {
|
||||
var sha1: String? = null
|
||||
var sha256: String? = null
|
||||
var homePage: String? = null
|
||||
var description: String? = null
|
||||
var description: String = "Dummy package"
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
package com.offsec.nhterm.component.pm
|
||||
|
||||
import android.util.Log
|
||||
import com.offsec.nhterm.App
|
||||
import com.offsec.nhterm.R
|
||||
import com.offsec.nhterm.component.ComponentManager
|
||||
import com.offsec.nhterm.component.config.NeoPreference
|
||||
import com.offsec.nhterm.component.config.NeoTermPath
|
||||
import com.offsec.nhterm.framework.NeoTermDatabase
|
||||
import com.offsec.nhterm.utils.NLog
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
@ -19,7 +22,7 @@ object SourceHelper {
|
||||
|
||||
fun syncSource(sourceManager: SourceManager) {
|
||||
val content = buildString {
|
||||
this.append("# Generated by NeoTerm-Preference\n")
|
||||
this.append("# Generated by NetHunter TerminalPreference\n")
|
||||
sourceManager.getEnabledSources()
|
||||
.joinTo(this, "\n") { "deb [trusted=yes] ${it.url} ${it.repo}\n" }
|
||||
}
|
||||
@ -29,6 +32,10 @@ object SourceHelper {
|
||||
}
|
||||
|
||||
fun detectSourceFiles(): List<File> {
|
||||
// Workaround to get things running
|
||||
// TODO: ( APT ) Make it prettier?
|
||||
copySourceFromChroot()
|
||||
|
||||
val sourceManager = ComponentManager.getComponent<PackageComponent>().sourceManager
|
||||
val sourceFiles = ArrayList<File>()
|
||||
try {
|
||||
@ -38,10 +45,9 @@ object SourceHelper {
|
||||
|
||||
File(NeoTermPath.PACKAGE_LIST_DIR)
|
||||
.listFiles()
|
||||
.filterTo(sourceFiles) { file ->
|
||||
prefixes.filter { file.name.startsWith(it) }
|
||||
.count() > 0
|
||||
}
|
||||
?.filterTo(sourceFiles) { file ->
|
||||
prefixes.count { file.name.startsWith(it) } > 0
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
sourceFiles.clear()
|
||||
NLog.e("PM", "Failed to detect source files: ${e.localizedMessage}")
|
||||
@ -50,7 +56,7 @@ object SourceHelper {
|
||||
return sourceFiles
|
||||
}
|
||||
|
||||
fun detectSourceFilePrefix(source: Source): String {
|
||||
private fun detectSourceFilePrefix(source: Source): String {
|
||||
try {
|
||||
val url = URL(source.url)
|
||||
val builder = StringBuilder(url.host)
|
||||
@ -65,12 +71,42 @@ object SourceHelper {
|
||||
builder.append(fixedPath)
|
||||
}
|
||||
builder.append("_dists_${source.repo.replace(" ".toRegex(), "_")}_binary-")
|
||||
Log.e("ERROR:", builder.toString())
|
||||
return builder.toString()
|
||||
} catch (e: Exception) {
|
||||
NLog.e("PM", "Failed to detect source file prefix: ${e.localizedMessage}")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun copySourceFromChroot() {
|
||||
val APP_MNT = NeoTermPath.USR_PATH
|
||||
val MNT = "/data/local/nhsystem/kalifs"
|
||||
val sources = "$MNT/etc/apt/sources.list"
|
||||
val lists = "$MNT/var/lib/apt/lists"
|
||||
|
||||
// Make sure that nhterm has locally required apt dir's
|
||||
Shell.cmd("mkdir -p $APP_MNT/etc/apt").exec()
|
||||
Shell.cmd("mkdir -p $APP_MNT/var/lib/apt/lists").exec()
|
||||
|
||||
// Also we cant be sure that folders are empty from last use so lets remove stuff
|
||||
Shell.cmd("rm -f $APP_MNT/etc/apt/*").exec()
|
||||
Shell.cmd("rm -f $APP_MNT/var/lib/apt/lists/*").exec()
|
||||
|
||||
// Now lets copy chroot apt sources.list and lists data to app
|
||||
// This allows us to read and show list of packages for user in manager
|
||||
Shell.cmd("cp -f $sources $APP_MNT/etc/apt/sources.list").exec()
|
||||
Shell.cmd("cp -f $lists/* $APP_MNT/var/lib/apt/lists/").exec()
|
||||
|
||||
// Now play with permissions so things are read/writable
|
||||
Shell.cmd("chmod -R 775 $APP_MNT/etc/apt").exec()
|
||||
Shell.cmd("chmod -R 775 $APP_MNT/var/lib/apt/lists").exec()
|
||||
}
|
||||
|
||||
fun updateChrootSource() {
|
||||
// TODO: ( APT ) Add option for user to edit and update sources.list in Package Manager option
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
class SourceManager internal constructor() {
|
||||
@ -84,7 +120,7 @@ class SourceManager internal constructor() {
|
||||
database.saveBean(
|
||||
Source(
|
||||
it,
|
||||
"stable main",
|
||||
"kali-rolling main",
|
||||
true
|
||||
)
|
||||
)
|
||||
@ -122,7 +158,7 @@ class SourceManager internal constructor() {
|
||||
fun getMainPackageSource(): String {
|
||||
return getEnabledSources()
|
||||
.map { it.repo }
|
||||
.singleOrNull { it.trim() == "stable main" }
|
||||
.singleOrNull { it.trim() == "kali-rolling main" }
|
||||
?: NeoTermPath.DEFAULT_MAIN_PACKAGE_SOURCE
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,6 @@ class ShellProfile : NeoProfile() {
|
||||
var initialCommand = DefaultValues.initialCommand
|
||||
|
||||
var enableBell = DefaultValues.enableBell
|
||||
var enableVibrate = DefaultValues.enableVibrate
|
||||
var enableExecveWrapper = DefaultValues.enableExecveWrapper
|
||||
var enableSpecialVolumeKeys = DefaultValues.enableSpecialVolumeKeys
|
||||
var enableAutoCompletion = DefaultValues.enableAutoCompletion
|
||||
@ -134,7 +133,6 @@ class ShellProfile : NeoProfile() {
|
||||
loginShell = NeoPreference.getLoginShellPath()
|
||||
initialCommand = NeoPreference.getInitialCommand()
|
||||
enableBell = NeoPreference.isBellEnabled()
|
||||
enableVibrate = NeoPreference.isVibrateEnabled()
|
||||
enableExecveWrapper = NeoPreference.isExecveWrapperEnabled()
|
||||
enableSpecialVolumeKeys = NeoPreference.isSpecialVolumeKeysEnabled()
|
||||
enableAutoCompletion = NeoPreference.isAutoCompletionEnabled()
|
||||
@ -148,7 +146,6 @@ class ShellProfile : NeoProfile() {
|
||||
loginShell = configVisitor.getProfileString(LOGIN_SHELL, loginShell)
|
||||
initialCommand = configVisitor.getProfileString(INITIAL_COMMAND, initialCommand)
|
||||
enableBell = configVisitor.getProfileBoolean(BELL, enableBell)
|
||||
enableVibrate = configVisitor.getProfileBoolean(VIBRATE, enableVibrate)
|
||||
enableExecveWrapper = configVisitor.getProfileBoolean(EXECVE_WRAPPER, enableExecveWrapper)
|
||||
enableSpecialVolumeKeys = configVisitor.getProfileBoolean(SPECIAL_VOLUME_KEYS, enableSpecialVolumeKeys)
|
||||
enableAutoCompletion = configVisitor.getProfileBoolean(AUTO_COMPLETION, enableAutoCompletion)
|
||||
|
@ -2,18 +2,22 @@ package com.offsec.nhterm.component.userscript
|
||||
|
||||
import android.content.Context
|
||||
import android.system.Os
|
||||
import android.util.Log
|
||||
import com.offsec.nhterm.App
|
||||
import com.offsec.nhterm.component.NeoComponent
|
||||
import com.offsec.nhterm.component.config.NeoTermPath
|
||||
import com.offsec.nhterm.utils.NLog
|
||||
import com.offsec.nhterm.utils.extractAssetsDir
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.File
|
||||
|
||||
class UserScript(val scriptFile: File)
|
||||
|
||||
class UserScriptComponent : NeoComponent {
|
||||
var userScripts = listOf<UserScript>()
|
||||
private val scriptDir = File(NeoTermPath.USER_SCRIPT_PATH)
|
||||
var binFiles = listOf<UserScript>()
|
||||
val scriptDir = File(NeoTermPath.USER_SCRIPT_PATH)
|
||||
val binDir = File(NeoTermPath.BIN_PATH)
|
||||
|
||||
override fun onServiceInit() = checkForFiles()
|
||||
|
||||
@ -22,11 +26,23 @@ class UserScriptComponent : NeoComponent {
|
||||
|
||||
override fun onServiceObtained() = checkForFiles()
|
||||
|
||||
private fun extractDefaultScript(context: Context) = kotlin.runCatching {
|
||||
fun extractDefaultScript(context: Context) = kotlin.runCatching {
|
||||
Shell.cmd("mkdir -p /data/data/com.offsec.nhterm/files/usr/").exec()
|
||||
Shell.cmd("rm -rf /data/data/com.offsec.nhterm/files/usr/bin/*")
|
||||
|
||||
// Usual user script extraction
|
||||
context.extractAssetsDir("scripts", NeoTermPath.USER_SCRIPT_PATH)
|
||||
scriptDir.listFiles().forEach {
|
||||
|
||||
scriptDir.listFiles()?.forEach {
|
||||
Os.chmod(it.absolutePath, 448 /*Dec of 0700*/)
|
||||
}
|
||||
|
||||
// Lets also extract the usual binaries too here
|
||||
context.extractAssetsDir("bin", NeoTermPath.BIN_PATH)
|
||||
binDir.listFiles()?.forEach {
|
||||
Os.chmod(it.absolutePath, 448 /*Dec of 0700*/)
|
||||
}
|
||||
|
||||
}.onFailure {
|
||||
NLog.e("UserScript", "Failed to extract default user scripts: ${it.localizedMessage}")
|
||||
}
|
||||
@ -41,5 +57,10 @@ class UserScriptComponent : NeoComponent {
|
||||
.takeWhile { it.canExecute() }
|
||||
.map { UserScript(it) }
|
||||
.toList()
|
||||
|
||||
binFiles = binDir.listFiles()
|
||||
.takeWhile { it.canExecute() }
|
||||
.map { UserScript(it) }
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,10 @@ import android.content.DialogInterface
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.offsec.nhterm.R
|
||||
import com.offsec.nhterm.backend.TerminalSession
|
||||
import com.offsec.nhterm.component.config.DefaultValues.initialCommand
|
||||
import com.offsec.nhterm.component.session.ShellParameter
|
||||
import com.offsec.nhterm.component.session.ShellTermSession
|
||||
import com.offsec.nhterm.frontend.session.terminal.BasicSessionCallback
|
||||
@ -36,12 +38,12 @@ class TerminalDialog(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun execute(executablePath: String, arguments: Array<String>?): TerminalDialog {
|
||||
fun execute(executablePath: String, arguments: String, extraarg: String): TerminalDialog {
|
||||
if (terminalSession != null) {
|
||||
terminalSession?.finishIfRunning()
|
||||
}
|
||||
|
||||
dialog = AlertDialog.Builder(context)
|
||||
dialog = MaterialAlertDialogBuilder(context, R.style.DialogStyle)
|
||||
.setView(termWindowView.rootView)
|
||||
.setOnCancelListener {
|
||||
terminalSession?.finishIfRunning()
|
||||
@ -49,15 +51,19 @@ class TerminalDialog(val context: Context) {
|
||||
}
|
||||
.create()
|
||||
|
||||
val cmd = listOf(arguments + " " + extraarg + " && exit 0")
|
||||
|
||||
val parameter = ShellParameter()
|
||||
.executablePath(executablePath)
|
||||
.arguments(arguments)
|
||||
.initialCommand(cmd.joinToString())
|
||||
.callback(terminalSessionCallback)
|
||||
.systemShell(false)
|
||||
|
||||
terminalSession = Terminals.createSession(context, parameter)
|
||||
if (terminalSession is ShellTermSession) {
|
||||
(terminalSession as ShellTermSession).exitPrompt = context.getString(R.string.process_exit_prompt_press_back)
|
||||
}
|
||||
|
||||
termWindowView.attachSession(terminalSession)
|
||||
return this
|
||||
}
|
||||
@ -107,7 +113,7 @@ class WindowTermView(val context: Context) {
|
||||
Terminals.setupTerminalView(terminalView)
|
||||
}
|
||||
|
||||
fun setTerminalViewClient(terminalViewClient: com.offsec.nhterm.frontend.session.view.TerminalViewClient?) {
|
||||
fun setTerminalViewClient(terminalViewClient: TerminalViewClient?) {
|
||||
terminalView.setTerminalViewClient(terminalViewClient)
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,14 @@ class BasicViewClient(val terminalView: TerminalView) :
|
||||
return false
|
||||
}
|
||||
|
||||
override fun readShiftKey(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun readFnKey(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onCodePoint(codePoint: Int, ctrlDown: Boolean, session: TerminalSession?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
@ -3,19 +3,13 @@ package com.offsec.nhterm.frontend.session.terminal
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Context.VIBRATOR_SERVICE
|
||||
import android.media.AudioManager
|
||||
import android.media.SoundPool
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import android.util.Log
|
||||
import android.view.InputDevice
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
import com.offsec.nhterm.BuildConfig
|
||||
import com.offsec.nhterm.R
|
||||
import com.offsec.nhterm.backend.KeyHandler
|
||||
import com.offsec.nhterm.backend.TerminalSession
|
||||
@ -36,6 +30,7 @@ class TermViewClient(val context: Context) :
|
||||
TerminalViewClient {
|
||||
private var mVirtualControlKeyDown: Boolean = false
|
||||
private var mVirtualFnKeyDown: Boolean = false
|
||||
private var mVirtualShiftKeyDown: Boolean = false
|
||||
private var lastTitle: String = ""
|
||||
|
||||
var termSessionData: TermSessionData? = null
|
||||
@ -69,11 +64,6 @@ class TermViewClient(val context: Context) :
|
||||
return true
|
||||
}
|
||||
|
||||
if (NeoPreference.isVibrateEnabled()) {
|
||||
val vibrator = context.getSystemService(Vibrator::class.java)
|
||||
vibrator.vibrate(VibrationEffect.createOneShot(40, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||
}
|
||||
|
||||
val termUI = termSessionData?.termUI
|
||||
|
||||
when (keyCode) {
|
||||
@ -140,6 +130,16 @@ class TermViewClient(val context: Context) :
|
||||
return (extraKeysView != null && extraKeysView.readAltButton()) || mVirtualFnKeyDown
|
||||
}
|
||||
|
||||
override fun readShiftKey(): Boolean {
|
||||
val extraKeysView = termSessionData?.extraKeysView
|
||||
return (extraKeysView != null && extraKeysView.readShiftButton()) || mVirtualShiftKeyDown
|
||||
}
|
||||
|
||||
override fun readFnKey(): Boolean {
|
||||
val extraKeysView = termSessionData?.extraKeysView
|
||||
return (extraKeysView != null && extraKeysView.readFnButton()) || mVirtualFnKeyDown
|
||||
}
|
||||
|
||||
override fun onCodePoint(codePoint: Int, ctrlDown: Boolean, session: TerminalSession?): Boolean {
|
||||
if (mVirtualFnKeyDown) {
|
||||
var resultingKeyCode: Int = -1
|
||||
@ -361,13 +361,6 @@ class BellController {
|
||||
}
|
||||
soundPool?.play(bellId, 1f, 1f, 0, 0, 1f)
|
||||
}
|
||||
|
||||
if (session.shellProfile.enableVibrate) {
|
||||
if (NeoPreference.isVibrateEnabled()) {
|
||||
val vibrator = context.getSystemService(Vibrator::class.java)
|
||||
vibrator.vibrate(VibrationEffect.createOneShot(40, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -434,14 +427,6 @@ class TermCompleteListener(var terminalView: TerminalView?) : OnAutoCompleteList
|
||||
}
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e(
|
||||
"NeoTerm-AC",
|
||||
"currentEditing: $textNeedCompletion, " +
|
||||
"deleteLength: $deleteLength, completeString: $newText"
|
||||
)
|
||||
}
|
||||
|
||||
pushString(newText)
|
||||
session.write(newText)
|
||||
// Trigger next completion
|
||||
|
@ -104,6 +104,11 @@ public final class TerminalView extends View {
|
||||
|
||||
private boolean mAccessibilityEnabled;
|
||||
|
||||
public final static int KEY_EVENT_SOURCE_VIRTUAL_KEYBOARD = KeyCharacterMap.VIRTUAL_KEYBOARD; // -1
|
||||
|
||||
/** The {@link KeyEvent} is generated from a non-physical device, like if 0 value is returned by {@link KeyEvent#getDeviceId()}. */
|
||||
public final static int KEY_EVENT_SOURCE_SOFT_KEYBOARD = 0;
|
||||
|
||||
public TerminalView(Context context) {
|
||||
super(context);
|
||||
commonInit(context);
|
||||
@ -334,11 +339,12 @@ public final class TerminalView extends View {
|
||||
// https://github.com/termux/termux-app/issues/87.
|
||||
// https://github.com/termux/termux-app/issues/126.
|
||||
// https://github.com/termux/termux-app/issues/137 (japanese chars and TYPE_NULL).
|
||||
|
||||
if (mEnableWordBasedIme) {
|
||||
// Workaround for Google Pinying cannot input Chinese
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
|
||||
outAttrs.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
|
||||
} else {
|
||||
outAttrs.inputType = InputType.TYPE_NULL;
|
||||
outAttrs.inputType = InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL | InputType.TYPE_NULL;
|
||||
}
|
||||
|
||||
// Note that IME_ACTION_NONE cannot be used as that makes it impossible to input newlines using the on-screen
|
||||
@ -432,7 +438,7 @@ public final class TerminalView extends View {
|
||||
}
|
||||
}
|
||||
|
||||
inputCodePoint(codePoint, ctrlHeld, false);
|
||||
inputCodePoint(KEY_EVENT_SOURCE_SOFT_KEYBOARD, codePoint, ctrlHeld, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,14 +750,16 @@ public final class TerminalView extends View {
|
||||
}
|
||||
|
||||
final int metaState = event.getMetaState();
|
||||
final boolean controlDownFromEvent = event.isCtrlPressed();
|
||||
final boolean leftAltDownFromEvent = (metaState & KeyEvent.META_ALT_LEFT_ON) != 0;
|
||||
final boolean controlDown = event.isCtrlPressed() || mClient.readControlKey();
|
||||
final boolean leftAltDown = (metaState & KeyEvent.META_ALT_LEFT_ON) != 0 || mClient.readAltKey();
|
||||
final boolean shiftDown = event.isShiftPressed() || mClient.readShiftKey();
|
||||
final boolean rightAltDownFromEvent = (metaState & KeyEvent.META_ALT_RIGHT_ON) != 0;
|
||||
|
||||
int keyMod = 0;
|
||||
if (controlDownFromEvent) keyMod |= KeyHandler.KEYMOD_CTRL;
|
||||
if (event.isAltPressed()) keyMod |= KeyHandler.KEYMOD_ALT;
|
||||
if (event.isShiftPressed()) keyMod |= KeyHandler.KEYMOD_SHIFT;
|
||||
if (controlDown) keyMod |= KeyHandler.KEYMOD_CTRL;
|
||||
if (event.isAltPressed() || leftAltDown) keyMod |= KeyHandler.KEYMOD_ALT;
|
||||
if (shiftDown) keyMod |= KeyHandler.KEYMOD_SHIFT;
|
||||
if (event.isNumLockOn()) keyMod |= KeyHandler.KEYMOD_NUM_LOCK;
|
||||
if (!event.isFunctionPressed() && handleKeyCode(keyCode, keyMod)) {
|
||||
if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "handleKeyCode() took key event");
|
||||
return true;
|
||||
@ -778,7 +786,7 @@ public final class TerminalView extends View {
|
||||
if ((result & KeyCharacterMap.COMBINING_ACCENT) != 0) {
|
||||
// If entered combining accent previously, write it out:
|
||||
if (mCombiningAccent != 0)
|
||||
inputCodePoint(mCombiningAccent, controlDownFromEvent, leftAltDownFromEvent);
|
||||
inputCodePoint(event.getDeviceId(), mCombiningAccent, controlDown, leftAltDown);
|
||||
mCombiningAccent = result & KeyCharacterMap.COMBINING_ACCENT_MASK;
|
||||
} else {
|
||||
if (mCombiningAccent != 0) {
|
||||
@ -786,7 +794,7 @@ public final class TerminalView extends View {
|
||||
if (combinedChar > 0) result = combinedChar;
|
||||
mCombiningAccent = 0;
|
||||
}
|
||||
inputCodePoint(result, controlDownFromEvent, leftAltDownFromEvent);
|
||||
inputCodePoint(event.getDeviceId(), result, controlDown, leftAltDown);
|
||||
}
|
||||
|
||||
if (mCombiningAccent != oldCombiningAccent) invalidate();
|
||||
@ -804,7 +812,7 @@ public final class TerminalView extends View {
|
||||
return true;
|
||||
}
|
||||
|
||||
void inputCodePoint(int codePoint, boolean controlDownFromEvent, boolean leftAltDownFromEvent) {
|
||||
public void inputCodePoint(int eventSource, int codePoint, boolean controlDownFromEvent, boolean leftAltDownFromEvent) {
|
||||
if (LOG_KEY_EVENTS) {
|
||||
Log.i(EmulatorDebug.LOG_TAG, "inputCodePoint(codePoint=" + codePoint + ", controlDownFromEvent=" + controlDownFromEvent + ", leftAltDownFromEvent="
|
||||
+ leftAltDownFromEvent + ")");
|
||||
@ -842,19 +850,22 @@ public final class TerminalView extends View {
|
||||
}
|
||||
|
||||
if (codePoint > -1) {
|
||||
// Work around bluetooth keyboards sending funny unicode characters instead
|
||||
// of the more normal ones from ASCII that terminal programs expect - the
|
||||
// desire to input the original characters should be low.
|
||||
switch (codePoint) {
|
||||
case 0x02DC: // SMALL TILDE.
|
||||
codePoint = 0x007E; // TILDE (~).
|
||||
break;
|
||||
case 0x02CB: // MODIFIER LETTER GRAVE ACCENT.
|
||||
codePoint = 0x0060; // GRAVE ACCENT (`).
|
||||
break;
|
||||
case 0x02C6: // MODIFIER LETTER CIRCUMFLEX ACCENT.
|
||||
codePoint = 0x005E; // CIRCUMFLEX ACCENT (^).
|
||||
break;
|
||||
// If not virtual or soft keyboard.
|
||||
if (eventSource > KEY_EVENT_SOURCE_SOFT_KEYBOARD) {
|
||||
// Work around bluetooth keyboards sending funny unicode characters instead
|
||||
// of the more normal ones from ASCII that terminal programs expect - the
|
||||
// desire to input the original characters should be low.
|
||||
switch (codePoint) {
|
||||
case 0x02DC: // SMALL TILDE.
|
||||
codePoint = 0x007E; // TILDE (~).
|
||||
break;
|
||||
case 0x02CB: // MODIFIER LETTER GRAVE ACCENT.
|
||||
codePoint = 0x0060; // GRAVE ACCENT (`).
|
||||
break;
|
||||
case 0x02C6: // MODIFIER LETTER CIRCUMFLEX ACCENT.
|
||||
codePoint = 0x005E; // CIRCUMFLEX ACCENT (^).
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If left alt, send escape before the code point to make e.g. Alt+B and Alt+F work in readline:
|
||||
|
@ -35,6 +35,10 @@ public interface TerminalViewClient {
|
||||
|
||||
boolean readAltKey();
|
||||
|
||||
boolean readShiftKey();
|
||||
|
||||
boolean readFnKey();
|
||||
|
||||
boolean onCodePoint(int codePoint, boolean ctrlDown, TerminalSession session);
|
||||
|
||||
boolean onLongPress(MotionEvent event);
|
||||
|
@ -2,6 +2,7 @@ package com.offsec.nhterm.frontend.session.view.extrakey
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.os.Build
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import android.util.AttributeSet
|
||||
@ -29,6 +30,7 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
|
||||
private val ARROW_DOWN = ArrowButton(IExtraButton.KEY_ARROW_DOWN)
|
||||
private val ARROW_LEFT = ArrowButton(IExtraButton.KEY_ARROW_LEFT)
|
||||
private val ARROW_RIGHT = ArrowButton(IExtraButton.KEY_ARROW_RIGHT)
|
||||
private val SLASH = ControlButton(IExtraButton.KEY_SLASH)
|
||||
private val TOGGLE_IME = object : ControlButton(KEY_TOGGLE_IME) {
|
||||
override fun onClick(view: View) {
|
||||
EventBus.getDefault().post(ToggleImeEvent())
|
||||
@ -51,8 +53,11 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
|
||||
// For avoid memory and context leak.
|
||||
private val CTRL = StatedControlButton(IExtraButton.KEY_CTRL)
|
||||
private val ALT = StatedControlButton(IExtraButton.KEY_ALT)
|
||||
private val FN = StatedControlButton(IExtraButton.KEY_FN)
|
||||
private val SHIFT = StatedControlButton(IExtraButton.KEY_SHIFT)
|
||||
|
||||
private var buttonPanelExpanded = false
|
||||
|
||||
private val EXPAND_BUTTONS = object : ControlButton(IExtraButton.KEY_SHOW_ALL_BUTTONS) {
|
||||
override fun onClick(view: View) {
|
||||
expandButtonPanel()
|
||||
@ -103,6 +108,14 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
|
||||
return ALT.readState()
|
||||
}
|
||||
|
||||
fun readFnButton(): Boolean {
|
||||
return FN.readState()
|
||||
}
|
||||
|
||||
fun readShiftButton(): Boolean {
|
||||
return SHIFT.readState()
|
||||
}
|
||||
|
||||
fun addUserKey(button: IExtraButton) {
|
||||
addKeyButton(userKeys, button)
|
||||
}
|
||||
@ -208,11 +221,6 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
|
||||
outerButton.isAllCaps = false
|
||||
|
||||
outerButton.setOnClickListener {
|
||||
if (NeoPreference.isVibrateEnabled()) {
|
||||
val vibrator = context.getSystemService(Vibrator::class.java)
|
||||
vibrator.vibrate(VibrationEffect.createOneShot(40, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||
}
|
||||
|
||||
val root = rootView
|
||||
extraButton.onClick(root)
|
||||
}
|
||||
@ -236,7 +244,12 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
|
||||
addBuiltinKey(HOME)
|
||||
addBuiltinKey(ARROW_UP)
|
||||
addBuiltinKey(END)
|
||||
addBuiltinKey(EXPAND_BUTTONS)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
addBuiltinKey(EXPAND_BUTTONS)
|
||||
} else {
|
||||
addBuiltinKey(SLASH)
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateButtonWidth(): Int {
|
||||
|
@ -50,6 +50,7 @@ abstract class IExtraButton : View.OnClickListener {
|
||||
const val KEY_ARROW_LEFT_TEXT = "Left"
|
||||
const val KEY_ARROW_RIGHT_TEXT = "Right"
|
||||
const val KEY_SHOW_ALL_BUTTONS = "···"
|
||||
const val KEY_SLASH = "/"
|
||||
const val KEY_TOGGLE_IME = "⌨"
|
||||
|
||||
const val KEY_ARROW_UP = "▲"
|
||||
@ -73,6 +74,7 @@ abstract class IExtraButton : View.OnClickListener {
|
||||
const val KEY_F12 = "F12"
|
||||
|
||||
// Extra keys
|
||||
const val KEY_SHIFT = "LShift"
|
||||
const val KEY_DEL = "Del"
|
||||
const val KEY_ENTER = "Enter"
|
||||
|
||||
@ -97,6 +99,9 @@ abstract class IExtraButton : View.OnClickListener {
|
||||
KEY_PAGE_DOWN -> keyCode = KeyEvent.KEYCODE_PAGE_DOWN
|
||||
KEY_HOME -> keyCode = KeyEvent.KEYCODE_MOVE_HOME
|
||||
KEY_END -> keyCode = KeyEvent.KEYCODE_MOVE_END
|
||||
KEY_FN -> keyCode = KeyEvent.KEYCODE_FUNCTION
|
||||
KEY_SHIFT -> keyCode = KeyEvent.KEYCODE_SHIFT_LEFT
|
||||
KEY_SLASH -> keyCode = KeyEvent.KEYCODE_SLASH
|
||||
"―" -> chars = "-"
|
||||
|
||||
// Function keys
|
||||
|
@ -5,6 +5,7 @@ import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.offsec.nhterm.App
|
||||
import com.offsec.nhterm.R
|
||||
import com.offsec.nhterm.component.config.NeoTermPath
|
||||
@ -69,7 +70,7 @@ object SetupHelper {
|
||||
}
|
||||
|
||||
fun makeErrorDialog(context: Context, message: String): AlertDialog {
|
||||
return AlertDialog.Builder(context)
|
||||
return MaterialAlertDialogBuilder(context, R.style.DialogStyle)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.yes, null)
|
||||
|
@ -13,6 +13,7 @@ import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.wrdlbrnft.sortedlistadapter.SortedListAdapter
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import es.dmoral.coloromatic.ColorOMaticDialog
|
||||
import es.dmoral.coloromatic.IndicatorMode
|
||||
import es.dmoral.coloromatic.colormode.ColorMode
|
||||
@ -77,7 +78,7 @@ class ColorSchemeActivity : BaseCustomizeActivity() {
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && event!!.action == KeyEvent.ACTION_DOWN && changed) {
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setMessage(getString(R.string.discard_changes))
|
||||
.setPositiveButton(R.string.save) { _, _ ->
|
||||
applyColorScheme(editingColorScheme, true)
|
||||
@ -129,7 +130,7 @@ class ColorSchemeActivity : BaseCustomizeActivity() {
|
||||
changed = true
|
||||
}
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setTitle(model.colorName)
|
||||
.setView(view)
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
@ -159,7 +160,7 @@ class ColorSchemeActivity : BaseCustomizeActivity() {
|
||||
val edit = view.findViewById<EditText>(R.id.dialog_edit_text_editor)
|
||||
edit.setText(getString(R.string.save_color_scheme_name_template))
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setTitle(R.string.save_color)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.yes) { _, _ ->
|
||||
|
@ -1,14 +1,17 @@
|
||||
package com.offsec.nhterm.ui.other
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.system.Os
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import de.psdev.licensesdialog.LicensesDialog
|
||||
import de.psdev.licensesdialog.licenses.ApacheSoftwareLicense20
|
||||
import de.psdev.licensesdialog.licenses.GnuGeneralPublicLicense30
|
||||
@ -17,9 +20,13 @@ import de.psdev.licensesdialog.model.Notice
|
||||
import de.psdev.licensesdialog.model.Notices
|
||||
import com.offsec.nhterm.App
|
||||
import com.offsec.nhterm.R
|
||||
import com.offsec.nhterm.component.config.NeoTermPath
|
||||
import com.offsec.nhterm.frontend.floating.TerminalDialog
|
||||
import com.offsec.nhterm.utils.extractAssetsDir
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import de.psdev.licensesdialog.licenses.SILOpenFontLicense11
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
|
||||
|
||||
@ -161,10 +168,10 @@ class AboutActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
findViewById<View>(R.id.about_reset_app_view).setOnClickListener {
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setMessage(R.string.reset_app_warning)
|
||||
.setPositiveButton(R.string.yes) { _, _ ->
|
||||
resetApp()
|
||||
.setPositiveButton("yes") { _, _ ->
|
||||
resetApp(this)
|
||||
resetisdone()
|
||||
}
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
@ -173,41 +180,29 @@ class AboutActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun resetisdone() {
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setMessage(R.string.done)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
.setPositiveButton("Ok") { _, _ ->
|
||||
return@setPositiveButton
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
fun resetApp() {
|
||||
// Manual way of resetting required assets
|
||||
Runtime.getRuntime().exec("mkdir -p "+" "+"/data/data/com.offsec.nhterm/files/usr/").waitFor()
|
||||
Executer("/system/bin/rm -rf /data/data/com.offsec.nhterm/files/usr/bin")
|
||||
Thread.sleep(1200)
|
||||
extractAssetsDir("bin", "/data/data/com.offsec.nhterm/files/usr/bin/")
|
||||
Thread.sleep(800)
|
||||
Executer("/system/bin/chmod +x /data/data/com.offsec.nhterm/files/usr/bin/bash") // Static bash for arm ( works for *64 too )
|
||||
Executer("/system/bin/chmod +x /data/data/com.offsec.nhterm/files/usr/bin/kali") // Kali chroot scriptlet
|
||||
Executer("/system/bin/chmod +x /data/data/com.offsec.nhterm/files/usr/bin/android-su") // Android su scriptlet
|
||||
}
|
||||
private fun resetApp(context: Context) {
|
||||
val binDir = File(NeoTermPath.BIN_PATH)
|
||||
////
|
||||
// As some roms act weird and cause issues like no assets are extracted on fresh run then we need to force
|
||||
// assets extraction
|
||||
////
|
||||
Shell.cmd("mkdir -p /data/data/com.offsec.nhterm/files/usr/").exec()
|
||||
Shell.cmd("rm -rf /data/data/com.offsec.nhterm/files/usr/bin/*").exec()
|
||||
|
||||
fun Executer(command: String?): String? {
|
||||
val output = StringBuilder()
|
||||
val p: Process
|
||||
try {
|
||||
p = Runtime.getRuntime().exec(command)
|
||||
p.waitFor()
|
||||
val reader = BufferedReader(InputStreamReader(p.inputStream))
|
||||
var line: String?
|
||||
while (reader.readLine().also { line = it } != null) {
|
||||
output.append(line).append('\n')
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return output.toString()
|
||||
extractAssetsDir("bin", "/data/data/com.offsec.nhterm/files/usr/bin/")
|
||||
|
||||
context.extractAssetsDir("bin", NeoTermPath.BIN_PATH)
|
||||
binDir.listFiles()?.forEach {
|
||||
Os.chmod(it.absolutePath, 448 /*Dec of 0700*/)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openUrl(url: String) {
|
||||
|
@ -9,6 +9,7 @@ import android.view.View
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.offsec.nhterm.App
|
||||
import com.offsec.nhterm.R
|
||||
import com.offsec.nhterm.component.config.NeoTermPath
|
||||
@ -142,7 +143,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
||||
|
||||
val edit = view.findViewById<EditText>(R.id.dialog_edit_text_editor)
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setTitle(R.string.new_source)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.yes) { _, _ ->
|
||||
@ -192,7 +193,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
||||
val titleId = if (needSetup) R.string.setup_confirm else R.string.setup_reset_confirm
|
||||
val messageId = if (needSetup) R.string.setup_confirm_text else R.string.setup_reset_confirm_text
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setTitle(titleId)
|
||||
.setMessage(messageId)
|
||||
.setPositiveButton(android.R.string.yes) { _, _ ->
|
||||
@ -213,7 +214,7 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
||||
executeAptUpdate()
|
||||
|
||||
} else {
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(error.toString())
|
||||
.setNegativeButton(R.string.use_system_shell) { _, _ ->
|
||||
@ -228,11 +229,11 @@ class SetupActivity : AppCompatActivity(), View.OnClickListener, ResultListener
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeAptUpdate() = runApt("update") {
|
||||
private fun executeAptUpdate() = runApt("apt","update", "") {
|
||||
it.onSuccess { executeAptUpgrade() }
|
||||
}
|
||||
|
||||
private fun executeAptUpgrade() = runApt("upgrade", "-y") {
|
||||
private fun executeAptUpgrade() = runApt("apt", "upgrade", "") {
|
||||
it.onSuccess { finish() }
|
||||
}
|
||||
}
|
||||
|
@ -15,12 +15,15 @@ import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.view.MenuItemCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.wrdlbrnft.sortedlistadapter.SortedListAdapter
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.offsec.nhterm.R
|
||||
import com.offsec.nhterm.component.ComponentManager
|
||||
import com.offsec.nhterm.component.config.NeoPreference
|
||||
import com.offsec.nhterm.component.pm.*
|
||||
import com.offsec.nhterm.utils.StringDistance
|
||||
import com.offsec.nhterm.utils.runApt
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@ -29,14 +32,14 @@ import java.util.*
|
||||
|
||||
class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListener, SortedListAdapter.Callback {
|
||||
private val comparator = SortedListAdapter.ComparatorBuilder<PackageModel>()
|
||||
.setOrderForModel<PackageModel>(PackageModel::class.java) { a, b ->
|
||||
.setOrderForModel(PackageModel::class.java) { a, b ->
|
||||
a.packageInfo.packageName!!.compareTo(b.packageInfo.packageName!!)
|
||||
}
|
||||
.build()
|
||||
|
||||
lateinit var recyclerView: androidx.recyclerview.widget.RecyclerView
|
||||
lateinit var adapter: PackageAdapter
|
||||
var models = listOf<PackageModel>()
|
||||
private lateinit var recyclerView: androidx.recyclerview.widget.RecyclerView
|
||||
private lateinit var adapter: PackageAdapter
|
||||
private var models = listOf<PackageModel>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -49,7 +52,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
recyclerView.setHasFixedSize(true)
|
||||
adapter = PackageAdapter(this, comparator, object : PackageAdapter.Listener {
|
||||
override fun onModelClicked(model: PackageModel) {
|
||||
AlertDialog.Builder(this@PackageManagerActivity)
|
||||
MaterialAlertDialogBuilder(this@PackageManagerActivity, R.style.DialogStyle)
|
||||
.setTitle(model.packageInfo.packageName)
|
||||
.setMessage(model.getPackageDetails(this@PackageManagerActivity))
|
||||
.setPositiveButton(R.string.install) { _, _ ->
|
||||
@ -63,11 +66,12 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
recyclerView.adapter = adapter
|
||||
|
||||
refreshPackageList()
|
||||
}
|
||||
|
||||
private fun installPackage(packageName: String?) = packageName?.let {
|
||||
runApt("install", "-y", it, autoClose = false) {
|
||||
private fun installPackage(packageName: String?) = packageName?.let { it ->
|
||||
runApt("apt install", "-y", it, autoClose = true) { it ->
|
||||
it.onSuccess { it.setTitle(getString(R.string.done)) }
|
||||
}
|
||||
}
|
||||
@ -81,14 +85,14 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item?.itemId) {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> finish()
|
||||
R.id.action_source -> changeSource()
|
||||
R.id.action_update_and_refresh -> executeAptUpdate()
|
||||
R.id.action_refresh -> refreshPackageList()
|
||||
R.id.action_upgrade -> executeAptUpgrade()
|
||||
}
|
||||
return item?.let { super.onOptionsItemSelected(it) }
|
||||
return item.let { super.onOptionsItemSelected(it) }
|
||||
}
|
||||
|
||||
private fun changeSource() {
|
||||
@ -97,7 +101,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
|
||||
val items = sourceList.map { "${it.url} :: ${it.repo}" }.toTypedArray()
|
||||
val selection = sourceList.map { it.enabled }.toBooleanArray()
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setTitle(R.string.pref_package_source)
|
||||
.setMultiChoiceItems(items, selection) { _, which, isChecked ->
|
||||
sourceList[which].enabled = isChecked
|
||||
@ -116,9 +120,9 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
|
||||
val urlEditor = view.findViewById<EditText>(R.id.dialog_edit_text_editor)
|
||||
val repoEditor = view.findViewById<EditText>(R.id.dialog_edit_text2_editor)
|
||||
repoEditor.setText("stable main")
|
||||
repoEditor.setText("kali-rolling main")
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setTitle(R.string.pref_package_source)
|
||||
.setView(view)
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
@ -156,14 +160,16 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
executeAptUpdate()
|
||||
}
|
||||
|
||||
private fun executeAptUpdate() = runApt("update") {
|
||||
private fun executeAptUpdate() = runApt("apt","update", "", autoClose = true) {
|
||||
Toast.makeText(this, R.string.apt_update_ok, Toast.LENGTH_LONG).show()
|
||||
|
||||
it.onSuccess { refreshPackageList() }
|
||||
}
|
||||
|
||||
private fun executeAptUpgrade() = runApt("update") { update ->
|
||||
private fun executeAptUpgrade() = runApt("apt", "update", "", autoClose = true) { update ->
|
||||
update.onSuccess {
|
||||
runApt("upgrade", "-y") {
|
||||
it.onSuccess { Toast.makeText(this, R.string.apt_upgrade_ok, Toast.LENGTH_SHORT).show() }
|
||||
runApt("apt", "upgrade", "-y", autoClose = true) {
|
||||
it.onSuccess { Toast.makeText(this, R.string.apt_upgrade_ok, Toast.LENGTH_LONG).show() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,7 +196,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
): List<Pair<PackageModel, Int>> {
|
||||
return models
|
||||
.map {
|
||||
it to StringDistance.distance(mapper(it.packageInfo).toLowerCase(Locale.ROOT), query.toLowerCase(Locale.ROOT))
|
||||
it to StringDistance.distance(mapper(it.packageInfo).lowercase(Locale.ENGLISH), query.lowercase(Locale.ENGLISH))
|
||||
}
|
||||
.sortedWith { l, r -> r.second.compareTo(l.second) }
|
||||
.toList()
|
||||
@ -199,11 +205,9 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
private fun filter(models: List<PackageModel>, query: String): List<PackageModel> {
|
||||
val prepared = models.filter {
|
||||
it.packageInfo.packageName!!.contains(query, true)
|
||||
|| it.packageInfo.description!!.contains(query, true)
|
||||
}
|
||||
|
||||
return sortDistance(prepared, query) { it.packageName!! }
|
||||
.plus(sortDistance(prepared, query) { it.description!! })
|
||||
.map { it.first }
|
||||
.toList()
|
||||
}
|
||||
|
@ -14,12 +14,12 @@ import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
|
||||
class PackageAdapter(
|
||||
context: Context,
|
||||
comparator: Comparator<PackageModel>,
|
||||
private val listener: PackageAdapter.Listener
|
||||
private val listener: Listener
|
||||
) : SortedListAdapter<PackageModel>(context, PackageModel::class.java, comparator),
|
||||
FastScrollRecyclerView.SectionedAdapter {
|
||||
|
||||
override fun getSectionName(position: Int): String {
|
||||
return getItem(position).packageInfo.packageName?.substring(0, 1) ?: "#"
|
||||
return getItem(position).packageInfo.packageName!!.substring(0, 1) ?: "#"
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
@ -53,14 +53,14 @@ class PackageViewHolder(private val rootView: View, private val listener: Packag
|
||||
*/
|
||||
|
||||
class PackageModel(val packageInfo: NeoPackageInfo) : SortedListAdapter.ViewModel {
|
||||
override fun <T> isSameModelAs(t: T): Boolean {
|
||||
override fun <T : Any> isSameModelAs(t: T): Boolean {
|
||||
if (t is PackageModel) {
|
||||
return t.packageInfo.packageName == packageInfo.packageName
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun <T> isContentTheSameAs(t: T): Boolean {
|
||||
override fun <T : Any> isContentTheSameAs(t: T): Boolean {
|
||||
return isSameModelAs(t)
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,8 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import com.offsec.nhterm.R;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class RecyclerTabLayout extends RecyclerView {
|
||||
|
||||
protected static final long DEFAULT_SCROLL_DURATION = 200;
|
||||
@ -397,6 +399,7 @@ public class RecyclerTabLayout extends RecyclerView {
|
||||
int center = mRecyclerTabLayout.getWidth() / 2;
|
||||
for (int position = first; position <= last; position++) {
|
||||
View view = mLinearLayoutManager.findViewByPosition(position);
|
||||
assert view != null;
|
||||
if (view.getLeft() + view.getWidth() >= center) {
|
||||
mRecyclerTabLayout.setCurrentItem(position, false);
|
||||
break;
|
||||
@ -535,14 +538,14 @@ public class RecyclerTabLayout extends RecyclerView {
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(DefaultAdapter.ViewHolder holder, int position) {
|
||||
CharSequence title = getViewPager().getAdapter().getPageTitle(position);
|
||||
CharSequence title = Objects.requireNonNull(getViewPager().getAdapter()).getPageTitle(position);
|
||||
holder.title.setText(title);
|
||||
holder.title.setSelected(getCurrentIndicatorPosition() == position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return getViewPager().getAdapter().getCount();
|
||||
return Objects.requireNonNull(getViewPager().getAdapter()).getCount();
|
||||
}
|
||||
|
||||
public void setTabPadding(int tabPaddingStart, int tabPaddingTop, int tabPaddingEnd,
|
||||
|
@ -16,14 +16,20 @@
|
||||
package com.offsec.nhterm.ui.settings
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources.Theme
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceActivity
|
||||
import android.view.MenuInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.StyleRes
|
||||
import androidx.appcompat.app.ActionBar
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.res.ResourcesCompat.ThemeCompat
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.offsec.nhterm.R
|
||||
|
||||
/**
|
||||
* A [android.preference.PreferenceActivity] which implements and proxies the necessary calls
|
||||
@ -39,6 +45,7 @@ abstract class BasePreferenceActivity : PreferenceActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
delegate.installViewFactory()
|
||||
delegate.onCreate(savedInstanceState)
|
||||
delegate.setTheme(R.style.AppTheme)
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
package com.offsec.nhterm.ui.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceActivity
|
||||
import android.view.MenuItem
|
||||
import androidx.preference.Preference
|
||||
import com.offsec.nhterm.R
|
||||
|
||||
/**
|
||||
@ -16,7 +18,7 @@ class GeneralSettingsActivity : BasePreferenceActivity() {
|
||||
addPreferencesFromResource(R.xml.setting_general)
|
||||
}
|
||||
|
||||
override fun onBuildHeaders(target: MutableList<Header>?) {
|
||||
override fun onBuildHeaders(target: MutableList<PreferenceActivity.Header>?) {
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.offsec.nhterm.ui.settings
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import com.offsec.nhterm.R
|
||||
@ -13,7 +14,11 @@ class SettingActivity : BasePreferenceActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
supportActionBar?.title = getString(R.string.settings)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
addPreferencesFromResource(R.xml.settings_main)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
addPreferencesFromResource(R.xml.settings_main)
|
||||
} else {
|
||||
addPreferencesFromResource(R.xml.older_settings_main)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBuildHeaders(target: MutableList<Header>?) {
|
||||
|
@ -9,6 +9,7 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.ImageButton
|
||||
@ -21,8 +22,8 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.OnApplyWindowInsetsListener
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.offsec.nhterm.App
|
||||
import com.offsec.nhterm.BuildConfig
|
||||
import com.offsec.nhterm.R
|
||||
import com.offsec.nhterm.backend.TerminalSession
|
||||
import com.offsec.nhterm.component.ComponentManager
|
||||
@ -34,14 +35,18 @@ import com.offsec.nhterm.component.session.XParameter
|
||||
import com.offsec.nhterm.component.session.XSession
|
||||
import com.offsec.nhterm.frontend.session.terminal.*
|
||||
import com.offsec.nhterm.services.NeoTermService
|
||||
import com.offsec.nhterm.ui.pm.PackageManagerActivity
|
||||
import com.offsec.nhterm.ui.settings.SettingActivity
|
||||
import com.offsec.nhterm.utils.FullScreenHelper
|
||||
import com.offsec.nhterm.utils.NeoPermission
|
||||
import com.offsec.nhterm.utils.RangedInt
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import de.mrapp.android.tabswitcher.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import java.lang.System.`in`
|
||||
import java.lang.System.out
|
||||
|
||||
|
||||
class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
@ -60,8 +65,18 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val SDCARD_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1
|
||||
|
||||
NeoPermission.initAppPermission(this, NeoPermission.REQUEST_APP_PERMISSION)
|
||||
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), SDCARD_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE)
|
||||
}
|
||||
|
||||
val fullscreen = NeoPreference.isFullScreenEnabled()
|
||||
if (fullscreen) {
|
||||
window.setFlags(
|
||||
@ -70,19 +85,6 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
)
|
||||
}
|
||||
|
||||
val SDCARD_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
|
||||
SDCARD_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE,
|
||||
)
|
||||
}
|
||||
|
||||
setContentView(R.layout.ui_main)
|
||||
|
||||
toolbar = findViewById(R.id.terminal_toolbar)
|
||||
@ -142,7 +144,11 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_main, menu)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
menuInflater.inflate(R.menu.menu_main, menu)
|
||||
} else {
|
||||
menuInflater.inflate(R.menu.older_menu_main, menu)
|
||||
}
|
||||
|
||||
TabSwitcher.setupWithMenu(
|
||||
tabSwitcher, toolbar.menu,
|
||||
@ -169,15 +175,23 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
true
|
||||
}
|
||||
R.id.menu_item_new_session -> {
|
||||
addNewNetHunterSession("KALI LINUX")
|
||||
addNewNetHunterSession("Kali Shell")
|
||||
true
|
||||
}
|
||||
R.id.menu_item_new_system_session -> {
|
||||
addNewAndroidSession("Android")
|
||||
R.id.menu_item_new_emergency_session -> {
|
||||
addNewEmergencySession("Emergency Shell")
|
||||
true
|
||||
}
|
||||
R.id.menu_item_new_bash_session -> {
|
||||
addNewAndroidSession("Android Shell")
|
||||
true
|
||||
}
|
||||
R.id.menu_item_new_root_session -> {
|
||||
addNewRootSession("Android SU")
|
||||
addNewRootSession("Root Shell")
|
||||
true
|
||||
}
|
||||
R.id.menu_item_package_settings -> {
|
||||
startActivity(Intent(this, PackageManagerActivity::class.java))
|
||||
true
|
||||
}
|
||||
else -> item?.let { super.onOptionsItemSelected(it) }
|
||||
@ -233,6 +247,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val tab = tabSwitcher.selectedTab as NeoTab?
|
||||
tab?.onResume()
|
||||
}
|
||||
@ -241,7 +256,9 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
super.onStart()
|
||||
EventBus.getDefault().register(this)
|
||||
val tab = tabSwitcher.selectedTab as NeoTab?
|
||||
tab?.onStart()
|
||||
if (tab != null) {
|
||||
tab.onStart()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
@ -303,7 +320,8 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
if (grantResults.isEmpty()
|
||||
|| grantResults[0] != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
AlertDialog.Builder(this).setMessage(R.string.permission_denied)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setMessage(R.string.permission_denied)
|
||||
.setPositiveButton(
|
||||
android.R.string.ok,
|
||||
{ _: DialogInterface, _: Int ->
|
||||
@ -459,7 +477,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
val profilesShell = profiles.filterIsInstance<ShellProfile>()
|
||||
|
||||
if (profiles.isEmpty()) {
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.no_profile_available)
|
||||
.setPositiveButton(android.R.string.yes, null)
|
||||
@ -467,7 +485,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
return
|
||||
}
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogStyle)
|
||||
.setTitle(R.string.new_session_with_profile)
|
||||
.setItems(
|
||||
profiles.map { it.profileName }.toTypedArray(),
|
||||
@ -481,11 +499,11 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
}
|
||||
|
||||
private fun addNewSession() {
|
||||
addNewNetHunterSession("KALI LINUX")
|
||||
addNewNetHunterSession("Kali Shell")
|
||||
}
|
||||
|
||||
private fun addNewSession(sessionName: String?, systemShell: Boolean, animation: Animation) {
|
||||
addNewNetHunterSession("KALI LINUX")
|
||||
addNewNetHunterSession("Kali Shell")
|
||||
}
|
||||
|
||||
private fun addNewSessionWithProfile(profile: ShellProfile) {
|
||||
@ -511,7 +529,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
.profile(profile)
|
||||
val session = termService!!.createTermSession(parameter)
|
||||
|
||||
session.mSessionName = sessionName ?: generateSessionName("Kali Linux")
|
||||
session.mSessionName = sessionName ?: generateSessionName("Kali Shell")
|
||||
|
||||
val tab = createTab(session.mSessionName) as TermTab
|
||||
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
|
||||
@ -520,6 +538,27 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
switchToSession(tab)
|
||||
}
|
||||
|
||||
@SuppressLint("SdCardPath")
|
||||
private fun addNewEmergencySession(sessionName: String?) {
|
||||
val sessionCallback = TermSessionCallback()
|
||||
val viewClient = TermViewClient(this)
|
||||
|
||||
val parameter = ShellParameter()
|
||||
.callback(sessionCallback)
|
||||
.executablePath("/system/bin/sh")
|
||||
.systemShell(true)
|
||||
|
||||
val session = termService!!.createTermSession(parameter)
|
||||
|
||||
session.mSessionName = sessionName ?: generateSessionName("Emergency Shell")
|
||||
|
||||
val tab = createTab(session.mSessionName) as TermTab
|
||||
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
|
||||
|
||||
addNewTab(tab, createRevealAnimation())
|
||||
switchToSession(tab)
|
||||
}
|
||||
|
||||
@SuppressLint("SdCardPath")
|
||||
private fun addNewAndroidSession(sessionName: String?) {
|
||||
val sessionCallback = TermSessionCallback()
|
||||
@ -532,7 +571,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
|
||||
val session = termService!!.createTermSession(parameter)
|
||||
|
||||
session.mSessionName = sessionName ?: generateSessionName("Android")
|
||||
session.mSessionName = sessionName ?: generateSessionName("Android Shell")
|
||||
|
||||
val tab = createTab(session.mSessionName) as TermTab
|
||||
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
|
||||
@ -550,7 +589,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
.executablePath("/data/data/com.offsec.nhterm/files/usr/bin/kali")
|
||||
val session = termService!!.createTermSession(parameter)
|
||||
|
||||
session.mSessionName = sessionName ?: generateSessionName("KALI LINUX")
|
||||
session.mSessionName = sessionName ?: generateSessionName("Kali Shell")
|
||||
|
||||
val tab = createTab(session.mSessionName) as TermTab
|
||||
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
|
||||
@ -572,7 +611,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
val session = termService!!.createTermSession(parameter)
|
||||
generateSessionName("Android")
|
||||
|
||||
session.mSessionName = sessionName ?: generateSessionName("ANDROID SU")
|
||||
session.mSessionName = sessionName ?: generateSessionName("Root Shell")
|
||||
|
||||
val tab = createTab(session.mSessionName) as TermTab
|
||||
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
|
||||
@ -605,15 +644,6 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
}
|
||||
|
||||
private fun addXSession() {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.sorry_for_development)
|
||||
.setPositiveButton(android.R.string.yes, null)
|
||||
.show()
|
||||
return
|
||||
}
|
||||
|
||||
if (!tabSwitcher.isSwitcherShown) {
|
||||
toggleSwitcher(showSwitcher = true, easterEgg = false)
|
||||
}
|
||||
@ -700,7 +730,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
}
|
||||
|
||||
private fun createXTab(tabTitle: String?): Tab {
|
||||
return postTabCreated(XSessionTab(tabTitle ?: "Kali Linux"))
|
||||
return postTabCreated(XSessionTab(tabTitle ?: "Kali Shell"))
|
||||
}
|
||||
|
||||
private fun <T : NeoTab> postTabCreated(tab: T): T {
|
||||
|
@ -10,6 +10,7 @@ import android.widget.ArrayAdapter
|
||||
import android.widget.ListView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.offsec.nhterm.App
|
||||
import com.offsec.nhterm.R
|
||||
import com.offsec.nhterm.bridge.Bridge.*
|
||||
@ -161,7 +162,7 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
||||
val filesAdapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, filesToHandle)
|
||||
filesList.adapter = filesAdapter
|
||||
filesList.setOnItemClickListener { _, _, position, _ ->
|
||||
AlertDialog.Builder(this@NeoTermRemoteInterface)
|
||||
MaterialAlertDialogBuilder(this@NeoTermRemoteInterface, R.style.DialogStyle)
|
||||
.setMessage(R.string.confirm_remove_file_from_list)
|
||||
.setPositiveButton(android.R.string.yes) { _, _ ->
|
||||
filesToHandle.removeAt(position)
|
||||
|
@ -3,6 +3,7 @@ package com.offsec.nhterm.ui.term
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Rect
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
@ -60,10 +61,12 @@ class NeoTabDecorator(val context: NeoTermActivity) : TabSwitcherDecorator() {
|
||||
Terminals.setupExtraKeysView(extraKeysView)
|
||||
|
||||
val colorSchemeManager = ComponentManager.getComponent<ColorSchemeComponent>()
|
||||
colorSchemeManager.applyColorScheme(
|
||||
terminalView, extraKeysView,
|
||||
colorSchemeManager.getCurrentColorScheme()
|
||||
)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
colorSchemeManager.applyColorScheme(
|
||||
terminalView, extraKeysView,
|
||||
colorSchemeManager.getCurrentColorScheme()
|
||||
)
|
||||
}
|
||||
view
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,13 @@ import android.Manifest
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.DialogInterface
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.offsec.nhterm.R
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -16,39 +19,35 @@ object NeoPermission {
|
||||
const val REQUEST_APP_PERMISSION = 10086
|
||||
|
||||
fun initAppPermission(context: AppCompatActivity, requestCode: Int) {
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
!= PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
) {
|
||||
AlertDialog.Builder(context).setMessage("需要存储权限来访问存储设备上的文件")
|
||||
.setPositiveButton(android.R.string.ok, { _: DialogInterface, _: Int ->
|
||||
doRequestPermission(context, requestCode)
|
||||
})
|
||||
.show()
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
} else {
|
||||
doRequestPermission(context, requestCode)
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
context,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)) {
|
||||
MaterialAlertDialogBuilder(context, R.style.DialogStyle).setMessage("Please enable Storage permission")
|
||||
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
|
||||
doRequestPermission(context, requestCode)
|
||||
}.show()
|
||||
|
||||
} else {
|
||||
doRequestPermission(context, requestCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doRequestPermission(context: AppCompatActivity, requestCode: Int) {
|
||||
try {
|
||||
ActivityCompat.requestPermissions(
|
||||
context,
|
||||
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
|
||||
requestCode
|
||||
)
|
||||
} catch (ignore: ActivityNotFoundException) {
|
||||
// for MIUI, we ignore it.
|
||||
}
|
||||
ActivityCompat.requestPermissions(
|
||||
context,
|
||||
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
|
||||
requestCode)
|
||||
} catch (ignore: ActivityNotFoundException) {
|
||||
// for MIUI, we ignore it.
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.offsec.nhterm.utils
|
||||
import android.content.ContentUris
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.MediaStore
|
||||
@ -37,25 +38,41 @@ fun Long.formatSizeInKB(): String {
|
||||
}
|
||||
|
||||
fun Context.extractAssetsDir(assetDir: String, extractDir: String) = kotlin.runCatching {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val targetDir = Paths.get(extractDir)
|
||||
Files.createDirectories(targetDir)
|
||||
val assets = this.assets
|
||||
assets.list(assetDir)?.let {
|
||||
it.map { targetDir.resolve(it) }
|
||||
.takeWhile { !Files.exists(it) }
|
||||
.forEach { targetPath ->
|
||||
assets.open("$assetDir/${targetPath.fileName}").use {
|
||||
Files.copy(it, targetPath)
|
||||
Paths.get(extractDir)
|
||||
Files.createDirectories(targetDir)
|
||||
val assets = this.assets
|
||||
assets.list(assetDir)?.let {
|
||||
it.map { targetDir.resolve(it) }
|
||||
.takeWhile { !Files.exists(it) }
|
||||
.forEach { targetPath ->
|
||||
assets.open("$assetDir/${targetPath.fileName}").use {
|
||||
Files.copy(it, targetPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val targetDir = com.llamalab.safs.Paths.get(extractDir)
|
||||
com.llamalab.safs.Files.createDirectories(targetDir)
|
||||
val assets = this.assets
|
||||
assets.list(assetDir)?.let {
|
||||
it.map { targetDir.resolve(it) }
|
||||
.takeWhile { !com.llamalab.safs.Files.exists(it) }
|
||||
.forEach { targetPath ->
|
||||
assets.open("$assetDir/${targetPath.fileName}").use {
|
||||
com.llamalab.safs.Files.copy(it, targetPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.runApt(
|
||||
subCommand: String, vararg extraArgs: String,
|
||||
command: String, subCommand: String, extraArgs: String,
|
||||
autoClose: Boolean = true, block: (Result<TerminalDialog>) -> Unit
|
||||
) = TerminalDialog(this)
|
||||
.execute(NeoTermPath.APT_BIN_PATH, arrayOf(NeoTermPath.APT_BIN_PATH, subCommand, *extraArgs))
|
||||
.execute(NeoTermPath.BIN_PATH + "/kali", command + " " + subCommand, extraArgs)
|
||||
.imeEnabled(true)
|
||||
.onFinish { dialog, session ->
|
||||
val exit = session?.exitStatus ?: 1
|
||||
|
78
nhterm/src/main/res/drawable/ic_launcher_background.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group android:scaleX="0"
|
||||
android:scaleY="0"
|
||||
android:translateX="54"
|
||||
android:translateY="54">
|
||||
<path android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
</group>
|
||||
</vector>
|
@ -9,7 +9,7 @@
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/package_item_padding">
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/package_item_name"
|
||||
style="@style/TextAppearance.AppCompat.Large"
|
||||
android:layout_width="match_parent"
|
||||
@ -18,7 +18,7 @@
|
||||
android:textColor="@color/textColor"
|
||||
tools:text="Package Name"/>
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/package_item_desc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -27,4 +27,4 @@
|
||||
android:textColor="@color/textColorSecondary"
|
||||
tools:text="Package Description"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@ -6,15 +6,14 @@
|
||||
android:background="@color/terminal_background"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/terminal_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:layout_height="55dp"
|
||||
android:background="@color/colorPrimary"
|
||||
android:theme="@style/app_toolbar"
|
||||
android:visibility="visible"/>
|
||||
|
||||
|
||||
<de.mrapp.android.tabswitcher.TabSwitcher
|
||||
android:id="@+id/tab_switcher"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -27,10 +27,11 @@
|
||||
android:background="@color/colorPrimary"/>
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pm_view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/pm_tab_header"/>
|
||||
android:layout_below="@id/pm_tab_header">
|
||||
</androidx.viewpager2.widget.ViewPager2>
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -4,10 +4,13 @@
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.offsec.nhterm.frontend.session.view.TerminalView
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
android:id="@+id/terminal_view_dialog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/terminal_dialog_height"
|
||||
android:layout_marginStart="@dimen/text_margin"
|
||||
android:layout_marginTop="@dimen/text_margin"
|
||||
android:layout_marginEnd="@dimen/text_margin"
|
||||
android:layout_marginBottom="@dimen/text_margin"
|
||||
android:background="@color/terminal_background"
|
||||
android:fadeScrollbars="true"
|
||||
android:focusable="false"
|
||||
|
@ -18,8 +18,12 @@
|
||||
app:showAsAction="never">
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/menu_item_new_system_session"
|
||||
android:title="@string/new_system_session"
|
||||
android:id="@+id/menu_item_new_emergency_session"
|
||||
android:title="@string/new_emergency_session"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/menu_item_new_bash_session"
|
||||
android:title="@string/new_bash_session"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
@ -29,6 +33,11 @@
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_item_package_settings"
|
||||
android:title="@string/package_settings"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_item_settings"
|
||||
android:title="@string/settings"
|
||||
|
@ -27,6 +27,7 @@
|
||||
<item
|
||||
android:id="@+id/action_source"
|
||||
android:title="@string/pref_package_source"
|
||||
android:enabled="false"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
</menu>
|
||||
</menu>
|
||||
|
41
nhterm/src/main/res/menu/older_menu_main.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/toggle_tab_switcher_menu_item"
|
||||
android:title="@string/toggle_tab_switcher_menu_item"
|
||||
app:actionLayout="@layout/tab_switcher_menu_item"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_item_new_session"
|
||||
android:title="@string/new_session"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
android:title="@string/new_session_more"
|
||||
app:showAsAction="never">
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/menu_item_new_emergency_session"
|
||||
android:title="@string/new_emergency_session"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/menu_item_new_bash_session"
|
||||
android:title="@string/new_bash_session"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_item_new_root_session"
|
||||
android:title="@string/new_root_session"
|
||||
app:showAsAction="never"/>
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_item_settings"
|
||||
android:title="@string/settings"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
</menu>
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
@ -10,4 +10,10 @@
|
||||
<color name="popup_background">#AE000000</color>
|
||||
<color name="popup_split_background">#efefef</color>
|
||||
<color name="list_download_item_color_dark">#363636</color>
|
||||
|
||||
<color name="tab_switcher_background_color">#202124</color>
|
||||
<color name="tab_background_color">#131415</color>
|
||||
<color name="tab_title_text_color">#A8D8D8D8</color>
|
||||
|
||||
<color name="button_color">#A88B9FBA</color>
|
||||
</resources>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<dimen name="eks_height">32dp</dimen>
|
||||
<dimen name="eks_height_two_line">72dp</dimen>
|
||||
<dimen name="eks_height_one_line">36dp</dimen>
|
||||
<dimen name="terminal_dialog_height">256dp</dimen>
|
||||
<dimen name="terminal_dialog_height">350dp</dimen>
|
||||
<dimen name="custom_editor_line_height">48dp</dimen>
|
||||
<dimen name="custom_install_icon_width">36dp</dimen>
|
||||
<dimen name="custom_install_icon_height">36dp</dimen>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#242424</color>
|
||||
<color name="ic_launcher_background">#595959</color>
|
||||
</resources>
|
@ -8,7 +8,8 @@
|
||||
<string name="toggle_tab_switcher_menu_item">Toggle Tabs</string>
|
||||
<string name="new_session">New Session</string>
|
||||
<string name="new_session_more">New Session…</string>
|
||||
<string name="new_system_session">New System Shell</string>
|
||||
<string name="new_emergency_session">New Emergency Shell</string>
|
||||
<string name="new_bash_session">New Bash Shell</string>
|
||||
<string name="new_root_session">New Root Shell</string>
|
||||
<string name="service_status_text">%d session(s)</string>
|
||||
<string name="service_lock_acquired">(Wake Locked)</string>
|
||||
@ -47,6 +48,7 @@
|
||||
<string name="package_settings">Package Settings</string>
|
||||
<string name="package_settings_desc">Source, Updates, Upgrades</string>
|
||||
<string name="customization_settings_desc">Font, ColorScheme</string>
|
||||
<string name="older_customization_settings_desc">Disabled as of no required functions available by old android api</string>
|
||||
<string name="customization_settings">Customization</string>
|
||||
|
||||
<string name="toggle_ime">Toggle Keyboard</string>
|
||||
@ -61,7 +63,7 @@
|
||||
<string name="source_changed">APT source changed, you may get it updated by executing: apt update</string>
|
||||
<string name="done">Done</string>
|
||||
<string name="install">Install</string>
|
||||
<string name="package_details">Package: %s\nVersion: %s\nDepends: %s\nInstalled Size: %s\nDescription: %s\nHome
|
||||
<string name="package_details">Package: %s\n\nVersion: %s\n\nDepends: %s\n\nInstalled Size: %s\n\nDescription: %s\n\nHome
|
||||
Page: %s
|
||||
</string>
|
||||
<string name="package_list_empty">Package list is empty, please check your source.</string>
|
||||
@ -185,8 +187,7 @@
|
||||
<string name="dangerous_zone">Danger Zone</string>
|
||||
<string name="reset_app_warning">This will delete and re-copy required files to boot kali chroot, confirm?</string>
|
||||
|
||||
<string name="default_source_url" translatable="false">https://example.com/nhterm
|
||||
</string>
|
||||
<string name="default_source_url" translatable="false">http://http.kali.org/kali</string>
|
||||
|
||||
<string-array name="pref_general_shell_entries" translatable="false">
|
||||
<item>sh</item>
|
||||
|
@ -1,18 +1,17 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<style name="AppTheme" parent="Theme.Material3.Dark">
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="checkboxStyle">@style/checkbox_theme</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Dark" parent="Theme.AppCompat">
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="android:actionBarStyle">@style/AppTheme.ActionBar</item>
|
||||
<item name="actionBarStyle">@style/AppTheme.ActionBar</item>
|
||||
|
||||
<item name="android:dialogPreferenceStyle">@style/DialogStyleCompat</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar" parent="@style/AppTheme">
|
||||
@ -20,14 +19,25 @@
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar.Dark" parent="@style/AppTheme.Dark">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<style name="AppTheme.ActionBar" parent="@style/Widget.Material3.ActionBar.Solid">
|
||||
<item name="windowNoTitle">false</item>
|
||||
<item name="windowActionBar">true</item>
|
||||
<item name="android:height">55dp</item>
|
||||
<item name="height">55dp</item>
|
||||
<item name="titleTextStyle">@style/AppTheme.ActionBar.TitleText</item>
|
||||
<item name="android:titleTextStyle">@style/AppTheme.ActionBar.TitleText</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||
<style name="checkbox_theme" parent="@style/Widget.Material3.CompoundButton.CheckBox">
|
||||
<item name="buttonTint">#2449A8</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
|
||||
|
||||
<style name="AppTheme.ActionBar.TitleText" parent="@style/AppTheme">
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.PopupOverlay" parent="@style/Theme.Material3.Dark"/>
|
||||
|
||||
<style name="rtl_RecyclerTabLayout">
|
||||
<item name="rtl_tabMinWidth">72dp</item>
|
||||
@ -51,4 +61,80 @@
|
||||
<item name="android:textStyle">normal</item>
|
||||
</style>
|
||||
|
||||
<style name="DialogStyle" parent="@style/MaterialAlertDialog.Material3">
|
||||
<item name="colorPrimary">#61A3D7</item>
|
||||
<item name="colorPrimaryDark">#8DB2D3</item>
|
||||
<item name="colorAccent">#61A3D7</item>
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:textColorSecondary">@color/textColor</item>
|
||||
<item name="android:textColorLink">#2255D3</item>
|
||||
<item name="background">@color/colorPrimary</item>
|
||||
|
||||
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
|
||||
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
|
||||
|
||||
<item name="buttonBarPositiveButtonStyle">@style/Alert.Button.Positive</item>
|
||||
<item name="android:buttonBarPositiveButtonStyle">@style/Alert.Button.Positive</item>
|
||||
<item name="buttonBarNegativeButtonStyle">@style/Alert.Button.Neutral</item>
|
||||
<item name="android:buttonBarNegativeButtonStyle">@style/Alert.Button.Neutral</item>
|
||||
<item name="buttonBarNeutralButtonStyle">@style/Alert.Button.Neutral</item>
|
||||
<item name="android:buttonBarNeutralButtonStyle">@style/Alert.Button.Neutral</item>
|
||||
</style>
|
||||
|
||||
<style name="DialogStyleCompat" parent="@style/ThemeOverlay.Material3.MaterialAlertDialog">
|
||||
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
|
||||
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
|
||||
|
||||
<item name="colorPrimary">#547383</item>
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:textColorSecondary">@color/textColor</item>
|
||||
<item name="android:textColorLink">#2D55A3</item>
|
||||
|
||||
<item name="buttonBarPositiveButtonStyle">@style/Alert.Button.Positive</item>
|
||||
<item name="buttonBarNegativeButtonStyle">@style/Alert.Button.Neutral</item>
|
||||
<item name="buttonBarNeutralButtonStyle">@style/Alert.Button.Neutral</item>
|
||||
</style>
|
||||
|
||||
<style name="Alert.Button.Positive" parent="@style/Widget.Material3.Button.TextButton">
|
||||
<item name="backgroundTint">@color/colorPrimary</item>
|
||||
<item name="colorPrimary">#61A3D7</item>
|
||||
<item name="colorPrimaryDark">#8DB2D3</item>
|
||||
<item name="colorAccent">#61A3D7</item>
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:textColorSecondary">@color/textColor</item>
|
||||
<item name="android:textColorLink">#2255D3</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:layout_marginStart">10dp</item>
|
||||
<item name="android:textColorPrimary">@color/textColor</item>
|
||||
</style>
|
||||
|
||||
<style name="Alert.Button.Negative" parent="@style/Widget.Material3.Button.TextButton">
|
||||
<item name="backgroundTint">@color/colorPrimary</item>
|
||||
<item name="colorPrimary">#61A3D7</item>
|
||||
<item name="colorPrimaryDark">#8DB2D3</item>
|
||||
<item name="colorAccent">#61A3D7</item>
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:textColorSecondary">@color/textColor</item>
|
||||
<item name="android:textColorLink">#2255D3</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:layout_marginStart">10dp</item>
|
||||
<item name="android:textColorPrimary">@color/textColor</item>
|
||||
</style>
|
||||
|
||||
<style name="Alert.Button.Neutral" parent="@style/Widget.Material3.Button.TextButton">
|
||||
<item name="backgroundTint">@color/colorPrimary</item>
|
||||
<item name="colorPrimary">#61A3D7</item>
|
||||
<item name="colorPrimaryDark">#8DB2D3</item>
|
||||
<item name="colorAccent">#61A3D7</item>
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:textColorSecondary">@color/textColor</item>
|
||||
<item name="android:textColorLink">#2255D3</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:layout_marginStart">10dp</item>
|
||||
<item name="android:textColorPrimary">@color/textColor</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
40
nhterm/src/main/res/xml/older_settings_main.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_general_white_36dp"
|
||||
android:summary="@string/general_settings_desc"
|
||||
android:title="@string/general_settings">
|
||||
<intent
|
||||
android:targetClass="com.offsec.nhterm.ui.settings.GeneralSettingsActivity"
|
||||
android:targetPackage="com.offsec.nhterm"/>
|
||||
</Preference>
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_ui_white_36dp"
|
||||
android:summary="@string/ui_settings_desc"
|
||||
android:title="@string/ui_settings">
|
||||
<intent
|
||||
android:targetClass="com.offsec.nhterm.ui.settings.UISettingsActivity"
|
||||
android:targetPackage="com.offsec.nhterm"/>
|
||||
</Preference>
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_customization_white_36dp"
|
||||
android:summary="@string/older_customization_settings_desc"
|
||||
android:title="@string/customization_settings"
|
||||
android:enabled="false">
|
||||
<intent
|
||||
android:targetClass="com.offsec.nhterm.ui.customize.CustomizeActivity"
|
||||
android:targetPackage="com.offsec.nhterm"/>
|
||||
</Preference>
|
||||
|
||||
<Preference
|
||||
android:icon="@drawable/ic_info_white_36dp"
|
||||
android:title="@string/about">
|
||||
<intent
|
||||
android:targetClass="com.offsec.nhterm.ui.other.AboutActivity"
|
||||
android:targetPackage="com.offsec.nhterm"/>
|
||||
</Preference>
|
||||
|
||||
</PreferenceScreen>
|
@ -5,12 +5,6 @@
|
||||
android:summary="@string/pref_general_initial_command_desc"
|
||||
android:title="@string/pref_general_initial_command"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_general_vibrate"
|
||||
android:summary="@string/pref_general_vibrate_desc"
|
||||
android:title="@string/pref_general_vibrate"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/key_generaL_backspace_map_to_esc"
|
||||
|