From 3fdeb40ddf083a63914d0360615919a7bd5c3158 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 28 Jul 2018 14:56:14 +0800 Subject: [PATCH 1/4] Update SNET extension dialog interface --- README.MD | 1 - .../magisk/asyncs/CheckSafetyNet.java | 10 +- .../magisk/components/FlavorActivity.java | 51 ------ .../com/topjohnwu/magisk/utils/Const.java | 4 +- snet/build.gradle | 2 +- snet/proguard-rules.pro | 2 +- .../com/topjohnwu/snet/ModdedGPSUtil.java | 145 ++++++++++++++++++ .../com/topjohnwu/snet/SafetyNetHelper.java | 57 ++++--- .../main/java/com/topjohnwu/snet/Snet.java | 13 ++ 9 files changed, 204 insertions(+), 81 deletions(-) create mode 100644 snet/src/main/java/com/topjohnwu/snet/ModdedGPSUtil.java create mode 100644 snet/src/main/java/com/topjohnwu/snet/Snet.java diff --git a/README.MD b/README.MD index 713460da8408..778800efee15 100644 --- a/README.MD +++ b/README.MD @@ -13,7 +13,6 @@ 2. Set configurations in `config.prop`. A sample file `config.prop.sample` is provided as an example. 3. Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h` 4. By default, `build.py` build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (via the `--release` flag), you need a Java Keystore file `release-key.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually). -5. The SafetyNet extension pack requires the full Magisk Manager as a `compileOnly` dependency. Build the **release** APK, convert it back to Java `.class` files (I use [dex2jar](https://github.com/pxb1988/dex2jar)), and place the converted JAR under `snet/libs` before compiling. ## License diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java b/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java index 0b39f2debc3c..7e21f3d2b06b 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java +++ b/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java @@ -45,10 +45,12 @@ private void dlSnet() throws Exception { private void dyload() throws Exception { DexClassLoader loader = new DexClassLoader(dexPath.getPath(), dexPath.getParent(), null, ISafetyNetHelper.class.getClassLoader()); - Class clazz = loader.loadClass("com.topjohnwu.snet.SafetyNetHelper"); - helper = (ISafetyNetHelper) clazz.getConstructors()[0] - .newInstance(getActivity(), (ISafetyNetHelper.Callback) - code -> MagiskManager.get().safetyNetDone.publish(false, code)); + Class clazz = loader.loadClass("com.topjohnwu.snet.Snet"); + helper = (ISafetyNetHelper) clazz.getMethod("newHelper", + Class.class, String.class, Activity.class, Object.class) + .invoke(null, ISafetyNetHelper.class, dexPath.getPath(), getActivity(), + (ISafetyNetHelper.Callback) code -> + MagiskManager.get().safetyNetDone.publish(false, code)); if (helper.getVersion() != Const.SNET_VER) { throw new Exception(); } diff --git a/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java b/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java index 7b7f307dbe83..ecc127b1dcc7 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java @@ -1,9 +1,6 @@ package com.topjohnwu.magisk.components; -import android.content.res.AssetManager; -import android.content.res.Resources; import android.os.Bundle; -import android.support.annotation.Keep; import android.support.annotation.Nullable; import android.support.annotation.StyleRes; import android.support.v7.app.AppCompatActivity; @@ -15,10 +12,6 @@ public abstract class FlavorActivity extends AppCompatActivity { - private AssetManager swappedAssetManager = null; - private Resources swappedResources = null; - private Resources.Theme backupTheme = null; - @StyleRes public int getDarkTheme() { return -1; @@ -61,48 +54,4 @@ protected void setFloating() { setFinishOnTouchOutside(true); } } - - @Override - public Resources.Theme getTheme() { - return backupTheme == null ? super.getTheme() : backupTheme; - } - - @Override - public AssetManager getAssets() { - return swappedAssetManager == null ? super.getAssets() : swappedAssetManager; - } - - private AssetManager getAssets(String apk) { - try { - AssetManager asset = AssetManager.class.newInstance(); - AssetManager.class.getMethod("addAssetPath", String.class).invoke(asset, apk); - return asset; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override - public Resources getResources() { - return swappedResources == null ? super.getResources() : swappedResources; - } - - @Keep - public void swapResources(String dexPath) { - AssetManager asset = getAssets(dexPath); - if (asset != null) { - backupTheme = super.getTheme(); - Resources res = super.getResources(); - swappedResources = new Resources(asset, res.getDisplayMetrics(), res.getConfiguration()); - swappedAssetManager = asset; - } - } - - @Keep - public void restoreResources() { - swappedAssetManager = null; - swappedResources = null; - backupTheme = null; - } } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Const.java b/app/src/main/java/com/topjohnwu/magisk/utils/Const.java index 49afb20afa73..122a1d3d486f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Const.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Const.java @@ -39,7 +39,7 @@ public class Const { // Versions public static final int UPDATE_SERVICE_VER = 1; - public static final int SNET_VER = 8; + public static final int SNET_VER = 9; public static int MIN_MODULE_VER() { return MagiskManager.get().magiskVersionCode >= MAGISK_VER.REMOVE_LEGACY_LINK ? 1500 : 1400; @@ -81,7 +81,7 @@ public static class ID { public static class Url { public static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json"; public static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/beta.json"; - public static final String SNET_URL = "https://github.com/topjohnwu/magisk_files/raw/727aa3a8642bf5f0982e5ea89b3f818bd783d5a2/snet.apk"; + public static final String SNET_URL = "https://github.com/topjohnwu/magisk_files/raw/fc819e3974e96d0e4430a2957df4410971ebd6f3/snet.apk"; public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&page=%d"; public static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s"; public static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip"; diff --git a/snet/build.gradle b/snet/build.gradle index a62b1bc366c2..23a48418299e 100644 --- a/snet/build.gradle +++ b/snet/build.gradle @@ -22,6 +22,6 @@ android { } dependencies { - compileOnly fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.google.android.gms:play-services-safetynet:7.0.0' /* The oldest version */ } diff --git a/snet/proguard-rules.pro b/snet/proguard-rules.pro index 56bba17b43ed..8cc07d286cc7 100644 --- a/snet/proguard-rules.pro +++ b/snet/proguard-rules.pro @@ -20,6 +20,6 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile --keep class com.topjohnwu.snet.SafetyNet* { *; } +-keep class com.topjohnwu.snet.* { *; } -dontwarn java.lang.invoke** -dontwarn com.google.android.gms.common.GooglePlayServicesUtil** diff --git a/snet/src/main/java/com/topjohnwu/snet/ModdedGPSUtil.java b/snet/src/main/java/com/topjohnwu/snet/ModdedGPSUtil.java new file mode 100644 index 000000000000..918c686617f7 --- /dev/null +++ b/snet/src/main/java/com/topjohnwu/snet/ModdedGPSUtil.java @@ -0,0 +1,145 @@ +package com.topjohnwu.snet; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.util.Log; + +import com.google.android.gms.common.GooglePlayServicesUtil; +import com.google.android.gms.common.internal.zzg; +import com.google.android.gms.internal.zzlu; + +/* Decompiled and modified from GooglePlayServiceUtil.class */ +public class ModdedGPSUtil { + + private static final String TAG = "GooglePlayServicesUtil"; + static String dexPath; + + static Dialog getErrorDialog(int errCode, Activity activity, int requestCode) { + SwapResContext ctx = new SwapResContext(activity, dexPath); + Resources res = ctx.getResources(); + if (zzlu.zzQ(ctx) && errCode == 2) { + errCode = 42; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + + builder.setMessage(GooglePlayServicesUtil.zze(ctx, errCode)); + + String btnMsg = GooglePlayServicesUtil.zzf(ctx, errCode); + if (btnMsg != null) { + Intent intent = GooglePlayServicesUtil.zzan(errCode); + builder.setPositiveButton(btnMsg, new zzg(activity, intent, requestCode)); + } + + switch(errCode) { + case 0: + return null; + case 1: + return builder.setTitle(res.getString(com.google.android.gms.R.string.common_google_play_services_install_title)).create(); + case 2: + return builder.setTitle(res.getString(com.google.android.gms.R.string.common_google_play_services_update_title)).create(); + case 3: + return builder.setTitle(res.getString(com.google.android.gms.R.string.common_google_play_services_enable_title)).create(); + case 4: + case 6: + return builder.create(); + case 5: + Log.e(TAG, "An invalid account was specified when connecting. Please provide a valid account."); + return builder.setTitle(res.getString(com.google.android.gms.R.string.common_google_play_services_invalid_account_title)).create(); + case 7: + Log.e(TAG, "Network error occurred. Please retry request later."); + return builder.setTitle(res.getString(com.google.android.gms.R.string.common_google_play_services_network_error_title)).create(); + case 8: + Log.e(TAG, "Internal error occurred. Please see logs for detailed information"); + return builder.create(); + case 9: + Log.e(TAG, "Google Play services is invalid. Cannot recover."); + return builder.setTitle(res.getString(com.google.android.gms.R.string.common_google_play_services_unsupported_title)).create(); + case 10: + Log.e(TAG, "Developer error occurred. Please see logs for detailed information"); + return builder.create(); + case 11: + Log.e(TAG, "The application is not licensed to the user."); + return builder.create(); + case 12: + case 13: + case 14: + case 15: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + default: + Log.e(TAG, "Unexpected error code " + errCode); + return builder.create(); + case 16: + Log.e(TAG, "One of the API components you attempted to connect to is not available."); + return builder.create(); + case 17: + Log.e(TAG, "The specified account could not be signed in."); + return builder.setTitle(res.getString(com.google.android.gms.R.string.common_google_play_services_sign_in_failed_title)).create(); + case 42: + return builder.setTitle(res.getString(com.google.android.gms.R.string.common_android_wear_update_title)).create(); + } + } + + public static class SwapResContext extends ContextWrapper { + + private AssetManager asset; + private Resources resources; + + public SwapResContext(Context base, String apk) { + super(base); + asset = getAssets(apk); + Resources res = base.getResources(); + resources = new Resources(asset, res.getDisplayMetrics(), res.getConfiguration()); + } + + private AssetManager getAssets(String apk) { + try { + AssetManager asset = AssetManager.class.newInstance(); + AssetManager.class.getMethod("addAssetPath", String.class).invoke(asset, apk); + return asset; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + @Override + public Resources getResources() { + return resources; + } + + @Override + public AssetManager getAssets() { + return asset; + } + } +} diff --git a/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java b/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java index 70f46ac32da1..777d0a49646f 100644 --- a/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java +++ b/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java @@ -1,5 +1,6 @@ package com.topjohnwu.snet; +import android.app.Activity; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -11,16 +12,15 @@ import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.safetynet.SafetyNet; import com.google.android.gms.safetynet.SafetyNetApi; -import com.topjohnwu.magisk.asyncs.CheckSafetyNet; -import com.topjohnwu.magisk.components.Activity; -import com.topjohnwu.magisk.utils.ISafetyNetHelper; import org.json.JSONException; import org.json.JSONObject; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; import java.security.SecureRandom; -public class SafetyNetHelper implements ISafetyNetHelper, GoogleApiClient.ConnectionCallbacks, +public class SafetyNetHelper implements InvocationHandler, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback { public static final int CAUSE_SERVICE_DISCONNECTED = 0x01; @@ -31,25 +31,24 @@ public class SafetyNetHelper implements ISafetyNetHelper, GoogleApiClient.Connec public static final int BASIC_PASS = 0x10; public static final int CTS_PASS = 0x20; - public static final int SNET_EXT_VER = 8; + public static final int SNET_EXT_VER = 9; private GoogleApiClient mGoogleApiClient; private Activity mActivity; - private Callback callback; + private Object callback; - @Override - public int getVersion() { - return SNET_EXT_VER; - } - - public SafetyNetHelper(Activity activity, Callback cb) { + SafetyNetHelper(Activity activity, Object cb) { mActivity = activity; callback = cb; } - // Entry point to start test - @Override - public void attest() { + /* Override ISafetyNetHelper.getVersion */ + private int getVersion() { + return SNET_EXT_VER; + } + + /* Override ISafetyNetHelper.attest */ + private void attest() { // Connect Google Service mGoogleApiClient = new GoogleApiClient.Builder(mActivity) .addApi(SafetyNet.API) @@ -59,17 +58,33 @@ public void attest() { mGoogleApiClient.connect(); } + @Override + public Object invoke(Object o, Method method, Object[] args) { + if (method.getName().equals("attest")) { + attest(); + } else if (method.getName().equals("getVersion")) { + return getVersion(); + } + return null; + } + + private void invokeCallback(int code) { + Class clazz = callback.getClass(); + try { + clazz.getMethod("onResponse", int.class).invoke(callback, code); + } catch (Exception ignored) {} + } + @Override public void onConnectionSuspended(int i) { - callback.onResponse(i); + invokeCallback(i); } @Override public void onConnectionFailed(@NonNull ConnectionResult result) { - mActivity.swapResources(CheckSafetyNet.dexPath.getPath()); - GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), mActivity, 0).show(); - mActivity.restoreResources(); - callback.onResponse(CONNECTION_FAIL); + if (GooglePlayServicesUtil.isUserRecoverableError(result.getErrorCode())) + ModdedGPSUtil.getErrorDialog(result.getErrorCode(), mActivity, 0).show(); + invokeCallback(CONNECTION_FAIL); } @Override @@ -101,6 +116,6 @@ public void onResult(SafetyNetApi.AttestationResult result) { mGoogleApiClient.disconnect(); // Return results - callback.onResponse(code); + invokeCallback(code); } } diff --git a/snet/src/main/java/com/topjohnwu/snet/Snet.java b/snet/src/main/java/com/topjohnwu/snet/Snet.java new file mode 100644 index 000000000000..44438cb32dd1 --- /dev/null +++ b/snet/src/main/java/com/topjohnwu/snet/Snet.java @@ -0,0 +1,13 @@ +package com.topjohnwu.snet; + +import android.app.Activity; + +import java.lang.reflect.Proxy; + +public class Snet { + public static Object newHelper(Class clazz, String dexPath, Activity activity, Object cb) { + ModdedGPSUtil.dexPath = dexPath; + return Proxy.newProxyInstance(SafetyNetHelper.class.getClassLoader(), + new Class[] { clazz }, new SafetyNetHelper(activity, cb)); + } +} From 27851bdefae150dad90f040cbc5939a74387698c Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 28 Jul 2018 15:10:06 +0800 Subject: [PATCH 2/4] Update README.md --- README.MD | 44 +++----------------------------------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/README.MD b/README.MD index 778800efee15..f910afc30257 100644 --- a/README.MD +++ b/README.MD @@ -14,6 +14,9 @@ 3. Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h` 4. By default, `build.py` build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (via the `--release` flag), you need a Java Keystore file `release-key.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually). +## Documentation +[Link to Documentation](docs/README.MD) + ## License ``` @@ -30,44 +33,3 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ``` - -## Credits - -**MagiskManager** (`app`) - -* Copyright 2016-2018, John Wu (@topjohnwu) -* All contributors and translators on Github - -**MagiskSU** (`native/jni/su`) - -* Copyright 2016-2018, John Wu (@topjohnwu) -* Copyright 2015, Pierre-Hugues Husson (phh@phh.me) -* Copyright 2013, Koushik Dutta (@koush) -* Copyright 2010, Adam Shanks (@ChainsDD) -* Copyright 2008, Zinx Verituse (@zinxv) - -**MagiskPolicy** (`native/jni/magiskpolicy`) - -* Copyright 2016-2018, John Wu (@topjohnwu) -* Copyright 2015, Pierre-Hugues Husson (phh@phh.me) -* Copyright 2015, Joshua Brindle (@joshua_brindle) - -**MagiskHide** (`native/jni/magiskhide`) - -* Copyright 2016-2018, John Wu (@topjohnwu) -* Copyright 2016, Pierre-Hugues Husson (phh@phh.me) - -**resetprop** (`native/jni/resetprop`) - - * Copyright 2016-2018 John Wu (@topjohnwu) - * Copyright 2016 nkk71 (nkk71x@gmail.com) - -**External Dependencies** (`native/jni/external`) - -* Makefile for busybox, generated by [ndk-busybox-kitchen](https://github.com/topjohnwu/ndk-busybox-kitchen) -* Each dependencies has its own license/copyright information in each subdirectory. -All of them are either GPL or GPL compatible. - -**Others Not Mentioned** - -* Copyright 2016-2018, John Wu (@topjohnwu) From a747fdd27d231efc4815f22f6dd44b3bc2f6ef84 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 28 Jul 2018 22:52:40 +0800 Subject: [PATCH 3/4] Organize dialog code --- .../com/topjohnwu/magisk/MagiskFragment.java | 30 +- .../magisk/adapters/PolicyAdapter.java | 4 +- .../magisk/adapters/ReposAdapter.java | 4 +- .../topjohnwu/magisk/asyncs/CheckUpdates.java | 6 +- ...logBuilder.java => CustomAlertDialog.java} | 23 +- .../magisk/components/EnvFixDialog.java | 33 +++ .../magisk/components/FlavorActivity.java | 20 +- .../components/InstallMethodDialog.java | 101 +++++++ .../components/MagiskInstallDialog.java | 53 ++++ .../components/ManagerInstallDialog.java | 38 +++ .../magisk/components/UninstallDialog.java | 40 +++ .../magisk/services/OnBootService.java | 4 +- .../magisk/utils/NotificationMgr.java | 84 ++++++ .../com/topjohnwu/magisk/utils/ShowUI.java | 278 ------------------ .../topjohnwu/magisk/components/Activity.java | 19 -- 15 files changed, 403 insertions(+), 334 deletions(-) rename app/src/full/java/com/topjohnwu/magisk/components/{AlertDialogBuilder.java => CustomAlertDialog.java} (92%) create mode 100644 app/src/full/java/com/topjohnwu/magisk/components/EnvFixDialog.java create mode 100644 app/src/full/java/com/topjohnwu/magisk/components/InstallMethodDialog.java create mode 100644 app/src/full/java/com/topjohnwu/magisk/components/MagiskInstallDialog.java create mode 100644 app/src/full/java/com/topjohnwu/magisk/components/ManagerInstallDialog.java create mode 100644 app/src/full/java/com/topjohnwu/magisk/components/UninstallDialog.java create mode 100644 app/src/full/java/com/topjohnwu/magisk/utils/NotificationMgr.java delete mode 100644 app/src/full/java/com/topjohnwu/magisk/utils/ShowUI.java diff --git a/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java index 46567a9f294f..b50e01b8a6dd 100644 --- a/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/full/java/com/topjohnwu/magisk/MagiskFragment.java @@ -3,6 +3,7 @@ import android.app.NotificationManager; import android.content.Context; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.v4.widget.SwipeRefreshLayout; @@ -20,12 +21,16 @@ import com.topjohnwu.magisk.asyncs.CheckSafetyNet; import com.topjohnwu.magisk.asyncs.CheckUpdates; -import com.topjohnwu.magisk.components.AlertDialogBuilder; +import com.topjohnwu.magisk.components.Activity; +import com.topjohnwu.magisk.components.CustomAlertDialog; +import com.topjohnwu.magisk.components.EnvFixDialog; import com.topjohnwu.magisk.components.ExpandableView; import com.topjohnwu.magisk.components.Fragment; +import com.topjohnwu.magisk.components.MagiskInstallDialog; +import com.topjohnwu.magisk.components.ManagerInstallDialog; +import com.topjohnwu.magisk.components.UninstallDialog; import com.topjohnwu.magisk.utils.Const; import com.topjohnwu.magisk.utils.ISafetyNetHelper; -import com.topjohnwu.magisk.utils.ShowUI; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.superuser.Shell; @@ -84,11 +89,11 @@ void safetyNet() { safetyNetProgress.setVisibility(View.VISIBLE); safetyNetRefreshIcon.setVisibility(View.GONE); safetyNetStatusText.setText(R.string.checking_safetyNet_status); - new CheckSafetyNet(getActivity()).exec(); + new CheckSafetyNet(requireActivity()).exec(); collapse(); }; if (!TextUtils.equals(mm.getPackageName(), Const.ORIG_PKG_NAME)) { - new AlertDialogBuilder(getActivity()) + new CustomAlertDialog(requireActivity()) .setTitle(R.string.cannot_check_sn_title) .setMessage(R.string.cannot_check_sn_notice) .setCancelable(true) @@ -96,7 +101,7 @@ void safetyNet() { .show(); } else if (!CheckSafetyNet.dexPath.exists()) { // Show dialog - new AlertDialogBuilder(getActivity()) + new CustomAlertDialog(requireActivity()) .setTitle(R.string.proprietary_title) .setMessage(R.string.proprietary_notice) .setCancelable(true) @@ -115,25 +120,26 @@ void install() { // Show Manager update first if (mm.remoteManagerVersionCode > BuildConfig.VERSION_CODE) { - ShowUI.managerInstallDialog(getActivity()); + new ManagerInstallDialog((Activity) requireActivity()).show(); return; } ((NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll(); - ShowUI.magiskInstallDialog(getActivity()); + new MagiskInstallDialog((Activity) getActivity()).show(); } @OnClick(R.id.uninstall_button) void uninstall() { - ShowUI.uninstallDialog(getActivity()); + new UninstallDialog(requireActivity()).show(); } @Nullable @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_magisk, container, false); unbinder = ButterKnife.bind(this, v); - getActivity().setTitle(R.string.magisk); + requireActivity().setTitle(R.string.magisk); mm = getApplication(); @@ -204,7 +210,7 @@ public Container getContainer() { } private void updateUI() { - ((MainActivity) getActivity()).checkHideSection(); + ((MainActivity) requireActivity()).checkHideSection(); boolean hasNetwork = Utils.checkNetworkStatus(); boolean hasRoot = Shell.rootAccess(); @@ -266,7 +272,7 @@ private void updateCheckUI() { install(); } else if (mm.remoteMagiskVersionCode >= Const.MAGISK_VER.FIX_ENV && !ShellUtils.fastCmdResult("env_check")) { - ShowUI.envFixDialog(getActivity()); + new EnvFixDialog(requireActivity()).show(); } } } diff --git a/app/src/full/java/com/topjohnwu/magisk/adapters/PolicyAdapter.java b/app/src/full/java/com/topjohnwu/magisk/adapters/PolicyAdapter.java index abaa4e8c331c..78383bd97376 100644 --- a/app/src/full/java/com/topjohnwu/magisk/adapters/PolicyAdapter.java +++ b/app/src/full/java/com/topjohnwu/magisk/adapters/PolicyAdapter.java @@ -12,7 +12,7 @@ import android.widget.TextView; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.components.AlertDialogBuilder; +import com.topjohnwu.magisk.components.CustomAlertDialog; import com.topjohnwu.magisk.components.ExpandableView; import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.container.Policy; @@ -93,7 +93,7 @@ public void onBindViewHolder(ViewHolder holder, int position) { dbHelper.updatePolicy(policy); } }); - holder.delete.setOnClickListener(v -> new AlertDialogBuilder((Activity) v.getContext()) + holder.delete.setOnClickListener(v -> new CustomAlertDialog((Activity) v.getContext()) .setTitle(R.string.su_revoke_title) .setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName)) .setPositiveButton(R.string.yes, (dialog, which) -> { diff --git a/app/src/full/java/com/topjohnwu/magisk/adapters/ReposAdapter.java b/app/src/full/java/com/topjohnwu/magisk/adapters/ReposAdapter.java index 959d074ddbd3..2b1224137610 100644 --- a/app/src/full/java/com/topjohnwu/magisk/adapters/ReposAdapter.java +++ b/app/src/full/java/com/topjohnwu/magisk/adapters/ReposAdapter.java @@ -16,7 +16,7 @@ import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.asyncs.MarkDownWindow; import com.topjohnwu.magisk.asyncs.ProcessRepoZip; -import com.topjohnwu.magisk.components.AlertDialogBuilder; +import com.topjohnwu.magisk.components.CustomAlertDialog; import com.topjohnwu.magisk.container.Module; import com.topjohnwu.magisk.container.Repo; import com.topjohnwu.magisk.database.RepoDatabaseHelper; @@ -102,7 +102,7 @@ public void onBindItemViewHolder(RepoHolder holder, int section, int position) { holder.downloadImage.setOnClickListener(v -> { String filename = repo.getName() + "-" + repo.getVersion() + ".zip"; - new AlertDialogBuilder((Activity) context) + new CustomAlertDialog((Activity) context) .setTitle(context.getString(R.string.repo_install_title, repo.getName())) .setMessage(context.getString(R.string.repo_install_msg, filename)) .setCancelable(true) diff --git a/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java b/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java index b8e6495a409b..06bd670553f0 100644 --- a/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java +++ b/app/src/full/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java @@ -3,7 +3,7 @@ import com.topjohnwu.magisk.BuildConfig; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.ShowUI; +import com.topjohnwu.magisk.utils.NotificationMgr; import com.topjohnwu.magisk.utils.WebService; import org.json.JSONException; @@ -59,9 +59,9 @@ protected void onPostExecute(Void v) { MagiskManager mm = MagiskManager.get(); if (showNotification) { if (BuildConfig.VERSION_CODE < mm.remoteManagerVersionCode) { - ShowUI.managerUpdateNotification(); + NotificationMgr.managerUpdate(); } else if (mm.magiskVersionCode < mm.remoteMagiskVersionCode) { - ShowUI.magiskUpdateNotification(); + NotificationMgr.magiskUpdate(); } } mm.updateCheckDone.publish(); diff --git a/app/src/full/java/com/topjohnwu/magisk/components/AlertDialogBuilder.java b/app/src/full/java/com/topjohnwu/magisk/components/CustomAlertDialog.java similarity index 92% rename from app/src/full/java/com/topjohnwu/magisk/components/AlertDialogBuilder.java rename to app/src/full/java/com/topjohnwu/magisk/components/CustomAlertDialog.java index 568d6944489b..c4ad3025150a 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/AlertDialogBuilder.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/CustomAlertDialog.java @@ -18,7 +18,7 @@ import butterknife.BindView; import butterknife.ButterKnife; -public class AlertDialogBuilder extends AlertDialog.Builder { +public class CustomAlertDialog extends AlertDialog.Builder { @BindView(R.id.button_panel) LinearLayout buttons; @BindView(R.id.message_panel) LinearLayout messagePanel; @@ -34,17 +34,7 @@ public class AlertDialogBuilder extends AlertDialog.Builder { private AlertDialog dialog; - public AlertDialogBuilder(@NonNull Activity context) { - super(context); - setup(); - } - - public AlertDialogBuilder(@NonNull Activity context, @StyleRes int themeResId) { - super(context, themeResId); - setup(); - } - - private void setup() { + { View v = LayoutInflater.from(getContext()).inflate(R.layout.alert_dialog, null); ButterKnife.bind(this, v); super.setView(v); @@ -55,9 +45,12 @@ private void setup() { messagePanel.setVisibility(View.GONE); } - @Override - public AlertDialog.Builder setTitle(int titleId) { - return super.setTitle(titleId); + public CustomAlertDialog(@NonNull Activity context) { + super(context); + } + + public CustomAlertDialog(@NonNull Activity context, @StyleRes int themeResId) { + super(context, themeResId); } @Override diff --git a/app/src/full/java/com/topjohnwu/magisk/components/EnvFixDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/EnvFixDialog.java new file mode 100644 index 000000000000..2a3afe31fe27 --- /dev/null +++ b/app/src/full/java/com/topjohnwu/magisk/components/EnvFixDialog.java @@ -0,0 +1,33 @@ +package com.topjohnwu.magisk.components; + +import android.app.Activity; +import android.content.Context; +import android.net.Uri; +import android.support.annotation.NonNull; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.asyncs.InstallMagisk; +import com.topjohnwu.magisk.receivers.DownloadReceiver; +import com.topjohnwu.magisk.utils.Utils; + +public class EnvFixDialog extends CustomAlertDialog { + + public EnvFixDialog(@NonNull Activity activity) { + super(activity); + MagiskManager mm = Utils.getMagiskManager(activity); + String filename = Utils.fmt("Magisk-v%s(%d).zip", + mm.remoteMagiskVersionString, mm.remoteMagiskVersionCode); + setTitle(R.string.env_fix_title); + setMessage(R.string.env_fix_msg); + setCancelable(true); + setPositiveButton(R.string.yes, (d, i) -> Utils.dlAndReceive(activity, + new DownloadReceiver() { + @Override + public void onDownloadDone(Context context, Uri uri) { + new InstallMagisk(activity, uri).exec(); + } + }, mm.magiskLink, filename)); + setNegativeButton(R.string.no_thanks, null); + } +} diff --git a/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java b/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java index ecc127b1dcc7..837dca09413e 100644 --- a/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java +++ b/app/src/full/java/com/topjohnwu/magisk/components/FlavorActivity.java @@ -1,5 +1,6 @@ package com.topjohnwu.magisk.components; +import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.annotation.StyleRes; @@ -12,6 +13,8 @@ public abstract class FlavorActivity extends AppCompatActivity { + private ActivityResultListener activityResultListener; + @StyleRes public int getDarkTheme() { return -1; @@ -27,7 +30,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { if (this instanceof Topic.Subscriber) { ((Topic.Subscriber) this).subscribeTopics(); } - if (getMagiskManager().isDarkTheme && getDarkTheme() != -1) { setTheme(getDarkTheme()); } @@ -54,4 +56,20 @@ protected void setFloating() { setFinishOnTouchOutside(true); } } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (activityResultListener != null) + activityResultListener.onActivityResult(requestCode, resultCode, data); + activityResultListener = null; + } + + public void startActivityForResult(Intent intent, int requestCode, ActivityResultListener listener) { + activityResultListener = listener; + super.startActivityForResult(intent, requestCode); + } + + public interface ActivityResultListener { + void onActivityResult(int requestCode, int resultCode, Intent data); + } } diff --git a/app/src/full/java/com/topjohnwu/magisk/components/InstallMethodDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/InstallMethodDialog.java new file mode 100644 index 000000000000..c59e224b5370 --- /dev/null +++ b/app/src/full/java/com/topjohnwu/magisk/components/InstallMethodDialog.java @@ -0,0 +1,101 @@ +package com.topjohnwu.magisk.components; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AlertDialog; +import android.widget.Toast; + +import com.topjohnwu.magisk.FlashActivity; +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.receivers.DownloadReceiver; +import com.topjohnwu.magisk.utils.Const; +import com.topjohnwu.magisk.utils.Utils; + +import java.util.List; + +class InstallMethodDialog extends AlertDialog.Builder { + + InstallMethodDialog(Activity activity, List options, String filename) { + super(activity); + MagiskManager mm = Utils.getMagiskManager(activity); + setTitle(R.string.select_method); + setItems(options.toArray(new String [0]), (dialog, idx) -> { + DownloadReceiver receiver = null; + switch (idx) { + case 1: + if (mm.remoteMagiskVersionCode < 1400) { + SnackbarMaker.make(activity, R.string.no_boot_file_patch_support, + Snackbar.LENGTH_LONG).show(); + return; + } + MagiskManager.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG); + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + activity.startActivityForResult(intent, Const.ID.SELECT_BOOT, + (requestCode, resultCode, data) -> { + if (requestCode == Const.ID.SELECT_BOOT && + resultCode == Activity.RESULT_OK && data != null) { + Utils.dlAndReceive(activity, new SelectBoot(data), + mm.magiskLink, filename); + } + }); + return; + case 0: + receiver = new DownloadReceiver() { + @Override + public void onDownloadDone(Context context, Uri uri) { + SnackbarMaker.showUri(activity, uri); + } + }; + break; + case 2: + receiver = new DownloadReceiver() { + @Override + public void onDownloadDone(Context context, Uri uri) { + Intent intent = new Intent(context, FlashActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .setData(uri).putExtra(Const.Key.FLASH_ACTION, + Const.Value.FLASH_MAGISK); + context.startActivity(intent); + } + }; + break; + case 3: + receiver = new DownloadReceiver() { + @Override + public void onDownloadDone(Context context, Uri uri) { + Intent intent = new Intent(context, FlashActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .setData(uri).putExtra(Const.Key.FLASH_ACTION, + Const.Value.FLASH_SECOND_SLOT); + context.startActivity(intent); + } + }; + default: + } + Utils.dlAndReceive(activity, receiver, mm.magiskLink, filename); + }); + } + + private class SelectBoot extends DownloadReceiver { + + private Intent data; + + public SelectBoot(Intent data) { + this.data = data; + } + + @Override + public void onDownloadDone(Context context, Uri uri) { + Intent intent = new Intent(context, FlashActivity.class); + intent.setData(uri) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .putExtra(Const.Key.FLASH_SET_BOOT, data.getData()) + .putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT); + context.startActivity(intent); + } + } +} diff --git a/app/src/full/java/com/topjohnwu/magisk/components/MagiskInstallDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/MagiskInstallDialog.java new file mode 100644 index 000000000000..6fcb2bb9d4fc --- /dev/null +++ b/app/src/full/java/com/topjohnwu/magisk/components/MagiskInstallDialog.java @@ -0,0 +1,53 @@ +package com.topjohnwu.magisk.components; + +import android.content.Intent; +import android.net.Uri; +import android.text.TextUtils; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.asyncs.MarkDownWindow; +import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; +import com.topjohnwu.superuser.ShellUtils; + +import java.util.ArrayList; +import java.util.List; + +public class MagiskInstallDialog extends CustomAlertDialog { + public MagiskInstallDialog(Activity activity) { + super(activity); + MagiskManager mm = Utils.getMagiskManager(activity); + String filename = Utils.fmt("Magisk-v%s(%d).zip", + mm.remoteMagiskVersionString, mm.remoteMagiskVersionCode); + setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.magisk))); + setMessage(mm.getString(R.string.repo_install_msg, filename)); + setCancelable(true); + setPositiveButton(R.string.install, (d, i) -> { + List options = new ArrayList<>(); + options.add(mm.getString(R.string.download_zip_only)); + options.add(mm.getString(R.string.patch_boot_file)); + if (Shell.rootAccess()) { + options.add(mm.getString(R.string.direct_install)); + } + String s = ShellUtils.fastCmd("grep_prop ro.build.ab_update"); + if (!s.isEmpty() && Boolean.parseBoolean(s)) { + options.add(mm.getString(R.string.install_second_slot)); + } + new InstallMethodDialog(activity, options, filename).show(); + }); + setNegativeButton(R.string.no_thanks, null); + if (!TextUtils.isEmpty(mm.magiskNoteLink)) { + setNeutralButton(R.string.release_notes, (d, i) -> { + if (mm.magiskNoteLink.contains("forum.xda-developers")) { + // Open forum links in browser + Intent openLink = new Intent(Intent.ACTION_VIEW, Uri.parse(mm.magiskNoteLink)); + openLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mm.startActivity(openLink); + } else { + new MarkDownWindow(activity, null, mm.magiskNoteLink).exec(); + } + }); + } + } +} diff --git a/app/src/full/java/com/topjohnwu/magisk/components/ManagerInstallDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/ManagerInstallDialog.java new file mode 100644 index 000000000000..31486b4bcbeb --- /dev/null +++ b/app/src/full/java/com/topjohnwu/magisk/components/ManagerInstallDialog.java @@ -0,0 +1,38 @@ +package com.topjohnwu.magisk.components; + +import android.Manifest; +import android.content.Intent; +import android.support.annotation.NonNull; +import android.text.TextUtils; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.asyncs.MarkDownWindow; +import com.topjohnwu.magisk.receivers.ManagerUpdate; +import com.topjohnwu.magisk.utils.Const; +import com.topjohnwu.magisk.utils.Utils; + +public class ManagerInstallDialog extends CustomAlertDialog { + + public ManagerInstallDialog(@NonNull Activity activity) { + super(activity); + MagiskManager mm = Utils.getMagiskManager(activity); + String filename = Utils.fmt("MagiskManager-v%s(%d).apk", + mm.remoteManagerVersionString, mm.remoteManagerVersionCode); + setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name))); + setMessage(mm.getString(R.string.repo_install_msg, filename)); + setCancelable(true); + setPositiveButton(R.string.install, (d, i) -> activity.runWithPermission( + new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, () -> { + Intent intent = new Intent(mm, ManagerUpdate.class); + intent.putExtra(Const.Key.INTENT_SET_LINK, mm.managerLink); + intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename); + mm.sendBroadcast(intent); + })) + .setNegativeButton(R.string.no_thanks, null); + if (!TextUtils.isEmpty(mm.managerNoteLink)) { + setNeutralButton(R.string.app_changelog, (d, i) -> + new MarkDownWindow(activity, null, mm.managerNoteLink).exec()); + } + } +} diff --git a/app/src/full/java/com/topjohnwu/magisk/components/UninstallDialog.java b/app/src/full/java/com/topjohnwu/magisk/components/UninstallDialog.java new file mode 100644 index 000000000000..e5ca5e7e8e9c --- /dev/null +++ b/app/src/full/java/com/topjohnwu/magisk/components/UninstallDialog.java @@ -0,0 +1,40 @@ +package com.topjohnwu.magisk.components; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.text.TextUtils; + +import com.topjohnwu.magisk.FlashActivity; +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.asyncs.RestoreImages; +import com.topjohnwu.magisk.receivers.DownloadReceiver; +import com.topjohnwu.magisk.utils.Const; +import com.topjohnwu.magisk.utils.Utils; + +public class UninstallDialog extends CustomAlertDialog { + + public UninstallDialog(@NonNull Activity activity) { + super(activity); + MagiskManager mm = Utils.getMagiskManager(activity); + setTitle(R.string.uninstall_magisk_title); + setMessage(R.string.uninstall_magisk_msg); + setNeutralButton(R.string.restore_img, (d, i) -> new RestoreImages(activity).exec()); + if (!TextUtils.isEmpty(mm.uninstallerLink)) { + setPositiveButton(R.string.complete_uninstall, (d, i) -> + Utils.dlAndReceive(activity, new DownloadReceiver() { + @Override + public void onDownloadDone(Context context, Uri uri) { + Intent intent = new Intent(context, FlashActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .setData(uri) + .putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL); + context.startActivity(intent); + } + }, mm.uninstallerLink, "magisk-uninstaller.zip")); + } + } +} diff --git a/app/src/full/java/com/topjohnwu/magisk/services/OnBootService.java b/app/src/full/java/com/topjohnwu/magisk/services/OnBootService.java index 26f8153c3bff..0613ec6fc780 100644 --- a/app/src/full/java/com/topjohnwu/magisk/services/OnBootService.java +++ b/app/src/full/java/com/topjohnwu/magisk/services/OnBootService.java @@ -6,7 +6,7 @@ import android.support.v4.app.JobIntentService; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.ShowUI; +import com.topjohnwu.magisk.utils.NotificationMgr; import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.ShellUtils; @@ -28,6 +28,6 @@ protected void onHandleWork(@NonNull Intent intent) { Shell shell = Shell.newInstance(); if (shell.getStatus() >= Shell.ROOT_SHELL && Boolean.parseBoolean(ShellUtils.fastCmd(shell, "mm_patch_dtbo"))) - ShowUI.dtboPatchedNotification(); + NotificationMgr.dtboPatched(); } } diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/NotificationMgr.java b/app/src/full/java/com/topjohnwu/magisk/utils/NotificationMgr.java new file mode 100644 index 000000000000..1f26539bfd5e --- /dev/null +++ b/app/src/full/java/com/topjohnwu/magisk/utils/NotificationMgr.java @@ -0,0 +1,84 @@ +package com.topjohnwu.magisk.utils; + +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.TaskStackBuilder; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.SplashActivity; +import com.topjohnwu.magisk.receivers.ManagerUpdate; +import com.topjohnwu.magisk.receivers.RebootReceiver; + +public class NotificationMgr { + + public static void magiskUpdate() { + MagiskManager mm = MagiskManager.get(); + + Intent intent = new Intent(mm, SplashActivity.class); + intent.putExtra(Const.Key.OPEN_SECTION, "magisk"); + TaskStackBuilder stackBuilder = TaskStackBuilder.create(mm); + stackBuilder.addParentStack(SplashActivity.class); + stackBuilder.addNextIntent(intent); + PendingIntent pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, + PendingIntent.FLAG_UPDATE_CURRENT); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL); + builder.setSmallIcon(R.drawable.ic_magisk_outline) + .setContentTitle(mm.getString(R.string.magisk_update_title)) + .setContentText(mm.getString(R.string.magisk_update_available, mm.remoteMagiskVersionString)) + .setVibrate(new long[]{0, 100, 100, 100}) + .setAutoCancel(true) + .setContentIntent(pendingIntent); + + NotificationManager notificationManager = + (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build()); + } + + public static void managerUpdate() { + MagiskManager mm = MagiskManager.get(); + String filename = Utils.fmt("MagiskManager-v%s(%d).apk", + mm.remoteManagerVersionString, mm.remoteManagerVersionCode); + + Intent intent = new Intent(mm, ManagerUpdate.class); + intent.putExtra(Const.Key.INTENT_SET_LINK, mm.managerLink); + intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename); + PendingIntent pendingIntent = PendingIntent.getBroadcast(mm, + Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL); + builder.setSmallIcon(R.drawable.ic_magisk_outline) + .setContentTitle(mm.getString(R.string.manager_update_title)) + .setContentText(mm.getString(R.string.manager_download_install)) + .setVibrate(new long[]{0, 100, 100, 100}) + .setAutoCancel(true) + .setContentIntent(pendingIntent); + + NotificationManager notificationManager = + (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build()); + } + + public static void dtboPatched() { + MagiskManager mm = MagiskManager.get(); + + Intent intent = new Intent(mm, RebootReceiver.class); + PendingIntent pendingIntent = PendingIntent.getBroadcast(mm, + Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL); + builder.setSmallIcon(R.drawable.ic_magisk_outline) + .setContentTitle(mm.getString(R.string.dtbo_patched_title)) + .setContentText(mm.getString(R.string.dtbo_patched_reboot)) + .setVibrate(new long[]{0, 100, 100, 100}) + .addAction(R.drawable.ic_refresh, mm.getString(R.string.reboot), pendingIntent); + + NotificationManager notificationManager = + (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build()); + } +} diff --git a/app/src/full/java/com/topjohnwu/magisk/utils/ShowUI.java b/app/src/full/java/com/topjohnwu/magisk/utils/ShowUI.java deleted file mode 100644 index 66f95ed76aa6..000000000000 --- a/app/src/full/java/com/topjohnwu/magisk/utils/ShowUI.java +++ /dev/null @@ -1,278 +0,0 @@ -package com.topjohnwu.magisk.utils; - -import android.Manifest; -import android.app.Activity; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.support.v4.app.NotificationCompat; -import android.support.v4.app.TaskStackBuilder; -import android.support.v7.app.AlertDialog; -import android.text.TextUtils; -import android.widget.Toast; - -import com.topjohnwu.magisk.FlashActivity; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.SplashActivity; -import com.topjohnwu.magisk.asyncs.InstallMagisk; -import com.topjohnwu.magisk.asyncs.MarkDownWindow; -import com.topjohnwu.magisk.asyncs.RestoreImages; -import com.topjohnwu.magisk.components.AlertDialogBuilder; -import com.topjohnwu.magisk.components.SnackbarMaker; -import com.topjohnwu.magisk.receivers.DownloadReceiver; -import com.topjohnwu.magisk.receivers.ManagerUpdate; -import com.topjohnwu.magisk.receivers.RebootReceiver; -import com.topjohnwu.superuser.Shell; -import com.topjohnwu.superuser.ShellUtils; - -import java.util.ArrayList; -import java.util.List; - -public class ShowUI { - - public static void magiskUpdateNotification() { - MagiskManager mm = MagiskManager.get(); - - Intent intent = new Intent(mm, SplashActivity.class); - intent.putExtra(Const.Key.OPEN_SECTION, "magisk"); - TaskStackBuilder stackBuilder = TaskStackBuilder.create(mm); - stackBuilder.addParentStack(SplashActivity.class); - stackBuilder.addNextIntent(intent); - PendingIntent pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, - PendingIntent.FLAG_UPDATE_CURRENT); - - NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL); - builder.setSmallIcon(R.drawable.ic_magisk_outline) - .setContentTitle(mm.getString(R.string.magisk_update_title)) - .setContentText(mm.getString(R.string.magisk_update_available, mm.remoteMagiskVersionString)) - .setVibrate(new long[]{0, 100, 100, 100}) - .setAutoCancel(true) - .setContentIntent(pendingIntent); - - NotificationManager notificationManager = - (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build()); - } - - public static void managerUpdateNotification() { - MagiskManager mm = MagiskManager.get(); - String filename = Utils.fmt("MagiskManager-v%s(%d).apk", - mm.remoteManagerVersionString, mm.remoteManagerVersionCode); - - Intent intent = new Intent(mm, ManagerUpdate.class); - intent.putExtra(Const.Key.INTENT_SET_LINK, mm.managerLink); - intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename); - PendingIntent pendingIntent = PendingIntent.getBroadcast(mm, - Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); - - NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL); - builder.setSmallIcon(R.drawable.ic_magisk_outline) - .setContentTitle(mm.getString(R.string.manager_update_title)) - .setContentText(mm.getString(R.string.manager_download_install)) - .setVibrate(new long[]{0, 100, 100, 100}) - .setAutoCancel(true) - .setContentIntent(pendingIntent); - - NotificationManager notificationManager = - (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build()); - } - - public static void dtboPatchedNotification() { - MagiskManager mm = MagiskManager.get(); - - Intent intent = new Intent(mm, RebootReceiver.class); - PendingIntent pendingIntent = PendingIntent.getBroadcast(mm, - Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); - - NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL); - builder.setSmallIcon(R.drawable.ic_magisk_outline) - .setContentTitle(mm.getString(R.string.dtbo_patched_title)) - .setContentText(mm.getString(R.string.dtbo_patched_reboot)) - .setVibrate(new long[]{0, 100, 100, 100}) - .addAction(R.drawable.ic_refresh, mm.getString(R.string.reboot), pendingIntent); - - NotificationManager notificationManager = - (NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build()); - } - - public static void envFixDialog(Activity activity) { - MagiskManager mm = Utils.getMagiskManager(activity); - String filename = Utils.fmt("Magisk-v%s(%d).zip", - mm.remoteMagiskVersionString, mm.remoteMagiskVersionCode); - new AlertDialogBuilder(activity) - .setTitle(R.string.env_fix_title) - .setMessage(R.string.env_fix_msg) - .setCancelable(true) - .setPositiveButton(R.string.yes, (d, i) -> { - Utils.dlAndReceive(activity, new DownloadReceiver() { - @Override - public void onDownloadDone(Context context, Uri uri) { - new InstallMagisk(activity, uri).exec(); - } - }, mm.magiskLink, filename); - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } - - public static void magiskInstallDialog(Activity activity) { - MagiskManager mm = Utils.getMagiskManager(activity); - String filename = Utils.fmt("Magisk-v%s(%d).zip", - mm.remoteMagiskVersionString, mm.remoteMagiskVersionCode); - AlertDialog.Builder b = new AlertDialogBuilder(activity) - .setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.magisk))) - .setMessage(mm.getString(R.string.repo_install_msg, filename)) - .setCancelable(true) - .setPositiveButton(R.string.install, (d, i) -> { - List options = new ArrayList<>(); - options.add(mm.getString(R.string.download_zip_only)); - options.add(mm.getString(R.string.patch_boot_file)); - if (Shell.rootAccess()) { - options.add(mm.getString(R.string.direct_install)); - } - String s = ShellUtils.fastCmd("grep_prop ro.build.ab_update"); - if (s != null && Boolean.parseBoolean(s)) { - options.add(mm.getString(R.string.install_second_slot)); - } - new AlertDialog.Builder(activity) - .setTitle(R.string.select_method) - .setItems( - options.toArray(new String [0]), - (dialog, idx) -> { - DownloadReceiver receiver = null; - switch (idx) { - case 1: - if (mm.remoteMagiskVersionCode < 1400) { - MagiskManager.toast(R.string.no_boot_file_patch_support, Toast.LENGTH_LONG); - return; - } - MagiskManager.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG); - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("*/*"); - ((com.topjohnwu.magisk.components.Activity) activity) - .startActivityForResult(intent, Const.ID.SELECT_BOOT, - (requestCode, resultCode, data) -> { - if (requestCode == Const.ID.SELECT_BOOT - && resultCode == Activity.RESULT_OK && data != null) { - Utils.dlAndReceive( - activity, - new DownloadReceiver() { - @Override - public void onDownloadDone(Context context, Uri uri) { - Intent intent = new Intent(mm, FlashActivity.class); - intent.setData(uri) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(Const.Key.FLASH_SET_BOOT, data.getData()) - .putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT); - mm.startActivity(intent); - } - }, - mm.magiskLink, - filename - ); - } - }); - return; - case 0: - receiver = new DownloadReceiver() { - @Override - public void onDownloadDone(Context context, Uri uri) { - SnackbarMaker.showUri(activity, uri); - } - }; - break; - case 2: - receiver = new DownloadReceiver() { - @Override - public void onDownloadDone(Context context, Uri uri) { - Intent intent = new Intent(mm, FlashActivity.class); - intent.setData(uri).putExtra(Const.Key.FLASH_ACTION, - Const.Value.FLASH_MAGISK); - activity.startActivity(intent); - } - }; - break; - case 3: - receiver = new DownloadReceiver() { - @Override - public void onDownloadDone(Context context, Uri uri) { - Intent intent = new Intent(mm, FlashActivity.class); - intent.setData(uri).putExtra(Const.Key.FLASH_ACTION, - Const.Value.FLASH_SECOND_SLOT); - activity.startActivity(intent); - } - }; - default: - } - Utils.dlAndReceive(activity, receiver, mm.magiskLink, filename); - } - ).show(); - }) - .setNegativeButton(R.string.no_thanks, null); - if (!TextUtils.isEmpty(mm.magiskNoteLink)) { - b.setNeutralButton(R.string.release_notes, (d, i) -> { - if (mm.magiskNoteLink.contains("forum.xda-developers")) { - // Open forum links in browser - Intent openLink = new Intent(Intent.ACTION_VIEW, Uri.parse(mm.magiskNoteLink)); - openLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mm.startActivity(openLink); - } else { - new MarkDownWindow(activity, null, mm.magiskNoteLink).exec(); - } - }); - } - b.show(); - } - - public static void managerInstallDialog(Activity activity) { - MagiskManager mm = Utils.getMagiskManager(activity); - String filename = Utils.fmt("MagiskManager-v%s(%d).apk", - mm.remoteManagerVersionString, mm.remoteManagerVersionCode); - AlertDialog.Builder b = new AlertDialogBuilder(activity) - .setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name))) - .setMessage(mm.getString(R.string.repo_install_msg, filename)) - .setCancelable(true) - .setPositiveButton(R.string.install, (d, i) -> { - com.topjohnwu.magisk.components.Activity.runWithPermission(activity, - new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, () -> { - Intent intent = new Intent(mm, ManagerUpdate.class); - intent.putExtra(Const.Key.INTENT_SET_LINK, mm.managerLink); - intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename); - mm.sendBroadcast(intent); - }); - }) - .setNegativeButton(R.string.no_thanks, null); - if (!TextUtils.isEmpty(mm.managerNoteLink)) { - b.setNeutralButton(R.string.app_changelog, (d, i) -> - new MarkDownWindow(activity, null, mm.managerNoteLink).exec()); - } - b.show(); - } - - public static void uninstallDialog(Activity activity) { - MagiskManager mm = Utils.getMagiskManager(activity); - AlertDialog.Builder b = new AlertDialogBuilder(activity) - .setTitle(R.string.uninstall_magisk_title) - .setMessage(R.string.uninstall_magisk_msg) - .setNeutralButton(R.string.restore_img, (d, i) -> new RestoreImages(activity).exec()); - if (!TextUtils.isEmpty(mm.uninstallerLink)) { - b.setPositiveButton(R.string.complete_uninstall, (d, i) -> - Utils.dlAndReceive(activity, new DownloadReceiver() { - @Override - public void onDownloadDone(Context context, Uri uri) { - Intent intent = new Intent(context, FlashActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .setData(uri) - .putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL); - context.startActivity(intent); - } - }, mm.uninstallerLink, "magisk-uninstaller.zip")); - } - b.show(); - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/components/Activity.java b/app/src/main/java/com/topjohnwu/magisk/components/Activity.java index 9c0e75c442e6..3cc4aba96b61 100644 --- a/app/src/main/java/com/topjohnwu/magisk/components/Activity.java +++ b/app/src/main/java/com/topjohnwu/magisk/components/Activity.java @@ -17,8 +17,6 @@ public abstract class Activity extends FlavorActivity { protected static Runnable permissionGrantCallback; - private ActivityResultListener activityResultListener; - public Activity() { super(); Configuration configuration = new Configuration(); @@ -74,21 +72,4 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis } permissionGrantCallback = null; } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (activityResultListener != null) - activityResultListener.onActivityResult(requestCode, resultCode, data); - activityResultListener = null; - } - - public void startActivityForResult(Intent intent, int requestCode, ActivityResultListener listener) { - activityResultListener = listener; - super.startActivityForResult(intent, requestCode); - } - - public interface ActivityResultListener { - void onActivityResult(int requestCode, int resultCode, Intent data); - } - } From b8eaff66faa0e10796f91d27a7398a2afb0e7610 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 28 Jul 2018 23:40:41 +0800 Subject: [PATCH 4/4] Shrink snet APK, and prevent crashing --- .../com/topjohnwu/magisk/utils/Const.java | 4 +-- snet/build.gradle | 7 +++-- snet/proguard-rules.pro | 3 +- .../com/topjohnwu/snet/ModdedGPSUtil.java | 29 ++++++++++--------- .../com/topjohnwu/snet/SafetyNetHelper.java | 8 ++--- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Const.java b/app/src/main/java/com/topjohnwu/magisk/utils/Const.java index 122a1d3d486f..b7ffbb5aa2a0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Const.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Const.java @@ -39,7 +39,7 @@ public class Const { // Versions public static final int UPDATE_SERVICE_VER = 1; - public static final int SNET_VER = 9; + public static final int SNET_VER = 10; public static int MIN_MODULE_VER() { return MagiskManager.get().magiskVersionCode >= MAGISK_VER.REMOVE_LEGACY_LINK ? 1500 : 1400; @@ -81,7 +81,7 @@ public static class ID { public static class Url { public static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json"; public static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/beta.json"; - public static final String SNET_URL = "https://github.com/topjohnwu/magisk_files/raw/fc819e3974e96d0e4430a2957df4410971ebd6f3/snet.apk"; + public static final String SNET_URL = "https://github.com/topjohnwu/magisk_files/raw/a300521162587da23e45010797bfd8c9a03594f6/snet.apk"; public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&page=%d"; public static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s"; public static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip"; diff --git a/snet/build.gradle b/snet/build.gradle index 23a48418299e..31a144e43de5 100644 --- a/snet/build.gradle +++ b/snet/build.gradle @@ -16,12 +16,15 @@ android { release { minifyEnabled true shrinkResources true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.google.android.gms:play-services-safetynet:7.0.0' /* The oldest version */ + /* The oldest version */ + implementation('com.google.android.gms:play-services-safetynet:7.0.0') { + exclude module: 'support-v4' + } } diff --git a/snet/proguard-rules.pro b/snet/proguard-rules.pro index 8cc07d286cc7..6f3f1285f82e 100644 --- a/snet/proguard-rules.pro +++ b/snet/proguard-rules.pro @@ -20,6 +20,7 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile --keep class com.topjohnwu.snet.* { *; } +-ignorewarnings +-keep class com.topjohnwu.snet.Snet { *; } -dontwarn java.lang.invoke** -dontwarn com.google.android.gms.common.GooglePlayServicesUtil** diff --git a/snet/src/main/java/com/topjohnwu/snet/ModdedGPSUtil.java b/snet/src/main/java/com/topjohnwu/snet/ModdedGPSUtil.java index 918c686617f7..3ab005e04a6e 100644 --- a/snet/src/main/java/com/topjohnwu/snet/ModdedGPSUtil.java +++ b/snet/src/main/java/com/topjohnwu/snet/ModdedGPSUtil.java @@ -5,13 +5,14 @@ import android.app.Dialog; import android.content.Context; import android.content.ContextWrapper; +import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Resources; import android.util.Log; import com.google.android.gms.common.GooglePlayServicesUtil; -import com.google.android.gms.common.internal.zzg; import com.google.android.gms.internal.zzlu; /* Decompiled and modified from GooglePlayServiceUtil.class */ @@ -20,7 +21,7 @@ public class ModdedGPSUtil { private static final String TAG = "GooglePlayServicesUtil"; static String dexPath; - static Dialog getErrorDialog(int errCode, Activity activity, int requestCode) { + static Dialog getErrorDialog(int errCode, final Activity activity, final int requestCode) { SwapResContext ctx = new SwapResContext(activity, dexPath); Resources res = ctx.getResources(); if (zzlu.zzQ(ctx) && errCode == 2) { @@ -33,8 +34,16 @@ static Dialog getErrorDialog(int errCode, Activity activity, int requestCode) { String btnMsg = GooglePlayServicesUtil.zzf(ctx, errCode); if (btnMsg != null) { - Intent intent = GooglePlayServicesUtil.zzan(errCode); - builder.setPositiveButton(btnMsg, new zzg(activity, intent, requestCode)); + final Intent intent = GooglePlayServicesUtil.zzan(errCode); + builder.setPositiveButton(btnMsg, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int i) { + PackageManager pm = activity.getPackageManager(); + if (intent != null && intent.resolveActivity(pm) != null) + activity.startActivityForResult(intent, requestCode); + dialog.dismiss(); + } + }); } switch(errCode) { @@ -116,20 +125,14 @@ public static class SwapResContext extends ContextWrapper { public SwapResContext(Context base, String apk) { super(base); - asset = getAssets(apk); - Resources res = base.getResources(); - resources = new Resources(asset, res.getDisplayMetrics(), res.getConfiguration()); - } - - private AssetManager getAssets(String apk) { try { - AssetManager asset = AssetManager.class.newInstance(); + asset = AssetManager.class.newInstance(); AssetManager.class.getMethod("addAssetPath", String.class).invoke(asset, apk); - return asset; } catch (Exception e) { e.printStackTrace(); - return null; } + Resources res = base.getResources(); + resources = new Resources(asset, res.getDisplayMetrics(), res.getConfiguration()); } @Override diff --git a/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java b/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java index 777d0a49646f..419e281120bf 100644 --- a/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java +++ b/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java @@ -2,8 +2,6 @@ import android.app.Activity; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.util.Base64; import com.google.android.gms.common.ConnectionResult; @@ -31,7 +29,7 @@ public class SafetyNetHelper implements InvocationHandler, GoogleApiClient.Conne public static final int BASIC_PASS = 0x10; public static final int CTS_PASS = 0x20; - public static final int SNET_EXT_VER = 9; + public static final int SNET_EXT_VER = 10; private GoogleApiClient mGoogleApiClient; private Activity mActivity; @@ -81,14 +79,14 @@ public void onConnectionSuspended(int i) { } @Override - public void onConnectionFailed(@NonNull ConnectionResult result) { + public void onConnectionFailed(ConnectionResult result) { if (GooglePlayServicesUtil.isUserRecoverableError(result.getErrorCode())) ModdedGPSUtil.getErrorDialog(result.getErrorCode(), mActivity, 0).show(); invokeCallback(CONNECTION_FAIL); } @Override - public void onConnected(@Nullable Bundle bundle) { + public void onConnected(Bundle bundle) { // Create nonce byte[] nonce = new byte[24]; new SecureRandom().nextBytes(nonce);