From 6a608ffbea87861392ccd5a67a67ec857eae33d9 Mon Sep 17 00:00:00 2001 From: Fox2Code Date: Tue, 12 Oct 2021 22:06:17 +0200 Subject: [PATCH] Release 0.0.3 - Improved non standard file picker response handling. (Should fix install module from storage on some devices, and notifying the user that their file manager is weird) - Handle file picker returning http/https urls for files. - Improved search icon padding for rounded corner phones - Fixed card background being invisible on light theme - Make install terminal light when light theme is on - Added a switch to force the terminal to be always dark (to restore old behavior, default is false) --- app/build.gradle | 4 +- app/proguard-rules.pro | 6 ++ .../com/fox2code/mmm/MainApplication.java | 22 +++++++ .../com/fox2code/mmm/ModuleViewAdapter.java | 8 ++- .../com/fox2code/mmm/NotificationType.java | 8 ++- .../mmm/installer/InstallerActivity.java | 19 +++++- .../mmm/installer/InstallerTerminal.java | 12 ++-- .../mmm/settings/SettingsActivity.java | 9 ++- .../com/fox2code/mmm/utils/IntentHelper.java | 63 ++++++++++++++----- .../main/res/drawable/ic_baseline_list_24.xml | 11 ++++ app/src/main/res/layout/activity_main.xml | 4 +- app/src/main/res/layout/installer.xml | 2 + app/src/main/res/layout/module_entry.xml | 3 +- app/src/main/res/values/strings.xml | 4 ++ app/src/main/res/values/themes.xml | 6 ++ app/src/main/res/xml/root_preferences.xml | 6 ++ build.gradle | 2 +- 17 files changed, 157 insertions(+), 32 deletions(-) create mode 100644 app/src/main/res/drawable/ic_baseline_list_24.xml diff --git a/app/build.gradle b/app/build.gradle index 9a7eb3d..4e04e1d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.fox2code.mmm" minSdk 21 targetSdk 30 - versionCode 2 - versionName "0.0.2" + versionCode 3 + versionName "0.0.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index dd5f7ed..0dc6496 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -46,6 +46,12 @@ int d(java.lang.String, java.lang.String); int d(java.lang.String, java.lang.String, java.lang.Throwable); } +-assumenosideeffects class androidx.loader.app.LoaderManager { + static void enableDebugLogging(boolean); +} +-assumevalues class androidx.loader.app.LoaderManagerImpl { + static boolean DEBUG return false; +} # This is just some proguard rules testes, might do a separate lib after # Made to help optimise the libraries and not the app directly diff --git a/app/src/main/java/com/fox2code/mmm/MainApplication.java b/app/src/main/java/com/fox2code/mmm/MainApplication.java index 64121e2..3281e28 100644 --- a/app/src/main/java/com/fox2code/mmm/MainApplication.java +++ b/app/src/main/java/com/fox2code/mmm/MainApplication.java @@ -1,5 +1,6 @@ package com.fox2code.mmm; +import android.annotation.SuppressLint; import android.app.Application; import android.content.Intent; import android.content.SharedPreferences; @@ -70,6 +71,10 @@ public class MainApplication extends Application implements CompatActivity.Appli return getSharedPreferences().getBoolean("pref_show_incompatible", false); } + public static boolean isForceDarkTerminal() { + return getSharedPreferences().getBoolean("pref_force_dark_terminal", false); + } + public static boolean hasGottenRootAccess() { return getSharedPreferences().getBoolean("has_root_access", false); } @@ -118,6 +123,23 @@ public class MainApplication extends Application implements CompatActivity.Appli return managerThemeResId; } + @SuppressLint("NonConstantResourceId") + public boolean isLightTheme() { + switch (this.managerThemeResId) { + case R.style.Theme_MagiskModuleManager: + return (this.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_NIGHT_MASK) + != Configuration.UI_MODE_NIGHT_YES; + case R.style.Theme_MagiskModuleManager_Light: + return true; + case R.style.Theme_MagiskModuleManager_Dark: + return false; + default: + throw new IllegalStateException("Non manager theme!"); + } + } + + @Override public void onCreate() { INSTANCE = this; diff --git a/app/src/main/java/com/fox2code/mmm/ModuleViewAdapter.java b/app/src/main/java/com/fox2code/mmm/ModuleViewAdapter.java index 8d0a7c6..d2cee1a 100644 --- a/app/src/main/java/com/fox2code/mmm/ModuleViewAdapter.java +++ b/app/src/main/java/com/fox2code/mmm/ModuleViewAdapter.java @@ -2,6 +2,7 @@ package com.fox2code.mmm; import android.annotation.SuppressLint; import android.content.res.Resources; +import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.util.TypedValue; @@ -11,6 +12,8 @@ import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.TextView; +import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; import androidx.annotation.NonNull; import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView; @@ -250,7 +253,10 @@ public final class ModuleViewAdapter extends RecyclerView.Adapter { - if (s) { + IntentHelper.openFileTo(compatActivity, module, (d, u, s) -> { + if (s == IntentHelper.RESPONSE_FILE) { try { boolean needPatch; try (ZipFile zipFile = new ZipFile(d)) { @@ -86,6 +86,10 @@ public enum NotificationType implements NotificationTypeCst { Toast.makeText(compatActivity, R.string.invalid_format, Toast.LENGTH_SHORT).show(); } + } else if (s == IntentHelper.RESPONSE_URL) { + IntentHelper.openInstaller(compatActivity, u.toString(), + compatActivity.getString( + R.string.remote_install_title), null); } }); }, true) { 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 f32095a..7b8738d 100644 --- a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java +++ b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java @@ -2,6 +2,8 @@ package com.fox2code.mmm.installer; import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; @@ -40,9 +42,9 @@ public class InstallerActivity extends CompatActivity { this.moduleCache = new File(this.getCacheDir(), "installer"); if (!this.moduleCache.exists() && !this.moduleCache.mkdirs()) Log.e(TAG, "Failed to mkdir module cache dir!"); + super.onCreate(savedInstanceState); this.setDisplayHomeAsUpEnabled(false); this.setOnBackPressedCallback(DISABLE_BACK_BUTTON); - super.onCreate(savedInstanceState); final Intent intent = this.getIntent(); final String target; final String name; @@ -64,8 +66,21 @@ public class InstallerActivity extends CompatActivity { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setTitle(name); setContentView(R.layout.installer); + int background; + int foreground; + if (MainApplication.getINSTANCE().isLightTheme() && + !MainApplication.isForceDarkTerminal()) { + background = Color.WHITE; + foreground = Color.BLACK; + } else { + background = Color.BLACK; + foreground = Color.WHITE; + } + findViewById(R.id.install_horizontal_scroller) + .setBackground(new ColorDrawable(background)); this.progressIndicator = findViewById(R.id.progress_bar); - this.installerTerminal = new InstallerTerminal(findViewById(R.id.install_terminal)); + this.installerTerminal = new InstallerTerminal( + findViewById(R.id.install_terminal), foreground); this.progressIndicator.setVisibility(View.GONE); this.progressIndicator.setIndeterminate(true); if (urlMode) { diff --git a/app/src/main/java/com/fox2code/mmm/installer/InstallerTerminal.java b/app/src/main/java/com/fox2code/mmm/installer/InstallerTerminal.java index 4428a1c..5b8b84a 100644 --- a/app/src/main/java/com/fox2code/mmm/installer/InstallerTerminal.java +++ b/app/src/main/java/com/fox2code/mmm/installer/InstallerTerminal.java @@ -16,21 +16,21 @@ public class InstallerTerminal extends RecyclerView.Adapter terminal; private final Object lock = new Object(); + private final int foreground; - public InstallerTerminal(RecyclerView recyclerView) { + public InstallerTerminal(RecyclerView recyclerView,int foreground) { recyclerView.setLayoutManager( new LinearLayoutManager(recyclerView.getContext())); this.recyclerView = recyclerView; + this.foreground = foreground; this.terminal = new ArrayList<>(); - this.recyclerView.setBackground( - new ColorDrawable(Color.BLACK)); this.recyclerView.setAdapter(this); } @NonNull @Override public TextViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new TextViewHolder(new TextView(parent.getContext())); + return new TextViewHolder(new TextView(parent.getContext()), this.foreground); } @Override @@ -116,11 +116,11 @@ public class InstallerTerminal extends RecyclerView.Adapter { + ListPreference themePreference = findPreference("pref_theme"); + themePreference.setSummaryProvider(p -> themePreference.getEntry()); + themePreference.setOnPreferenceChangeListener((preference, newValue) -> { @StyleRes int themeResId; switch (String.valueOf(newValue)) { default: @@ -55,6 +59,9 @@ public class SettingsActivity extends CompatActivity { CompatActivity.getCompatActivity(this).setThemeRecreate(themeResId); return true; }); + if ("dark".equals(themePreference.getValue())) { + findPreference("pref_force_dark_terminal").setEnabled(false); + } setRepoNameResolution("pref_repo_main", RepoManager.MAGISK_REPO, "Magisk Modules Repo (Official)", RepoManager.MAGISK_REPO_HOMEPAGE); 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 bddfa0f..8a8362a 100644 --- a/app/src/main/java/com/fox2code/mmm/utils/IntentHelper.java +++ b/app/src/main/java/com/fox2code/mmm/utils/IntentHelper.java @@ -1,13 +1,16 @@ package com.fox2code.mmm.utils; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.util.Log; import android.widget.Toast; @@ -15,12 +18,16 @@ import androidx.core.app.ActivityOptionsCompat; import com.fox2code.mmm.Constants; import com.fox2code.mmm.MainApplication; +import com.fox2code.mmm.R; import com.fox2code.mmm.compat.CompatActivity; import com.fox2code.mmm.installer.InstallerActivity; import com.fox2code.mmm.markdown.MarkdownActivity; +import com.topjohnwu.superuser.io.SuFileInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -144,50 +151,78 @@ public class IntentHelper { return (Activity) context; } + public static final int RESPONSE_ERROR = 0; + public static final int RESPONSE_FILE = 1; + public static final int RESPONSE_URL = 2; + + @SuppressLint("SdCardPath") public static void openFileTo(CompatActivity compatActivity, File destination, - OnFileReceivedCallback callback) { + OnFileReceivedCallback callback) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("application/zip"); intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); + intent.putExtra(Intent.EXTRA_LOCAL_ONLY, false); intent.addCategory(Intent.CATEGORY_OPENABLE); Bundle param = ActivityOptionsCompat.makeCustomAnimation(compatActivity, android.R.anim.fade_in, android.R.anim.fade_out).toBundle(); compatActivity.startActivityForResult(intent, param, (result, data) -> { - String name = destination.getName(); - if (data == null || result != Activity.RESULT_OK) { - callback.onReceived(destination, false); + Uri uri = data == null ? null : data.getData(); + if (uri == null || (result == Activity.RESULT_CANCELED && !(( + ContentResolver.SCHEME_FILE.equals(uri.getScheme()) + && uri.getPath() != null && + (uri.getPath().startsWith("/sdcard/") || + uri.getPath().startsWith("/data/")) + ) || ContentResolver.SCHEME_ANDROID_RESOURCE.equals(uri.getScheme())))) { + callback.onReceived(destination, null, RESPONSE_ERROR); return; } - Uri uri = data.getData(); - if (uri == null || "http".equals(uri.getScheme()) || + Log.d("IntentHelper", "FilePicker returned " + uri.toString()); + if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) { - callback.onReceived(destination, false); + callback.onReceived(destination, uri, RESPONSE_URL); return; } + if (ContentResolver.SCHEME_FILE.equals(uri.getScheme()) || + (result != Activity.RESULT_OK && result != Activity.RESULT_FIRST_USER)) { + Toast.makeText(compatActivity, + R.string.file_picker_wierd, + Toast.LENGTH_SHORT).show(); + } InputStream inputStream = null; OutputStream outputStream = null; boolean success = false; try { - inputStream = compatActivity.getContentResolver() - .openInputStream(uri); + if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) { + String path = uri.getPath(); + if (path.startsWith("/sdcard/")) { // Fix file paths + path = Environment.getExternalStorageDirectory() + .getAbsolutePath() + path.substring(7); + } + inputStream = SuFileInputStream.open( + new File(path).getAbsoluteFile()); + } else { + inputStream = compatActivity.getContentResolver() + .openInputStream(uri); + } outputStream = new FileOutputStream(destination); Files.copy(inputStream, outputStream); - String newName = uri.getLastPathSegment(); - if (newName.endsWith(".zip")) name = newName; success = true; } catch (Exception e) { Log.e("IntentHelper", "fail copy", e); + Toast.makeText(compatActivity, + R.string.file_picker_failure, + Toast.LENGTH_SHORT).show(); } finally { Files.closeSilently(inputStream); Files.closeSilently(outputStream); if (!success && destination.exists() && !destination.delete()) Log.e("IntentHelper", "Failed to delete artefact!"); } - callback.onReceived(destination, success); + callback.onReceived(destination, uri, success ? RESPONSE_FILE : RESPONSE_ERROR); }); } public interface OnFileReceivedCallback { - void onReceived(File target,boolean success); + void onReceived(File target,Uri uri,int response); } } diff --git a/app/src/main/res/drawable/ic_baseline_list_24.xml b/app/src/main/res/drawable/ic_baseline_list_24.xml new file mode 100644 index 0000000..f20eac3 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_list_24.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 2c7ee12..8304e67 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -35,8 +35,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" - android:layout_marginTop="2dp" - android:layout_marginBottom="2dp" + android:layout_marginTop="8dp" + android:layout_marginBottom="8dp" android:gravity="center_vertical" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/layout/installer.xml b/app/src/main/res/layout/installer.xml index d554cb9..30473c7 100644 --- a/app/src/main/res/layout/installer.xml +++ b/app/src/main/res/layout/installer.xml @@ -8,6 +8,7 @@ diff --git a/app/src/main/res/layout/module_entry.xml b/app/src/main/res/layout/module_entry.xml index 0cb1dd3..276605e 100644 --- a/app/src/main/res/layout/module_entry.xml +++ b/app/src/main/res/layout/module_entry.xml @@ -8,7 +8,8 @@ android:layout_marginRight="8dp" android:layout_marginTop="2dp" android:layout_marginBottom="2dp" - android:gravity="center_vertical"> + android:gravity="center_vertical" + android:background="@null"> Source code Last update: Magisk builtin module + Force dark mode terminal + Your current file picker failed to give access to the file. + Remote install + Your file picker returned a non standard response. \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 6166cb3..aa9e3a8 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,5 +1,8 @@