diff --git a/DEVELOPERS.md b/DEVELOPERS.md index 0a5cab3..b914807 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -81,6 +81,7 @@ Variables: - `MMM_EXT_SUPPORT` declared if extensions are supported - `MMM_USER_LANGUAGE` the current user selected language - `MMM_APP_VERSION` display version of the app (Ex: `x.y.z`) +- `MMM_TEXT_WRAP` is set to `1` if text wrapping is enabled Note: The current behavior with unknown command is to ignore them, diff --git a/app/build.gradle b/app/build.gradle index b1f80a8..e712157 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.fox2code.mmm" minSdk 21 targetSdk 32 - versionCode 19 - versionName "0.2.8" + versionCode 20 + versionName "0.2.9" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/assets/module_installer_test.sh b/app/src/main/assets/module_installer_test.sh new file mode 100644 index 0000000..c3dbddb --- /dev/null +++ b/app/src/main/assets/module_installer_test.sh @@ -0,0 +1,24 @@ +#!/sbin/sh +# This script is only used to test debug builds + +umask 022 + +API=$(getprop ro.build.version.sdk) +OUTFD=$2 +ZIPFILE=$3 +MODPATH="${ZIPFILE%/*}" + +ui_print() { echo "$1"; } +abort() { + ui_print "$1" + [ -f $MODPATH/customize.sh ] && rm -f $MODPATH/customize.sh + exit 1 +} + +ui_print "! Using rootless installer test script" + +unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2 + +[ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh + +ui_print "- Done" diff --git a/app/src/main/java/com/fox2code/mmm/Constants.java b/app/src/main/java/com/fox2code/mmm/Constants.java index 4ac56cd..e2d073f 100644 --- a/app/src/main/java/com/fox2code/mmm/Constants.java +++ b/app/src/main/java/com/fox2code/mmm/Constants.java @@ -13,6 +13,7 @@ public class Constants { public static final String EXTRA_INSTALL_CONFIG = "extra_install_config"; public static final String EXTRA_INSTALL_NO_PATCH = "extra_install_no_patch"; public static final String EXTRA_INSTALL_NO_EXTENSIONS = "extra_install_no_extensions"; + public static final String EXTRA_INSTALL_TEST_ROOTLESS = "extra_install_test_rootless"; public static final String EXTRA_MARKDOWN_URL = "extra_markdown_url"; public static final String EXTRA_MARKDOWN_TITLE = "extra_markdown_title"; public static final String EXTRA_MARKDOWN_CONFIG = "extra_markdown_config"; diff --git a/app/src/main/java/com/fox2code/mmm/MainApplication.java b/app/src/main/java/com/fox2code/mmm/MainApplication.java index ddff07f..ee251e6 100644 --- a/app/src/main/java/com/fox2code/mmm/MainApplication.java +++ b/app/src/main/java/com/fox2code/mmm/MainApplication.java @@ -102,6 +102,10 @@ public class MainApplication extends Application implements CompatActivity.Appli return getSharedPreferences().getBoolean("pref_force_dark_terminal", false); } + public static boolean isTextWrapEnabled() { + return getSharedPreferences().getBoolean("pref_wrap_text", false); + } + public static boolean isDeveloper() { return BuildConfig.DEBUG || getSharedPreferences().getBoolean("developer", false); diff --git a/app/src/main/java/com/fox2code/mmm/NotificationType.java b/app/src/main/java/com/fox2code/mmm/NotificationType.java index 3c0aa28..f0acb20 100644 --- a/app/src/main/java/com/fox2code/mmm/NotificationType.java +++ b/app/src/main/java/com/fox2code/mmm/NotificationType.java @@ -21,6 +21,7 @@ import java.util.zip.ZipFile; interface NotificationTypeCst { String TAG = "NotificationType"; + boolean ROOTLESS_TEST = true; } public enum NotificationType implements NotificationTypeCst { @@ -88,7 +89,9 @@ public enum NotificationType implements NotificationTypeCst { } else { IntentHelper.openInstaller(compatActivity, d.getAbsolutePath(), compatActivity.getString( - R.string.local_install_title), null); + R.string.local_install_title), null, false, + BuildConfig.DEBUG && // Use debug mode if no root + InstallerInitializer.peekMagiskPath() == null); } } catch (IOException ignored) { if (d.exists() && !d.delete()) @@ -99,14 +102,17 @@ public enum NotificationType implements NotificationTypeCst { } else if (s == IntentHelper.RESPONSE_URL) { IntentHelper.openInstaller(compatActivity, u.toString(), compatActivity.getString( - R.string.remote_install_title), null); + R.string.remote_install_title), null, false, + BuildConfig.DEBUG && // Use debug mode if no root + InstallerInitializer.peekMagiskPath() == null); } }); }, true) { @Override public boolean shouldRemove() { - return MainApplication.isShowcaseMode() || - InstallerInitializer.peekMagiskPath() == null; + return (!(ROOTLESS_TEST && BuildConfig.DEBUG)) && + (MainApplication.isShowcaseMode() || + InstallerInitializer.peekMagiskPath() == null); } }; diff --git a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java index 7338c0c..03cc408 100644 --- a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java +++ b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java @@ -12,6 +12,8 @@ import android.view.View; import android.view.WindowManager; import android.widget.Toast; +import androidx.recyclerview.widget.RecyclerView; + import com.fox2code.mmm.ActionButtonType; import com.fox2code.mmm.BuildConfig; import com.fox2code.mmm.Constants; @@ -39,6 +41,7 @@ public class InstallerActivity extends CompatActivity { public InstallerTerminal installerTerminal; private File moduleCache; private File toDelete; + private boolean textWrap; @Override protected void onCreate(Bundle savedInstanceState) { @@ -53,6 +56,7 @@ public class InstallerActivity extends CompatActivity { final String name; final boolean noPatch; final boolean noExtensions; + final boolean rootless; // Should we allow 3rd part app to install modules? if (Constants.INTENT_INSTALL_INTERNAL.equals(intent.getAction())) { if (!MainApplication.checkSecret(intent)) { @@ -65,6 +69,8 @@ public class InstallerActivity extends CompatActivity { noPatch = intent.getBooleanExtra(Constants.EXTRA_INSTALL_NO_PATCH, false); noExtensions = intent.getBooleanExtra(// Allow intent to disable extensions Constants.EXTRA_INSTALL_NO_EXTENSIONS, false); + rootless = intent.getBooleanExtra(// For debug only + Constants.EXTRA_INSTALL_TEST_ROOTLESS, false); } else { Toast.makeText(this, "Unknown intent!", Toast.LENGTH_SHORT).show(); this.forceBackPressed(); @@ -74,7 +80,9 @@ public class InstallerActivity extends CompatActivity { boolean urlMode = target.startsWith("http://") || target.startsWith("https://"); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setTitle(name); - setContentView(R.layout.installer); + setContentView((this.textWrap = + MainApplication.isTextWrapEnabled()) ? + R.layout.installer_wrap :R.layout.installer); int background; int foreground; if (MainApplication.getINSTANCE().isLightTheme() && @@ -85,11 +93,13 @@ public class InstallerActivity extends CompatActivity { background = Color.BLACK; foreground = Color.WHITE; } - findViewById(R.id.install_horizontal_scroller) - .setBackground(new ColorDrawable(background)); + View horizontalScroller = findViewById(R.id.install_horizontal_scroller); + RecyclerView installTerminal; this.progressIndicator = findViewById(R.id.progress_bar); this.installerTerminal = new InstallerTerminal( - findViewById(R.id.install_terminal), foreground); + installTerminal = findViewById(R.id.install_terminal), foreground); + (horizontalScroller != null ? horizontalScroller : installTerminal) + .setBackground(new ColorDrawable(background)); this.progressIndicator.setVisibility(View.GONE); this.progressIndicator.setIndeterminate(true); if (urlMode) { @@ -134,7 +144,7 @@ public class InstallerActivity extends CompatActivity { this.runOnUiThread(() -> { this.installerTerminal.addLine("- Installing " + name); }); - this.doInstall(moduleCache, noExtensions); + this.doInstall(moduleCache, noExtensions, rootless); } catch (IOException e) { Log.e(TAG, "Failed to download module zip", e); this.setInstallStateFinished(false, @@ -144,19 +154,32 @@ public class InstallerActivity extends CompatActivity { } else { this.installerTerminal.addLine("- Installing " + name); new Thread(() -> this.doInstall( - this.toDelete = new File(target), noExtensions), + this.toDelete = new File(target), noExtensions, rootless), "Install Thread").start(); } } - private void doInstall(File file,boolean noExtensions) { + private void doInstall(File file,boolean noExtensions,boolean rootless) { Log.i(TAG, "Installing: " + moduleCache.getName()); InstallerController installerController = new InstallerController( this.progressIndicator, this.installerTerminal, file.getAbsoluteFile(), noExtensions); InstallerMonitor installerMonitor; Shell.Job installJob; - if (MainApplication.isUsingMagiskCommand() || noExtensions) { + if (rootless) { // rootless is only used for debugging + File installScript = this.extractInstallScript("module_installer_test.sh"); + if (installScript == null) { + this.setInstallStateFinished(false, + "! Failed to extract test install script", ""); + return; + } + installerMonitor = new InstallerMonitor(installScript); + installJob = Shell.sh("export MMM_EXT_SUPPORT=1", + "cd \"" + this.moduleCache.getAbsolutePath() + "\"", + "sh \"" + installScript.getAbsolutePath() + "\"" + + " /dev/null 1 \"" + file.getAbsolutePath() + "\"") + .to(installerController, installerMonitor); + } else if (MainApplication.isUsingMagiskCommand() || noExtensions) { installerMonitor = new InstallerMonitor(new File(InstallerInitializer .peekMagiskPath().equals("/sbin") ? "/sbin/magisk" : "/system/bin/magisk")); if (noExtensions) { @@ -170,12 +193,13 @@ public class InstallerActivity extends CompatActivity { "en-US" : Resources.getSystem() .getConfiguration().locale.toLanguageTag()), "export MMM_APP_VERSION=" + BuildConfig.VERSION_NAME, + "export MMM_TEXT_WRAP=" + (this.textWrap ? "1" : "0"), "cd \"" + this.moduleCache.getAbsolutePath() + "\"", "magisk --install-module \"" + file.getAbsolutePath() + "\"") .to(installerController, installerMonitor); } } else { - File installScript = this.extractCompatScript(); + File installScript = this.extractInstallScript("module_installer_compat.sh"); if (installScript == null) { this.setInstallStateFinished(false, "! Failed to extract module install script", ""); @@ -187,6 +211,7 @@ public class InstallerActivity extends CompatActivity { "en-US" : Resources.getSystem() .getConfiguration().locale.toLanguageTag()), "export MMM_APP_VERSION=" + BuildConfig.VERSION_NAME, + "export MMM_TEXT_WRAP=" + (this.textWrap ? "1" : "0"), "cd \"" + this.moduleCache.getAbsolutePath() + "\"", "sh \"" + installScript.getAbsolutePath() + "\"" + " /dev/null 1 \"" + file.getAbsolutePath() + "\"") @@ -370,16 +395,16 @@ public class InstallerActivity extends CompatActivity { private static boolean didExtract = false; - private File extractCompatScript() { - File compatInstallScript = new File(this.moduleCache, "module_installer_compat.sh"); + private File extractInstallScript(String script) { + File compatInstallScript = new File(this.moduleCache, script); if (!compatInstallScript.exists() || compatInstallScript.length() == 0 || !didExtract) { try { Files.write(compatInstallScript, Files.readAllBytes( - this.getAssets().open("module_installer_compat.sh"))); + this.getAssets().open(script))); didExtract = true; } catch (IOException e) { compatInstallScript.delete(); - Log.e(TAG, "Failed to extract module_installer_compat.sh", e); + Log.e(TAG, "Failed to extract " + script, e); return null; } } diff --git a/app/src/main/java/com/fox2code/mmm/utils/IntentHelper.java b/app/src/main/java/com/fox2code/mmm/utils/IntentHelper.java index dbde641..1bff216 100644 --- a/app/src/main/java/com/fox2code/mmm/utils/IntentHelper.java +++ b/app/src/main/java/com/fox2code/mmm/utils/IntentHelper.java @@ -16,6 +16,7 @@ import android.widget.Toast; import androidx.core.app.ActivityOptionsCompat; +import com.fox2code.mmm.BuildConfig; import com.fox2code.mmm.Constants; import com.fox2code.mmm.MainApplication; import com.fox2code.mmm.R; @@ -88,6 +89,11 @@ public class IntentHelper { } public static void openInstaller(Context context, String url, String title, String config) { + openInstaller(context, url, title, config, false, false); + } + + public static void openInstaller(Context context, String url, String title, String config, + boolean noPatch,boolean testDebug) { try { Intent intent = new Intent(context, InstallerActivity.class); intent.setAction(Constants.INTENT_INSTALL_INTERNAL); @@ -96,6 +102,10 @@ public class IntentHelper { intent.putExtra(Constants.EXTRA_INSTALL_NAME, title); if (config != null && !config.isEmpty()) intent.putExtra(Constants.EXTRA_INSTALL_CONFIG, config); + if (noPatch) + intent.putExtra(Constants.EXTRA_INSTALL_NO_PATCH, true); + if (testDebug && BuildConfig.DEBUG) + intent.putExtra(Constants.EXTRA_INSTALL_TEST_ROOTLESS, true); startActivity(context, intent, true); } catch (ActivityNotFoundException e) { Toast.makeText(context, @@ -158,6 +168,12 @@ public class IntentHelper { @SuppressLint("SdCardPath") public static void openFileTo(CompatActivity compatActivity, File destination, OnFileReceivedCallback callback) { + File destinationFolder; + if (destination == null || (destinationFolder = destination.getParentFile()) == null || + (!destinationFolder.isDirectory() && !destinationFolder.mkdirs())) { + callback.onReceived(destination, null, RESPONSE_ERROR); + return; + } Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("application/zip"); intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); diff --git a/app/src/main/res/drawable/ic_baseline_keyboard_return_24.xml b/app/src/main/res/drawable/ic_baseline_keyboard_return_24.xml new file mode 100644 index 0000000..b3a8cc1 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_keyboard_return_24.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/layout/installer_wrap.xml b/app/src/main/res/layout/installer_wrap.xml new file mode 100644 index 0000000..4601ed4 --- /dev/null +++ b/app/src/main/res/layout/installer_wrap.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 3714272..0ee54ae 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -75,8 +75,8 @@ 禁用 Fox\'s Mmm 扩展, 这可以防止模块使用 终端扩展, 如果模块滥用 Fox\'s Mmm 的扩展, 这会有用 - 文字换行 - + 文字换行 + 将文本换行至新行,而不是将所有文本放在同一行 启用仓库 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 53d0a7b..7637527 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -75,9 +75,10 @@ Disable Fox\'s Mmm extensions, this prevent modules from using terminal extensions, useful if a module misuse Fox\'s Mmm extensions. - Warp text - - Warp text to new line instead of putting all text on the same line + Wrap text + + Wrap text to a new line instead of putting + all text on the same line when installing a module Repo enabled Repo disabled diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 90d0606..c1eccc0 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -34,6 +34,14 @@ app:summary="@string/showcase_mode_desc" app:singleLineTitle="false" /> + +