mirror of
https://github.com/topjohnwu/Magisk
synced 2025-11-11 03:47:37 +01:00
Compare commits
36 Commits
manager-v5
...
manager-v5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
759e905c3c | ||
|
|
8bf7e42913 | ||
|
|
0dcd073554 | ||
|
|
2fe35d578d | ||
|
|
8d139e156e | ||
|
|
7c2849356a | ||
|
|
0025ffd1c0 | ||
|
|
2ef7146642 | ||
|
|
1b27e69e40 | ||
|
|
8e7b757efd | ||
|
|
1ab543cea1 | ||
|
|
a3f86903e4 | ||
|
|
c239c305ab | ||
|
|
2e02af994e | ||
|
|
836d9afe17 | ||
|
|
007a352742 | ||
|
|
e526e5659e | ||
|
|
4a5227c7bf | ||
|
|
c2c151ec4c | ||
|
|
452096e7e4 | ||
|
|
50c2a9859e | ||
|
|
677b667307 | ||
|
|
1adf331268 | ||
|
|
349b3e961b | ||
|
|
96650c06f0 | ||
|
|
26038a0a07 | ||
|
|
6a148b5dd9 | ||
|
|
0e109ef979 | ||
|
|
de2285d5e9 | ||
|
|
b2483ba437 | ||
|
|
a82a5e5a49 | ||
|
|
d161a02e71 | ||
|
|
d2b6a700b1 | ||
|
|
af203cef24 | ||
|
|
673e917e76 | ||
|
|
a3bd41db54 |
@@ -2,14 +2,14 @@ apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion "27.0.2"
|
||||
buildToolsVersion "27.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.topjohnwu.magisk"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 27
|
||||
versionCode 80
|
||||
versionName "5.5.0"
|
||||
versionCode 91
|
||||
versionName "5.5.5"
|
||||
ndk {
|
||||
moduleName 'zipadjust'
|
||||
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
||||
|
||||
3
proguard-rules.pro
vendored
3
proguard-rules.pro
vendored
@@ -22,3 +22,6 @@
|
||||
# BouncyCastle
|
||||
-keep class org.bouncycastle.jcajce.provider.** { *; }
|
||||
-dontwarn javax.naming.**
|
||||
|
||||
# Gson
|
||||
-keepattributes Signature
|
||||
@@ -9,6 +9,7 @@
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
|
||||
<application
|
||||
android:name=".MagiskManager"
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
### v5.5.0
|
||||
- Fix dynamic resource loading, prevent crashes when checking SafetyNet
|
||||
- Update SignAPK to use very little RAM for supporting old devices
|
||||
- Support settings migration after hiding Magisk Manager
|
||||
- Add reboot menu in modules section
|
||||
- Add dark theme to superuser request dialogs
|
||||
- Properly handle new `HIGHCOMP` and add recommended `KEEPVERITY` and `KEEPFORCEENCRYPT` flags for installation
|
||||
- Support new paths for v14.6
|
||||
- Massive improvements in repackaging Magisk Manager
|
||||
### v5.5.5
|
||||
- Fix crashes on Lollipop and some devices that don't follow AOSP standards
|
||||
|
||||
### v5.5.4
|
||||
- Fix on-boot dtbo detection
|
||||
- Add fingerprint authentication for Superuser requests
|
||||
|
||||
@@ -56,7 +56,7 @@ public class FlashActivity extends Activity {
|
||||
void saveLogs() {
|
||||
Calendar now = Calendar.getInstance();
|
||||
String filename = String.format(Locale.US,
|
||||
"install_log_%04d%02d%02d_%02d:%02d:%02d.log",
|
||||
"install_log_%04d%02d%02d_%02d%02d%02d.log",
|
||||
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
||||
|
||||
@@ -91,7 +91,7 @@ public class MagiskFragment extends Fragment
|
||||
new CheckSafetyNet(getActivity()).exec();
|
||||
collapse();
|
||||
};
|
||||
if (mm.snetVersion < 0) {
|
||||
if (!CheckSafetyNet.dexPath.exists()) {
|
||||
// Show dialog
|
||||
new AlertDialogBuilder(getActivity())
|
||||
.setTitle(R.string.proprietary_title)
|
||||
@@ -138,13 +138,9 @@ public class MagiskFragment extends Fragment
|
||||
setupExpandable();
|
||||
|
||||
keepVerityChkbox.setChecked(mm.keepVerity);
|
||||
keepVerityChkbox.setOnCheckedChangeListener((view, isChecked) -> {
|
||||
mm.keepVerity = isChecked;
|
||||
});
|
||||
keepVerityChkbox.setOnCheckedChangeListener((view, checked) -> mm.keepVerity = checked);
|
||||
keepEncChkbox.setChecked(mm.keepEnc);
|
||||
keepEncChkbox.setOnCheckedChangeListener((view, isChecked) -> {
|
||||
mm.keepEnc = isChecked;
|
||||
});
|
||||
keepEncChkbox.setOnCheckedChangeListener((view, checked) -> mm.keepEnc = checked);
|
||||
|
||||
mSwipeRefreshLayout.setOnRefreshListener(this);
|
||||
updateUI();
|
||||
|
||||
@@ -114,7 +114,7 @@ public class MagiskLogFragment extends Fragment {
|
||||
switch (mode) {
|
||||
case 0:
|
||||
StringBuildingList logList = new StringBuildingList();
|
||||
Shell.su(logList, "cat " + Const.MAGISK_LOG + " | tail -n 1000");
|
||||
Shell.su(logList, "cat " + Const.MAGISK_LOG + " | tail -n 5000");
|
||||
return logList.getCharSequence();
|
||||
|
||||
case 1:
|
||||
@@ -125,7 +125,7 @@ public class MagiskLogFragment extends Fragment {
|
||||
case 2:
|
||||
Calendar now = Calendar.getInstance();
|
||||
String filename = String.format(Locale.US,
|
||||
"magisk_log_%04d%02d%02d_%02d:%02d:%02d.log",
|
||||
"magisk_log_%04d%02d%02d_%02d%02d%02d.log",
|
||||
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
||||
|
||||
@@ -49,7 +49,6 @@ public class MagiskManager extends Application {
|
||||
public int remoteManagerVersionCode = -1;
|
||||
public String managerLink;
|
||||
public String bootBlock = null;
|
||||
public int snetVersion;
|
||||
public boolean keepVerity = false;
|
||||
public boolean keepEnc = false;
|
||||
|
||||
@@ -63,8 +62,6 @@ public class MagiskManager extends Application {
|
||||
|
||||
public boolean magiskHide;
|
||||
public boolean isDarkTheme;
|
||||
public boolean updateNotification;
|
||||
public boolean suReauth;
|
||||
public int suRequestTimeout;
|
||||
public int suLogTimeout = 14;
|
||||
public int suAccessState;
|
||||
@@ -75,7 +72,7 @@ public class MagiskManager extends Application {
|
||||
public String localeConfig;
|
||||
public int updateChannel;
|
||||
public String bootFormat;
|
||||
public String customChannelUrl;
|
||||
public int repoOrder;
|
||||
|
||||
// Global resources
|
||||
public SharedPreferences prefs;
|
||||
@@ -106,7 +103,7 @@ public class MagiskManager extends Application {
|
||||
} catch (PackageManager.NameNotFoundException ignored) { /* Expected */ }
|
||||
}
|
||||
|
||||
suDB = new SuDatabaseHelper(false);
|
||||
suDB = SuDatabaseHelper.getSuDB(false);
|
||||
repoDB = new RepoDatabaseHelper(this);
|
||||
defaultLocale = Locale.getDefault();
|
||||
setLocale();
|
||||
@@ -135,21 +132,38 @@ public class MagiskManager extends Application {
|
||||
suRequestTimeout = Utils.getPrefsInt(prefs, Const.Key.SU_REQUEST_TIMEOUT, Const.Value.timeoutList[2]);
|
||||
suResponseType = Utils.getPrefsInt(prefs, Const.Key.SU_AUTO_RESPONSE, Const.Value.SU_PROMPT);
|
||||
suNotificationType = Utils.getPrefsInt(prefs, Const.Key.SU_NOTIFICATION, Const.Value.NOTIFICATION_TOAST);
|
||||
suReauth = prefs.getBoolean(Const.Key.SU_REAUTH, false);
|
||||
suAccessState = suDB.getSettings(Const.Key.ROOT_ACCESS, Const.Value.ROOT_ACCESS_APPS_AND_ADB);
|
||||
multiuserMode = suDB.getSettings(Const.Key.SU_MULTIUSER_MODE, Const.Value.MULTIUSER_MODE_OWNER_ONLY);
|
||||
suNamespaceMode = suDB.getSettings(Const.Key.SU_MNT_NS, Const.Value.NAMESPACE_MODE_REQUESTER);
|
||||
|
||||
// config
|
||||
isDarkTheme = prefs.getBoolean(Const.Key.DARK_THEME, false);
|
||||
updateNotification = prefs.getBoolean(Const.Key.UPDATE_NOTIFICATION, true);
|
||||
updateChannel = Utils.getPrefsInt(prefs, Const.Key.UPDATE_CHANNEL, Const.Value.STABLE_CHANNEL);
|
||||
bootFormat = prefs.getString(Const.Key.BOOT_FORMAT, ".img");
|
||||
snetVersion = prefs.getInt(Const.Key.SNET_VER, -1);
|
||||
customChannelUrl = prefs.getString(Const.Key.CUSTOM_CHANNEL, "");
|
||||
repoOrder = prefs.getInt(Const.Key.REPO_ORDER, Const.Value.ORDER_NAME);
|
||||
}
|
||||
|
||||
public static void toast(String msg, int duration) {
|
||||
public void writeConfig() {
|
||||
prefs.edit()
|
||||
.putBoolean(Const.Key.DARK_THEME, isDarkTheme)
|
||||
.putBoolean(Const.Key.MAGISKHIDE, magiskHide)
|
||||
.putBoolean(Const.Key.HOSTS, Utils.itemExist(Const.MAGISK_HOST_FILE()))
|
||||
.putBoolean(Const.Key.COREONLY, Utils.itemExist(Const.MAGISK_DISABLE_FILE))
|
||||
.putString(Const.Key.SU_REQUEST_TIMEOUT, String.valueOf(suRequestTimeout))
|
||||
.putString(Const.Key.SU_AUTO_RESPONSE, String.valueOf(suResponseType))
|
||||
.putString(Const.Key.SU_NOTIFICATION, String.valueOf(suNotificationType))
|
||||
.putString(Const.Key.ROOT_ACCESS, String.valueOf(suAccessState))
|
||||
.putString(Const.Key.SU_MULTIUSER_MODE, String.valueOf(multiuserMode))
|
||||
.putString(Const.Key.SU_MNT_NS, String.valueOf(suNamespaceMode))
|
||||
.putString(Const.Key.UPDATE_CHANNEL, String.valueOf(updateChannel))
|
||||
.putString(Const.Key.LOCALE, localeConfig)
|
||||
.putString(Const.Key.BOOT_FORMAT, bootFormat)
|
||||
.putInt(Const.Key.UPDATE_SERVICE_VER, Const.UPDATE_SERVICE_VER)
|
||||
.putInt(Const.Key.REPO_ORDER, repoOrder)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void toast(CharSequence msg, int duration) {
|
||||
mHandler.post(() -> Toast.makeText(weakSelf.get(), msg, duration).show());
|
||||
}
|
||||
|
||||
@@ -190,6 +204,14 @@ public class MagiskManager extends Application {
|
||||
if (Utils.isValidShellResponse(ret))
|
||||
bootBlock = ret.get(0);
|
||||
|
||||
if (suDB != null && !SuDatabaseHelper.verified) {
|
||||
suDB.close();
|
||||
suDB = SuDatabaseHelper.getSuDB(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void getDefaultInstallFlags() {
|
||||
List<String> ret;
|
||||
ret = Shell.su("echo \"$DTBOIMAGE\"");
|
||||
if (Utils.isValidShellResponse(ret))
|
||||
keepVerity = true;
|
||||
@@ -213,11 +235,6 @@ public class MagiskManager extends Application {
|
||||
if (Utils.isValidShellResponse(ret))
|
||||
keepEnc = Boolean.parseBoolean(ret.get(0));
|
||||
} catch (NumberFormatException ignored) {}
|
||||
|
||||
if (suDB != null && !SuDatabaseHelper.verified) {
|
||||
suDB.close();
|
||||
suDB = new SuDatabaseHelper();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPermissionGrantCallback(Runnable callback) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
@@ -7,6 +8,7 @@ import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.SearchView;
|
||||
@@ -15,6 +17,7 @@ import android.widget.TextView;
|
||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||
import com.topjohnwu.magisk.components.Fragment;
|
||||
import com.topjohnwu.magisk.utils.Const;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
|
||||
import butterknife.BindView;
|
||||
@@ -98,6 +101,22 @@ public class ReposFragment extends Fragment implements Topic.Subscriber {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
MagiskManager mm = getApplication();
|
||||
if (item.getItemId() == R.id.repo_sort) {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle(R.string.sorting_order)
|
||||
.setSingleChoiceItems(R.array.sorting_orders, mm.repoOrder, (d, which) -> {
|
||||
mm.repoOrder = which;
|
||||
mm.prefs.edit().putInt(Const.Key.REPO_ORDER, mm.repoOrder).apply();
|
||||
adapter.notifyDBChanged();
|
||||
d.dismiss();
|
||||
}).show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||
import com.topjohnwu.magisk.asyncs.HideManager;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.utils.Const;
|
||||
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
@@ -112,13 +113,14 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
|
||||
multiuserMode = (ListPreference) findPreference(Const.Key.SU_MULTIUSER_MODE);
|
||||
namespaceMode = (ListPreference) findPreference(Const.Key.SU_MNT_NS);
|
||||
SwitchPreference reauth = (SwitchPreference) findPreference(Const.Key.SU_REAUTH);
|
||||
SwitchPreference fingerprint = (SwitchPreference) findPreference(Const.Key.SU_FINGERPRINT);
|
||||
|
||||
updateChannel.setOnPreferenceChangeListener((pref, o) -> {
|
||||
mm.updateChannel = Integer.parseInt((String) o);
|
||||
if (mm.updateChannel == Const.Value.CUSTOM_CHANNEL) {
|
||||
View v = LayoutInflater.from(getActivity()).inflate(R.layout.custom_channel_dialog, null);
|
||||
EditText url = v.findViewById(R.id.custom_url);
|
||||
url.setText(mm.customChannelUrl);
|
||||
url.setText(mm.prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle(R.string.settings_update_custom)
|
||||
.setView(v)
|
||||
@@ -144,6 +146,11 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
|
||||
reauth.setSummary(R.string.android_o_not_support);
|
||||
}
|
||||
|
||||
// Remove fingerprint option if not possible
|
||||
if (!FingerprintHelper.canUseFingerprint()) {
|
||||
suCategory.removePreference(fingerprint);
|
||||
}
|
||||
|
||||
if (mm.getPackageName().equals(Const.ORIG_PKG_NAME) && mm.magiskVersionCode >= 1440) {
|
||||
hideManager.setOnPreferenceClickListener((pref) -> {
|
||||
Utils.runWithPermission(getActivity(),
|
||||
|
||||
@@ -34,6 +34,7 @@ public class SplashActivity extends Activity {
|
||||
MagiskManager mm = getMagiskManager();
|
||||
|
||||
mm.loadMagiskInfo();
|
||||
mm.getDefaultInstallFlags();
|
||||
Utils.loadPrefs();
|
||||
|
||||
// Dynamic detect all locales
|
||||
@@ -61,7 +62,7 @@ public class SplashActivity extends Activity {
|
||||
if (Shell.rootAccess() && mm.magiskVersionCode > 0) {
|
||||
|
||||
// Add update checking service
|
||||
if (Const.Value.UPDATE_SERVICE_VER > mm.prefs.getInt(Const.Key.UPDATE_SERVICE_VER, -1)) {
|
||||
if (Const.UPDATE_SERVICE_VER > mm.prefs.getInt(Const.Key.UPDATE_SERVICE_VER, -1)) {
|
||||
ComponentName service = new ComponentName(this, UpdateCheckService.class);
|
||||
JobInfo info = new JobInfo.Builder(Const.ID.UPDATE_SERVICE_ID, service)
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
||||
@@ -79,24 +80,7 @@ public class SplashActivity extends Activity {
|
||||
}
|
||||
|
||||
// Write back default values
|
||||
mm.prefs.edit()
|
||||
.putBoolean(Const.Key.DARK_THEME, mm.isDarkTheme)
|
||||
.putBoolean(Const.Key.MAGISKHIDE, mm.magiskHide)
|
||||
.putBoolean(Const.Key.UPDATE_NOTIFICATION, mm.updateNotification)
|
||||
.putBoolean(Const.Key.HOSTS, Utils.itemExist(Const.MAGISK_HOST_FILE()))
|
||||
.putBoolean(Const.Key.COREONLY, Utils.itemExist(Const.MAGISK_DISABLE_FILE))
|
||||
.putBoolean(Const.Key.SU_REAUTH, mm.suReauth)
|
||||
.putString(Const.Key.SU_REQUEST_TIMEOUT, String.valueOf(mm.suRequestTimeout))
|
||||
.putString(Const.Key.SU_AUTO_RESPONSE, String.valueOf(mm.suResponseType))
|
||||
.putString(Const.Key.SU_NOTIFICATION, String.valueOf(mm.suNotificationType))
|
||||
.putString(Const.Key.ROOT_ACCESS, String.valueOf(mm.suAccessState))
|
||||
.putString(Const.Key.SU_MULTIUSER_MODE, String.valueOf(mm.multiuserMode))
|
||||
.putString(Const.Key.SU_MNT_NS, String.valueOf(mm.suNamespaceMode))
|
||||
.putString(Const.Key.UPDATE_CHANNEL, String.valueOf(mm.updateChannel))
|
||||
.putString(Const.Key.LOCALE, mm.localeConfig)
|
||||
.putString(Const.Key.BOOT_FORMAT, mm.bootFormat)
|
||||
.putInt(Const.Key.UPDATE_SERVICE_VER, Const.Value.UPDATE_SERVICE_VER)
|
||||
.apply();
|
||||
mm.writeConfig();
|
||||
|
||||
mm.hasInit = true;
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
|
||||
|
||||
@BindView(R.id.app_icon) ImageView appIcon;
|
||||
@BindView(R.id.app_name) TextView appName;
|
||||
@BindView(R.id.app_package) TextView appPackage;
|
||||
@BindView(R.id.package_name) TextView appPackage;
|
||||
@BindView(R.id.checkbox) CheckBox checkBox;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
|
||||
@@ -95,6 +95,7 @@ public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, R
|
||||
String author = repo.getAuthor();
|
||||
holder.author.setText(TextUtils.isEmpty(author) ? null : context.getString(R.string.author, author));
|
||||
holder.description.setText(repo.getDescription());
|
||||
holder.updateTime.setText(context.getString(R.string.updated_on, repo.getLastUpdateString()));
|
||||
|
||||
holder.infoLayout.setOnClickListener(v ->
|
||||
new MarkDownWindow((Activity) context, null, repo.getDetailUrl()).exec());
|
||||
@@ -180,6 +181,7 @@ public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, R
|
||||
@BindView(R.id.author) TextView author;
|
||||
@BindView(R.id.info_layout) LinearLayout infoLayout;
|
||||
@BindView(R.id.download) ImageView downloadImage;
|
||||
@BindView(R.id.update_time) TextView updateTime;
|
||||
|
||||
RepoHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Proxy;
|
||||
@@ -21,28 +22,17 @@ import dalvik.system.DexClassLoader;
|
||||
|
||||
public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
|
||||
|
||||
private File dexPath;
|
||||
public static final File dexPath =
|
||||
new File(MagiskManager.get().getFilesDir().getParent() + "/snet", "snet.apk");
|
||||
private DexClassLoader loader;
|
||||
private Class<?> helperClazz, callbackClazz;
|
||||
|
||||
public CheckSafetyNet(Activity activity) {
|
||||
super(activity);
|
||||
dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
MagiskManager mm = MagiskManager.get();
|
||||
if (mm.snetVersion != Const.Value.SNET_VER) {
|
||||
private void dlSnet() throws IOException {
|
||||
Shell.sh("rm -rf " + dexPath.getParent());
|
||||
}
|
||||
mm.snetVersion = Const.Value.SNET_VER;
|
||||
mm.prefs.edit().putInt(Const.Key.SNET_VER, Const.Value.SNET_VER).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Exception doInBackground(Void... voids) {
|
||||
try {
|
||||
if (!dexPath.exists()) {
|
||||
HttpURLConnection conn = WebService.request(Const.Url.SNET_URL, null);
|
||||
dexPath.getParentFile().mkdir();
|
||||
try (
|
||||
@@ -52,11 +42,37 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
|
||||
}
|
||||
conn.disconnect();
|
||||
}
|
||||
|
||||
private void loadClasses() throws ClassNotFoundException {
|
||||
loader = new DexClassLoader(dexPath.toString(), dexPath.getParent(),
|
||||
null, ClassLoader.getSystemClassLoader());
|
||||
helperClazz = loader.loadClass(Const.SNET_PKG + ".SafetyNetHelper");
|
||||
callbackClazz = loader.loadClass(Const.SNET_PKG + ".SafetyNetCallback");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Exception doInBackground(Void... voids) {
|
||||
int snet_ver = -1;
|
||||
|
||||
try {
|
||||
if (!dexPath.exists())
|
||||
dlSnet();
|
||||
loadClasses();
|
||||
|
||||
try {
|
||||
snet_ver = (int) helperClazz.getMethod("getVersion").invoke(null);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (snet_ver != Const.SNET_VER) {
|
||||
dlSnet();
|
||||
loadClasses();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -65,8 +81,6 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
|
||||
MagiskManager mm = MagiskManager.get();
|
||||
try {
|
||||
if (err != null) throw err;
|
||||
Class<?> helperClazz = loader.loadClass(Const.SNET_PKG + ".SafetyNetHelper");
|
||||
Class<?> callbackClazz = loader.loadClass(Const.SNET_PKG + ".SafetyNetCallback");
|
||||
Object helper = helperClazz.getConstructors()[0].newInstance(
|
||||
getActivity(), dexPath.getPath(), Proxy.newProxyInstance(
|
||||
loader, new Class[] { callbackClazz }, (proxy, method, args) -> {
|
||||
|
||||
@@ -33,7 +33,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
jsonStr = WebService.getString(Const.Url.BETA_URL);
|
||||
break;
|
||||
case Const.Value.CUSTOM_CHANNEL:
|
||||
jsonStr = WebService.getString(mm.customChannelUrl);
|
||||
jsonStr = WebService.getString(mm.prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
||||
break;
|
||||
}
|
||||
try {
|
||||
@@ -54,7 +54,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
||||
@Override
|
||||
protected void onPostExecute(Void v) {
|
||||
MagiskManager mm = MagiskManager.get();
|
||||
if (showNotification && mm.updateNotification) {
|
||||
if (showNotification && mm.prefs.getBoolean(Const.Key.UPDATE_NOTIFICATION, true)) {
|
||||
if (BuildConfig.VERSION_CODE < mm.remoteManagerVersionCode) {
|
||||
ShowUI.managerUpdateNotification();
|
||||
} else if (mm.magiskVersionCode < mm.remoteMagiskVersionCode) {
|
||||
|
||||
@@ -3,9 +3,11 @@ package com.topjohnwu.magisk.container;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.utils.Const;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class Repo extends BaseModule {
|
||||
@@ -40,7 +42,7 @@ public class Repo extends BaseModule {
|
||||
if (getVersionCode() < 0) {
|
||||
throw new IllegalRepoException("Repo [" + repoName + "] does not contain versionCode");
|
||||
}
|
||||
if (getMinMagiskVersion() < Const.Value.MIN_MODULE_VER) {
|
||||
if (getMinMagiskVersion() < Const.MIN_MODULE_VER) {
|
||||
throw new IllegalRepoException("Repo [" + repoName + "] is outdated");
|
||||
}
|
||||
}
|
||||
@@ -78,6 +80,11 @@ public class Repo extends BaseModule {
|
||||
return String.format(Const.Url.FILE_URL, repoName, "README.md");
|
||||
}
|
||||
|
||||
public String getLastUpdateString() {
|
||||
return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM,
|
||||
MagiskManager.locale).format(mLastUpdate);
|
||||
}
|
||||
|
||||
public Date getLastUpdate() {
|
||||
return mLastUpdate;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
// Clear bad repos
|
||||
mDb.delete(TABLE_NAME, "minMagisk<?",
|
||||
new String[] { String.valueOf(Const.Value.MIN_MODULE_VER) });
|
||||
new String[] { String.valueOf(Const.MIN_MODULE_VER) });
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,9 +95,17 @@ public class RepoDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
|
||||
public Cursor getRepoCursor() {
|
||||
String orderBy = null;
|
||||
switch (mm.repoOrder) {
|
||||
case Const.Value.ORDER_NAME:
|
||||
orderBy = "name COLLATE NOCASE";
|
||||
break;
|
||||
case Const.Value.ORDER_DATE:
|
||||
orderBy = "last_update DESC";
|
||||
}
|
||||
return mDb.query(TABLE_NAME, null, "minMagisk<=?",
|
||||
new String[] { String.valueOf(mm.magiskVersionCode) },
|
||||
null, null, "name COLLATE NOCASE");
|
||||
null, null, orderBy);
|
||||
}
|
||||
|
||||
public List<String> getRepoIDList() {
|
||||
|
||||
@@ -41,6 +41,10 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
private PackageManager pm;
|
||||
private SQLiteDatabase mDb;
|
||||
|
||||
private static void unmntDB() {
|
||||
Shell.su(Utils.fmt("umount -l /data/user*/*/%s/*/*.db", MagiskManager.get().getPackageName()));
|
||||
}
|
||||
|
||||
private static Context initDB(boolean verify) {
|
||||
Context context, de = null;
|
||||
MagiskManager ce = MagiskManager.get();
|
||||
@@ -58,7 +62,7 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
File db = Utils.getDB(context, DB_NAME);
|
||||
if (!verify) {
|
||||
if (db.length() == 0) {
|
||||
if (db.exists() && db.length() == 0) {
|
||||
ce.loadMagiskInfo();
|
||||
// Continue verification
|
||||
} else {
|
||||
@@ -70,16 +74,20 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
if (ce.magiskVersionCode < 1410) {
|
||||
if (context == de) {
|
||||
unmntDB();
|
||||
ce.moveDatabaseFrom(de, DB_NAME);
|
||||
context = ce;
|
||||
}
|
||||
} else {
|
||||
if (context == ce) {
|
||||
unmntDB();
|
||||
de.moveDatabaseFrom(ce, DB_NAME);
|
||||
context = de;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Context might be updated
|
||||
db = Utils.getDB(context, DB_NAME);
|
||||
|
||||
if (!Shell.rootAccess())
|
||||
return context;
|
||||
@@ -100,7 +108,7 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
// New global su db
|
||||
Shell.su(Utils.fmt("mkdir %s 2>/dev/null; chmod 700 %s", GLOBAL_DB.getParent(), GLOBAL_DB.getParent()));
|
||||
if (!Utils.itemExist(GLOBAL_DB)) {
|
||||
Utils.javaCreateFile(db);
|
||||
context.openOrCreateDatabase(DB_NAME, 0, null).close();
|
||||
Shell.su(Utils.fmt("cp -af %s %s; rm -f %s*", db, GLOBAL_DB, db));
|
||||
}
|
||||
verified = TextUtils.equals(Utils.checkInode(GLOBAL_DB), Utils.checkInode(db));
|
||||
@@ -117,12 +125,17 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||
return context;
|
||||
}
|
||||
|
||||
public SuDatabaseHelper() {
|
||||
this(true);
|
||||
public static SuDatabaseHelper getSuDB(boolean verify) {
|
||||
try {
|
||||
return new SuDatabaseHelper(initDB(verify));
|
||||
} catch(Exception e) {
|
||||
// Try to catch runtime exceptions and remove all db for retry
|
||||
unmntDB();
|
||||
Shell.su(Utils.fmt("rm -rf /data/user*/*/magisk.db /data/adb/magisk.db /data/user*/*/%s/databases",
|
||||
MagiskManager.get().getPackageName()));
|
||||
e.printStackTrace();
|
||||
return new SuDatabaseHelper(initDB(false));
|
||||
}
|
||||
|
||||
public SuDatabaseHelper(boolean verify) {
|
||||
this(initDB(verify));
|
||||
}
|
||||
|
||||
private SuDatabaseHelper(Context context) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.utils.Const;
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
@@ -18,7 +19,7 @@ public class PackageReceiver extends BroadcastReceiver {
|
||||
switch (intent.getAction()) {
|
||||
case Intent.ACTION_PACKAGE_REPLACED:
|
||||
// This will only work pre-O
|
||||
if (mm.suReauth) {
|
||||
if (mm.prefs.getBoolean(Const.Key.SU_REAUTH, false)) {
|
||||
mm.suDB.deletePolicy(pkg);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -41,6 +41,7 @@ public class OnBootIntentService extends IntentService {
|
||||
* */
|
||||
MagiskManager mm = Utils.getMagiskManager(this);
|
||||
mm.loadMagiskInfo();
|
||||
mm.getDefaultInstallFlags();
|
||||
if (Shell.rootAccess()) {
|
||||
Utils.patchDTBO();
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ package com.topjohnwu.magisk.superuser;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.net.LocalSocket;
|
||||
import android.net.LocalSocketAddress;
|
||||
import android.os.Bundle;
|
||||
import android.os.CountDownTimer;
|
||||
import android.os.FileObserver;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
@@ -23,6 +25,7 @@ import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||
import com.topjohnwu.magisk.components.Activity;
|
||||
import com.topjohnwu.magisk.container.Policy;
|
||||
import com.topjohnwu.magisk.utils.Const;
|
||||
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
@@ -40,6 +43,8 @@ public class RequestActivity extends Activity {
|
||||
@BindView(R.id.package_name) TextView packageNameView;
|
||||
@BindView(R.id.grant_btn) Button grant_btn;
|
||||
@BindView(R.id.deny_btn) Button deny_btn;
|
||||
@BindView(R.id.fingerprint) ImageView fingerprintImg;
|
||||
@BindView(R.id.warning) TextView warning;
|
||||
|
||||
private String socketPath;
|
||||
private LocalSocket socket;
|
||||
@@ -49,6 +54,7 @@ public class RequestActivity extends Activity {
|
||||
private boolean hasTimeout;
|
||||
private Policy policy;
|
||||
private CountDownTimer timer;
|
||||
private FingerprintHelper fingerprintHelper;
|
||||
|
||||
@Override
|
||||
public int getDarkTheme() {
|
||||
@@ -80,6 +86,15 @@ public class RequestActivity extends Activity {
|
||||
new SocketManager(this).exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (timer != null)
|
||||
timer.cancel();
|
||||
if (fingerprintHelper != null)
|
||||
fingerprintHelper.cancel();
|
||||
super.finish();
|
||||
}
|
||||
|
||||
private boolean cancelTimeout() {
|
||||
timer.cancel();
|
||||
deny_btn.setText(getString(R.string.deny));
|
||||
@@ -128,11 +143,49 @@ public class RequestActivity extends Activity {
|
||||
}
|
||||
};
|
||||
|
||||
boolean useFingerprint = mm.prefs.getBoolean(Const.Key.SU_FINGERPRINT, false) && FingerprintHelper.canUseFingerprint();
|
||||
|
||||
if (useFingerprint) {
|
||||
try {
|
||||
fingerprintHelper = new FingerprintHelper() {
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, CharSequence errString) {
|
||||
warning.setText(errString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
|
||||
warning.setText(helpString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
|
||||
handleAction(Policy.ALLOW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
warning.setText(R.string.auth_fail);
|
||||
}
|
||||
};
|
||||
fingerprintHelper.startAuth();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
useFingerprint = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!useFingerprint) {
|
||||
grant_btn.setOnClickListener(v -> {
|
||||
handleAction(Policy.ALLOW);
|
||||
timer.cancel();
|
||||
});
|
||||
grant_btn.requestFocus();
|
||||
}
|
||||
|
||||
grant_btn.setVisibility(useFingerprint ? View.GONE : View.VISIBLE);
|
||||
fingerprintImg.setVisibility(useFingerprint ? View.VISIBLE : View.GONE);
|
||||
|
||||
deny_btn.setOnClickListener(v -> {
|
||||
handleAction(Policy.DENY);
|
||||
timer.cancel();
|
||||
@@ -151,9 +204,10 @@ public class RequestActivity extends Activity {
|
||||
public void onBackPressed() {
|
||||
if (policy != null) {
|
||||
handleAction(Policy.DENY);
|
||||
}
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
void handleAction() {
|
||||
String response;
|
||||
|
||||
@@ -23,6 +23,8 @@ public class Const {
|
||||
public static final String UTIL_FUNCTIONS= "util_functions.sh";
|
||||
public static final String ANDROID_MANIFEST = "AndroidManifest.xml";
|
||||
|
||||
public static final String SU_KEYSTORE_KEY = "su_key";
|
||||
|
||||
// Paths
|
||||
public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk";
|
||||
public static final String TMP_FOLDER_PATH = "/dev/tmp";
|
||||
@@ -30,6 +32,11 @@ public class Const {
|
||||
public static final File EXTERNAL_PATH = new File(Environment.getExternalStorageDirectory(), "MagiskManager");
|
||||
public static final String MANAGER_CONFIGS = ".tmp.magisk.config";
|
||||
|
||||
// Versions
|
||||
public static final int UPDATE_SERVICE_VER = 1;
|
||||
public static final int SNET_VER = 7;
|
||||
public static final int MIN_MODULE_VER = 1400;
|
||||
|
||||
public static String BUSYBOX_PATH() {
|
||||
if (Utils.itemExist("/sbin/.core/busybox/busybox")) {
|
||||
return "/sbin/.core/busybox";
|
||||
@@ -84,12 +91,12 @@ public class Const {
|
||||
public static class Url {
|
||||
public static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/stable.json";
|
||||
public static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/update/beta.json";
|
||||
public static final String SNET_URL = "https://github.com/topjohnwu/MagiskManager/raw/afff3c0a49cec8d797e486be3092e256b4bf5375/snet.apk";
|
||||
public static final String SNET_URL = "https://github.com/topjohnwu/MagiskManager/raw/a82a5e5a49285df65da91d2e8b24f4783841b515/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";
|
||||
public static final String DONATION_URL = "https://www.paypal.me/topjohnwu";
|
||||
public static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
|
||||
public static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3473445";
|
||||
public static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/MagiskManager";
|
||||
}
|
||||
|
||||
@@ -104,6 +111,7 @@ public class Const {
|
||||
public static final String SU_AUTO_RESPONSE = "su_auto_response";
|
||||
public static final String SU_NOTIFICATION = "su_notification";
|
||||
public static final String SU_REAUTH = "su_reauth";
|
||||
public static final String SU_FINGERPRINT = "su_fingerprint";
|
||||
|
||||
// intents
|
||||
public static final String OPEN_SECTION = "section";
|
||||
@@ -118,7 +126,6 @@ public class Const {
|
||||
public static final String UPDATE_CHANNEL = "update_channel";
|
||||
public static final String CUSTOM_CHANNEL = "custom_channel";
|
||||
public static final String BOOT_FORMAT = "boot_format";
|
||||
public static final String SNET_VER = "snet_version";
|
||||
public static final String UPDATE_SERVICE_VER = "update_service_version";
|
||||
public static final String APP_VER = "app_version";
|
||||
public static final String MAGISKHIDE = "magiskhide";
|
||||
@@ -129,6 +136,7 @@ public class Const {
|
||||
public static final String ETAG_KEY = "ETag";
|
||||
public static final String LINK_KEY = "Link";
|
||||
public static final String IF_NONE_MATCH = "If-None-Match";
|
||||
public static final String REPO_ORDER = "repo_order";
|
||||
}
|
||||
|
||||
|
||||
@@ -158,8 +166,7 @@ public class Const {
|
||||
public static final String PATCH_BOOT = "patch";
|
||||
public static final String FLASH_MAGISK = "magisk";
|
||||
public static final int[] timeoutList = {0, -1, 10, 20, 30, 60};
|
||||
public static final int UPDATE_SERVICE_VER = 1;
|
||||
public static final int SNET_VER = 6;
|
||||
public static final int MIN_MODULE_VER = 1400;
|
||||
public static final int ORDER_NAME = 0;
|
||||
public static final int ORDER_DATE = 1;
|
||||
}
|
||||
}
|
||||
|
||||
112
src/main/java/com/topjohnwu/magisk/utils/FingerprintHelper.java
Normal file
112
src/main/java/com/topjohnwu/magisk/utils/FingerprintHelper.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.KeyguardManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Build;
|
||||
import android.os.CancellationSignal;
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyPermanentlyInvalidatedException;
|
||||
import android.security.keystore.KeyProperties;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
|
||||
import java.security.KeyStore;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public abstract class FingerprintHelper {
|
||||
|
||||
private FingerprintManager manager;
|
||||
private Cipher cipher;
|
||||
private CancellationSignal cancel;
|
||||
|
||||
public static boolean canUseFingerprint() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||
return false;
|
||||
MagiskManager mm = MagiskManager.get();
|
||||
KeyguardManager km = mm.getSystemService(KeyguardManager.class);
|
||||
FingerprintManager fm = mm.getSystemService(FingerprintManager.class);
|
||||
return km.isKeyguardSecure() && fm != null && fm.isHardwareDetected() && fm.hasEnrolledFingerprints();
|
||||
}
|
||||
|
||||
protected FingerprintHelper() throws Exception {
|
||||
MagiskManager mm = MagiskManager.get();
|
||||
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||
manager = mm.getSystemService(FingerprintManager.class);
|
||||
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
|
||||
+ KeyProperties.BLOCK_MODE_CBC + "/"
|
||||
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
||||
keyStore.load(null);
|
||||
SecretKey key = (SecretKey) keyStore.getKey(Const.SU_KEYSTORE_KEY, null);
|
||||
if (key == null) {
|
||||
key = generateKey();
|
||||
}
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
} catch (KeyPermanentlyInvalidatedException e) {
|
||||
// Only happens on Marshmallow
|
||||
key = generateKey();
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onAuthenticationError(int errorCode, CharSequence errString);
|
||||
|
||||
public abstract void onAuthenticationHelp(int helpCode, CharSequence helpString);
|
||||
|
||||
public abstract void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result);
|
||||
|
||||
public abstract void onAuthenticationFailed();
|
||||
|
||||
public void startAuth() {
|
||||
cancel = new CancellationSignal();
|
||||
FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher);
|
||||
manager.authenticate(cryptoObject, cancel, 0, new FingerprintManager.AuthenticationCallback() {
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, CharSequence errString) {
|
||||
FingerprintHelper.this.onAuthenticationError(errorCode, errString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
|
||||
FingerprintHelper.this.onAuthenticationHelp(helpCode, helpString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
|
||||
FingerprintHelper.this.onAuthenticationSucceeded(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
FingerprintHelper.this.onAuthenticationFailed();
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (cancel != null)
|
||||
cancel.cancel();
|
||||
}
|
||||
|
||||
private SecretKey generateKey() throws Exception {
|
||||
KeyGenerator keygen = KeyGenerator
|
||||
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
|
||||
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
|
||||
Const.SU_KEYSTORE_KEY,
|
||||
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
|
||||
.setUserAuthenticationRequired(true)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
builder.setInvalidatedByBiometricEnrollment(false);
|
||||
}
|
||||
keygen.init(builder.build());
|
||||
return keygen.generateKey();
|
||||
}
|
||||
}
|
||||
@@ -89,13 +89,10 @@ public class Shell {
|
||||
}
|
||||
|
||||
// Root shell initialization
|
||||
String bbpath = Const.BUSYBOX_PATH();
|
||||
mm.shell.run_raw(false, false,
|
||||
"export PATH=" + bbpath + ":$PATH",
|
||||
"export PATH=" + Const.BUSYBOX_PATH() + ":$PATH",
|
||||
"mount_partitions",
|
||||
"find_boot_image",
|
||||
"find_dtbo_image",
|
||||
"migrate_boot_backup");
|
||||
"run_migrations");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class ZipUtils {
|
||||
|
||||
@@ -30,9 +30,9 @@ public class ZipUtils {
|
||||
|
||||
public static void unzip(InputStream zip, File folder, String path, boolean junkPath) throws Exception {
|
||||
try {
|
||||
JarInputStream zipfile = new JarInputStream(zip);
|
||||
JarEntry entry;
|
||||
while ((entry = zipfile.getNextJarEntry()) != null) {
|
||||
ZipInputStream zipfile = new ZipInputStream(zip);
|
||||
ZipEntry entry;
|
||||
while ((entry = zipfile.getNextEntry()) != null) {
|
||||
if (!entry.getName().startsWith(path) || entry.isDirectory()){
|
||||
// Ignore directories, only create files
|
||||
continue;
|
||||
|
||||
9
src/main/res/drawable/ic_fingerprint.xml
Normal file
9
src/main/res/drawable/ic_fingerprint.xml
Normal file
File diff suppressed because one or more lines are too long
9
src/main/res/drawable/ic_sort.xml
Normal file
9
src/main/res/drawable/ic_sort.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/imageColorTint"
|
||||
android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
|
||||
</vector>
|
||||
@@ -101,18 +101,27 @@
|
||||
<Button
|
||||
style="?android:buttonBarButtonStyle"
|
||||
android:text="@string/deny_with_str"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/deny_btn"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
style="?android:buttonBarButtonStyle"
|
||||
android:text="@string/grant"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/grant_btn"
|
||||
android:layout_weight="1" />
|
||||
style="?android:buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/grant" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fingerprint"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="7dp"
|
||||
android:tint="?attr/colorAccent"
|
||||
android:src="@drawable/ic_fingerprint" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -15,72 +15,64 @@
|
||||
card_view:cardCornerRadius="@dimen/card_corner_radius"
|
||||
card_view:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<RelativeLayout
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:padding="@dimen/card_layout_padding">
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/info_layout"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="@dimen/card_appicon_size"
|
||||
android:layout_height="@dimen/card_appicon_size"
|
||||
android:layout_centerVertical="true"
|
||||
android:scaleType="centerCrop"/>
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="end" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_alignBottom="@+id/app_icon"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="@dimen/card_appicon_size"
|
||||
android:paddingStart="65dp"
|
||||
android:weightSum="1">
|
||||
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="1"
|
||||
android:paddingEnd="3dp"
|
||||
android:paddingStart="3dp"
|
||||
android:textStyle="bold"/>
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textIsSelectable="false"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_package"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="25dp"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="center_vertical"
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:paddingEnd="3dp"
|
||||
android:paddingStart="3dp"
|
||||
android:singleLine="true"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/package_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true">
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="false"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/ic_menu_overflow_material"
|
||||
android:checked="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textIsSelectable="false"/>
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -67,6 +67,15 @@
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/update_time"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:textIsSelectable="false"
|
||||
android:textStyle="bold|italic" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user