[app] Async improvements
This commit is contained in:
parent
eb61f84c67
commit
8d3e8e8ed2
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
package org.lsposed.manager;
|
package org.lsposed.manager;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
@ -30,6 +29,7 @@ import android.system.Os;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
|
@ -47,6 +47,8 @@ import java.io.StringWriter;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import okhttp3.Cache;
|
import okhttp3.Cache;
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
|
|
@ -67,12 +69,11 @@ public class App extends Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String TAG = "LSPosedManager";
|
public static final String TAG = "LSPosedManager";
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
private static App instance = null;
|
private static App instance = null;
|
||||||
private static OkHttpClient okHttpClient;
|
private static OkHttpClient okHttpClient;
|
||||||
private static Cache okHttpCache;
|
private static Cache okHttpCache;
|
||||||
private SharedPreferences pref;
|
private SharedPreferences pref;
|
||||||
|
private ExecutorService executorService;
|
||||||
|
|
||||||
public static App getInstance() {
|
public static App getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
|
|
@ -82,6 +83,10 @@ public class App extends Application {
|
||||||
return instance.pref;
|
return instance.pref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ExecutorService getExecutorService() {
|
||||||
|
return instance.executorService;
|
||||||
|
}
|
||||||
|
|
||||||
private void setCrashReport() {
|
private void setCrashReport() {
|
||||||
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
|
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
|
||||||
|
|
||||||
|
|
@ -116,6 +121,8 @@ public class App extends Application {
|
||||||
|
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
|
executorService = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
pref = PreferenceManager.getDefaultSharedPreferences(this);
|
pref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
if ("CN".equals(Locale.getDefault().getCountry())) {
|
if ("CN".equals(Locale.getDefault().getCountry())) {
|
||||||
if (!pref.contains("doh")) {
|
if (!pref.contains("doh")) {
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
if (launchIntent != null) {
|
if (launchIntent != null) {
|
||||||
ConfigManager.startActivityAsUserWithFeature(launchIntent, module.userId);
|
ConfigManager.startActivityAsUserWithFeature(launchIntent, module.userId);
|
||||||
} else {
|
} else {
|
||||||
fragment.makeSnackBar(R.string.module_no_ui, Snackbar.LENGTH_LONG);
|
Snackbar.make(fragment.binding.snackbar, R.string.module_no_ui, Snackbar.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (itemId == R.id.backup) {
|
} else if (itemId == R.id.backup) {
|
||||||
|
|
@ -469,7 +469,7 @@ public class ScopeAdapter extends RecyclerView.Adapter<ScopeAdapter.ViewHolder>
|
||||||
checkedList.remove(appInfo.application);
|
checkedList.remove(appInfo.application);
|
||||||
}
|
}
|
||||||
if (!ConfigManager.setModuleScope(module.packageName, checkedList)) {
|
if (!ConfigManager.setModuleScope(module.packageName, checkedList)) {
|
||||||
fragment.makeSnackBar(R.string.failed_to_save_scope_list, Snackbar.LENGTH_SHORT);
|
Snackbar.make(fragment.binding.snackbar, R.string.failed_to_save_scope_list, Snackbar.LENGTH_SHORT).show();
|
||||||
if (!isChecked) {
|
if (!isChecked) {
|
||||||
checkedList.add(appInfo.application);
|
checkedList.add(appInfo.application);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -19,28 +19,25 @@
|
||||||
|
|
||||||
package org.lsposed.manager.ui.fragment;
|
package org.lsposed.manager.ui.fragment;
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.OnBackPressedCallback;
|
import androidx.activity.OnBackPressedCallback;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.appcompat.widget.SearchView;
|
import androidx.appcompat.widget.SearchView;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.lsposed.manager.BuildConfig;
|
import org.lsposed.manager.App;
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.adapters.ScopeAdapter;
|
import org.lsposed.manager.adapters.ScopeAdapter;
|
||||||
import org.lsposed.manager.databinding.FragmentAppListBinding;
|
import org.lsposed.manager.databinding.FragmentAppListBinding;
|
||||||
|
|
@ -111,56 +108,35 @@ public class AppListFragment extends BaseFragment {
|
||||||
|
|
||||||
backupLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
|
backupLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
|
||||||
uri -> {
|
uri -> {
|
||||||
if (uri != null) {
|
if (uri == null) return;
|
||||||
|
runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
// grantUriPermission might throw RemoteException on MIUI
|
BackupUtils.backup(uri, modulePackageName);
|
||||||
requireActivity().grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
var text = App.getInstance().getString(R.string.settings_backup_failed2, e.getMessage());
|
||||||
|
if (binding != null && isResumed()) {
|
||||||
|
Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(App.getInstance(), text, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
|
||||||
.setCancelable(false)
|
|
||||||
.setMessage(R.string.settings_backuping)
|
|
||||||
.show();
|
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
|
||||||
boolean success = BackupUtils.backup(requireActivity(), uri, modulePackageName);
|
|
||||||
try {
|
|
||||||
requireActivity().runOnUiThread(() -> {
|
|
||||||
alertDialog.dismiss();
|
|
||||||
makeSnackBar(success ? R.string.settings_backup_success : R.string.settings_backup_failed, Snackbar.LENGTH_SHORT);
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
restoreLauncher = registerForActivityResult(new ActivityResultContracts.OpenDocument(),
|
restoreLauncher = registerForActivityResult(new ActivityResultContracts.OpenDocument(),
|
||||||
uri -> {
|
uri -> {
|
||||||
if (uri != null) {
|
if (uri == null) return;
|
||||||
|
runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
// grantUriPermission might throw RemoteException on MIUI
|
BackupUtils.restore(uri, modulePackageName);
|
||||||
requireActivity().grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
var text = App.getInstance().getString(R.string.settings_restore_failed2, e.getMessage());
|
||||||
|
if (binding != null && isResumed()) {
|
||||||
|
Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(App.getInstance(), text, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
|
||||||
.setCancelable(false)
|
|
||||||
.setMessage(R.string.settings_restoring)
|
|
||||||
.show();
|
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
|
||||||
boolean success = BackupUtils.restore(requireActivity(), uri, modulePackageName);
|
|
||||||
try {
|
|
||||||
requireActivity().runOnUiThread(() -> {
|
|
||||||
alertDialog.dismiss();
|
|
||||||
makeSnackBar(success ? R.string.settings_restore_success : R.string.settings_restore_failed, Snackbar.LENGTH_SHORT);
|
|
||||||
scopeAdapter.refresh(false);
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
requireActivity().getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
requireActivity().getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
||||||
|
|
@ -207,12 +183,4 @@ public class AppListFragment extends BaseFragment {
|
||||||
}
|
}
|
||||||
return super.onContextItemSelected(item);
|
return super.onContextItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void makeSnackBar(String text, @Snackbar.Duration int duration) {
|
|
||||||
Snackbar.make(binding.snackbar, text, duration).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void makeSnackBar(@StringRes int text, @Snackbar.Duration int duration) {
|
|
||||||
Snackbar.make(binding.snackbar, text, duration).show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,11 @@ import androidx.fragment.app.Fragment;
|
||||||
import androidx.navigation.NavController;
|
import androidx.navigation.NavController;
|
||||||
import androidx.navigation.fragment.NavHostFragment;
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
|
|
||||||
|
import org.lsposed.manager.App;
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
|
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
public class BaseFragment extends Fragment {
|
public class BaseFragment extends Fragment {
|
||||||
public void navigateUp() {
|
public void navigateUp() {
|
||||||
getNavController().navigateUp();
|
getNavController().navigateUp();
|
||||||
|
|
@ -59,4 +62,8 @@ public class BaseFragment extends Fragment {
|
||||||
onPrepareOptionsMenu(toolbar.getMenu());
|
onPrepareOptionsMenu(toolbar.getMenu());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Future<?> runAsync(Runnable runnable) {
|
||||||
|
return App.getExecutorService().submit(runnable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatDialogFragment;
|
import androidx.appcompat.app.AppCompatDialogFragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.lifecycle.Lifecycle;
|
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
|
|
@ -93,7 +92,7 @@ public class CompileDialogFragment extends AppCompatDialogFragment {
|
||||||
appInfo = arguments.getParcelable(KEY_APP_INFO);
|
appInfo = arguments.getParcelable(KEY_APP_INFO);
|
||||||
String[] command = COMPILE_RESET_COMMAND;
|
String[] command = COMPILE_RESET_COMMAND;
|
||||||
command[6] = appInfo.packageName;
|
command[6] = appInfo.packageName;
|
||||||
new CompileTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, command);
|
new CompileTask(this).executeOnExecutor(App.getExecutorService(), command);
|
||||||
} else {
|
} else {
|
||||||
dismissAllowingStateLoss();
|
dismissAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
@ -156,8 +155,8 @@ public class CompileDialogFragment extends AppCompatDialogFragment {
|
||||||
if (fragment != null) {
|
if (fragment != null) {
|
||||||
fragment.dismissAllowingStateLoss();
|
fragment.dismissAllowingStateLoss();
|
||||||
AppListFragment appListFragment = (AppListFragment) fragment.getParentFragment();
|
AppListFragment appListFragment = (AppListFragment) fragment.getParentFragment();
|
||||||
if (appListFragment != null && appListFragment.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
if (appListFragment != null && appListFragment.binding != null && appListFragment.isResumed()) {
|
||||||
appListFragment.makeSnackBar(text, Snackbar.LENGTH_LONG);
|
Snackbar.make(appListFragment.binding.snackbar, text, Snackbar.LENGTH_LONG).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
|
@ -46,6 +47,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.google.android.material.tabs.TabLayout;
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
|
||||||
|
import org.lsposed.manager.App;
|
||||||
import org.lsposed.manager.ConfigManager;
|
import org.lsposed.manager.ConfigManager;
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.databinding.FragmentLogsBinding;
|
import org.lsposed.manager.databinding.FragmentLogsBinding;
|
||||||
|
|
@ -80,15 +82,18 @@ public class LogsFragment extends BaseFragment {
|
||||||
new ActivityResultContracts.CreateDocument(),
|
new ActivityResultContracts.CreateDocument(),
|
||||||
uri -> {
|
uri -> {
|
||||||
if (uri == null) return;
|
if (uri == null) return;
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
runAsync(() -> {
|
||||||
try (var os = new ZipOutputStream(requireContext().getContentResolver().openOutputStream(uri))) {
|
try (var os = new ZipOutputStream(requireContext().getContentResolver().openOutputStream(uri))) {
|
||||||
os.setLevel(Deflater.BEST_COMPRESSION);
|
os.setLevel(Deflater.BEST_COMPRESSION);
|
||||||
zipLogs(os);
|
zipLogs(os);
|
||||||
os.finish();
|
os.finish();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
var str = getResources().getString(R.string.logs_save_failed);
|
var text = App.getInstance().getString(R.string.logs_save_failed2, e.getMessage());
|
||||||
Snackbar.make(binding.snackbar, str + "\n" + e.getMessage(),
|
if (binding != null && isResumed()) {
|
||||||
Snackbar.LENGTH_LONG).show();
|
Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(App.getInstance(), text, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -19,21 +19,20 @@
|
||||||
|
|
||||||
package org.lsposed.manager.ui.fragment;
|
package org.lsposed.manager.ui.fragment;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.SwitchPreference;
|
import androidx.preference.SwitchPreference;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
@ -42,7 +41,6 @@ import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.takisoft.preferencex.PreferenceFragmentCompat;
|
import com.takisoft.preferencex.PreferenceFragmentCompat;
|
||||||
|
|
||||||
import org.lsposed.manager.App;
|
import org.lsposed.manager.App;
|
||||||
import org.lsposed.manager.BuildConfig;
|
|
||||||
import org.lsposed.manager.ConfigManager;
|
import org.lsposed.manager.ConfigManager;
|
||||||
import org.lsposed.manager.R;
|
import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.databinding.FragmentSettingsBinding;
|
import org.lsposed.manager.databinding.FragmentSettingsBinding;
|
||||||
|
|
@ -82,61 +80,55 @@ public class SettingsFragment extends BaseFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PreferenceFragment extends PreferenceFragmentCompat {
|
public static class PreferenceFragment extends PreferenceFragmentCompat {
|
||||||
|
private SettingsFragment parentFragment;
|
||||||
|
|
||||||
ActivityResultLauncher<String> backupLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
|
ActivityResultLauncher<String> backupLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument(),
|
||||||
uri -> {
|
uri -> {
|
||||||
if (uri != null) {
|
if (uri == null || parentFragment == null) return;
|
||||||
|
parentFragment.runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
// grantUriPermission might throw RemoteException on MIUI
|
BackupUtils.backup(uri);
|
||||||
requireActivity().grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
var text = App.getInstance().getString(R.string.settings_backup_failed2, e.getMessage());
|
||||||
|
if (parentFragment != null && parentFragment.binding != null && isResumed()) {
|
||||||
|
Snackbar.make(parentFragment.binding.snackbar, text, Snackbar.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(App.getInstance(), text, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
|
||||||
.setCancelable(false)
|
|
||||||
.setMessage(R.string.settings_backuping)
|
|
||||||
.show();
|
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
|
||||||
boolean success = BackupUtils.backup(requireContext(), uri);
|
|
||||||
try {
|
|
||||||
SettingsFragment fragment = (SettingsFragment) getParentFragment();
|
|
||||||
requireActivity().runOnUiThread(() -> {
|
|
||||||
alertDialog.dismiss();
|
|
||||||
fragment.makeSnackBar(success ? R.string.settings_backup_success : R.string.settings_backup_failed, Snackbar.LENGTH_SHORT);
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
ActivityResultLauncher<String[]> restoreLauncher = registerForActivityResult(new ActivityResultContracts.OpenDocument(),
|
ActivityResultLauncher<String[]> restoreLauncher = registerForActivityResult(new ActivityResultContracts.OpenDocument(),
|
||||||
uri -> {
|
uri -> {
|
||||||
if (uri != null) {
|
if (uri == null || parentFragment == null) return;
|
||||||
|
parentFragment.runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
// grantUriPermission might throw RemoteException on MIUI
|
BackupUtils.restore(uri);
|
||||||
requireActivity().grantUriPermission(BuildConfig.APPLICATION_ID, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
var text = App.getInstance().getString(R.string.settings_restore_failed2, e.getMessage());
|
||||||
|
if (parentFragment != null && parentFragment.binding != null && isResumed()) {
|
||||||
|
Snackbar.make(parentFragment.binding.snackbar, text, Snackbar.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(App.getInstance(), text, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
AlertDialog alertDialog = new AlertDialog.Builder(requireActivity())
|
|
||||||
.setCancelable(false)
|
|
||||||
.setMessage(R.string.settings_restoring)
|
|
||||||
.show();
|
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
|
||||||
boolean success = BackupUtils.restore(requireContext(), uri);
|
|
||||||
try {
|
|
||||||
SettingsFragment fragment = (SettingsFragment) getParentFragment();
|
|
||||||
requireActivity().runOnUiThread(() -> {
|
|
||||||
alertDialog.dismiss();
|
|
||||||
fragment.makeSnackBar(success ? R.string.settings_restore_success : R.string.settings_restore_failed, Snackbar.LENGTH_SHORT);
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(@NonNull Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
|
||||||
|
parentFragment = (SettingsFragment) requireParentFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetach() {
|
||||||
|
super.onDetach();
|
||||||
|
|
||||||
|
parentFragment = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferencesFix(Bundle savedInstanceState, String rootKey) {
|
public void onCreatePreferencesFix(Bundle savedInstanceState, String rootKey) {
|
||||||
addPreferencesFromResource(R.xml.prefs);
|
addPreferencesFromResource(R.xml.prefs);
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,16 @@
|
||||||
|
|
||||||
package org.lsposed.manager.util;
|
package org.lsposed.manager.util;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import org.lsposed.manager.App;
|
||||||
import org.lsposed.manager.ConfigManager;
|
import org.lsposed.manager.ConfigManager;
|
||||||
import org.lsposed.manager.adapters.ScopeAdapter;
|
import org.lsposed.manager.adapters.ScopeAdapter;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
@ -38,12 +38,11 @@ import java.util.zip.GZIPOutputStream;
|
||||||
public class BackupUtils {
|
public class BackupUtils {
|
||||||
private static final int VERSION = 2;
|
private static final int VERSION = 2;
|
||||||
|
|
||||||
public static boolean backup(Context context, Uri uri) {
|
public static void backup(Uri uri) throws JSONException, IOException {
|
||||||
return backup(context, uri, null);
|
backup(uri, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean backup(Context context, Uri uri, String packageName) {
|
public static void backup(Uri uri, String packageName) throws IOException, JSONException {
|
||||||
try {
|
|
||||||
JSONObject rootObject = new JSONObject();
|
JSONObject rootObject = new JSONObject();
|
||||||
rootObject.put("version", VERSION);
|
rootObject.put("version", VERSION);
|
||||||
JSONArray modulesArray = new JSONArray();
|
JSONArray modulesArray = new JSONArray();
|
||||||
|
|
@ -67,26 +66,17 @@ public class BackupUtils {
|
||||||
modulesArray.put(moduleObject);
|
modulesArray.put(moduleObject);
|
||||||
}
|
}
|
||||||
rootObject.put("modules", modulesArray);
|
rootObject.put("modules", modulesArray);
|
||||||
OutputStream outputStream = context.getContentResolver().openOutputStream(uri);
|
try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(App.getInstance().getContentResolver().openOutputStream(uri))) {
|
||||||
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
|
|
||||||
gzipOutputStream.write(rootObject.toString().getBytes());
|
gzipOutputStream.write(rootObject.toString().getBytes());
|
||||||
gzipOutputStream.close();
|
|
||||||
outputStream.close();
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean restore(Context context, Uri uri) {
|
public static void restore(Uri uri) throws JSONException, IOException {
|
||||||
return restore(context, uri, null);
|
restore(uri, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean restore(Context context, Uri uri, String packageName) {
|
public static void restore(Uri uri, String packageName) throws IOException, JSONException {
|
||||||
try {
|
try (GZIPInputStream gzipInputStream = new GZIPInputStream(App.getInstance().getContentResolver().openInputStream(uri), 32)) {
|
||||||
InputStream inputStream = context.getContentResolver().openInputStream(uri);
|
|
||||||
GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream, 32);
|
|
||||||
StringBuilder string = new StringBuilder();
|
StringBuilder string = new StringBuilder();
|
||||||
byte[] data = new byte[32];
|
byte[] data = new byte[32];
|
||||||
int bytesRead;
|
int bytesRead;
|
||||||
|
|
@ -94,7 +84,6 @@ public class BackupUtils {
|
||||||
string.append(new String(data, 0, bytesRead));
|
string.append(new String(data, 0, bytesRead));
|
||||||
}
|
}
|
||||||
gzipInputStream.close();
|
gzipInputStream.close();
|
||||||
inputStream.close();
|
|
||||||
JSONObject rootObject = new JSONObject(string.toString());
|
JSONObject rootObject = new JSONObject(string.toString());
|
||||||
int version = rootObject.getInt("version");
|
int version = rootObject.getInt("version");
|
||||||
if (version == VERSION || version == 1) {
|
if (version == VERSION || version == 1) {
|
||||||
|
|
@ -122,12 +111,8 @@ public class BackupUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
throw new IllegalArgumentException("Unknown backup file version");
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package org.lsposed.manager.util;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
import android.view.accessibility.AccessibilityNodeProvider;
|
||||||
|
|
||||||
|
public class EmptyAccessibilityDelegate extends View.AccessibilityDelegate {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendAccessibilityEvent(View host, int eventType) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performAccessibilityAction(View host, int action, Bundle args) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addExtraDataToAccessibilityNodeInfo(View host, AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
<string name="menuSaveToSd">Save</string>
|
<string name="menuSaveToSd">Save</string>
|
||||||
<string name="nav_item_logs_lsp">LSPosed Logs</string>
|
<string name="nav_item_logs_lsp">LSPosed Logs</string>
|
||||||
<string name="nav_item_logs_module">Modules Logs</string>
|
<string name="nav_item_logs_module">Modules Logs</string>
|
||||||
<string name="logs_save_failed">Failed to save:</string>
|
<string name="logs_save_failed2">Failed to save:\n%s</string>
|
||||||
<string name="menuClearLog">Clear log now</string>
|
<string name="menuClearLog">Clear log now</string>
|
||||||
<string name="logs_cleared">Log successfully cleared.</string>
|
<string name="logs_cleared">Log successfully cleared.</string>
|
||||||
<string name="scroll_top">Scroll to top</string>
|
<string name="scroll_top">Scroll to top</string>
|
||||||
|
|
@ -72,6 +72,8 @@
|
||||||
<string name="menuReload">Reload</string>
|
<string name="menuReload">Reload</string>
|
||||||
<string name="logs_clear_failed_2">Failed to clear the log</string>
|
<string name="logs_clear_failed_2">Failed to clear the log</string>
|
||||||
<string name="verbose_log_not_avaliable">Verbose log is not available, if you just enabled it without reboot, try again after reboot.</string>
|
<string name="verbose_log_not_avaliable">Verbose log is not available, if you just enabled it without reboot, try again after reboot.</string>
|
||||||
|
<string name="logs_saving">Saving logs…</string>
|
||||||
|
<string name="logs_saved">Logs saved!</string>
|
||||||
|
|
||||||
<!-- Notification -->
|
<!-- Notification -->
|
||||||
<string name="module_is_not_activated_yet">Xposed module is not activated yet</string>
|
<string name="module_is_not_activated_yet">Xposed module is not activated yet</string>
|
||||||
|
|
@ -155,11 +157,11 @@
|
||||||
<string name="settings_backup">Backup</string>
|
<string name="settings_backup">Backup</string>
|
||||||
<string name="settings_backuping">Backing up…</string>
|
<string name="settings_backuping">Backing up…</string>
|
||||||
<string name="settings_backup_success">Backup finished!</string>
|
<string name="settings_backup_success">Backup finished!</string>
|
||||||
<string name="settings_backup_failed">Failed to backup</string>
|
<string name="settings_backup_failed2">Failed to backup:\n%s</string>
|
||||||
<string name="settings_restore">Restore</string>
|
<string name="settings_restore">Restore</string>
|
||||||
<string name="settings_restoring">Restoring…</string>
|
<string name="settings_restoring">Restoring…</string>
|
||||||
<string name="settings_restore_success">Restore finished!</string>
|
<string name="settings_restore_success">Restore finished!</string>
|
||||||
<string name="settings_restore_failed">Failed to restore</string>
|
<string name="settings_restore_failed2">Failed to restore:\n%s</string>
|
||||||
<string name="group_network">Network</string>
|
<string name="group_network">Network</string>
|
||||||
<string name="dns_over_http">DNS over HTTPS</string>
|
<string name="dns_over_http">DNS over HTTPS</string>
|
||||||
<string name="dns_over_http_summary">Workaround DNS poisoning in some nations</string>
|
<string name="dns_over_http_summary">Workaround DNS poisoning in some nations</string>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue