Simplify asynchronous tasks
This commit is contained in:
parent
075737a4ec
commit
9ac71ff8af
@ -172,7 +172,7 @@ public class MagiskFragment extends BaseFragment
|
|||||||
|
|
||||||
// Trigger state check
|
// Trigger state check
|
||||||
if (Download.checkNetworkStatus(mm)) {
|
if (Download.checkNetworkStatus(mm)) {
|
||||||
new CheckUpdates().exec();
|
CheckUpdates.check();
|
||||||
} else {
|
} else {
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import android.content.res.Configuration;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.container.Module;
|
|
||||||
import com.topjohnwu.magisk.database.MagiskDatabaseHelper;
|
import com.topjohnwu.magisk.database.MagiskDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
import com.topjohnwu.magisk.utils.LocaleManager;
|
||||||
@ -15,16 +14,12 @@ import com.topjohnwu.superuser.ContainerApp;
|
|||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class MagiskManager extends ContainerApp {
|
public class MagiskManager extends ContainerApp {
|
||||||
|
|
||||||
// Info
|
// Info
|
||||||
public boolean hasInit = false;
|
public boolean hasInit = false;
|
||||||
|
|
||||||
// Data
|
|
||||||
public Map<String, Module> moduleMap;
|
|
||||||
|
|
||||||
// Global resources
|
// Global resources
|
||||||
public SharedPreferences prefs;
|
public SharedPreferences prefs;
|
||||||
public MagiskDatabaseHelper mDB;
|
public MagiskDatabaseHelper mDB;
|
||||||
|
@ -17,14 +17,15 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
import com.topjohnwu.magisk.adapters.ModulesAdapter;
|
||||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
|
||||||
import com.topjohnwu.magisk.components.BaseFragment;
|
import com.topjohnwu.magisk.components.BaseFragment;
|
||||||
import com.topjohnwu.magisk.container.Module;
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@ -57,7 +58,7 @@ public class ModulesFragment extends BaseFragment implements Topic.Subscriber {
|
|||||||
|
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
new LoadModules().exec();
|
Utils.loadModules();
|
||||||
});
|
});
|
||||||
|
|
||||||
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
@ -84,7 +85,7 @@ public class ModulesFragment extends BaseFragment implements Topic.Subscriber {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPublish(int topic, Object[] result) {
|
public void onPublish(int topic, Object[] result) {
|
||||||
updateUI();
|
updateUI((Map<String, Module>) result[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -128,9 +129,9 @@ public class ModulesFragment extends BaseFragment implements Topic.Subscriber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUI() {
|
private void updateUI(Map<String, Module> moduleMap) {
|
||||||
listModules.clear();
|
listModules.clear();
|
||||||
listModules.addAll(mm.moduleMap.values());
|
listModules.addAll(moduleMap.values());
|
||||||
if (listModules.size() == 0) {
|
if (listModules.size() == 0) {
|
||||||
emptyRv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
|
@ -2,6 +2,7 @@ package com.topjohnwu.magisk;
|
|||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
@ -17,8 +18,11 @@ import android.widget.TextView;
|
|||||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||||
import com.topjohnwu.magisk.components.BaseFragment;
|
import com.topjohnwu.magisk.components.BaseFragment;
|
||||||
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import butterknife.Unbinder;
|
import butterknife.Unbinder;
|
||||||
@ -40,30 +44,24 @@ public class ReposFragment extends BaseFragment implements Topic.Subscriber {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@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 view = inflater.inflate(R.layout.fragment_repos, container, false);
|
View view = inflater.inflate(R.layout.fragment_repos, container, false);
|
||||||
unbinder = ButterKnife.bind(this, view);
|
unbinder = ButterKnife.bind(this, view);
|
||||||
|
|
||||||
mSwipeRefreshLayout.setRefreshing(true);
|
mSwipeRefreshLayout.setRefreshing(true);
|
||||||
|
recyclerView.setVisibility(View.GONE);
|
||||||
|
|
||||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
emptyRv.setVisibility(View.GONE);
|
emptyRv.setVisibility(View.GONE);
|
||||||
new UpdateRepos(true).exec();
|
new UpdateRepos().exec(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
getActivity().setTitle(R.string.downloads);
|
requireActivity().setTitle(R.string.downloads);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
adapter = new ReposAdapter(mm.repoDB, mm.moduleMap);
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
super.onResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
@ -72,15 +70,24 @@ public class ReposFragment extends BaseFragment implements Topic.Subscriber {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getSubscribedTopics() {
|
public int[] getSubscribedTopics() {
|
||||||
return new int[] {Topic.REPO_LOAD_DONE};
|
return new int[] {Topic.MODULE_LOAD_DONE, Topic.REPO_LOAD_DONE};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPublish(int topic, Object[] result) {
|
public void onPublish(int topic, Object[] result) {
|
||||||
|
if (topic == Topic.MODULE_LOAD_DONE) {
|
||||||
|
adapter = new ReposAdapter(mm.repoDB, (Map<String, Module>) result[0]);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
|
emptyRv.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
if (Topic.isPublished(getSubscribedTopics())) {
|
||||||
|
adapter.notifyDBChanged();
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
||||||
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
@ -21,7 +21,7 @@ import android.widget.EditText;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
import com.topjohnwu.magisk.asyncs.HideManager;
|
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
||||||
import com.topjohnwu.magisk.components.BaseActivity;
|
import com.topjohnwu.magisk.components.BaseActivity;
|
||||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
@ -163,7 +163,7 @@ public class SettingsActivity extends BaseActivity implements Topic.Subscriber {
|
|||||||
if (Data.magiskVersionCode >= Const.MAGISK_VER.MANAGER_HIDE) {
|
if (Data.magiskVersionCode >= Const.MAGISK_VER.MANAGER_HIDE) {
|
||||||
if (mm.getPackageName().equals(Const.ORIG_PKG_NAME)) {
|
if (mm.getPackageName().equals(Const.ORIG_PKG_NAME)) {
|
||||||
hideManager.setOnPreferenceClickListener((pref) -> {
|
hideManager.setOnPreferenceClickListener((pref) -> {
|
||||||
new HideManager(getActivity()).exec();
|
PatchAPK.hideManager(requireActivity());
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
generalCatagory.removePreference(restoreManager);
|
generalCatagory.removePreference(restoreManager);
|
||||||
@ -287,7 +287,7 @@ public class SettingsActivity extends BaseActivity implements Topic.Subscriber {
|
|||||||
Topic.publish(false, Topic.RELOAD_ACTIVITY);
|
Topic.publish(false, Topic.RELOAD_ACTIVITY);
|
||||||
break;
|
break;
|
||||||
case Const.Key.UPDATE_CHANNEL:
|
case Const.Key.UPDATE_CHANNEL:
|
||||||
new CheckUpdates().exec();
|
CheckUpdates.check();
|
||||||
break;
|
break;
|
||||||
case Const.Key.CHECK_UPDATES:
|
case Const.Key.CHECK_UPDATES:
|
||||||
Utils.setupUpdateCheck();
|
Utils.setupUpdateCheck();
|
||||||
|
@ -7,7 +7,6 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
|
||||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||||
import com.topjohnwu.magisk.components.BaseActivity;
|
import com.topjohnwu.magisk.components.BaseActivity;
|
||||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||||
@ -23,8 +22,13 @@ public class SplashActivity extends BaseActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// Force create a shell if not created yet
|
// Magisk working as expected
|
||||||
boolean root = Shell.rootAccess();
|
if (Shell.rootAccess() && Data.magiskVersionCode > 0) {
|
||||||
|
// Update check service
|
||||||
|
Utils.setupUpdateCheck();
|
||||||
|
// Load modules
|
||||||
|
Utils.loadModules();
|
||||||
|
}
|
||||||
|
|
||||||
mm.repoDB = new RepoDatabaseHelper(this);
|
mm.repoDB = new RepoDatabaseHelper(this);
|
||||||
Data.importPrefs();
|
Data.importPrefs();
|
||||||
@ -42,21 +46,11 @@ public class SplashActivity extends BaseActivity {
|
|||||||
// Setup shortcuts
|
// Setup shortcuts
|
||||||
sendBroadcast(new Intent(this, ShortcutReceiver.class));
|
sendBroadcast(new Intent(this, ShortcutReceiver.class));
|
||||||
|
|
||||||
LoadModules loadModuleTask = new LoadModules();
|
|
||||||
|
|
||||||
if (Download.checkNetworkStatus(this)) {
|
if (Download.checkNetworkStatus(this)) {
|
||||||
// Fire update check
|
// Fire update check
|
||||||
new CheckUpdates().exec();
|
CheckUpdates.check();
|
||||||
// Add repo update check
|
// Repo update check
|
||||||
loadModuleTask.setCallBack(() -> new UpdateRepos(false).exec());
|
new UpdateRepos().exec();
|
||||||
}
|
|
||||||
|
|
||||||
// Magisk working as expected
|
|
||||||
if (root && Data.magiskVersionCode > 0) {
|
|
||||||
// Update check service
|
|
||||||
Utils.setupUpdateCheck();
|
|
||||||
// Fire asynctasks
|
|
||||||
loadModuleTask.exec();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write back default values
|
// Write back default values
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.BuildConfig;
|
import com.topjohnwu.magisk.BuildConfig;
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
|
||||||
import com.topjohnwu.magisk.utils.NotificationMgr;
|
import com.topjohnwu.magisk.utils.NotificationMgr;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
import com.topjohnwu.magisk.utils.WebService;
|
||||||
@ -11,19 +12,9 @@ import com.topjohnwu.magisk.utils.WebService;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
public class CheckUpdates {
|
||||||
|
|
||||||
private boolean showNotification;
|
private static int getInt(JSONObject json, String name, int defValue) {
|
||||||
|
|
||||||
public CheckUpdates() {
|
|
||||||
this(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CheckUpdates(boolean b) {
|
|
||||||
showNotification = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getInt(JSONObject json, String name, int defValue) {
|
|
||||||
if (json == null)
|
if (json == null)
|
||||||
return defValue;
|
return defValue;
|
||||||
try {
|
try {
|
||||||
@ -33,7 +24,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getString(JSONObject json, String name, String defValue) {
|
private static String getString(JSONObject json, String name, String defValue) {
|
||||||
if (json == null)
|
if (json == null)
|
||||||
return defValue;
|
return defValue;
|
||||||
try {
|
try {
|
||||||
@ -43,7 +34,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JSONObject getJson(JSONObject json, String name) {
|
private static JSONObject getJson(JSONObject json, String name) {
|
||||||
try {
|
try {
|
||||||
return json.getJSONObject(name);
|
return json.getJSONObject(name);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
@ -51,9 +42,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static void fetchUpdates() {
|
||||||
protected Void doInBackground(Void... voids) {
|
|
||||||
MagiskManager mm = Data.MM();
|
|
||||||
String jsonStr = "";
|
String jsonStr = "";
|
||||||
switch (Data.updateChannel) {
|
switch (Data.updateChannel) {
|
||||||
case Const.Value.STABLE_CHANNEL:
|
case Const.Value.STABLE_CHANNEL:
|
||||||
@ -63,7 +52,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
|||||||
jsonStr = WebService.getString(Const.Url.BETA_URL);
|
jsonStr = WebService.getString(Const.Url.BETA_URL);
|
||||||
break;
|
break;
|
||||||
case Const.Value.CUSTOM_CHANNEL:
|
case Const.Value.CUSTOM_CHANNEL:
|
||||||
jsonStr = WebService.getString(mm.prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
jsonStr = WebService.getString(Data.MM().prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +60,7 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
|||||||
try {
|
try {
|
||||||
json = new JSONObject(jsonStr);
|
json = new JSONObject(jsonStr);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject magisk = getJson(json, "magisk");
|
JSONObject magisk = getJson(json, "magisk");
|
||||||
@ -88,20 +77,24 @@ public class CheckUpdates extends ParallelTask<Void, Void, Void> {
|
|||||||
|
|
||||||
JSONObject uninstaller = getJson(json, "uninstaller");
|
JSONObject uninstaller = getJson(json, "uninstaller");
|
||||||
Data.uninstallerLink = getString(uninstaller, "link", null);
|
Data.uninstallerLink = getString(uninstaller, "link", null);
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static void check(Runnable cb) {
|
||||||
protected void onPostExecute(Void v) {
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
if (showNotification) {
|
fetchUpdates();
|
||||||
|
if (cb != null) {
|
||||||
if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) {
|
if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) {
|
||||||
NotificationMgr.managerUpdate();
|
NotificationMgr.managerUpdate();
|
||||||
} else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) {
|
} else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) {
|
||||||
NotificationMgr.magiskUpdate();
|
NotificationMgr.magiskUpdate();
|
||||||
}
|
}
|
||||||
|
cb.run();
|
||||||
}
|
}
|
||||||
Topic.publish(Topic.UPDATE_CHECK_DONE);
|
Topic.publish(Topic.UPDATE_CHECK_DONE);
|
||||||
super.onPostExecute(v);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void check() {
|
||||||
|
check(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,8 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
|
|||||||
console.add("! This zip is not a Magisk Module!");
|
console.add("! This zip is not a Magisk Module!");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// Success
|
// Reload modules
|
||||||
new LoadModules().exec();
|
Utils.loadModules();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE);
|
activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE);
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
|
||||||
import com.topjohnwu.magisk.Data;
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
import com.topjohnwu.magisk.utils.PatchAPK;
|
|
||||||
import com.topjohnwu.magisk.utils.RootUtils;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
|
||||||
import com.topjohnwu.superuser.io.SuFile;
|
|
||||||
import com.topjohnwu.superuser.io.SuFileOutputStream;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
|
|
||||||
public class HideManager extends ParallelTask<Void, Void, Boolean> {
|
|
||||||
|
|
||||||
private ProgressDialog dialog;
|
|
||||||
|
|
||||||
public HideManager(Activity activity) {
|
|
||||||
super(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String genPackageName(String prefix, int length) {
|
|
||||||
StringBuilder builder = new StringBuilder(length);
|
|
||||||
builder.append(prefix);
|
|
||||||
length -= prefix.length();
|
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
String base = "abcdefghijklmnopqrstuvwxyz";
|
|
||||||
String alpha = base + base.toUpperCase();
|
|
||||||
String full = alpha + "0123456789..........";
|
|
||||||
char next, prev = '\0';
|
|
||||||
for (int i = 0; i < length; ++i) {
|
|
||||||
if (prev == '.' || i == length - 1 || i == 0) {
|
|
||||||
next = alpha.charAt(random.nextInt(alpha.length()));
|
|
||||||
} else {
|
|
||||||
next = full.charAt(random.nextInt(full.length()));
|
|
||||||
}
|
|
||||||
builder.append(next);
|
|
||||||
prev = next;
|
|
||||||
}
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPreExecute() {
|
|
||||||
dialog = ProgressDialog.show(getActivity(),
|
|
||||||
getActivity().getString(R.string.hide_manager_toast),
|
|
||||||
getActivity().getString(R.string.hide_manager_toast2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(Void... voids) {
|
|
||||||
MagiskManager mm = Data.MM();
|
|
||||||
|
|
||||||
// Generate a new app with random package name
|
|
||||||
SuFile repack = new SuFile("/data/local/tmp/repack.apk");
|
|
||||||
String pkg = genPackageName("com.", Const.ORIG_PKG_NAME.length());
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!PatchAPK.patchPackageID(
|
|
||||||
mm.getPackageCodePath(),
|
|
||||||
new SuFileOutputStream(repack),
|
|
||||||
Const.ORIG_PKG_NAME, pkg))
|
|
||||||
return false;
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install the application
|
|
||||||
if (!ShellUtils.fastCmdResult(Shell.getShell(), "pm install " + repack))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
repack.delete();
|
|
||||||
|
|
||||||
mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
|
|
||||||
Data.exportPrefs();
|
|
||||||
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Boolean b) {
|
|
||||||
dialog.dismiss();
|
|
||||||
if (!b) {
|
|
||||||
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
|
||||||
}
|
|
||||||
super.onPostExecute(b);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
|
||||||
import com.topjohnwu.magisk.Data;
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
|
||||||
import com.topjohnwu.magisk.container.Module;
|
|
||||||
import com.topjohnwu.magisk.container.ValueSortedMap;
|
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
|
||||||
import com.topjohnwu.superuser.io.SuFile;
|
|
||||||
|
|
||||||
public class LoadModules extends ParallelTask<Void, Void, Void> {
|
|
||||||
|
|
||||||
private String[] getModList() {
|
|
||||||
SuFile path = new SuFile(Const.MAGISK_PATH);
|
|
||||||
return path.list((file, name) -> !name.equals("lost+found") && !name.equals(".core"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... voids) {
|
|
||||||
MagiskManager mm = Data.MM();
|
|
||||||
mm.moduleMap = new ValueSortedMap<>();
|
|
||||||
|
|
||||||
for (String name : getModList()) {
|
|
||||||
Module module = new Module(Const.MAGISK_PATH + "/" + name);
|
|
||||||
mm.moduleMap.put(module.getId(), module);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void v) {
|
|
||||||
Topic.publish(Topic.MODULE_LOAD_DONE);
|
|
||||||
super.onPostExecute(v);
|
|
||||||
}
|
|
||||||
}
|
|
153
app/src/full/java/com/topjohnwu/magisk/asyncs/PatchAPK.java
Normal file
153
app/src/full/java/com/topjohnwu/magisk/asyncs/PatchAPK.java
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.Const;
|
||||||
|
import com.topjohnwu.magisk.Data;
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.utils.RootUtils;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||||
|
import com.topjohnwu.superuser.ShellUtils;
|
||||||
|
import com.topjohnwu.superuser.io.SuFile;
|
||||||
|
import com.topjohnwu.superuser.io.SuFileOutputStream;
|
||||||
|
import com.topjohnwu.utils.JarMap;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
|
||||||
|
public class PatchAPK {
|
||||||
|
|
||||||
|
private static String genPackageName(String prefix, int length) {
|
||||||
|
StringBuilder builder = new StringBuilder(length);
|
||||||
|
builder.append(prefix);
|
||||||
|
length -= prefix.length();
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
String base = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
String alpha = base + base.toUpperCase();
|
||||||
|
String full = alpha + "0123456789..........";
|
||||||
|
char next, prev = '\0';
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
if (prev == '.' || i == length - 1 || i == 0) {
|
||||||
|
next = alpha.charAt(random.nextInt(alpha.length()));
|
||||||
|
} else {
|
||||||
|
next = full.charAt(random.nextInt(full.length()));
|
||||||
|
}
|
||||||
|
builder.append(next);
|
||||||
|
prev = next;
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int findOffset(byte buf[], byte pattern[]) {
|
||||||
|
int offset = -1;
|
||||||
|
for (int i = 0; i < buf.length - pattern.length; ++i) {
|
||||||
|
boolean match = true;
|
||||||
|
for (int j = 0; j < pattern.length; ++j) {
|
||||||
|
if (buf[i + j] != pattern[j]) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
offset = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It seems that AAPT sometimes generate another type of string format */
|
||||||
|
private static boolean fallbackPatch(byte xml[], String from, String to) {
|
||||||
|
|
||||||
|
byte[] target = new byte[from.length() * 2 + 2];
|
||||||
|
for (int i = 0; i < from.length(); ++i) {
|
||||||
|
target[i * 2] = (byte) from.charAt(i);
|
||||||
|
}
|
||||||
|
int offset = findOffset(xml, target);
|
||||||
|
if (offset < 0)
|
||||||
|
return false;
|
||||||
|
byte[] dest = new byte[target.length - 2];
|
||||||
|
for (int i = 0; i < to.length(); ++i) {
|
||||||
|
dest[i * 2] = (byte) to.charAt(i);
|
||||||
|
}
|
||||||
|
System.arraycopy(dest, 0, xml, offset, dest.length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean findAndPatch(byte xml[], String from, String to) {
|
||||||
|
byte target[] = (from + '\0').getBytes();
|
||||||
|
int offset = findOffset(xml, target);
|
||||||
|
if (offset < 0)
|
||||||
|
return fallbackPatch(xml, from, to);
|
||||||
|
System.arraycopy(to.getBytes(), 0, xml, offset, to.length());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean patchAndHide() {
|
||||||
|
MagiskManager mm = Data.MM();
|
||||||
|
|
||||||
|
// Generate a new app with random package name
|
||||||
|
SuFile repack = new SuFile("/data/local/tmp/repack.apk");
|
||||||
|
String pkg = genPackageName("com.", Const.ORIG_PKG_NAME.length());
|
||||||
|
|
||||||
|
try {
|
||||||
|
JarMap apk = new JarMap(mm.getPackageCodePath());
|
||||||
|
if (!patchPackageID(apk, Const.ORIG_PKG_NAME, pkg))
|
||||||
|
return false;
|
||||||
|
ZipUtils.signZip(apk, new SuFileOutputStream(repack));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install the application
|
||||||
|
if (!ShellUtils.fastCmdResult("pm install " + repack))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
repack.delete();
|
||||||
|
|
||||||
|
mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
|
||||||
|
Data.exportPrefs();
|
||||||
|
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean patchPackageID(JarMap apk, String from, String to) {
|
||||||
|
try {
|
||||||
|
JarEntry je = apk.getJarEntry(Const.ANDROID_MANIFEST);
|
||||||
|
byte xml[] = apk.getRawData(je);
|
||||||
|
|
||||||
|
if (!findAndPatch(xml, from, to))
|
||||||
|
return false;
|
||||||
|
if (!findAndPatch(xml, from + ".provider", to + ".provider"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Write in changes
|
||||||
|
apk.getOutputStream(je).write(xml);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void hideManager(Activity activity) {
|
||||||
|
ProgressDialog dialog = ProgressDialog.show(activity,
|
||||||
|
activity.getString(R.string.hide_manager_toast),
|
||||||
|
activity.getString(R.string.hide_manager_toast2));
|
||||||
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
|
boolean b = patchAndHide();
|
||||||
|
Data.mainHandler.post(() -> {
|
||||||
|
dialog.cancel();
|
||||||
|
if (!b) {
|
||||||
|
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,39 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
import com.topjohnwu.superuser.ShellUtils;
|
|
||||||
|
|
||||||
public class RestoreImages extends ParallelTask<Void, Void, Boolean> {
|
|
||||||
|
|
||||||
private ProgressDialog dialog;
|
|
||||||
|
|
||||||
public RestoreImages(Activity activity) {
|
|
||||||
super(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPreExecute() {
|
|
||||||
Activity a = getActivity();
|
|
||||||
dialog = ProgressDialog.show(a, a.getString(R.string.restore_img), a.getString(R.string.restore_img_msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(Void... voids) {
|
|
||||||
return ShellUtils.fastCmdResult("restore_imgs");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Boolean result) {
|
|
||||||
dialog.cancel();
|
|
||||||
if (result) {
|
|
||||||
Utils.toast(R.string.restore_done, Toast.LENGTH_SHORT);
|
|
||||||
} else {
|
|
||||||
Utils.toast(R.string.restore_fail, Toast.LENGTH_LONG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
@ -34,7 +35,7 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
public class UpdateRepos {
|
||||||
|
|
||||||
private static final int CHECK_ETAG = 0;
|
private static final int CHECK_ETAG = 0;
|
||||||
private static final int LOAD_NEXT = 1;
|
private static final int LOAD_NEXT = 1;
|
||||||
@ -44,16 +45,14 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
|||||||
private static final int CORE_POOL_SIZE = Math.max(2, CPU_COUNT - 1);
|
private static final int CORE_POOL_SIZE = Math.max(2, CPU_COUNT - 1);
|
||||||
|
|
||||||
private MagiskManager mm;
|
private MagiskManager mm;
|
||||||
private List<String> etags, newEtags = new LinkedList<>();
|
private List<String> etags, newEtags;
|
||||||
private Set<String> cached;
|
private Set<String> cached;
|
||||||
private boolean forceUpdate;
|
|
||||||
private ExecutorService threadPool;
|
private ExecutorService threadPool;
|
||||||
|
|
||||||
public UpdateRepos(boolean force) {
|
public UpdateRepos() {
|
||||||
Topic.reset(Topic.REPO_LOAD_DONE);
|
|
||||||
mm = Data.MM();
|
mm = Data.MM();
|
||||||
forceUpdate = force;
|
|
||||||
threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
|
threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
|
||||||
|
newEtags = new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitTasks() {
|
private void waitTasks() {
|
||||||
@ -85,7 +84,10 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
|||||||
set.remove(id);
|
set.remove(id);
|
||||||
repo.update(date);
|
repo.update(date);
|
||||||
mm.repoDB.addRepo(repo);
|
mm.repoDB.addRepo(repo);
|
||||||
publishProgress();
|
Data.mainHandler.post(() -> {
|
||||||
|
if (ReposFragment.adapter != null)
|
||||||
|
ReposFragment.adapter.notifyDBChanged();
|
||||||
|
});
|
||||||
} catch (Repo.IllegalRepoException e) {
|
} catch (Repo.IllegalRepoException e) {
|
||||||
Logger.debug(e.getMessage());
|
Logger.debug(e.getMessage());
|
||||||
mm.repoDB.removeRepo(id);
|
mm.repoDB.removeRepo(id);
|
||||||
@ -142,26 +144,7 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void fullReload() {
|
||||||
protected void onProgressUpdate(Void... values) {
|
|
||||||
if (ReposFragment.adapter != null)
|
|
||||||
ReposFragment.adapter.notifyDBChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... voids) {
|
|
||||||
etags = Arrays.asList(mm.prefs.getString(Const.Key.ETAG_KEY, "").split(","));
|
|
||||||
cached = mm.repoDB.getRepoIDSet();
|
|
||||||
|
|
||||||
if (loadPage(0, CHECK_ETAG)) {
|
|
||||||
waitTasks();
|
|
||||||
|
|
||||||
// The leftover cached means they are removed from online repo
|
|
||||||
mm.repoDB.removeRepo(cached);
|
|
||||||
|
|
||||||
// Update ETag
|
|
||||||
mm.prefs.edit().putString(Const.Key.ETAG_KEY, TextUtils.join(",", newEtags)).apply();
|
|
||||||
} else if (forceUpdate) {
|
|
||||||
Cursor c = mm.repoDB.getRawCursor();
|
Cursor c = mm.repoDB.getRawCursor();
|
||||||
while (c.moveToNext()) {
|
while (c.moveToNext()) {
|
||||||
Repo repo = new Repo(c);
|
Repo repo = new Repo(c);
|
||||||
@ -177,12 +160,29 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
|
|||||||
}
|
}
|
||||||
waitTasks();
|
waitTasks();
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
public void exec(boolean force) {
|
||||||
|
Topic.reset(Topic.REPO_LOAD_DONE);
|
||||||
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
|
etags = Arrays.asList(mm.prefs.getString(Const.Key.ETAG_KEY, "").split(","));
|
||||||
|
cached = mm.repoDB.getRepoIDSet();
|
||||||
|
|
||||||
|
if (loadPage(0, CHECK_ETAG)) {
|
||||||
|
waitTasks();
|
||||||
|
|
||||||
|
// The leftover cached means they are removed from online repo
|
||||||
|
mm.repoDB.removeRepo(cached);
|
||||||
|
|
||||||
|
// Update ETag
|
||||||
|
mm.prefs.edit().putString(Const.Key.ETAG_KEY, TextUtils.join(",", newEtags)).apply();
|
||||||
|
} else if (force) {
|
||||||
|
fullReload();
|
||||||
|
}
|
||||||
|
Topic.publish(Topic.REPO_LOAD_DONE);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void exec() {
|
||||||
protected void onPostExecute(Void v) {
|
exec(false);
|
||||||
Topic.publish(Topic.REPO_LOAD_DONE);
|
|
||||||
super.onPostExecute(v);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
package com.topjohnwu.magisk.components;
|
package com.topjohnwu.magisk.components;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.FlashActivity;
|
import com.topjohnwu.magisk.FlashActivity;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.RestoreImages;
|
|
||||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
public class UninstallDialog extends CustomAlertDialog {
|
public class UninstallDialog extends CustomAlertDialog {
|
||||||
|
|
||||||
@ -23,7 +26,19 @@ public class UninstallDialog extends CustomAlertDialog {
|
|||||||
MagiskManager mm = Data.MM();
|
MagiskManager mm = Data.MM();
|
||||||
setTitle(R.string.uninstall_magisk_title);
|
setTitle(R.string.uninstall_magisk_title);
|
||||||
setMessage(R.string.uninstall_magisk_msg);
|
setMessage(R.string.uninstall_magisk_msg);
|
||||||
setNeutralButton(R.string.restore_img, (d, i) -> new RestoreImages(activity).exec());
|
setNeutralButton(R.string.restore_img, (d, i) -> {
|
||||||
|
ProgressDialog dialog = ProgressDialog.show(activity,
|
||||||
|
activity.getString(R.string.restore_img),
|
||||||
|
activity.getString(R.string.restore_img_msg));
|
||||||
|
Shell.su("restore_imgs").submit(result -> {
|
||||||
|
dialog.cancel();
|
||||||
|
if (result.isSuccess()) {
|
||||||
|
Utils.toast(R.string.restore_done, Toast.LENGTH_SHORT);
|
||||||
|
} else {
|
||||||
|
Utils.toast(R.string.restore_fail, Toast.LENGTH_LONG);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
if (!TextUtils.isEmpty(Data.uninstallerLink)) {
|
if (!TextUtils.isEmpty(Data.uninstallerLink)) {
|
||||||
setPositiveButton(R.string.complete_uninstall, (d, i) ->
|
setPositiveButton(R.string.complete_uninstall, (d, i) ->
|
||||||
Download.receive(activity, new DownloadReceiver() {
|
Download.receive(activity, new DownloadReceiver() {
|
||||||
|
@ -7,12 +7,13 @@ import android.net.Uri;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
|
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
||||||
import com.topjohnwu.magisk.utils.Download;
|
import com.topjohnwu.magisk.utils.Download;
|
||||||
import com.topjohnwu.magisk.utils.PatchAPK;
|
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||||
|
import com.topjohnwu.utils.JarMap;
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
public class ManagerUpdate extends BroadcastReceiver {
|
public class ManagerUpdate extends BroadcastReceiver {
|
||||||
@ -31,13 +32,14 @@ public class ManagerUpdate extends BroadcastReceiver {
|
|||||||
public void onDownloadDone(Context context, Uri uri) {
|
public void onDownloadDone(Context context, Uri uri) {
|
||||||
if (!context.getPackageName().equals(Const.ORIG_PKG_NAME)) {
|
if (!context.getPackageName().equals(Const.ORIG_PKG_NAME)) {
|
||||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
String o = uri.getPath();
|
String orig = uri.getPath();
|
||||||
String p = o.substring(0, o.lastIndexOf('.')) + "-patched.apk";
|
String patch = orig.substring(0, orig.lastIndexOf('.')) + "-patched.apk";
|
||||||
try {
|
try {
|
||||||
PatchAPK.patchPackageID(o, new BufferedOutputStream(new FileOutputStream(p)),
|
JarMap apk = new JarMap(orig);
|
||||||
Const.ORIG_PKG_NAME, context.getPackageName());
|
PatchAPK.patchPackageID(apk, Const.ORIG_PKG_NAME, context.getPackageName());
|
||||||
} catch (FileNotFoundException ignored) { }
|
ZipUtils.signZip(apk, new BufferedOutputStream(new FileOutputStream(patch)));
|
||||||
super.onDownloadDone(context, Uri.fromFile(new File(p)));
|
super.onDownloadDone(context, Uri.fromFile(new File(patch)));
|
||||||
|
} catch (Exception ignored) { }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
super.onDownloadDone(context, uri);
|
super.onDownloadDone(context, uri);
|
||||||
|
@ -11,7 +11,7 @@ public class UpdateCheckService extends JobService {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onStartJob(JobParameters params) {
|
public boolean onStartJob(JobParameters params) {
|
||||||
Shell.getShell();
|
Shell.getShell();
|
||||||
new CheckUpdates(true).setCallBack(() -> jobFinished(params, false)).exec();
|
CheckUpdates.check(() -> jobFinished(params, false));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
|
||||||
import com.topjohnwu.utils.JarMap;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
|
|
||||||
public class PatchAPK {
|
|
||||||
|
|
||||||
private static int findOffset(byte buf[], byte pattern[]) {
|
|
||||||
int offset = -1;
|
|
||||||
for (int i = 0; i < buf.length - pattern.length; ++i) {
|
|
||||||
boolean match = true;
|
|
||||||
for (int j = 0; j < pattern.length; ++j) {
|
|
||||||
if (buf[i + j] != pattern[j]) {
|
|
||||||
match = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (match) {
|
|
||||||
offset = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* It seems that AAPT sometimes generate another type of string format */
|
|
||||||
private static boolean fallbackPatch(byte xml[], String from, String to) {
|
|
||||||
|
|
||||||
byte[] target = new byte[from.length() * 2 + 2];
|
|
||||||
for (int i = 0; i < from.length(); ++i) {
|
|
||||||
target[i * 2] = (byte) from.charAt(i);
|
|
||||||
}
|
|
||||||
int offset = findOffset(xml, target);
|
|
||||||
if (offset < 0)
|
|
||||||
return false;
|
|
||||||
byte[] dest = new byte[target.length - 2];
|
|
||||||
for (int i = 0; i < to.length(); ++i) {
|
|
||||||
dest[i * 2] = (byte) to.charAt(i);
|
|
||||||
}
|
|
||||||
System.arraycopy(dest, 0, xml, offset, dest.length);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean findAndPatch(byte xml[], String from, String to) {
|
|
||||||
byte target[] = (from + '\0').getBytes();
|
|
||||||
int offset = findOffset(xml, target);
|
|
||||||
if (offset < 0)
|
|
||||||
return fallbackPatch(xml, from, to);
|
|
||||||
System.arraycopy(to.getBytes(), 0, xml, offset, to.length());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean patchPackageID(String fileName, OutputStream out, String from, String to) {
|
|
||||||
try {
|
|
||||||
JarMap apk = new JarMap(fileName);
|
|
||||||
JarEntry je = apk.getJarEntry(Const.ANDROID_MANIFEST);
|
|
||||||
byte xml[] = apk.getRawData(je);
|
|
||||||
|
|
||||||
if (!findAndPatch(xml, from, to))
|
|
||||||
return false;
|
|
||||||
if (!findAndPatch(xml, from + ".provider", to + ".provider"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Write in changes
|
|
||||||
apk.getOutputStream(je).write(xml);
|
|
||||||
|
|
||||||
// Sign the APK
|
|
||||||
ZipUtils.signZip(apk, out);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -81,6 +81,16 @@ public class Topic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPublished(@TopicID int... topics) {
|
||||||
|
for (int topic : topics) {
|
||||||
|
if (topicList[topic] == null)
|
||||||
|
return false;
|
||||||
|
if (!topicList[topic].published)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static class Store {
|
private static class Store {
|
||||||
boolean published = false;
|
boolean published = false;
|
||||||
Set<Subscriber> subscribers = new HashSet<>();
|
Set<Subscriber> subscribers = new HashSet<>();
|
||||||
|
@ -7,15 +7,20 @@ import android.content.Context;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Const;
|
import com.topjohnwu.magisk.Const;
|
||||||
import com.topjohnwu.magisk.Data;
|
import com.topjohnwu.magisk.Data;
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.container.Module;
|
||||||
|
import com.topjohnwu.magisk.container.ValueSortedMap;
|
||||||
import com.topjohnwu.magisk.services.UpdateCheckService;
|
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||||
|
import com.topjohnwu.superuser.io.SuFile;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
@ -90,4 +95,19 @@ public class Utils {
|
|||||||
public static void toast(int resId, int duration) {
|
public static void toast(int resId, int duration) {
|
||||||
Data.mainHandler.post(() -> Toast.makeText(Data.MM(), resId, duration).show());
|
Data.mainHandler.post(() -> Toast.makeText(Data.MM(), resId, duration).show());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void loadModules() {
|
||||||
|
Topic.reset(Topic.MODULE_LOAD_DONE);
|
||||||
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||||
|
Map<String, Module> moduleMap = new ValueSortedMap<>();
|
||||||
|
SuFile path = new SuFile(Const.MAGISK_PATH);
|
||||||
|
String[] modules = path.list(
|
||||||
|
(file, name) -> !name.equals("lost+found") && !name.equals(".core"));
|
||||||
|
for (String name : modules) {
|
||||||
|
Module module = new Module(Const.MAGISK_PATH + "/" + name);
|
||||||
|
moduleMap.put(module.getId(), module);
|
||||||
|
}
|
||||||
|
Topic.publish(Topic.MODULE_LOAD_DONE, moduleMap);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user