├── .github
├── FUNDING.yml
└── workflows
│ └── android.yml
├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── deploymentTargetDropDown.xml
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── migrations.xml
├── misc.xml
└── vcs.xml
├── LICENSE.md
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ └── in
│ │ └── sunilpaulmathew
│ │ └── ashell
│ │ ├── activities
│ │ ├── CommandPickerActivity.java
│ │ ├── ExamplesActivity.java
│ │ ├── SettingsActivity.java
│ │ ├── WelcomeActivity.java
│ │ └── aShellActivity.java
│ │ ├── adapters
│ │ ├── CommandsAdapter.java
│ │ ├── ExamplesAdapter.java
│ │ ├── PolicyAdapter.java
│ │ ├── SettingsAdapter.java
│ │ ├── ShellOutputAdapter.java
│ │ └── WelcomeAdapter.java
│ │ ├── dialogs
│ │ └── SingleChoiceDialog.java
│ │ ├── fragments
│ │ └── aShellFragment.java
│ │ ├── serializable
│ │ ├── CommandItems.java
│ │ └── SettingsItems.java
│ │ └── utils
│ │ ├── Commands.java
│ │ ├── Settings.java
│ │ ├── ShizukuShell.java
│ │ └── Utils.java
│ └── res
│ ├── drawable
│ ├── ic_amoled_theme.xml
│ ├── ic_arrow.xml
│ ├── ic_background_gradient.xml
│ ├── ic_bookmarks.xml
│ ├── ic_email.xml
│ ├── ic_help.xml
│ ├── ic_history.xml
│ ├── ic_info.xml
│ ├── ic_info_outlined.xml
│ ├── ic_language.xml
│ ├── ic_launcher_foreground.xml
│ ├── ic_learn.xml
│ ├── ic_numbers.xml
│ ├── ic_privacy.xml
│ ├── ic_refresh.xml
│ ├── ic_save.xml
│ ├── ic_search.xml
│ ├── ic_send.xml
│ ├── ic_settings.xml
│ ├── ic_star.xml
│ ├── ic_starred.xml
│ ├── ic_start.xml
│ ├── ic_stop.xml
│ ├── ic_theme.xml
│ └── ic_translate.xml
│ ├── layout
│ ├── activity_ashell.xml
│ ├── activity_examples.xml
│ ├── activity_settings.xml
│ ├── activity_welcome.xml
│ ├── fragment_ashell.xml
│ ├── layout_about.xml
│ ├── layout_privacy_policy.xml
│ ├── recycler_view_policy.xml
│ ├── recycler_view_settings.xml
│ ├── recycler_view_welcome.xml
│ ├── rv_commands.xml
│ ├── rv_examples.xml
│ └── rv_shell_output.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-mdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── values-b+zh+Hans
│ └── strings.xml
│ ├── values-el
│ └── strings.xml
│ ├── values-hu
│ └── strings.xml
│ ├── values-in
│ └── strings.xml
│ ├── values-ko
│ └── strings.xml
│ ├── values-pt-rBR
│ └── strings.xml
│ ├── values-pt-rPT
│ └── strings.xml
│ ├── values-ru
│ └── strings.xml
│ ├── values-zh-rTW
│ └── strings.xml
│ ├── values
│ ├── colors.xml
│ ├── strings.xml
│ └── theme.xml
│ └── xml
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── build.gradle
├── fastlane
└── metadata
│ └── android
│ └── en-US
│ ├── changelogs
│ └── 15.txt
│ ├── full_description.txt
│ ├── images
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ └── 5.png
│ └── short_description.txt
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: sunilpaulmathew
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: ['https://www.paypal.me/menacherry', 'https://play.google.com/store/apps/details?id=com.smartpack.donate']
13 |
--------------------------------------------------------------------------------
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 |
17 | # Set Current Date As Env Variable
18 | - name: Set current date as env variable
19 | run: echo "date_today=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
20 |
21 | # Set App Name As Env Variable
22 | - name: Set repository name as env variable
23 | run: echo "repository_name=aShell" >> $GITHUB_ENV
24 |
25 | - name: set up JDK 17
26 | uses: actions/setup-java@v4
27 | with:
28 | java-version: '17'
29 | distribution: 'temurin'
30 | cache: gradle
31 |
32 | - name: Grant execute permission for gradlew
33 | run: chmod +x ./gradlew
34 |
35 | # Run Tests Build
36 | - name: Run gradle tests
37 | run: ./gradlew test
38 |
39 | # Run Build Project
40 | - name: Build gradle project
41 | run: ./gradlew build
42 |
43 | # Create APK Release
44 | - name: Build apk release project (APK) - ${{ env.main_project_module }} module
45 | run: ./gradlew assemble
46 |
47 | # Upload Artifact Build
48 | - name: Upload APK Release - ${{ env.repository_name }}
49 | uses: actions/upload-artifact@v3
50 | with:
51 | name: ${{ env.repository_name }} - ${{ env.date_today }} - APK release generated
52 | path: app/build/outputs/apk/release/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/.name
5 | /.idea/caches
6 | /.idea/libraries
7 | /.idea/modules.xml
8 | /.idea/workspace.xml
9 | /.idea/navEditor.xml
10 | /.idea/assetWizardSettings.xml
11 | .DS_Store
12 | /build
13 | /captures
14 | .externalNativeBuild
15 | .cxx
16 | local.properties
17 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # aShell - Effortlessly execute ADB commands on your Shizuku-enabled Android device.
2 |
3 |
4 |
5 | [](https://play.google.com/store/apps/details?id=in.sunilpaulmathew.ashell)
6 |
7 | ### A local ADB shell for [Shizuku](https://shizuku.rikka.app/) powered android devices!
8 |
9 | ## Requirements
10 | * A fully working [Shizuku](https://shizuku.rikka.app/) environment.
11 | * Knowledge about basic ADB/Linux commands.
12 |
13 | ## Download
14 |
15 | [ ](https://play.google.com/store/apps/details?id=in.sunilpaulmathew.ashell)
18 | [ ](https://f-droid.org/packages/in.sunilpaulmathew.ashell/)
21 | [ ](https://apt.izzysoft.de/fdroid/index/apk/in.sunilpaulmathew.ashell)
24 |
25 | Or get the APK from the [Releases Section](https://gitlab.com/sunilpaulmathew/ashell/-/releases).
26 |
27 | ## Features
28 | * An elegantly designed user interface.
29 | * Included a bundle of examples about common ADB commands.
30 | * Handles continuously running commands, such as logcat, top, etc.
31 | * Search for specific text from the last command output.
32 | * Option to save last command output as a text file.
33 | * Bookmark frequently using commands.
34 | * Support multiple languages (configurable).
35 | * An auto-dark/light theme.
36 | * A lot more.
37 |
38 | ## Support development
39 |
40 | If you like to appreciate the efforts of the developer to provide this application entirely free, non-intrusive and without Ads, please consider supporting the development in some way. Maintaining this project takes a lot of time. So, each and every support from the android community will be hugely appreciated.
41 |
42 |
43 |
44 | Liberapay Donation url : https://liberapay.com/sunilpaulmathew/donate PayPal Donation url : https://www.paypal.me/menacherry PayPal Donation email : sunil.kde@gmail.com Ko-fi Donation url : https://ko-fi.com/sunilpaulmathew
45 |
46 | Some other ways to support the development includes, but not limited to
47 |
48 | Contribute code to this project.
49 | Translate this application into your local language (or improve existing translations).
50 | Share good words about this application with others (family, friends, and other enthusiastic android users).
51 |
52 |
53 | ## License
54 |
55 | Copyright (C) 2022-2025 sunilpaulmathew
56 |
57 | aShell is a free softwares: you can redistribute it and/or modify it
58 | under the terms of the GNU General Public License as published by the
59 | Free Software Foundation, either version 3 of the License, or (at
60 | your option) any later version.
61 |
62 | aShell is distributed in the hope that it will be useful, but WITHOUT
63 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
64 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
65 | for more details.
66 |
67 | You should have received a copy of the GNU General Public License along
68 | with aShell. If not, see .
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /release
3 | *.jks
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.androidApplication)
3 | }
4 |
5 | def keystoreFile = rootProject.file("app/sp.jks")
6 |
7 | android {
8 | if (keystoreFile.exists()) {
9 | signingConfigs {
10 | release {
11 | storeFile file("sp.jks")
12 | storePassword "smartpack"
13 | keyAlias "sp_key1"
14 | keyPassword "smartpack"
15 | }
16 | }
17 | }
18 |
19 | dependenciesInfo {
20 | // Disables dependency metadata when building APKs.
21 | includeInApk = false
22 | // Disables dependency metadata when building Android App Bundles.
23 | includeInBundle = false
24 | }
25 |
26 | namespace 'in.sunilpaulmathew.ashell'
27 | compileSdk 34
28 |
29 | defaultConfig {
30 | applicationId "in.sunilpaulmathew.ashell"
31 | minSdk 24
32 | targetSdk 34
33 | versionCode 15
34 | versionName "v0.15"
35 | }
36 |
37 | buildTypes {
38 | debug {
39 | applicationIdSuffix '.debug'
40 | }
41 | release {
42 | if (keystoreFile.exists()) {
43 | signingConfig signingConfigs.release
44 | }
45 | minifyEnabled true
46 | shrinkResources true
47 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
48 | }
49 | }
50 | buildFeatures {
51 | buildConfig = true
52 | }
53 | }
54 |
55 | dependencies {
56 | implementation libs.material
57 | implementation libs.preference
58 | implementation libs.shizukuApi
59 | implementation libs.shizukuProvider
60 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
45 |
46 |
48 |
49 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/activities/CommandPickerActivity.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.activities;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.os.Parcelable;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.appcompat.app.AppCompatActivity;
10 |
11 | import java.io.BufferedInputStream;
12 | import java.io.ByteArrayOutputStream;
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 | import java.util.Objects;
16 |
17 | import in.sunilpaulmathew.ashell.R;
18 | import in.sunilpaulmathew.ashell.utils.Utils;
19 |
20 | /*
21 | * Created by sunilpaulmathew on January 08, 2025
22 | */
23 | public class CommandPickerActivity extends AppCompatActivity {
24 |
25 | @Override
26 | protected void onCreate(@Nullable Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 |
29 | if (Objects.equals(getIntent().getAction(), Intent.ACTION_SEND)) {
30 | String mString = null;
31 | Parcelable parcelable = getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
32 | if (parcelable != null) {
33 | if (!(parcelable instanceof Uri)) {
34 | parcelable = Uri.parse(parcelable.toString());
35 | }
36 | Uri uri = (Uri) parcelable;
37 | try {
38 | InputStream inputStream = getContentResolver().openInputStream(uri);
39 | BufferedInputStream bis = new BufferedInputStream(inputStream);
40 | ByteArrayOutputStream buf = new ByteArrayOutputStream();
41 | for (int result = bis.read(); result != -1; result = bis.read()) {
42 | buf.write((byte) result);
43 | }
44 | mString = buf.toString("UTF-8");
45 | } catch (IOException ignored) {}
46 | } else if (getIntent().getStringExtra(Intent.EXTRA_TEXT) != null) {
47 | mString = getIntent().getStringExtra(Intent.EXTRA_TEXT);
48 | }
49 |
50 | if (mString != null) {
51 | Intent startActivity = new Intent(this, aShellActivity.class);
52 | startActivity.putExtra("command", mString);
53 | startActivity(startActivity);
54 | } else {
55 | Utils.toast(getString(R.string.file_manager_error_toast), this).show();
56 | }
57 | finish();
58 | }
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/activities/ExamplesActivity.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.activities;
2 |
3 | import android.content.res.Configuration;
4 | import android.os.Bundle;
5 | import android.text.Editable;
6 | import android.text.TextWatcher;
7 | import android.view.View;
8 |
9 | import androidx.activity.OnBackPressedCallback;
10 | import androidx.appcompat.app.AppCompatActivity;
11 | import androidx.appcompat.widget.LinearLayoutCompat;
12 | import androidx.recyclerview.widget.GridLayoutManager;
13 | import androidx.recyclerview.widget.LinearLayoutManager;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | import com.google.android.material.textfield.MaterialAutoCompleteTextView;
17 |
18 | import in.sunilpaulmathew.ashell.R;
19 | import in.sunilpaulmathew.ashell.adapters.ExamplesAdapter;
20 | import in.sunilpaulmathew.ashell.utils.Commands;
21 | import in.sunilpaulmathew.ashell.utils.Settings;
22 | import in.sunilpaulmathew.ashell.utils.Utils;
23 |
24 | /*
25 | * Created by sunilpaulmathew on November 05, 2022
26 | */
27 | public class ExamplesActivity extends AppCompatActivity {
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_examples);
33 |
34 | LinearLayoutCompat mMain = findViewById(R.id.layout_main);
35 | MaterialAutoCompleteTextView mSearchWord = findViewById(R.id.search_word);
36 | RecyclerView mRecyclerView = findViewById(R.id.recycler_view);
37 |
38 | if (Settings.isAmoledBlackEnabled(this)) {
39 | mMain.setBackgroundColor(Utils.getColor(R.color.colorBlack, this));
40 | }
41 |
42 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
43 | GridLayoutManager mLayoutManager = new GridLayoutManager(this, getResources().getConfiguration()
44 | .orientation == Configuration.ORIENTATION_LANDSCAPE ? 2 : 1);
45 | mRecyclerView.setLayoutManager(mLayoutManager);
46 | mRecyclerView.setAdapter(new ExamplesAdapter(Commands.getCommand("")));
47 | mRecyclerView.setVisibility(View.VISIBLE);
48 |
49 | mSearchWord.addTextChangedListener(new TextWatcher() {
50 | @Override
51 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
52 | }
53 |
54 | @Override
55 | public void onTextChanged(CharSequence s, int start, int before, int count) {
56 | }
57 |
58 | @Override
59 | public void afterTextChanged(Editable s) {
60 | mRecyclerView.setAdapter(new ExamplesAdapter(Commands.getCommand(s.toString().trim())));
61 | }
62 | });
63 |
64 | getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) {
65 | @Override
66 | public void handleOnBackPressed() {
67 | if (mSearchWord.getText() != null && !mSearchWord.getText().toString().isEmpty()) {
68 | mSearchWord.setText(null);
69 | return;
70 | }
71 | finish();
72 | }
73 | });
74 | }
75 |
76 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/activities/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.activities;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.appcompat.app.AppCompatActivity;
10 | import androidx.appcompat.widget.LinearLayoutCompat;
11 | import androidx.recyclerview.widget.LinearLayoutManager;
12 | import androidx.recyclerview.widget.RecyclerView;
13 |
14 | import com.google.android.material.textview.MaterialTextView;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | import in.sunilpaulmathew.ashell.BuildConfig;
20 | import in.sunilpaulmathew.ashell.R;
21 | import in.sunilpaulmathew.ashell.adapters.SettingsAdapter;
22 | import in.sunilpaulmathew.ashell.serializable.SettingsItems;
23 | import in.sunilpaulmathew.ashell.utils.Settings;
24 |
25 | /*
26 | * Created by sunilpaulmathew on April 21, 2022
27 | */
28 | public class SettingsActivity extends AppCompatActivity {
29 |
30 | @Override
31 | protected void onCreate(@Nullable Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | setContentView(R.layout.activity_settings);
34 |
35 | LinearLayoutCompat mTitleLayout = findViewById(R.id.title_layout);
36 | MaterialTextView mAppInfo = findViewById(R.id.app_info);
37 | MaterialTextView mCopyright = findViewById(R.id.copyright);
38 | RecyclerView mRecyclerView = findViewById(R.id.recycler_view);
39 |
40 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
41 |
42 | mAppInfo.setText(getString(R.string.app_version, BuildConfig.VERSION_NAME));
43 | mCopyright.setText(getString(R.string.copyright_text));
44 |
45 | mRecyclerView.setAdapter(new SettingsAdapter(getData(), this));
46 |
47 | mTitleLayout.setOnClickListener(v -> {
48 | Intent settings = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
49 | settings.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
50 | Uri uri = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null);
51 | settings.setData(uri);
52 | startActivity(settings);
53 | });
54 | }
55 |
56 | private List getData() {
57 | List mData = new ArrayList<>();
58 | mData.add(new SettingsItems(getString(R.string.user_interface)));
59 | mData.add(new SettingsItems(1, R.drawable.ic_theme, getString(R.string.app_theme), Settings.getAppTheme(this)));
60 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && Settings.isDarkTheme(this)) {
61 | mData.add(new SettingsItems(2, R.drawable.ic_amoled_theme, getString(R.string.app_theme_amoled), getString(R.string.app_theme_amoled_description), true, Settings.isAmoledBlackEnabled(this)));
62 | }
63 | mData.add(new SettingsItems(3, R.drawable.ic_language, getString(R.string.language), Settings.getLanguageDescription(this)));
64 | mData.add(new SettingsItems(getString(R.string.general)));
65 | mData.add(new SettingsItems(4, R.drawable.ic_help, getString(R.string.examples), getString(R.string.examples_description)));
66 | mData.add(new SettingsItems(5, R.drawable.ic_learn, getString(R.string.shizuku_learn), getString(R.string.shizuku_learn_description)));
67 | mData.add(new SettingsItems(getString(R.string.miscellaneous)));
68 | mData.add(new SettingsItems(6, R.drawable.ic_translate, getString(R.string.translations), getString(R.string.translations_description)));
69 | mData.add(new SettingsItems(7, R.drawable.ic_privacy, getString(R.string.privacy_policy), getString(R.string.privacy_policy_description)));
70 | mData.add(new SettingsItems(8, R.drawable.ic_email, getString(R.string.developer_contact), getString(R.string.developer_contact_description)));
71 | return mData;
72 | }
73 |
74 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/activities/WelcomeActivity.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.activities;
2 |
3 | import android.content.Intent;
4 | import android.content.pm.PackageManager;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.view.View;
8 |
9 | import androidx.activity.OnBackPressedCallback;
10 | import androidx.annotation.NonNull;
11 | import androidx.annotation.Nullable;
12 | import androidx.appcompat.app.AppCompatActivity;
13 | import androidx.recyclerview.widget.LinearLayoutManager;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | import com.google.android.material.button.MaterialButton;
17 | import com.google.android.material.dialog.MaterialAlertDialogBuilder;
18 | import com.google.android.material.textview.MaterialTextView;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | import in.sunilpaulmathew.ashell.BuildConfig;
24 | import in.sunilpaulmathew.ashell.R;
25 | import in.sunilpaulmathew.ashell.adapters.WelcomeAdapter;
26 | import in.sunilpaulmathew.ashell.serializable.CommandItems;
27 | import in.sunilpaulmathew.ashell.utils.Utils;
28 | import rikka.shizuku.Shizuku;
29 |
30 | /*
31 | * Created by sunilpaulmathew on April 16, 2025
32 | */
33 | public class WelcomeActivity extends AppCompatActivity {
34 |
35 | private final Shizuku.OnRequestPermissionResultListener REQUEST_PERMISSION_RESULT_LISTENER = this::onRequestPermissionsResult;
36 |
37 | @Override
38 | protected void onCreate(@Nullable Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.activity_welcome);
41 |
42 | Shizuku.addRequestPermissionResultListener(REQUEST_PERMISSION_RESULT_LISTENER);
43 |
44 | MaterialButton mStart = findViewById(R.id.start);
45 | MaterialTextView mVersionInfo = findViewById(R.id.version_info);
46 | mVersionInfo.setText(getString(R.string.app_version, BuildConfig.VERSION_NAME));
47 |
48 | RecyclerView mRecyclerView = findViewById(R.id.recycler_view);
49 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
50 | WelcomeAdapter mAdapter = new WelcomeAdapter(getData());
51 | mRecyclerView.setAdapter(mAdapter);
52 |
53 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
54 | @Override
55 | public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
56 | super.onScrollStateChanged(recyclerView, newState);
57 | if (!Shizuku.pingBinder() || Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) {
58 | mStart.setVisibility(newState == RecyclerView.SCROLL_STATE_IDLE ? View.VISIBLE : View.GONE);
59 | }
60 | }
61 | });
62 |
63 | if (Shizuku.pingBinder()) {
64 | if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) {
65 | mStart.setIcon(Utils.getDrawable(R.drawable.ic_start, this));
66 | mStart.setText(R.string.start);
67 | } else {
68 | mStart.setVisibility(View.GONE);
69 | }
70 | } else {
71 | accessUnavailableDialog().show();
72 | mStart.setText(R.string.quit);
73 | }
74 |
75 | mAdapter.setOnItemClickListener(this::checkPermission);
76 |
77 | mStart.setOnClickListener(v-> {
78 | if (Shizuku.pingBinder() && Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) {
79 | Intent intent = new Intent(this, aShellActivity.class);
80 | startActivity(intent);
81 | }
82 | if (!Utils.getBoolean("welcome_screen_viewed", false, this)) {
83 | Utils.saveBoolean("welcome_screen_viewed", true, this);
84 | }
85 | finish();
86 | });
87 |
88 | getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) {
89 | @Override
90 | public void handleOnBackPressed() {
91 | }
92 | });
93 | }
94 |
95 | private List getData() {
96 | List mData = new ArrayList<>();
97 | mData.add(new CommandItems(getString(R.string.features_title), getString(R.string.features_description)));
98 | mData.add(new CommandItems(getString(R.string.permissions_title), getString(R.string.permissions_shizuku_description) + ":" +
99 | (!Shizuku.pingBinder() ? " *" + getString(R.string.shizuku_unavailable_title) + "*" : Shizuku.checkSelfPermission() ==
100 | PackageManager.PERMISSION_GRANTED ? " " + getString(R.string.granted) : " " + getString(R.string.authorize_click_message)) + "\n" +
101 | (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q ? getString(R.string.permissions_storage_description) : "")));
102 | mData.add(new CommandItems(getString(R.string.disclaimer), getString(R.string.disclaimer_description)));
103 | return mData;
104 | }
105 |
106 | private MaterialAlertDialogBuilder accessDeniedDialog() {
107 | return new MaterialAlertDialogBuilder(this)
108 | .setCancelable(false)
109 | .setIcon(R.mipmap.ic_launcher)
110 | .setTitle(getString(R.string.shizuku_access_denied_title))
111 | .setMessage(getString(R.string.shizuku_access_denied_message))
112 | .setNeutralButton(getString(R.string.quit), (dialogInterface, i) -> finish())
113 | .setPositiveButton(getString(R.string.request_permission), (dialogInterface, i) ->
114 | Shizuku.requestPermission(0)
115 | );
116 | }
117 |
118 | public MaterialAlertDialogBuilder accessUnavailableDialog() {
119 | return new MaterialAlertDialogBuilder(this)
120 | .setCancelable(false)
121 | .setIcon(R.mipmap.ic_launcher)
122 | .setTitle(getString(R.string.shizuku_unavailable_title))
123 | .setMessage(getString(R.string.shizuku_unavailable_message))
124 | .setNeutralButton(getString(R.string.quit), (dialogInterface, i) -> finish())
125 | .setPositiveButton(getString(R.string.shizuku_learn), (dialogInterface, i) ->
126 | Utils.loadUrl("https://shizuku.rikka.app/", this)
127 | );
128 | }
129 |
130 | private void onRequestPermissionsResult(int requestCode, int grantResult) {
131 | boolean granted = grantResult == PackageManager.PERMISSION_GRANTED;
132 | if (granted) {
133 | Utils.toast(getString(R.string.shizuku_access_granted_message), this).show();
134 | recreate();
135 | } else {
136 | accessDeniedDialog().show();
137 | }
138 | Utils.saveBoolean("welcome_screen_viewed", granted, this);
139 | }
140 |
141 | private void checkPermission() {
142 | if (Shizuku.isPreV11()) {
143 | return;
144 | }
145 |
146 | if (Shizuku.shouldShowRequestPermissionRationale()) {
147 | accessDeniedDialog().show();
148 | } else {
149 | Shizuku.requestPermission(0);
150 | }
151 | }
152 |
153 | @Override
154 | protected void onDestroy() {
155 | super.onDestroy();
156 | Shizuku.removeRequestPermissionResultListener(REQUEST_PERMISSION_RESULT_LISTENER);
157 | }
158 |
159 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/activities/aShellActivity.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.activities;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.os.Handler;
6 | import android.os.Looper;
7 |
8 | import androidx.appcompat.app.AppCompatActivity;
9 | import androidx.fragment.app.Fragment;
10 |
11 | import java.util.concurrent.ExecutorService;
12 | import java.util.concurrent.Executors;
13 |
14 | import in.sunilpaulmathew.ashell.R;
15 | import in.sunilpaulmathew.ashell.fragments.aShellFragment;
16 | import in.sunilpaulmathew.ashell.utils.Commands;
17 | import in.sunilpaulmathew.ashell.utils.Settings;
18 | import in.sunilpaulmathew.ashell.utils.Utils;
19 |
20 | /*
21 | * Created by sunilpaulmathew on October 28, 2022
22 | */
23 | public class aShellActivity extends AppCompatActivity {
24 |
25 | private String mCommand = null;
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 |
31 | // Initialize App Theme & language
32 | Settings.initializeAppTheme(this);
33 | Settings.initializeAppLanguage(this);
34 |
35 | setContentView(R.layout.activity_ashell);
36 |
37 | if (!Utils.getBoolean("welcome_screen_viewed", false, this)) {
38 | Intent intent = new Intent(this, WelcomeActivity.class);
39 | startActivity(intent);
40 | finish();
41 | }
42 | loadUI();
43 | }
44 |
45 | private void loadUI() {
46 | ExecutorService mExecutors = Executors.newSingleThreadExecutor();
47 | mExecutors.execute(() -> {
48 | Commands.loadPackageInfo();
49 | mCommand = getIntent().getStringExtra("command");
50 | new Handler(Looper.getMainLooper()).post(() -> {
51 | Bundle bundle = new Bundle();
52 | if (mCommand != null) {
53 | bundle.putString("command", mCommand);
54 | }
55 | Fragment fragment = new aShellFragment();
56 | fragment.setArguments(bundle);
57 |
58 | getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
59 | fragment).commitAllowingStateLoss();
60 | });
61 | if (!mExecutors.isShutdown()) mExecutors.shutdown();
62 | });
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/adapters/CommandsAdapter.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.adapters;
2 |
3 | import android.graphics.Typeface;
4 | import android.util.TypedValue;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | import com.google.android.material.textview.MaterialTextView;
13 |
14 | import java.util.List;
15 |
16 | import in.sunilpaulmathew.ashell.R;
17 | import in.sunilpaulmathew.ashell.serializable.CommandItems;
18 |
19 | /*
20 | * Created by sunilpaulmathew on November 05, 2022
21 | */
22 | public class CommandsAdapter extends RecyclerView.Adapter {
23 |
24 | private final List data;
25 |
26 | private static ClickListener mClickListener;
27 |
28 | public CommandsAdapter(List data) {
29 | this.data = data;
30 | }
31 |
32 | @NonNull
33 | @Override
34 | public CommandsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
35 | View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_commands, parent, false);
36 | return new CommandsAdapter.ViewHolder(rowItem);
37 | }
38 |
39 | @Override
40 | public void onBindViewHolder(@NonNull CommandsAdapter.ViewHolder holder, int position) {
41 | holder.mTitle.setText(this.data.get(position).getTitle());
42 | if (this.data.get(position).getSummary() != null) {
43 | holder.mSummary.setText(this.data.get(position).getSummary());
44 | } else {
45 | holder.mTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);
46 | holder.mTitle.setTypeface(null, Typeface.BOLD_ITALIC);
47 | holder.mSummary.setVisibility(View.GONE);
48 | }
49 | }
50 |
51 | @Override
52 | public int getItemCount() {
53 | return this.data.size();
54 | }
55 |
56 | public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
57 | private final MaterialTextView mTitle, mSummary;
58 |
59 | public ViewHolder(View view) {
60 | super(view);
61 | view.setOnClickListener(this);
62 | this.mTitle = view.findViewById(R.id.title);
63 | this.mSummary = view.findViewById(R.id.summary);
64 | }
65 |
66 | @Override
67 | public void onClick(View view) {
68 | mClickListener.onItemClick(this.mTitle.getText().toString(), view);
69 | }
70 | }
71 |
72 | public void setOnItemClickListener(ClickListener clickListener) {
73 | CommandsAdapter.mClickListener = clickListener;
74 | }
75 |
76 | public interface ClickListener {
77 | void onItemClick(String command, View v);
78 | }
79 |
80 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/adapters/ExamplesAdapter.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.adapters;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.recyclerview.widget.RecyclerView;
9 |
10 | import com.google.android.material.dialog.MaterialAlertDialogBuilder;
11 | import com.google.android.material.textview.MaterialTextView;
12 |
13 | import java.util.List;
14 |
15 | import in.sunilpaulmathew.ashell.R;
16 | import in.sunilpaulmathew.ashell.serializable.CommandItems;
17 | import in.sunilpaulmathew.ashell.utils.Utils;
18 |
19 | /*
20 | * Created by sunilpaulmathew on November 08, 2022
21 | */
22 | public class ExamplesAdapter extends RecyclerView.Adapter {
23 |
24 | private final List data;
25 |
26 | public ExamplesAdapter(List data) {
27 | this.data = data;
28 | }
29 |
30 | @NonNull
31 | @Override
32 | public ExamplesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
33 | View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_examples, parent, false);
34 | return new ExamplesAdapter.ViewHolder(rowItem);
35 | }
36 |
37 | @Override
38 | public void onBindViewHolder(@NonNull ExamplesAdapter.ViewHolder holder, int position) {
39 | holder.mTitle.setText(this.data.get(position).getTitle());
40 | if (this.data.get(position).getSummary() != null) {
41 | holder.mSummary.setText(this.data.get(position).getSummary());
42 | }
43 | }
44 |
45 | @Override
46 | public int getItemCount() {
47 | return this.data.size();
48 | }
49 |
50 | public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
51 | private final MaterialTextView mTitle, mSummary;
52 |
53 | public ViewHolder(View view) {
54 | super(view);
55 | view.setOnClickListener(this);
56 | this.mTitle = view.findViewById(R.id.title);
57 | this.mSummary = view.findViewById(R.id.summary);
58 | }
59 |
60 | @Override
61 | public void onClick(View view) {
62 | if (data.get(getAdapterPosition()).getExample() != null) {
63 | new MaterialAlertDialogBuilder(view.getContext())
64 | .setIcon(R.mipmap.ic_launcher)
65 | .setTitle(data.get(getAdapterPosition()).getTitle())
66 | .setMessage(data.get(getAdapterPosition()).getExample())
67 | .setNegativeButton(R.string.cancel, (dialogInterface, i) -> {
68 | })
69 | .setPositiveButton(R.string.copy_clipboard, (dialogInterface, i) ->
70 | Utils.copyToClipboard(data.get(getAdapterPosition()).getExample(), view.getContext())
71 | ).show();
72 | }
73 | }
74 | }
75 |
76 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/adapters/PolicyAdapter.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.adapters;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.recyclerview.widget.RecyclerView;
9 |
10 | import com.google.android.material.textview.MaterialTextView;
11 |
12 | import java.util.List;
13 |
14 | import in.sunilpaulmathew.ashell.R;
15 | import in.sunilpaulmathew.ashell.serializable.CommandItems;
16 |
17 | /*
18 | * Created by sunilpaulmathew on April 21, 2022
19 | */
20 | public class PolicyAdapter extends RecyclerView.Adapter {
21 |
22 | private final List data;
23 |
24 | public PolicyAdapter(List data) {
25 | this.data = data;
26 | }
27 |
28 | @NonNull
29 | @Override
30 | public PolicyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
31 | View rowItem = LayoutInflater.from(parent.getContext()).inflate(in.sunilpaulmathew.ashell.R.layout.recycler_view_policy, parent, false);
32 | return new ViewHolder(rowItem);
33 | }
34 |
35 | @Override
36 | public void onBindViewHolder(@NonNull PolicyAdapter.ViewHolder holder, int position) {
37 | holder.mTitle.setText(data.get(position).getTitle());
38 | holder.mText.setText(data.get(position).getSummary());
39 | holder.mText.setTextColor(holder.mText.getHintTextColors());
40 | }
41 |
42 | @Override
43 | public int getItemCount() {
44 | return data.size();
45 | }
46 |
47 | public static class ViewHolder extends RecyclerView.ViewHolder {
48 |
49 | private final MaterialTextView mText, mTitle;
50 |
51 | public ViewHolder(View view) {
52 | super(view);
53 | this.mText = view.findViewById(R.id.text);
54 | this.mTitle = view.findViewById(R.id.title);
55 | view.setOnClickListener(v -> {
56 | if (mText.getMaxLines() == 1) {
57 | mText.setSingleLine(false);
58 | } else {
59 | mText.setMaxLines(1);
60 | }
61 | });
62 | }
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/adapters/SettingsAdapter.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.adapters;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.content.Intent;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.appcompat.widget.AppCompatImageButton;
12 | import androidx.appcompat.widget.LinearLayoutCompat;
13 | import androidx.recyclerview.widget.LinearLayoutManager;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | import com.google.android.material.checkbox.MaterialCheckBox;
17 | import com.google.android.material.dialog.MaterialAlertDialogBuilder;
18 | import com.google.android.material.textview.MaterialTextView;
19 |
20 | import java.util.List;
21 |
22 | import in.sunilpaulmathew.ashell.BuildConfig;
23 | import in.sunilpaulmathew.ashell.R;
24 | import in.sunilpaulmathew.ashell.activities.ExamplesActivity;
25 | import in.sunilpaulmathew.ashell.serializable.SettingsItems;
26 | import in.sunilpaulmathew.ashell.utils.Settings;
27 | import in.sunilpaulmathew.ashell.utils.Utils;
28 |
29 | /*
30 | * Created by sunilpaulmathew on April 21, 2022
31 | */
32 | public class SettingsAdapter extends RecyclerView.Adapter {
33 |
34 | private final Activity activity;
35 | private final List data;
36 |
37 | public SettingsAdapter(List data, Activity activity) {
38 | this.data = data;
39 | this.activity = activity;
40 | }
41 |
42 | @NonNull
43 | @Override
44 | public SettingsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
45 | View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_settings, parent, false);
46 | return new ViewHolder(rowItem);
47 | }
48 |
49 | @Override
50 | public void onBindViewHolder(@NonNull SettingsAdapter.ViewHolder holder, int position) {
51 | holder.mTitle.setText(data.get(position).geTitle());
52 | if (data.get(position).getDescription() != null) {
53 | holder.mDescription.setText(data.get(position).getDescription());
54 | holder.mDescription.setVisibility(View.VISIBLE);
55 | } else {
56 | holder.mDescription.setVisibility(View.GONE);
57 | }
58 |
59 | if (data.get(position).getIcon() != Integer.MIN_VALUE) {
60 | holder.mIcon.setImageDrawable(Utils.getDrawable(data.get(position).getIcon(), holder.mIcon.getContext()));
61 | holder.mIcon.setVisibility(View.VISIBLE);
62 | } else {
63 | holder.mIcon.setVisibility(View.GONE);
64 | }
65 |
66 | if (data.get(position).isSwitch()) {
67 | holder.mCheckBox.setVisibility(View.VISIBLE);
68 | holder.mCheckBox.setChecked(data.get(position).isEnabled());
69 | } else {
70 | holder.mCheckBox.setVisibility(View.GONE);
71 | }
72 |
73 | if (data.get(position).getPosition() == 0) {
74 | holder.mDivider.setVisibility(View.VISIBLE);
75 | holder.mTitle.setLayoutParams(new LinearLayoutCompat.LayoutParams(LinearLayoutCompat.LayoutParams.MATCH_PARENT,
76 | ViewGroup.LayoutParams.WRAP_CONTENT));
77 | holder.mTitle.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
78 | holder.mTitle.setTextColor(Settings.getColorAccent(holder.mTitle.getContext()));
79 | } else {
80 | holder.mTitle.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
81 | holder.mTitle.setTextColor(Settings.getColorText(holder.mTitle.getContext()));
82 | holder.mDivider.setVisibility(View.GONE);
83 | }
84 |
85 | holder.mCheckBox.setOnClickListener(v -> {
86 | if (data.get(position).getPosition() == 2) {
87 | Utils.saveBoolean("amoledTheme", !Utils.getBoolean("amoledTheme", false, holder.mCheckBox.getContext()), holder.mCheckBox.getContext());
88 | Settings.restartApp(activity);
89 | }
90 | });
91 | }
92 |
93 | @Override
94 | public int getItemCount() {
95 | return data.size();
96 | }
97 |
98 | public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
99 |
100 | private final AppCompatImageButton mIcon;
101 | private final MaterialCheckBox mCheckBox;
102 | private final MaterialTextView mTitle, mDescription;
103 | private final View mDivider;
104 |
105 | public ViewHolder(View view) {
106 | super(view);
107 | view.setOnClickListener(this);
108 | this.mIcon = view.findViewById(R.id.icon);
109 | this.mTitle = view.findViewById(R.id.title);
110 | this.mDescription = view.findViewById(R.id.description);
111 | this.mCheckBox = view.findViewById(R.id.checkbox);
112 | this.mDivider = view.findViewById(R.id.divider);
113 | }
114 |
115 | @SuppressLint("StringFormatMatches")
116 | @Override
117 | public void onClick(View view) {
118 | int position = data.get(getAdapterPosition()).getPosition();
119 | if (position == 1) {
120 | Settings.setAppTheme(view.getContext());
121 | } else if (position == 2) {
122 | Utils.saveBoolean("amoledTheme", !Utils.getBoolean("amoledTheme", false, view.getContext()), view.getContext());
123 | Settings.restartApp(activity);
124 | } else if (position == 3) {
125 | Settings.setAppLanguage(activity);
126 | } else if (position == 4) {
127 | Intent examples = new Intent(view.getContext(), ExamplesActivity.class);
128 | view.getContext().startActivity(examples);
129 | } else if (position == 5) {
130 | Utils.loadUrl("https://shizuku.rikka.app/", view.getContext());
131 | } else if (position == 6) {
132 | Utils.loadUrl("https://poeditor.com/join/project/20PSoEAgfX", view.getContext());
133 | } else if (position == 7) {
134 | LayoutInflater layoutInflater = LayoutInflater.from(view.getContext());
135 | View policyLayout = layoutInflater.inflate(R.layout.layout_privacy_policy, null);
136 | MaterialTextView version = policyLayout.findViewById(R.id.title);
137 | RecyclerView recyclerView = policyLayout.findViewById(R.id.recycler_view);
138 | version.setText(view.getContext().getString(R.string.app_version, BuildConfig.VERSION_NAME));
139 | recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
140 | recyclerView.setAdapter(new PolicyAdapter(Settings.getPolicyData()));
141 | new MaterialAlertDialogBuilder(view.getContext())
142 | .setView(policyLayout)
143 | .setPositiveButton(R.string.cancel, (dialog, id) -> {
144 | }).show();
145 | } else if (position == 8) {
146 | Utils.loadUrl("mailto:smartpack.org@gmail.com", view.getContext());
147 | }
148 | }
149 | }
150 |
151 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/adapters/ShellOutputAdapter.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.adapters;
2 |
3 | import android.text.Html;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.recyclerview.widget.RecyclerView;
10 |
11 | import com.google.android.material.textview.MaterialTextView;
12 |
13 | import java.util.List;
14 |
15 | import in.sunilpaulmathew.ashell.R;
16 |
17 | /*
18 | * Created by sunilpaulmathew on November 09, 2022
19 | */
20 | public class ShellOutputAdapter extends RecyclerView.Adapter {
21 |
22 | private final List data;
23 |
24 | public ShellOutputAdapter(List data) {
25 | this.data = data;
26 | }
27 |
28 | @NonNull
29 | @Override
30 | public ShellOutputAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
31 | View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_shell_output, parent, false);
32 | return new ShellOutputAdapter.ViewHolder(rowItem);
33 | }
34 |
35 | @Override
36 | public void onBindViewHolder(@NonNull ShellOutputAdapter.ViewHolder holder, int position) {
37 | holder.mOutput.setText(Html.fromHtml(this.data.get(position), Html.FROM_HTML_MODE_LEGACY));
38 | }
39 |
40 | @Override
41 | public int getItemCount() {
42 | return this.data.size();
43 | }
44 |
45 | public static class ViewHolder extends RecyclerView.ViewHolder {
46 | private final MaterialTextView mOutput;
47 |
48 | public ViewHolder(View view) {
49 | super(view);
50 | this.mOutput = view.findViewById(R.id.shell_output);
51 | }
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/adapters/WelcomeAdapter.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.adapters;
2 |
3 | import android.content.pm.PackageManager;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.appcompat.widget.AppCompatImageButton;
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | import com.google.android.material.button.MaterialButton;
13 | import com.google.android.material.textview.MaterialTextView;
14 |
15 | import java.util.List;
16 |
17 | import in.sunilpaulmathew.ashell.R;
18 | import in.sunilpaulmathew.ashell.serializable.CommandItems;
19 | import rikka.shizuku.Shizuku;
20 |
21 | /*
22 | * Created by sunilpaulmathew on April 16, 2025
23 | */
24 | public class WelcomeAdapter extends RecyclerView.Adapter {
25 |
26 | private final List data;
27 | private static ClickListener mClickListener;
28 |
29 | public WelcomeAdapter(List data) {
30 | this.data = data;
31 | }
32 |
33 | @NonNull
34 | @Override
35 | public WelcomeAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
36 | View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_welcome, parent, false);
37 | return new ViewHolder(rowItem);
38 | }
39 |
40 | @Override
41 | public void onBindViewHolder(@NonNull WelcomeAdapter.ViewHolder holder, int position) {
42 | holder.mTitle.setText(data.get(position).getTitle());
43 | holder.mText.setText(data.get(position).getSummary());
44 | holder.mText.setTextColor(holder.mText.getHintTextColors());
45 |
46 | if (position == 1 && Shizuku.pingBinder() && Shizuku.checkSelfPermission() != PackageManager.PERMISSION_GRANTED) {
47 | holder.mButton.setVisibility(View.GONE);
48 | holder.mPermission.setVisibility(View.VISIBLE);
49 | } else {
50 | holder.mButton.setVisibility(View.VISIBLE);
51 | holder.mPermission.setVisibility(View.GONE);
52 | }
53 |
54 | holder.mPermission.setOnClickListener(v -> {
55 | if (Shizuku.pingBinder() && Shizuku.checkSelfPermission() != PackageManager.PERMISSION_GRANTED) {
56 | mClickListener.onItemClick();
57 | }
58 | });
59 | }
60 |
61 | @Override
62 | public int getItemCount() {
63 | return data.size();
64 | }
65 |
66 | public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
67 | private final AppCompatImageButton mButton;
68 | private final MaterialButton mPermission;
69 | private final MaterialTextView mText, mTitle;
70 |
71 | public ViewHolder(View view) {
72 | super(view);
73 | this.mButton = view.findViewById(R.id.button);
74 | this.mPermission = view.findViewById(R.id.permission);
75 | this.mText = view.findViewById(R.id.text);
76 | this.mTitle = view.findViewById(R.id.title);
77 |
78 | view.setOnClickListener(this);
79 | }
80 |
81 | @Override
82 | public void onClick(View view) {
83 | if (getAdapterPosition() == 1 && Shizuku.pingBinder() && Shizuku.checkSelfPermission() != PackageManager.PERMISSION_GRANTED) {
84 | mClickListener.onItemClick();
85 | } else {
86 | if (mText.getMaxLines() == 1) {
87 | mText.setSingleLine(false);
88 | mButton.setRotation(180);
89 | } else {
90 | mButton.setRotation(0);
91 | mText.setMaxLines(1);
92 | }
93 | }
94 | }
95 | }
96 |
97 | public void setOnItemClickListener(ClickListener clickListener) {
98 | mClickListener = clickListener;
99 | }
100 |
101 | public interface ClickListener {
102 | void onItemClick();
103 | }
104 |
105 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/dialogs/SingleChoiceDialog.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.dialogs;
2 |
3 | import android.content.Context;
4 |
5 | import com.google.android.material.dialog.MaterialAlertDialogBuilder;
6 |
7 | /*
8 | * Created by sunilpaulmathew on April 21, 2025
9 | */
10 | public abstract class SingleChoiceDialog {
11 |
12 | private final int mIcon;
13 | private final int mPosition;
14 | private final MaterialAlertDialogBuilder mDialogBuilder;
15 | private final String mTitle;
16 | private final String[] mSingleChoiceItems;
17 |
18 | public SingleChoiceDialog(int icon, String title, String[] singleChoiceItems,
19 | int position, Context context) {
20 | this.mIcon = icon;
21 | this.mTitle = title;
22 | this.mSingleChoiceItems = singleChoiceItems;
23 | this.mPosition = position;
24 | this.mDialogBuilder = new MaterialAlertDialogBuilder(context);
25 | }
26 |
27 | private void startDialog() {
28 | if (mIcon > Integer.MIN_VALUE) {
29 | mDialogBuilder.setIcon(mIcon);
30 | }
31 | if (mTitle != null) {
32 | mDialogBuilder.setTitle(mTitle);
33 | }
34 | mDialogBuilder.setSingleChoiceItems(mSingleChoiceItems, mPosition, (dialog, itemPosition) -> {
35 | onItemSelected(itemPosition);
36 | dialog.dismiss();
37 | }).show();
38 | }
39 |
40 | public void show() {
41 | startDialog();
42 | }
43 |
44 | public abstract void onItemSelected(int position);
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/serializable/CommandItems.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.serializable;
2 |
3 | import java.io.Serializable;
4 |
5 | /*
6 | * Created by sunilpaulmathew on November 05, 2022
7 | */
8 | public class CommandItems implements Serializable {
9 |
10 | private final String mTitle, mSummary, mExample;
11 |
12 | public CommandItems(String title, String summary) {
13 | this.mTitle = title;
14 | this.mSummary = summary;
15 | this.mExample = null;
16 | }
17 |
18 | public CommandItems(String title, String summary, String example) {
19 | this.mTitle = title;
20 | this.mSummary = summary;
21 | this.mExample = example;
22 | }
23 |
24 | public String getTitle() {
25 | return mTitle;
26 | }
27 |
28 | public String getSummary() {
29 | return mSummary;
30 | }
31 |
32 | public String getExample() {
33 | return mExample;
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/serializable/SettingsItems.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.serializable;
2 |
3 | import java.io.Serializable;
4 |
5 | /*
6 | * Created by sunilpaulmathew on April 21, 2022
7 | */
8 | public class SettingsItems implements Serializable {
9 |
10 | private final boolean mEnabled, mSwitch;
11 | private final int mIcon, mPosition;
12 | private final String mTitle, mDescription;
13 |
14 | public SettingsItems(String title) {
15 | this.mPosition = 0;
16 | this.mIcon = Integer.MIN_VALUE;
17 | this.mTitle = title;
18 | this.mDescription = null;
19 | this.mSwitch = false;
20 | this.mEnabled = false;
21 | }
22 |
23 | public SettingsItems(int position, int icon, String title, String description) {
24 | this.mPosition = position;
25 | this.mIcon = icon;
26 | this.mTitle = title;
27 | this.mDescription = description;
28 | this.mSwitch = false;
29 | this.mEnabled = false;
30 | }
31 |
32 | public SettingsItems(int position, int icon, String title, String description, boolean isSwitch, boolean enabled) {
33 | this.mPosition = position;
34 | this.mIcon = icon;
35 | this.mTitle = title;
36 | this.mDescription = description;
37 | this.mSwitch = isSwitch;
38 | this.mEnabled = enabled;
39 | }
40 |
41 | public boolean isEnabled() {
42 | return mEnabled;
43 | }
44 |
45 | public boolean isSwitch() {
46 | return mSwitch;
47 | }
48 |
49 | public int getIcon() {
50 | return mIcon;
51 | }
52 |
53 | public int getPosition() {
54 | return mPosition;
55 | }
56 |
57 | public String geTitle() {
58 | return mTitle;
59 | }
60 |
61 | public String getDescription() {
62 | return mDescription;
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/utils/Commands.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.utils;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStreamReader;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import in.sunilpaulmathew.ashell.serializable.CommandItems;
9 |
10 | /*
11 | * Created by sunilpaulmathew on November 05, 2022
12 | */
13 | public class Commands {
14 |
15 | private static List mPackages = null;
16 |
17 | public static List commandList() {
18 | List mCommands = new ArrayList<>();
19 | mCommands.add(new CommandItems("am force-stop ", "Completely stop a given package", "am force-stop com.android.package"));
20 | mCommands.add(new CommandItems("am kill ", "Kill all background processes associated with a given package", "am kill com.android.package"));
21 | mCommands.add(new CommandItems("am kill-all", "Kill all processes that are safe to kill (cached, etc)"));
22 | mCommands.add(new CommandItems("cat ", "Display the contents of a text file", "cat /system/build.prop"));
23 | mCommands.add(new CommandItems("clear", "Clear terminal screen"));
24 | mCommands.add(new CommandItems("cp ", "Copy a file", "cp /system/build.prop /sdcard"));
25 | mCommands.add(new CommandItems("cp -r ", "Copy a file or directory", "cp -r /system/app /sdcard"));
26 | mCommands.add(new CommandItems("dumpsys activity", "Print activity info"));
27 | mCommands.add(new CommandItems("dumpsys battery", "Primt battery stats"));
28 | mCommands.add(new CommandItems("dumpsys battery set level ", "Change the level from 0 to 100", "dumpsys battery set level 95"));
29 | mCommands.add(new CommandItems("dumpsys battery set status ", "Change the level to unknown, charging, discharging, not charging or full", "dumpsys battery set status 0"));
30 | mCommands.add(new CommandItems("dumpsys battery reset", "Reset battery"));
31 | mCommands.add(new CommandItems("dumpsys display", "Primt display stats"));
32 | mCommands.add(new CommandItems("dumpsys iphonesybinfo", "Get IMEI"));
33 | mCommands.add(new CommandItems("echo ", "Display message on screen", "echo Hallo World"));
34 | mCommands.add(new CommandItems("exit", "Exit the shell"));
35 | mCommands.add(new CommandItems("file ", "Determine file type", "file /system/build.prop"));
36 | mCommands.add(new CommandItems("grep", "Search file(s) for lines that match a given pattern"));
37 | mCommands.add(new CommandItems("kill ", "Kill a process by specifying its PID"));
38 | mCommands.add(new CommandItems("logcat", "Display real-time log of system messages, including stack traces"));
39 | mCommands.add(new CommandItems("ls", "List contents of a directory", "ls /system"));
40 | mCommands.add(new CommandItems("ls -R", "List subdirectories recursively", "ls -R /system"));
41 | mCommands.add(new CommandItems("ls -s", "Print size of each file", "ls -s /system"));
42 | mCommands.add(new CommandItems("mkdir ", "Create a directory", "mkdir /sdcard/abc"));
43 | mCommands.add(new CommandItems("mv ", "Move a file or directory", "mv /system/app /sdcard"));
44 | mCommands.add(new CommandItems("netstat", "List TCP connectivity"));
45 | mCommands.add(new CommandItems("ping", "Test a network connection"));
46 | mCommands.add(new CommandItems("pm clear ", "Delete all data associated with an app", "pm clear com.android.package"));
47 | mCommands.add(new CommandItems("pm clear --cache-only ", "Only clear cache data associated with an app", "pm clear --cache-only com.android.package"));
48 | mCommands.add(new CommandItems("pm clear --user ", "Only delete the data associated with a given user", "pm clear --user 0 com.android.package"));
49 | mCommands.add(new CommandItems("pm disable ", "Disable a given package or component (written as package/class", "pm disable com.android.package/com.android.package.exampleActivity"));
50 | mCommands.add(new CommandItems("pm dump ", "List info of one app", "pm dump com.android.package"));
51 | mCommands.add(new CommandItems("pm dump package packages", "List info of all apps"));
52 | mCommands.add(new CommandItems("pm enable ", "Enable a given package or component (written as package/class", "pm enable com.android.package/com.android.package.exampleActivity"));
53 | mCommands.add(new CommandItems("pm grant ", "Grant a permission to an app", "pm grant com.android.package android.permission.WRITE_EXTERNAL_STORAGE"));
54 | mCommands.add(new CommandItems("pm install ", "Install an apk file", "pm install /data/local/tmp/aShell.apk"));
55 | mCommands.add(new CommandItems("pm install -d ", "Allow version code downgrade (debuggable packages only)", "pm install -d /data/local/tmp/aShell.apk"));
56 | mCommands.add(new CommandItems("pm install -f ", "Install application on internal flash", "pm install -f /data/local/tmp/aShell.apk"));
57 | mCommands.add(new CommandItems("pm install -g ", "Grant all runtime permissions", "pm install -g /data/local/tmp/aShell.apk"));
58 | mCommands.add(new CommandItems("pm install -i ", "Specify package name of installer owning the app", "pm install -i com.google.android.packageinstaller /data/local/tmp/aShell.apk"));
59 | mCommands.add(new CommandItems("pm install -p ", "Partial application install (new split on top of existing pkg)", "pm install -p /data/local/tmp/base.apk"));
60 | mCommands.add(new CommandItems("pm install -R ", "Update an existing apps, but disallow replacement of existing one", "pm install -R /data/local/tmp/aShell.apk"));
61 | mCommands.add(new CommandItems("pm install -t ", "Allow installing test packages", "pm install -t /data/local/tmp/aShell.apk"));
62 | mCommands.add(new CommandItems("pm install --abi ", "Override the default ABI of the platform", "pm install --abi /data/local/tmp/aShell.apk"));
63 | mCommands.add(new CommandItems("pm install --dont-kill ", "Install a new feature split without killing the running app", "pm install --dont-kill /data/local/tmp/aShell.apk"));
64 | mCommands.add(new CommandItems("pm install --full ", "Cause the app to be installed as a non-ephemeral full app", "pm install --full /data/local/tmp/aShell.apk"));
65 | mCommands.add(new CommandItems("pm install --install-location ", "Force the install location (Options, 0=auto, 1=internal only, 2=prefer external)", "pm install --install-location 1 /data/local/tmp/aShell.apk"));
66 | mCommands.add(new CommandItems("pm install --install-reason ", "Indicates why the app is being installed (Options, 0=unknown, 1=admin policy, 2=device restore,3=device setup, 4=user request)", "install --install-reason 2 /data/local/tmp/aShell.apk"));
67 | mCommands.add(new CommandItems("pm install --instant ", "Cause the app to be installed as an ephemeral install app", "pm install --instant /data/local/tmp/aShell.apk"));
68 | mCommands.add(new CommandItems("pm install --restrict-permissions ", "Don't whitelist restricted permissions at install", "pm install --restrict-permissions /data/local/tmp/aShell.apk"));
69 | mCommands.add(new CommandItems("pm install --pkg ", "Specify expected package name of app being installed", "pm install --pkg in.sunilpaulmathew.ashell /data/local/tmp/aShell.apk"));
70 | mCommands.add(new CommandItems("pm install --user ", "Install for a given user", "pm install --user0 /data/local/tmp/aShell.apk"));
71 | mCommands.add(new CommandItems("pm install-abandon ", "Delete the given active install session", "pm install-abandon 01234567"));
72 | mCommands.add(new CommandItems("pm install-commit ", "Commit the given active install session, installing the app", "pm install-commit 01234567"));
73 | mCommands.add(new CommandItems("pm install-create", "Create an install session"));
74 | mCommands.add(new CommandItems("pm install-existing", "Installs an existing application for a new user", "pm install-existing com.android.package"));
75 | mCommands.add(new CommandItems("pm install-existing --full ", "Install as a full app", "pm install-existing --full com.android.package"));
76 | mCommands.add(new CommandItems("pm install-existing --instant ", "Install as an instant app", "pm install-existing --instant com.android.package"));
77 | mCommands.add(new CommandItems("pm install-existing --restrict-permissions ", "Don't whitelist restricted permissions", "pm install-existing --restrict-permissions com.android.package"));
78 | mCommands.add(new CommandItems("pm install-existing --user ", "Install for a given user", "pm install-existing --user 0 com.android.package"));
79 | mCommands.add(new CommandItems("pm install-existing --wait ", "Wait until the package is installed", "pm install-existing --wait com.android.package"));
80 | mCommands.add(new CommandItems("pm install-remove ", "Mark SPLIT(s) as removed in the given install session", "pm install-remove 01234567 /data/local/tmp/base.apk"));
81 | mCommands.add(new CommandItems("pm install-write ", "Write an apk into the given install session", "pm install-write 123 01234567 base.apk /data/local/tmp/base.apk"));
82 | mCommands.add(new CommandItems("pm list features", "List phone features"));
83 | mCommands.add(new CommandItems("pm list libraries", "List all system libraries"));
84 | mCommands.add(new CommandItems("pm list packages", "List package names"));
85 | mCommands.add(new CommandItems("pm list packages -3", "List only third party packages"));
86 | mCommands.add(new CommandItems("pm list packages -a", "List all known packages, but excluding APEXes"));
87 | mCommands.add(new CommandItems("pm list packages -d", "List all disabled packages"));
88 | mCommands.add(new CommandItems("pm list packages -e", "List all enabled packages"));
89 | mCommands.add(new CommandItems("pm list packages -f", "List package names along with their associated file"));
90 | mCommands.add(new CommandItems("pm list packages -i", "List package names along with their installer"));
91 | mCommands.add(new CommandItems("pm list packages -s", "List only system packages"));
92 | mCommands.add(new CommandItems("pm list packages --show-versioncode", "List package names along with their version code"));
93 | mCommands.add(new CommandItems("pm list packages -u", "List package names of all apps including the uninstalled ones"));
94 | mCommands.add(new CommandItems("pm list packages -U", "List package names along with their package UID"));
95 | mCommands.add(new CommandItems("pm list permissions", "Print all known permission groups"));
96 | mCommands.add(new CommandItems("pm list permissions -d", "Print only dangerous permissions"));
97 | mCommands.add(new CommandItems("pm list permissions -f", "Print all information about the known permissions"));
98 | mCommands.add(new CommandItems("pm list permissions -g", "Organize all known permission by group"));
99 | mCommands.add(new CommandItems("pm list permissions -s", "Print a short summary about the known permissions"));
100 | mCommands.add(new CommandItems("pm list permissions -u", "Print only permissions that users will see"));
101 | mCommands.add(new CommandItems("pm list users", "List all user names"));
102 | mCommands.add(new CommandItems("pm path ", "Show apk file path of an app", "pm path com.android.package"));
103 | mCommands.add(new CommandItems("pm revoke ", "Revoke a permission from an app", "pm revoke com.android.package android.permission.WRITE_EXTERNAL_STORAGE"));
104 | mCommands.add(new CommandItems("pm reset-permissions -p ", "Reset permissions of an app", "pm reset-permissions -p com.android.package"));
105 | mCommands.add(new CommandItems("pm uninstall ", "Uninstall an app", "pm uninstall com.android.package"));
106 | mCommands.add(new CommandItems("pm uninstall -k ", "Uninstall an app but keep the data and cache untouched", "pm uninstall -k com.android.package"));
107 | mCommands.add(new CommandItems("pm uninstall --user ", "Uninstall an app from a given user", "pm uninstall --user 0 com.android.package"));
108 | mCommands.add(new CommandItems("pm uninstall --versionCode ", "Only uninstall if the app has the given version code", "pm uninstall --versionCode 123 com.android.package"));
109 | mCommands.add(new CommandItems("pm uninstall-system-updates", "Removes updates to all system applications and falls back to its system version"));
110 | mCommands.add(new CommandItems("pm uninstall-system-updates ", "Removes updates to a given system application and falls back to its system version", "pm uninstall-system-updates com.android.package"));
111 | mCommands.add(new CommandItems("ps", "Print process status"));
112 | mCommands.add(new CommandItems("pwd", "Print current working directory"));
113 | mCommands.add(new CommandItems("reboot", "Reboot device"));
114 | mCommands.add(new CommandItems("reboot -p", "Shutdown device"));
115 | mCommands.add(new CommandItems("reboot recovery", "Reboot device into recovery mode"));
116 | mCommands.add(new CommandItems("reboot fastboot", "Reboot device into fastboot"));
117 | mCommands.add(new CommandItems("reboot bootloader", "Reboot device into bootloader"));
118 | mCommands.add(new CommandItems("rm ", "Delete a file", "rm /sdcard/example.txt"));
119 | mCommands.add(new CommandItems("rm -r ", "Delete a file or directory", "rm -r /sdcard/abc"));
120 | mCommands.add(new CommandItems("service list", "List all services"));
121 | mCommands.add(new CommandItems("sleep ", "Delay for a specified time", "sleep 5"));
122 | mCommands.add(new CommandItems("sync", "Synchronize data on disk with memory"));
123 | mCommands.add(new CommandItems("top", "List processes running on the system"));
124 | mCommands.add(new CommandItems("top -n ", "Update display times, then exit", "top -n1"));
125 | mCommands.add(new CommandItems("whoami", "Print the current user id and name"));
126 | mCommands.add(new CommandItems("wm density", "Displays current screen density"));
127 | mCommands.add(new CommandItems("wm density reset", "Reset screen density to default"));
128 | mCommands.add(new CommandItems("wm size", "Displays the current screen resolution"));
129 | mCommands.add(new CommandItems("wm size reset", "Reset screen resolution to default"));
130 | return mCommands;
131 | }
132 |
133 | public static List getCommand(String command) {
134 | List mCommands = new ArrayList<>();
135 | for (CommandItems commands: commandList()) {
136 | if (commands == null || commands.getTitle().startsWith(command)) {
137 | mCommands.add(commands);
138 | }
139 | }
140 | return mCommands;
141 | }
142 |
143 | public static List getPackageInfo(String command) {
144 | List mCommands = new ArrayList<>();
145 | for (CommandItems packages: mPackages) {
146 | if (packages.getTitle().startsWith(command)) {
147 | mCommands.add(packages);
148 | }
149 | }
150 | return mCommands;
151 | }
152 |
153 | public static void loadPackageInfo() {
154 | mPackages = new ArrayList<>();
155 |
156 | try {
157 | Process mProcess = Runtime.getRuntime().exec("pm list packages");
158 | BufferedReader mInput = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
159 | String line;
160 | while ((line = mInput.readLine()) != null) {
161 | if (line.startsWith("package:")) {
162 | mPackages.add(new CommandItems(line.replace("package:", ""), null));
163 | }
164 | }
165 | mProcess.waitFor();
166 | } catch (Exception ignored) {
167 | }
168 | }
169 |
170 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/utils/Settings.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.utils;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.res.Configuration;
7 | import android.content.res.Resources;
8 | import android.content.res.TypedArray;
9 | import android.util.DisplayMetrics;
10 |
11 | import androidx.appcompat.app.AppCompatDelegate;
12 |
13 | import com.google.android.material.color.DynamicColors;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 | import java.util.Locale;
18 | import java.util.Objects;
19 |
20 | import in.sunilpaulmathew.ashell.R;
21 | import in.sunilpaulmathew.ashell.activities.aShellActivity;
22 | import in.sunilpaulmathew.ashell.dialogs.SingleChoiceDialog;
23 | import in.sunilpaulmathew.ashell.serializable.CommandItems;
24 |
25 | /*
26 | * Created by sunilpaulmathew on April 21, 2022
27 | */
28 | public class Settings {
29 |
30 | public static boolean isAmoledBlackEnabled(Context context) {
31 | return isDarkTheme(context) && Utils.getBoolean("amoledTheme", false, context);
32 | }
33 |
34 | public static boolean isDarkTheme(Context context) {
35 | int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
36 | return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
37 | }
38 |
39 | public static int getColorAccent(Context context) {
40 | return getMaterial3Colors(Utils.getColor(R.color.colorBlue, context), context);
41 | }
42 |
43 | public static int getColorText(Context context) {
44 | return Utils.getColor(isDarkTheme(context) ? R.color.colorWhite : R.color.colorBlack, context);
45 | }
46 |
47 | private static int getMaterial3Colors(int defaultColor, Context context) {
48 | int color = defaultColor;
49 | if (DynamicColors.isDynamicColorAvailable()) {
50 | Context dynamicClrCtx = DynamicColors.wrapContextIfAvailable(context, com.google.android.material.R.style.MaterialAlertDialog_Material3);
51 | TypedArray ta = dynamicClrCtx.obtainStyledAttributes(new int[] {
52 | com.google.android.material.R.attr.colorPrimary
53 | });
54 | color = ta.getColor(0, defaultColor);
55 | ta.recycle();
56 | }
57 | return color;
58 | }
59 |
60 | private static int getAppThemePosition(Context context) {
61 | return Utils.getInt("appTheme", 0, context);
62 | }
63 |
64 | private static int getLanguagePosition(Context context) {
65 | String country = getCountry(context);
66 | switch (getLanguage(context)) {
67 | case "ko":
68 | return 10;
69 | case "zh":
70 | return country.equalsIgnoreCase("Hans") ? 9 : 8;
71 | case "ru":
72 | return 7;
73 | case "pt":
74 | return country.equalsIgnoreCase("BR") ? 5 : 6;
75 | case "in":
76 | return 4;
77 | case "hu":
78 | return 3;
79 | case "en":
80 | return country.equalsIgnoreCase("us") ? 2 : 0;
81 | case "el":
82 | return 1;
83 | default:
84 | return 0;
85 | }
86 | }
87 |
88 | public static List getPolicyData() {
89 | List mData = new ArrayList<>();
90 | mData.add(new CommandItems("Introduction", "aShell is developed by one main developer, sunilpaulmathew, leveraging code from various open-source projects. This Privacy Policy outlines how we handle user privacy."));
91 | mData.add(new CommandItems("Scope", "This policy applies exclusively to the original version of aShell published by the developer on Google Play, F-Droid, IzzyOnDroid, and GitHub."));
92 | mData.add(new CommandItems("Personal Information", "We do not collect, store, or share any personal information about our users. User identities remain anonymous. If we inadvertently receive any personal information, we will not disclose or share it with third parties."));
93 | mData.add(new CommandItems("Permissions", "aShell requires the following permissions to deliver its features:" +
94 | "\n\uD83D\uDD10 moe.shizuku.manager.permission.API_V23: Permission required to use Shizuku’s privileged APIs." +
95 | "\n\uD83D\uDCC2 WRITE_EXTERNAL_STORAGE: Allows aShell to write recent command results to device storage."));
96 | mData.add(new CommandItems("Contact Us", "If you have questions or concerns about this Privacy Policy, please contact us at: smartpack.org@gmail.com"));
97 | mData.add(new CommandItems("Changes to This Policy", "We may update this policy from time to time. Changes will be posted here."));
98 | return mData;
99 | }
100 |
101 | public static String getAppTheme(Context context) {
102 | int appTheme = Utils.getInt("appTheme", 0, context);
103 | switch (appTheme) {
104 | case 2:
105 | return context.getString(R.string.app_theme_light);
106 | case 1:
107 | return context.getString(R.string.app_theme_dark);
108 | default:
109 | return context.getString(R.string.app_theme_auto);
110 | }
111 | }
112 |
113 | private static String getCountry(Context context) {
114 | return Utils.getString("country", java.util.Locale.getDefault().getLanguage(), context);
115 | }
116 |
117 | private static String getLanguage(Context context) {
118 | return Utils.getString("appLanguage", java.util.Locale.getDefault().getLanguage(), context);
119 | }
120 |
121 | public static String getLanguageDescription(Context context) {
122 | String country = getCountry(context);
123 | switch (getLanguage(context)) {
124 | case "en":
125 | return country.equalsIgnoreCase("US") ? context.getString(R.string.language_en, "US")
126 | : context.getString(R.string.app_theme_auto);
127 | case "el":
128 | return context.getString(R.string.language_el);
129 | case "pt":
130 | return context.getString(R.string.language_pt, country.equalsIgnoreCase("BR") ? "BR" : "PT");
131 | case "ru":
132 | return context.getString(R.string.language_ru);
133 | case "hu":
134 | return context.getString(R.string.language_hu);
135 | case "in":
136 | return context.getString(R.string.language_in);
137 | case "ko":
138 | return context.getString(R.string.language_ko);
139 | case "zh":
140 | return country.equalsIgnoreCase("Hans") ? context.getString(R.string.language_zh, "Hans")
141 | : country.equalsIgnoreCase("TW") ? context.getString(R.string.language_zh, "TW")
142 | : context.getString(R.string.app_theme_auto);
143 | default:
144 | return context.getString(R.string.app_theme_auto);
145 | }
146 | }
147 |
148 | private static String[] getAppThemeMenu(Context context) {
149 | return new String[] {
150 | context.getString(R.string.app_theme_auto),
151 | context.getString(R.string.app_theme_dark),
152 | context.getString(R.string.app_theme_light)
153 | };
154 | }
155 |
156 | private static String[] getLanguageMenu(Context context) {
157 | return new String[] {
158 | context.getString(R.string.app_theme_auto),
159 | context.getString(R.string.language_el),
160 | context.getString(R.string.language_en, "US"),
161 | context.getString(R.string.language_hu),
162 | context.getString(R.string.language_in),
163 | context.getString(R.string.language_pt, "BR"),
164 | context.getString(R.string.language_pt, "PT"),
165 | context.getString(R.string.language_ru),
166 | context.getString(R.string.language_zh, "TW"),
167 | context.getString(R.string.language_zh, "Hans"),
168 | context.getString(R.string.language_ko),
169 | };
170 | }
171 |
172 | public static void initializeAppTheme(Context context) {
173 | int appTheme = Utils.getInt("appTheme", 0, context);
174 | switch (appTheme) {
175 | case 1:
176 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
177 | break;
178 | case 2:
179 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
180 | break;
181 | default:
182 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
183 | break;
184 | }
185 | context.setTheme(Settings.isAmoledBlackEnabled(context) ? R.style.AppTheme_Amoled : R.style.AppTheme);
186 | }
187 |
188 | private static Locale getLocale(Context context) {
189 | if (getCountry(context) != null) {
190 | return new Locale(getLanguage(context), getCountry(context));
191 | } else {
192 | return new Locale(getLanguage(context));
193 | }
194 | }
195 |
196 | public static void initializeAppLanguage(Context context) {
197 | Resources res = context.getResources();
198 | DisplayMetrics dm = res.getDisplayMetrics();
199 | Configuration conf = res.getConfiguration();
200 | conf.setLocale(getLocale(context));
201 | res.updateConfiguration(conf, dm);
202 | }
203 |
204 | public static void restartApp(Activity activity) {
205 | Intent mainActivity = new Intent(activity, aShellActivity.class);
206 | mainActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
207 | activity.startActivity(mainActivity);
208 | activity.finish();
209 | }
210 |
211 | public static void setAppLanguage(Activity activity) {
212 | new SingleChoiceDialog(R.drawable.ic_language, activity.getString(R.string.language),
213 | getLanguageMenu(activity), getLanguagePosition(activity), activity) {
214 |
215 | @Override
216 | public void onItemSelected(int position) {
217 | switch (position) {
218 | case 0:
219 | if (Objects.equals(getLanguage(activity), Locale.getDefault().getLanguage()) && Objects.equals(getCountry(activity), Locale.getDefault().getCountry())) {
220 | return;
221 | }
222 | Utils.saveString("appLanguage", java.util.Locale.getDefault().getLanguage(), activity);
223 | Utils.saveString("country", java.util.Locale.getDefault().getCountry(), activity);
224 | break;
225 | case 1:
226 | if (Objects.equals(getLanguage(activity), "el") && Objects.equals(getCountry(activity), null)) {
227 | return;
228 | }
229 | Utils.saveString("appLanguage", "el", activity);
230 | Utils.saveString("country", null, activity);
231 | break;
232 | case 2:
233 | if (Objects.equals(getLanguage(activity), "en") && Objects.equals(getCountry(activity), "US")) {
234 | return;
235 | }
236 | Utils.saveString("appLanguage", "en", activity);
237 | Utils.saveString("country", "US", activity);
238 | break;
239 | case 3:
240 | if (Objects.equals(getLanguage(activity), "hu") && Objects.equals(getCountry(activity), null)) {
241 | return;
242 | }
243 | Utils.saveString("appLanguage", "hu", activity);
244 | Utils.saveString("country", null, activity);
245 | break;
246 | case 4:
247 | if (Objects.equals(getLanguage(activity), "in") && Objects.equals(getCountry(activity), null)) {
248 | return;
249 | }
250 | Utils.saveString("appLanguage", "in", activity);
251 | Utils.saveString("country", null, activity);
252 | break;
253 | case 5:
254 | if (Objects.equals(getLanguage(activity), "pt") && Objects.equals(getCountry(activity), "BR")) {
255 | return;
256 | }
257 | Utils.saveString("appLanguage", "pt", activity);
258 | Utils.saveString("country", "BR", activity);
259 | break;
260 | case 6:
261 | if (Objects.equals(getLanguage(activity), "pt") && Objects.equals(getCountry(activity), "PT")) {
262 | return;
263 | }
264 | Utils.saveString("appLanguage", "pt", activity);
265 | Utils.saveString("country", "PT", activity);
266 | break;
267 | case 7:
268 | if (Objects.equals(getLanguage(activity), "ru") && Objects.equals(getCountry(activity), null)) {
269 | return;
270 | }
271 | Utils.saveString("appLanguage", "ru", activity);
272 | Utils.saveString("country", null, activity);
273 | break;
274 | case 8:
275 | if (Objects.equals(getLanguage(activity), "zh") && Objects.equals(getCountry(activity), "TW")) {
276 | return;
277 | }
278 | Utils.saveString("appLanguage", "zh", activity);
279 | Utils.saveString("country", "TW", activity);
280 | break;
281 | case 9:
282 | if (Objects.equals(getLanguage(activity), "zh") && Objects.equals(getCountry(activity), "Hans")) {
283 | return;
284 | }
285 | Utils.saveString("appLanguage", "zh", activity);
286 | Utils.saveString("country", "Hans", activity);
287 | break;
288 | case 10:
289 | if (Objects.equals(getLanguage(activity), "ko") && Objects.equals(getCountry(activity), null)) {
290 | return;
291 | }
292 | Utils.saveString("appLanguage", "ko", activity);
293 | Utils.saveString("country", null, activity);
294 | break;
295 | }
296 | restartApp(activity);
297 | }
298 | }.show();
299 | }
300 |
301 | public static void setAppTheme(Context context) {
302 | new SingleChoiceDialog(R.drawable.ic_theme, context.getString(R.string.app_theme),
303 | getAppThemeMenu(context), getAppThemePosition(context), context) {
304 |
305 | @Override
306 | public void onItemSelected(int position) {
307 | if (position == Utils.getInt("appTheme", 0, context)) {
308 | return;
309 | }
310 | switch (position) {
311 | case 2:
312 | Utils.saveInt("appTheme", 2, context);
313 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
314 | break;
315 | case 1:
316 | Utils.saveInt("appTheme", 1, context);
317 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
318 | break;
319 | default:
320 | Utils.saveInt("appTheme", 0, context);
321 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
322 | break;
323 | }
324 | }
325 | }.show();
326 | }
327 |
328 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/utils/ShizukuShell.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.utils;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStreamReader;
5 | import java.util.List;
6 |
7 | import rikka.shizuku.Shizuku;
8 | import rikka.shizuku.ShizukuRemoteProcess;
9 |
10 | /*
11 | * Created by sunilpaulmathew on November 12, 2022
12 | */
13 | public class ShizukuShell {
14 |
15 | private static List mOutput;
16 | private static ShizukuRemoteProcess mProcess = null;
17 | private static String mCommand;
18 | private static String mDir = "/";
19 |
20 | public ShizukuShell(List output, String command) {
21 | mOutput = output;
22 | mCommand = command;
23 | }
24 |
25 | public boolean isBusy() {
26 | return mOutput != null && !mOutput.isEmpty() && !mOutput.get(mOutput.size() - 1).equals("aShell: Finish");
27 | }
28 |
29 | public void exec() {
30 | try {
31 | mProcess = Shizuku.newProcess(new String[] {"sh", "-c", mCommand}, null, mDir);
32 | BufferedReader mInput = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
33 | BufferedReader mError = new BufferedReader(new InputStreamReader(mProcess.getErrorStream()));
34 | String line;
35 | while ((line = mInput.readLine()) != null) {
36 | mOutput.add(line);
37 | }
38 | while ((line = mError.readLine()) != null) {
39 | mOutput.add("" + line + " ");
40 | }
41 |
42 | // Handle current directory
43 | if (mCommand.startsWith("cd ") && !mOutput.get(mOutput.size() - 1).endsWith("")) {
44 | String[] array = mCommand.split("\\s+");
45 | String dir;
46 | if (array[array.length - 1].equals("/")) {
47 | dir = "/";
48 | } else if (array[array.length - 1].startsWith("/")) {
49 | dir = array[array.length - 1];
50 | } else {
51 | dir = mDir + array[array.length - 1];
52 | }
53 | if (!dir.endsWith("/")) {
54 | dir = dir + "/";
55 | }
56 | mDir = dir;
57 | }
58 |
59 | mProcess.waitFor();
60 | } catch (Exception ignored) {
61 | }
62 | }
63 |
64 | public void destroy() {
65 | if (mProcess != null) mProcess.destroy();
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/in/sunilpaulmathew/ashell/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package in.sunilpaulmathew.ashell.utils;
2 |
3 | import android.content.ActivityNotFoundException;
4 | import android.content.ClipData;
5 | import android.content.ClipboardManager;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.graphics.drawable.Drawable;
9 | import android.net.Uri;
10 | import android.os.Build;
11 | import android.widget.Toast;
12 |
13 | import androidx.core.content.ContextCompat;
14 | import androidx.preference.PreferenceManager;
15 |
16 | import java.io.BufferedReader;
17 | import java.io.File;
18 | import java.io.FileReader;
19 | import java.io.FileWriter;
20 | import java.io.IOException;
21 | import java.util.ArrayList;
22 | import java.util.List;
23 | import java.util.Objects;
24 |
25 | /*
26 | * Created by sunilpaulmathew on October 28, 2022
27 | */
28 | public class Utils {
29 |
30 | public static boolean isBookmarked(String command, Context context) {
31 | if (isValidFilename(command)) {
32 | return new File(context.getExternalFilesDir("bookmarks"), command).exists();
33 | } else {
34 | if (new File(context.getExternalFilesDir("bookmarks"), "specialCommands").exists()) {
35 | for (String commands : Objects.requireNonNull(read(new File(context.getExternalFilesDir("bookmarks"), "specialCommands"))).split("\\r?\\n")) {
36 | if (commands.trim().equals(command)) {
37 | return true;
38 | }
39 | }
40 | }
41 | }
42 | return false;
43 | }
44 |
45 | public static boolean deleteFromBookmark(String command, Context context) {
46 | if (isValidFilename(command)) {
47 | return new File(context.getExternalFilesDir("bookmarks"), command).delete();
48 | } else {
49 | StringBuilder sb = new StringBuilder();
50 | for (String commands : Objects.requireNonNull(read(new File(context.getExternalFilesDir("bookmarks"), "specialCommands"))).split("\\r?\\n")) {
51 | if (!commands.equals(command)) {
52 | sb.append(commands).append("\n");
53 | }
54 | }
55 | create(sb.toString(), new File(context.getExternalFilesDir("bookmarks"), "specialCommands"));
56 | return true;
57 | }
58 | }
59 |
60 | public static boolean getBoolean(String name, boolean defaults, Context context) {
61 | return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(name, defaults);
62 | }
63 |
64 | /*
65 | * Adapted from android.os.FileUtils
66 | * Ref: https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/FileUtils.java;l=972?q=isValidFatFilenameChar
67 | */
68 | private static boolean isValidFilename(String s) {
69 | return !s.contains("*") && !s.contains("/") && !s.contains(":")
70 | && !s.contains("<") && !s.contains(">") && !s.contains("?")
71 | && !s.contains("\\") && !s.contains("|");
72 | }
73 |
74 | public static Drawable getDrawable(int drawable, Context context) {
75 | return ContextCompat.getDrawable(context, drawable);
76 | }
77 |
78 | public static int getColor(int color, Context context) {
79 | return ContextCompat.getColor(context, color);
80 | }
81 |
82 | public static int getInt(String name, int defaults, Context context) {
83 | return PreferenceManager.getDefaultSharedPreferences(context).getInt(name, defaults);
84 | }
85 |
86 | public static List getBookmarks(Context context) {
87 | List mBookmarks = new ArrayList<>();
88 | for (File file : Objects.requireNonNull(Objects.requireNonNull(context.getExternalFilesDir("bookmarks")).listFiles())) {
89 | if (!file.getName().equalsIgnoreCase("specialCommands")) {
90 | mBookmarks.add(file.getName());
91 | }
92 | }
93 | if (new File(context.getExternalFilesDir("bookmarks"), "specialCommands").exists()) {
94 | for (String commands : Objects.requireNonNull(read(new File(context.getExternalFilesDir("bookmarks"), "specialCommands"))).split("\\r?\\n")) {
95 | if (!commands.trim().isEmpty()) {
96 | mBookmarks.add(commands.trim());
97 | }
98 | }
99 | }
100 | return mBookmarks;
101 | }
102 |
103 | public static String getDeviceName() {
104 | return Build.MODEL;
105 | }
106 |
107 | public static String getString(String name, String defaults, Context context) {
108 | return PreferenceManager.getDefaultSharedPreferences(context).getString(name, defaults);
109 | }
110 |
111 | private static String read(File file) {
112 | try (BufferedReader buf = new BufferedReader(new FileReader(file))) {
113 |
114 | StringBuilder stringBuilder = new StringBuilder();
115 | String line;
116 | while ((line = buf.readLine()) != null) {
117 | stringBuilder.append(line).append("\n");
118 | }
119 |
120 | return stringBuilder.toString().trim();
121 | } catch (IOException ignored) {
122 | }
123 | return null;
124 | }
125 |
126 | public static Toast toast(String message, Context context) {
127 | return Toast.makeText(context, message, Toast.LENGTH_LONG);
128 | }
129 |
130 | public static void addToBookmark(String command, Context context) {
131 | if (isValidFilename(command)) {
132 | create(command, new File(context.getExternalFilesDir("bookmarks"), command));
133 | } else {
134 | StringBuilder sb = new StringBuilder();
135 | if (new File(context.getExternalFilesDir("bookmarks"), "specialCommands").exists()) {
136 | for (String commands : Objects.requireNonNull(read(new File(context.getExternalFilesDir("bookmarks"), "specialCommands"))).split("\\r?\\n")) {
137 | sb.append(commands).append("\n");
138 | }
139 | sb.append(command).append("\n");
140 | } else {
141 | sb.append(command).append("\n");
142 | }
143 | create(sb.toString(), new File(context.getExternalFilesDir("bookmarks"), "specialCommands"));
144 | }
145 | }
146 |
147 | public static void copyToClipboard(String text, Context context) {
148 | ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
149 | ClipData clip = ClipData.newPlainText("Copied to clipboard", text);
150 | clipboard.setPrimaryClip(clip);
151 | Toast.makeText(context, "Copied to clipboard", Toast.LENGTH_SHORT).show();
152 | }
153 |
154 | public static void create(String text, File path) {
155 | try {
156 | FileWriter writer = new FileWriter(path);
157 | writer.write(text);
158 | writer.close();
159 | } catch (IOException ignored) {
160 | }
161 | }
162 |
163 | public static void loadUrl(String url, Context context) {
164 | try {
165 | Intent intent = new Intent(Intent.ACTION_VIEW);
166 | intent.setData(Uri.parse(url));
167 | context.startActivity(intent);
168 | } catch (ActivityNotFoundException ignored) {}
169 | }
170 |
171 | public static void saveBoolean(String name, boolean value, Context context) {
172 | PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(name, value).apply();
173 | }
174 |
175 | public static void saveInt(String name, int value, Context context) {
176 | PreferenceManager.getDefaultSharedPreferences(context).edit().putInt(name, value).apply();
177 | }
178 |
179 | public static void saveString(String name, String value, Context context) {
180 | PreferenceManager.getDefaultSharedPreferences(context).edit().putString(name, value).apply();
181 | }
182 |
183 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_amoled_theme.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_background_gradient.xml:
--------------------------------------------------------------------------------
1 |
2 | -
3 |
4 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmarks.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_email.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_help.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_history.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info_outlined.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_language.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_learn.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_numbers.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_privacy.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_refresh.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_save.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_send.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_starred.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_start.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_stop.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_translate.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_ashell.xml:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_examples.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
18 |
19 |
26 |
27 |
36 |
37 |
38 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
23 |
24 |
25 |
33 |
34 |
40 |
41 |
46 |
47 |
54 |
55 |
61 |
62 |
63 |
64 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_welcome.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
16 |
17 |
24 |
25 |
33 |
34 |
38 |
39 |
47 |
48 |
55 |
56 |
57 |
58 |
63 |
64 |
65 |
76 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_ashell.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
20 |
21 |
30 |
31 |
41 |
42 |
52 |
53 |
63 |
64 |
73 |
74 |
82 |
83 |
84 |
91 |
92 |
102 |
103 |
104 |
110 |
111 |
114 |
115 |
122 |
123 |
131 |
132 |
147 |
148 |
149 |
158 |
159 |
166 |
167 |
178 |
179 |
180 |
181 |
186 |
187 |
195 |
196 |
197 |
206 |
207 |
217 |
218 |
229 |
230 |
231 |
245 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_about.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
18 |
19 |
23 |
24 |
32 |
33 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_privacy_policy.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_view_policy.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
20 |
21 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_view_settings.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
15 |
16 |
23 |
24 |
32 |
33 |
40 |
41 |
48 |
49 |
50 |
59 |
60 |
61 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_view_welcome.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
17 |
18 |
28 |
29 |
40 |
41 |
51 |
52 |
53 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_commands.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
17 |
18 |
27 |
28 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_examples.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
15 |
16 |
24 |
25 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_shell_output.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values-b+zh+Hans/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | "欢迎使用 aShell:适用于 Shizuku 驱动的 Android 设备的本地 ADB shell。"
4 | "aShell 还在工作中。请等待完成或手动停止(通过点击停止按钮)以运行新指令"
5 | "'%s' 已被添加至书签"
6 | "'%s' 已从书签移除"
7 | "取消"
8 | "清除屏幕上的所有内容?"
9 | "在此输入ADB指令"
10 | "aShell 指令框"
11 | "驳回"
12 | "示例"
13 | "再次点击后退以退出"
14 | "aShell 还在工作中。你确定要停止当前的进程吗?"
15 | "退出"
16 | "你确定要退出 aShell 吗?"
17 | "请求权限"
18 | "开始"
19 | "最后一个命令的输出将导出到 '%s' 文件夹"
20 | "aShell 对 Shizuku 服务的访问被拒绝。 没有合适的 Shizuku 环境 aShell 将无法工作。"
21 | "您的设备上未安装或未正确配置 Shizuku。如果没有合适的 Shizuku 环境 aShell 将无法工作。单击此处了解有关 Shizuku 的更多信息。"
22 | "aShell 不是为与 root 相关的用途而设计的。中止。"
23 | "是"
24 | "版权: © 2024–2025, sunilpaulmathew"
25 | "保存"
26 | "应用主题"
27 | "AMOLED 黑"
28 | "节省电池并提供时尚、现代的外观"
29 | "自动"
30 | "深色"
31 | "浅色"
32 | "aShell %s"
33 | "点击以授权"
34 | "复制到剪贴板"
35 | "联系开发者"
36 | "需要帮助或想要反馈?联系开发者"
37 | "免责声明"
38 | "🧩 Shizuku 依赖项:aShell 需要一个完全正常运行的 Shizuku 环境才能运行。请确保在使用此应用程序之前设置 Shizuku。 👨💻 所需基础知识:为了有效使用,需要熟悉 ADB 和 Linux 命令行基础知识。 🌐 开源:aShell 是开源的,可以免费构建。欢迎通过 GitLab 和 POEditor 进行贡献和翻译。 ⚠️ 无责任: 对于使用此应用程序时可能发生的任何问题、数据丢失或损坏,我们概不负责。"
39 | "发现常用的ADB指令"
40 | "📜 轻松运行 ADB 命令 - 包括内置示例和书签。 📊 处理 logcat 或 top 等连续命令,并提供搜索和保存输出选项。 🎨 时尚的用户界面,带有自动深色/浅色主题,可提供流畅的现代体验。"
41 | "特点"
42 | "从外部文件管理器获取数据失败。中止。"
43 | "通用"
44 | "授权"
45 | "语言"
46 | "杂项"
47 | "🔐 moe.shizuku.manager.permission.API_V23: 需要权限以使用 Shizuku 的特权API"
48 | "📂 写入外部存储:将最后一个命令输出保存到您的设备必需(可选)"
49 | "需要权限"
50 | "隐私政策"
51 | "你的隐私很重要:了解更多"
52 | "设置"
53 | "aShell 的 Shizuku 访问被拒绝"
54 | "aShell 可以访问 Shizuku 服务。点击‘开始’继续"
55 | "了解 Shizuku"
56 | "了解更多关于 Shizuku: shizuku.rikka.app"
57 | "没有找到 Shizuku 支持"
58 | "翻译"
59 | "为本应用的翻译作出贡献"
60 | "请求权限"
61 | "用户界面"
62 |
--------------------------------------------------------------------------------
/app/src/main/res/values-el/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Μαύρο Amoled
4 | Καλώς ήρθατε στο aShell: Ένα τοπικό κέλυφος ADB για συσκευές Android που τροφοδοτούνται από το Shizuku.
5 | aShell λειτουργεί ακόμα. Περιμένετε να τελειώσει ή σταματήστε χειροκίνητα (κάνοντας κλικ στο κουμπί διακοπής) για να εκτελέσετε μια νέα εντολή
6 | \'%s\' προσθέθηκε σε σελιδοδείκτη
7 | \'%s\' αφαιρέθηκε από το σελιδοδείκτη
8 | Ακύρωση
9 | Καθαρισμός όλων στην οθόνη?
10 | Εισαγάγετε την εντολή ADB εδώ
11 | aShell Πλαίσιο Εντολών
12 | "Αντιγραφή"
13 | Copyright: © 2025–2026, sunilpaulmathew
14 | Παράβλεψη
15 | Παραδείγματα
16 | Αποτυχία λήψης δεδομένων από εξωτερικό διαχειριστή αρχείων. Ματαίωση.
17 | Πατήστε ξανά πίσω για έξοδο
18 | aShell λειτουργεί ακόμα. Θέλετε να σταματήσετε την τρέχουσα διαδικασία?
19 | Τερματισμός
20 | Θέλετε να τερματίσετε το aShell?
21 | Αίτημα Άδειας
22 | Αποθήκευση
23 | Η έξοδος της τελευταίας εντολής εξάγεται στον φάκελο \'%s\'
24 | Η πρόσβαση στην υπηρεσία Shizuku δεν επιτρέπεται για το aShell. Το aShell δεν θα λειτουργήσει χωρίς ένα κατάλληλο περιβάλλον Shizuku.
25 | Το Shizuku δεν είναι εγκατεστημένο ή δεν έχει ρυθμιστεί σωστά στη συσκευή σας. Το aShell δεν θα λειτουργήσει χωρίς ένα κατάλληλο περιβάλλον Shizuku.
26 | Έναρξη
27 | Το aShell δεν έχει σχεδιαστεί για χρήσεις που σχετίζονται με το root. Ματαίωση.
28 | Ναι
29 |
--------------------------------------------------------------------------------
/app/src/main/res/values-hu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | "Üdvözöljük az aShellben: Egy helyi ADB héj, a Shizuku alapú android eszközökhöz."
4 | "Amoled fekete"
5 | "App Téma"
6 | "Automatikus"
7 | "Sötét"
8 | "Világos"
9 | "Az aShell még mindig működik. Kérjük várja meg amíg befejeződik, vagy manuálisan állítsa le (a leállítás gombra kattintva) egy új parancs futtatásához"
10 | "'%s' könyvjelzővel ellátva"
11 | "'%s' eltávolítva a könyvjelzőkből"
12 | "Mégse"
13 | "Töröl mindent a képernyőn?"
14 | "Ide írja be az ADB parancsot"
15 | "aShell Command Box"
16 | "Másolás"
17 | "Elvetés"
18 | "Példák"
19 | "Nyomja meg ismét a vissza gombot a kilépéshez"
20 | "Az aShell még mindig működik. Le akarja állítani a jelenlegi folyamatot?"
21 | "Kilépés"
22 | "Ki akar lépni az aShellből?"
23 | "Engedély kérés"
24 | "Indítás"
25 | "'%s' mappába kerül exportálásra az utolsó parancs kimenete"
26 | "A hozzáférés a Shizuku szolgáltatáshoz, az aShell számára meg lett tagadva. Az aShell nem fog működni megfelelő Shizuku környezet nélkül."
27 | "A Shizuku nincs telepítve, vagy nincs megfelelően konfigurálva az eszközön. Az aShell nem fog működni megfelelő Shizuku környezet nélkül."
28 | "Az aShell nem root alapú felhasználásra készült. Megszakítás."
29 | "Fordítások"
30 | "Igen"
31 | "Szerzői jog: © 2024–2025, sunilpaulmathew"
32 | "Mentés"
33 |
--------------------------------------------------------------------------------
/app/src/main/res/values-in/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | "Selamat datang di aShell: Sebuah shell ADB lokal untuk perangkat-perangkat android terdukung Shizuku"
4 | "Tema Aplikasi"
5 | "Otomatis"
6 | "Gelap"
7 | "Terang"
8 | "aShell masih bekerja. Mohon menunggu hingga selesai atau menghentikannya (dengan mengklik tombol henti) untuk menjalankan perintah baru"
9 | "'%s' telah ditandai"
10 | "'%s' telah dihapus dari penanda"
11 | "Batal"
12 | "Kosongkan layar?"
13 | "Masukkan perintah ADB di sini"
14 | "Kotak Perintah ADB"
15 | "Salin"
16 | "Hentikan"
17 | "Contoh"
18 | "Tekan kembali lagi untuk keluar"
19 | "aShell masih bekerja. Apakah anda ingin menghentikan proses ini?"
20 | "Keluar"
21 | "Apakah anda ingin keluar dari aShell?"
22 | "Meminta izin"
23 | "Mulai"
24 | "Keluaran perintah terakhir telah diekspor ke folder '%s'"
25 | "Akses aShell ke layanan Shizuku ditolak. aShell tidak dapat bekerja tanpa lingkungan Shizuku yang sesuai."
26 | "Shizuku tidak terpasang atau tidak terkonfigurasi dengan benar di perangkat anda. aShell tidak dapat bekerja tanpa lingkungan Shizuku yang sesuai."
27 | "aShell tidak dirancang untuk penggunaan seputar root. Membatalkan."
28 | "Terjemahan"
29 | "Ya"
30 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ko/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | "aShell에 오신 것을 환영합니다: Shizuku 기반 안드로이드 기기용 로컬 ADB 셸입니다."
4 | "aShell이 아직 작동 중입니다. 새 명령을 실행하려면 완료될 때까지 기다리거나 수동으로 중지(중지 버튼 클릭)하세요"
5 | "'%s'이(가) 북마크에 추가되었습니다"
6 | "'%s'이(가) 북마크에서 제거되었습니다"
7 | "취소"
8 | "이 화면에서 모든 항목을 지우시겠습니까?"
9 | "여기에 ADB 명령 입력"
10 | "aShell 명령 상자"
11 | "해제"
12 | "예제"
13 | "종료하려면 뒤로가기 버튼을 다시 누르세요"
14 | "aShell이 아직 작동 중입니다. 현재 프로세스를 중지하시겠습니까?"
15 | "종료"
16 | "aShell을 종료하시겠습니까?"
17 | "권한 요청"
18 | "시작"
19 | "마지막 명령의 출력이 '%s' 폴더로 내보냅니다"
20 | "aShell의 Shizuku 서비스 접근이 거부되었습니다. 적절한 Shizuku 환경이 없으면 aShell이 작동하지 않습니다."
21 | "Shizuku가 기기에 설치되어 있지 않거나 제대로 구성되지 않았습니다. 적절한 Shizuku 환경이 없으면 aShell이 작동하지 않습니다. Shizuku에 대해 자세히 알아보려면 여기를 클릭하세요."
22 | "aShell은 루팅 관련 용도로 설계되지 않았습니다. 실행을 중단합니다."
23 | "확인"
24 | "저작권: © 2024–2025, sunilpaulmathew"
25 | "저장"
26 | "앱 테마"
27 | "아몰레드 블랙"
28 | "배터리 절약 및 세련되고 현대적인 디자인을 제공"
29 | "자동"
30 | "다크"
31 | "라이트"
32 | "aShell %s"
33 | "클릭하여 권한을 부여하세요"
34 | "클립보드에 복사"
35 | "개발자에게 문의하기"
36 | "도움이 필요하거나 피드백이 있으신가요? 개발자에게 문의하세요"
37 | "면책 조항"
38 | "\uD83E\uDDE9 Shizuku 의존성: aShell이 작동하려면 완전히 작동하는 Shizuku 환경이 필요합니다. 이 앱을 사용하기 전에 Shizuku가 설정되어 있는지 확인해 주세요. \uD83D\uDC68\u200D\uD83D\uDCBB 기본 지식 필요: 효과적인 사용을 위해 ADB 및 Linux 명령줄 기본 지식을 숙지하는 것이 좋습니다. \uD83C\uDF10 오픈 소스: aShell은 오픈 소스이며 무료로 빌드할 수 있습니다. 기여와 번역은 GitLab과 POEditor를 통해 부탁드립니다. ⚠️ 책임 없음: 당사는 이 앱을 사용하는 동안 발생할 수 있는 문제, 데이터 손실 또는 손상에 대해서는 당사가 책임지지 않습니다."
39 | "자주 사용되는 ADB 명령 살펴보기"
40 | "\uD83D\uDCDC ADB 명령어 간편 실행: 내장된 예제 및 북마크 기능 제공. \uD83D\uDCCA 연속 명령어 처리: logcat, top 등 연속적인 명령어 실행 및 출력 내용 검색/저장 옵션 지원. \uD83C\uDFA8 세련된 UI: 자동이나 다크/라이트 테마 지원으로 매끄럽고 현대적인 사용 경험 제공."
41 | "기능"
42 | "외부 파일 관리자에서 데이터를 가져오지 못했습니다. 실행을 중단합니다."
43 | "일반"
44 | "허용됨"
45 | "언어"
46 | "기타"
47 | "🔐 moe.shizuku.manager.permission.API_V23: Shizuku의 권한 있는 API를 사용하려면 권한이 필요합니다"
48 | "📂 WRITE_EXTERNAL_STORAGE: 마지막 명령어 출력 결과를 기기에 저장하려면 필요합니다 (선택)"
49 | "필요한 권한"
50 | "개인정보 처리방침"
51 | "개인정보는 중요합니다: 자세히 알아보기"
52 | "설정"
53 | "Shizuku가 aShell의 권한을 거부했습니다"
54 | "aShell이 Shizuku 서비스 권한을 얻었습니다. 계속하려면 '시작'을 누르세요"
55 | "shizuku 알아보기"
56 | "shizuku에 대한 자세한 정보: shizuku.rikka.app"
57 | "Shizuku 서비스를 찾을 수 없습니다"
58 | "번역"
59 | "앱 번역에 기여하기"
60 | "권한 요청"
61 | "사용자 환경"
62 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt-rBR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bem-vindo ao aShell: um shell ADB local para dispositivos Android com suporte ao Shizuku.
4 | "Tema do App"
5 | "Escuro"
6 | "Claro"
7 | aShell está em execução. Aguarde até que termine ou pare manualmente (clicando no botão de parar) para executar um novo comando.
8 | \'%s\' foi adicionado aos favoritos
9 | \'%s\' foi removido dos favoritos
10 | Cancelar
11 | Limpar tudo nesta tela?
12 | Digite o comando ADB aqui
13 | Caixa de Comando aShell
14 | Copiar
15 | Dispensar
16 | Exemplos
17 | Pressione voltar novamente para sair
18 | aShell está em execução. Deseja parar o processo atual?
19 | Sair
20 | Deseja sair do aShell?
21 | Solicitar Permissão
22 | Iniciar
23 | A saída do último comando foi exportada para a pasta \'%s\'
24 | Acesso ao serviço Shizuku foi negado para o aShell. O aShell não funcionará sem um ambiente Shizuku adequado.
25 | O Shizuku não está instalado ou configurado corretamente no seu dispositivo. O aShell não funcionará sem um ambiente Shizuku adequado.
26 | O aShell não é projetado para usos relacionados ao root. Abortando.
27 | "Traduções"
28 | Sim
29 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt-rPT/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | "Bem-vindo ao aShell: Uma shell ADB local para dispositivos android com Shizuku."
4 | "Tema da aplicação"
5 | "Automático"
6 | "Escuro"
7 | "Claro"
8 | "O aShell ainda está a funcionar. Aguarde que termine ou pare manualmente (clicando no botão de parar) para executar um novo comando"
9 | "'%s' está marcado como favorito"
10 | "'%s' foi removido dos favoritos"
11 | "Cancelar"
12 | "Limpar tudo o que está neste ecrã?"
13 | "Introduzir aqui o comando ADB"
14 | "Caixa de comando do aShell"
15 | "Copiar"
16 | "Ignorar"
17 | "Exemplos"
18 | "Premir novamente para sair"
19 | "O aShell ainda está a funcionar. Pretende parar o processo atual?"
20 | "Sair"
21 | "Quer sair do aShell?"
22 | "Solicitar autorização"
23 | "Iniciar"
24 | "A saída do último comando é exportada para a pasta '%s'"
25 | "O acesso ao serviço Shizuku é negado para o aShell. O aShell não funciona sem um ambiente Shizuku adequado."
26 | "O Shizuku não está instalado ou não está configurado corretamente no seu dispositivo. O aShell não funcionará sem um ambiente Shizuku adequado."
27 | "O aShell não foi projetado para utilizações relacionadas com acesso root. A abortar."
28 | "Traduções"
29 | "Sim"
30 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | "Добро пожаловать в aShell: локальную оболочку ADB для устройств Android на платформе Shizuku."
5 | "Тема приложения"
6 | "Авто"
7 | "Тёмная"
8 | "Светлая"
9 | "aShell все еще выполняется. Подождите, пока он завершится, или остановите его вручную (нажав кнопку остановки), чтобы запустить новую команду."
10 | "Отмена"
11 | "Очистить все на этом экране?"
12 | "Введите команду ADB здесь"
13 | "Поле команды aShell"
14 | "Отклонить"
15 | "Примеры"
16 | "Нажмите ещё раз для выхода"
17 | "aShell все ещё выполняется. Вы хотите остановить процесс?"
18 | "Выйти"
19 | "Вы хотите выйти из aShell?"
20 | "Запросить разрешение"
21 | "Начать"
22 | "Вывод последней команды экспортируется в папку \'%s\'"
23 | "Доступ к Shizuku запрещен для aShell. aShell не может работать без разрешения Shizuku."
24 | "Приложение Shizuku не установлено или неправильно настроено на вашем устройстве. aShell не может работать без среды Shizuku."
25 | "aShell не предназначен для использования с правами root. Остановка."
26 | "Переводы"
27 | "Да"
28 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh-rTW/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | "歡迎使用 aShell:為裝載 Shizuku 的 Android 裝置而生的 ADB 指令集。"
4 | "aShell 仍在執行,請等待完成或手動終止以執行新命令。(按下「停止」)"
5 | "「%s」已新增至書籤"
6 | "「%s」已從書籤移除"
7 | "取消"
8 | "要清除畫面中的所有內容嗎?"
9 | "請在此輸入 ADB 指令"
10 | "aShell 指令集"
11 | "關閉"
12 | "範例"
13 | "再按一次返回鍵即可關閉"
14 | "aShell 仍在執行。 您要停止目前作業嗎?"
15 | "離開"
16 | "您要離開 aShell 嗎?"
17 | "權限要求"
18 | "開始"
19 | "已將最後輸出的指令儲存至「%s」資料夾"
20 | "aShell 已被拒絕存取 Shizuku 服務。 aShell 無法在沒有合適的 Shizuku 環境下運作。"
21 | "您的裝置尚未安裝或正確配置 Shizuku。 aShell 無法在沒有合適的 Shizuku 環境下運作。 輕觸這裡了解更多資訊。"
22 | "aShell 並非為 Root 相關操作而設,作業已終止。"
23 | "是"
24 | "版權所有:© 2024–2025, sunilpaulmathew"
25 | "儲存"
26 | "主題"
27 | "AMOLED 深色"
28 | "現代時尚的外觀,同時節省電力"
29 | "自動"
30 | "深色"
31 | "淺色"
32 | "aShell %s"
33 | "輕觸即可授予"
34 | "複製到剪貼簿"
35 | "聯絡開發人員"
36 | "需要協助或提供意見嗎?請聯絡我們"
37 | "免責聲明"
38 | "\uD83E\uDDE9 Shizuku 架構:aShell 需要完整的 Shizuku 環境才能運作,使用前請先確認您已配置完成。 \uD83D\uDC68\u200D\uD83D\uDCBB 基本概念:建議事先了解 ADB 與 Linux 命令相關知識以有效運用。 \uD83C\uDF10 開放原始碼:aShell 資源公開並可免費開發,歡迎透過 GitLab 和 POEditor 提供協助或翻譯。 ⚠️ 免責聲明:我們不會對使用本應用程式所造成的錯誤、資料遺失或裝置損壞承擔任何責任。"
39 | "瀏覽常用 ADB 指令"
40 | "\uD83D\uDCDC 輕鬆執行 ADB 指令 — 內建範例與書籤管理。 \uD83D\uDCCA 處理 logcat、top 等連續指令,搜尋與儲存輸出內容。 \uD83C\uDFA8 現代介面與流暢體驗,支援自動切換深色 / 淺色。"
41 | "特色"
42 | "以外部檔案管理員擷取資料失敗,作業已終止。"
43 | "一般"
44 | "授予"
45 | "語言"
46 | "其他"
47 | "🔐 moe.shizuku.manager.permission.API_V23:需要使用 Shizuku 特殊 API 的權限"
48 | "📂 WRITE_EXTERNAL_STORAGE:將最後輸出的內容儲存至您的裝置 (選用)"
49 | "權限要求"
50 | "隱私權政策"
51 | "與您的隱私相關:了解更多"
52 | "設定"
53 | "aShell 存取 Shizuku 遭拒"
54 | "aShell 已可存取 Shizuku 服務。輕觸「開始」繼續"
55 | "認識 Shizuku"
56 | "了解更多關於 Shizuku:shizuku.rikka.app"
57 | "找不到 Shizuku 支援"
58 | "翻譯"
59 | "協助翻譯應用程式"
60 | "權限要求"
61 | "介面"
62 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #000000
4 | #4285f4
5 | #FF0000
6 | #26a69a
7 | #FFFFFF
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | aShell
3 |
4 | Effortlessly execute ADB commands on your Shizuku-enabled Android device.
5 | App theme
6 | Amoled black
7 | Save battery and offer a sleek, modern look
8 | Auto
9 | Dark
10 | Light
11 | aShell %s
12 | aShell is still working. Please wait for it to finish or manually stop (by clicking the stop button) to run a new command
13 | Click to authorize
14 | \'%s\' is bookmarked
15 | \'%s\' has been removed from bookmark
16 | Cancel
17 | Clear everything on this screen?
18 | Input ADB command here
19 | aShell Command Box
20 | "Copy to clipboard"
21 | Copyright: © 2022–2025, sunilpaulmathew
22 | Contact developer
23 | Need help or have feedback? Contact the developer
24 | Disclaimer
25 | \uD83E\uDDE9 Shizuku Dependency: aShell requires a fully working Shizuku environment to function. Please ensure Shizuku is set up before using this app.\n\uD83D\uDC68\u200D\uD83D\uDCBB Basic Knowledge Required: Familiarity with ADB and Linux command-line basics is recommended for effective use.\n\uD83C\uDF10 Open Source: aShell is open-source and free to build. Contributions and translations are welcome via GitLab and POEditor.\n⚠️ No Liability: We are not liable for any issues, data loss, or damage that may occur while using this app.
26 | Dismiss
27 | Examples
28 | Explore popular ADB commands
29 | \uD83D\uDCDC Run ADB commands with ease—includes built-in examples and bookmarking.\n\uD83D\uDCCA Handles continuous commands like logcat or top, with search and save options for output.\n\uD83C\uDFA8 Sleek UI with auto dark/light theme for a smooth, modern experience.
30 | Features
31 | Failed to get data from external file manager. Aborting.
32 | General
33 | Granted
34 | Language
35 | Ελληνικά
36 | English (%s)
37 | Magyar
38 | bahasa Indonesia
39 | 한국어
40 | Português (%s)
41 | русский
42 | 中文 (%s)
43 | Miscellaneous
44 | 🔐 moe.shizuku.manager.permission.API_V23: Permission required to use Shizuku’s privileged APIs
45 | 📂 WRITE_EXTERNAL_STORAGE: Needed to save the last command output to your device (optional)
46 | Permissions required
47 | Press back again to exit
48 | Privacy policy
49 | Your privacy matters: Learn more
50 | aShell is still working. Do you want to stop the current process?
51 | Quit
52 | Do you want to quit aShell?
53 | Request Permission
54 | Save
55 | Settings
56 | The output of last command is exported to \'%s\' folder
57 | Access to Shizuku service is denied for aShell. aShell won\'t work without a proper Shizuku environment.
58 | Shizuku access denied for aShell
59 | aShell got access to Shizuku service. Click \'Start\' to continue
60 | Learn shizuku
61 | Learn more about shizuku at: shizuku.rikka.app
62 | Shizuku is not installed or not properly configured on your device. aShell won\'t work without a proper Shizuku environment.
63 | Shizuku support not found
64 | Start
65 | aShell is not designed for root-related uses. Aborting.
66 | Translations
67 | Contribute to the app\'s translation
68 | Request Permission
69 | User interface
70 | Yes
71 |
--------------------------------------------------------------------------------
/app/src/main/res/values/theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
24 |
25 |
32 |
33 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | alias(libs.plugins.androidApplication) apply false
4 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/15.txt:
--------------------------------------------------------------------------------
1 | * Improved Shizuku permission checking.
2 | * Added Chinese (Simplified) and Korean translations
3 | * Updated Chinese (TW) translations.
4 | * Miscellaneous changes.
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | aShell is a local ADB shell for [Shizuku](https://shizuku.rikka.app/) powered android devices.
2 |
3 | Requirements
4 |
5 | - A fully working [Shizuku](https://shizuku.rikka.app/) (a completely opn-source project) environment. If you are not aware about Shizuku or don't want to use it, please do not bother installing this app. It simply won't work.
6 | - Basic knowledge about adb/Linux command-line.
7 |
8 | Features
9 |
10 | - An elegantly designed user interface.
11 | - Included a bundle of examples about common adb commands.
12 | - Handles continuously running commands, such as logcat, top, etc.
13 | - Search for specific text from the last command output.
14 | - Option to save last command output as a text file.
15 | - Bookmark frequently using commands.
16 | - An auto-dark/light theme.
17 | - A lot more.
18 |
19 | Translations
20 |
21 | Please help me to translate this application via POEditor . You may also translate after downloading the original language string available GitHub .
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | aShell: A local ADB shell for Shizuku powered android devices
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Enables namespacing of each library's R class so that its R class includes only the
19 | # resources declared in the library itself and none from the library's dependencies,
20 | # thereby reducing the size of the R class for that library
21 | android.nonTransitiveRClass=true
22 | android.defaults.buildfeatures.buildconfig=false
23 | android.nonFinalResIds=false
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.3.2"
3 | material = "1.12.0"
4 | preference = "1.2.1"
5 | shizuku = "13.1.0"
6 |
7 | [libraries]
8 | material = { group = "com.google.android.material", name = "material", version.ref = "material" }
9 | preference = { module = "androidx.preference:preference", version.ref = "preference" }
10 | shizukuApi = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" }
11 | shizukuProvider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" }
12 |
13 | [plugins]
14 | androidApplication = { id = "com.android.application", version.ref = "agp" }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunilpaulmathew/aShell/2c55a6d05aba5b6811d67dfc43a0640ef89a0e06/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Oct 28 20:41:01 CEST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Fri Oct 28 12:50:38 CET 2022
8 | sdk.dir=C\:\\Users\\HP\\AppData\\Local\\Android\\Sdk
9 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "aShell"
16 | include ':app'
17 |
--------------------------------------------------------------------------------