Reload ModulesFragment after user removed or added (#1465)
Co-authored-by: LoveSy <shana@zju.edu.cn>
This commit is contained in:
parent
61c447091f
commit
6a735d2064
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
package org.lsposed.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Application;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
|
|
@ -116,6 +117,10 @@ public class App extends Application {
|
|||
}
|
||||
|
||||
public static final String TAG = "LSPosedManager";
|
||||
private static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
|
||||
private static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
|
||||
private static final String ACTION_USER_INFO_CHANGED = "android.intent.action.USER_INFO_CHANGED";
|
||||
private static final String EXTRA_REMOVED_FOR_ALL_USERS = "android.intent.extra.REMOVED_FOR_ALL_USERS";
|
||||
private static App instance = null;
|
||||
private static OkHttpClient okHttpClient;
|
||||
private static Cache okHttpCache;
|
||||
|
|
@ -138,6 +143,7 @@ public class App extends Application {
|
|||
return !Process.isApplicationUid(Process.myUid());
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
private void setCrashReport() {
|
||||
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
|
||||
|
||||
|
|
@ -182,17 +188,39 @@ public class App extends Application {
|
|||
DayNightDelegate.setDefaultNightMode(ThemeUtil.getDarkTheme());
|
||||
LocaleDelegate.setDefaultLocale(getLocale());
|
||||
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction("org.lsposed.manager.NOTIFICATION");
|
||||
registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
int userId = intent.getIntExtra(Intent.EXTRA_USER, 0);
|
||||
String packageName = intent.getStringExtra("android.intent.extra.PACKAGES");
|
||||
boolean packageFullyRemoved = intent.getBooleanExtra(Intent.ACTION_PACKAGE_FULLY_REMOVED, false);
|
||||
if (packageName != null) {
|
||||
ModuleUtil.getInstance().reloadSingleModule(packageName, userId, packageFullyRemoved);
|
||||
public void onReceive(Context context, Intent inIntent) {
|
||||
var intent = (Intent) inIntent.getParcelableExtra(Intent.EXTRA_INTENT);
|
||||
Log.d(TAG, "onReceive: " + intent);
|
||||
switch (intent.getAction()) {
|
||||
case Intent.ACTION_PACKAGE_ADDED:
|
||||
case Intent.ACTION_PACKAGE_CHANGED:
|
||||
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
|
||||
case Intent.ACTION_UID_REMOVED: {
|
||||
var userId = intent.getIntExtra(Intent.EXTRA_USER, 0);
|
||||
var packageName = intent.getStringExtra("android.intent.extra.PACKAGES");
|
||||
var packageRemovedForAllUsers = intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false);
|
||||
var isXposedModule = intent.getBooleanExtra("isXposedModule", false);
|
||||
if (packageName != null) {
|
||||
if (isXposedModule)
|
||||
ModuleUtil.getInstance().reloadSingleModule(packageName, userId, packageRemovedForAllUsers);
|
||||
else
|
||||
App.getExecutorService().submit(() -> AppHelper.getAppList(true));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACTION_USER_ADDED:
|
||||
case ACTION_USER_REMOVED:
|
||||
case ACTION_USER_INFO_CHANGED: {
|
||||
App.getExecutorService().submit(() -> ModuleUtil.getInstance().reloadInstalledModules());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, new IntentFilter(Intent.ACTION_PACKAGE_CHANGED));
|
||||
}, intentFilter);
|
||||
|
||||
UpdateUtil.loadRemoteVersion();
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
package org.lsposed.manager.adapters;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
|
@ -44,6 +45,7 @@ public class AppHelper {
|
|||
private static List<PackageInfo> appList;
|
||||
private static final ConcurrentHashMap<PackageInfo, CharSequence> appLabel = new ConcurrentHashMap<>();
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
public static Intent getSettingsIntent(String packageName, int userId) {
|
||||
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
|
||||
intentToResolve.addCategory(SETTINGS_CATEGORY);
|
||||
|
|
@ -63,6 +65,7 @@ public class AppHelper {
|
|||
return intent;
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
public static Intent getLaunchIntentForPackage(String packageName, int userId) {
|
||||
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
|
||||
intentToResolve.addCategory(Intent.CATEGORY_INFO);
|
||||
|
|
|
|||
|
|
@ -266,6 +266,7 @@ public class ScopeAdapter extends EmptyStateRecyclerView.EmptyStateAdapter<Scope
|
|||
return true;
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
public boolean onContextItemSelected(@NonNull MenuItem item) {
|
||||
ApplicationInfo info = selectedInfo;
|
||||
if (info == null) {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
package org.lsposed.manager.ui.fragment;
|
||||
|
||||
import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
|
||||
import static androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
|
|
@ -37,6 +36,7 @@ import android.text.TextUtils;
|
|||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.TypefaceSpan;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
|
@ -72,9 +72,9 @@ import org.lsposed.manager.App;
|
|||
import org.lsposed.manager.ConfigManager;
|
||||
import org.lsposed.manager.R;
|
||||
import org.lsposed.manager.adapters.AppHelper;
|
||||
import org.lsposed.manager.databinding.SwiperefreshRecyclerviewBinding;
|
||||
import org.lsposed.manager.databinding.FragmentPagerBinding;
|
||||
import org.lsposed.manager.databinding.ItemModuleBinding;
|
||||
import org.lsposed.manager.databinding.SwiperefreshRecyclerviewBinding;
|
||||
import org.lsposed.manager.repo.RepoLoader;
|
||||
import org.lsposed.manager.ui.dialog.BlurBehindDialogBuilder;
|
||||
import org.lsposed.manager.ui.widget.EmptyStateRecyclerView;
|
||||
|
|
@ -95,12 +95,12 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
private static final PackageManager pm = App.getInstance().getPackageManager();
|
||||
private static final ModuleUtil moduleUtil = ModuleUtil.getInstance();
|
||||
private static final RepoLoader repoLoader = RepoLoader.getInstance();
|
||||
private static final List<UserInfo> users = ConfigManager.getUsers();
|
||||
protected FragmentPagerBinding binding;
|
||||
protected SearchView searchView;
|
||||
private SearchView.OnQueryTextListener searchListener;
|
||||
|
||||
final ArrayList<ModuleAdapter> adapters = new ArrayList<>();
|
||||
SparseArray<ModuleAdapter> adapters = new SparseArray<>();
|
||||
PagerAdapter pagerAdapter = null;
|
||||
|
||||
private ModuleUtil.InstalledModule selectedModule;
|
||||
|
||||
|
|
@ -110,24 +110,22 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
searchListener = new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
adapters.forEach(adapter -> adapter.getFilter().filter(query));
|
||||
forEachAdaptor(adapter -> adapter.getFilter().filter(query));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String query) {
|
||||
adapters.forEach(adapter -> adapter.getFilter().filter(query));
|
||||
forEachAdaptor(adapter -> adapter.getFilter().filter(query));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (users != null) {
|
||||
for (var user : users) {
|
||||
var adapter = new ModuleAdapter(user);
|
||||
adapter.setHasStableIds(true);
|
||||
adapter.setStateRestorationPolicy(PREVENT_WHEN_EMPTY);
|
||||
adapters.add(adapter);
|
||||
}
|
||||
private void forEachAdaptor(Consumer<? super ModuleAdapter> action) {
|
||||
var snapshot = adapters;
|
||||
for (var i = 0; i < snapshot.size(); ++i) {
|
||||
action.accept(snapshot.valueAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +147,8 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
binding = FragmentPagerBinding.inflate(inflater, container, false);
|
||||
binding.appBar.setLiftable(true);
|
||||
setupToolbar(binding.toolbar, binding.clickView, R.string.Modules, R.menu.menu_modules);
|
||||
binding.viewPager.setAdapter(new PagerAdapter(this));
|
||||
pagerAdapter = new PagerAdapter(this);
|
||||
binding.viewPager.setAdapter(pagerAdapter);
|
||||
binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
|
|
@ -159,29 +158,22 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
|
||||
new TabLayoutMediator(binding.tabLayout, binding.viewPager, (tab, position) -> {
|
||||
if (position < adapters.size()) {
|
||||
tab.setText(adapters.get(position).getUser().name);
|
||||
tab.setText(adapters.valueAt(position).getUser().name);
|
||||
}
|
||||
}).attach();
|
||||
|
||||
if (users != null && users.size() != 1) {
|
||||
binding.viewPager.setUserInputEnabled(true);
|
||||
binding.tabLayout.setVisibility(View.VISIBLE);
|
||||
binding.tabLayout.addOnLayoutChangeListener((view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||
ViewGroup vg = (ViewGroup) binding.tabLayout.getChildAt(0);
|
||||
int tabLayoutWidth = IntStream.range(0, binding.tabLayout.getTabCount()).map(i -> vg.getChildAt(i).getWidth()).sum();
|
||||
if (tabLayoutWidth <= binding.getRoot().getWidth()) {
|
||||
binding.tabLayout.setTabMode(TabLayout.MODE_FIXED);
|
||||
binding.tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
|
||||
}
|
||||
});
|
||||
binding.fab.show();
|
||||
} else {
|
||||
binding.viewPager.setUserInputEnabled(false);
|
||||
binding.tabLayout.setVisibility(View.GONE);
|
||||
}
|
||||
binding.tabLayout.addOnLayoutChangeListener((view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||
ViewGroup vg = (ViewGroup) binding.tabLayout.getChildAt(0);
|
||||
int tabLayoutWidth = IntStream.range(0, binding.tabLayout.getTabCount()).map(i -> vg.getChildAt(i).getWidth()).sum();
|
||||
if (tabLayoutWidth <= binding.getRoot().getWidth()) {
|
||||
binding.tabLayout.setTabMode(TabLayout.MODE_FIXED);
|
||||
binding.tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
|
||||
}
|
||||
});
|
||||
|
||||
binding.fab.setOnClickListener(v -> {
|
||||
var bundle = new Bundle();
|
||||
var user = adapters.get(binding.viewPager.getCurrentItem()).getUser();
|
||||
var user = adapters.valueAt(binding.viewPager.getCurrentItem()).getUser();
|
||||
bundle.putParcelable("userInfo", user);
|
||||
var f = new RecyclerViewDialogFragment();
|
||||
f.setArguments(bundle);
|
||||
|
|
@ -190,7 +182,7 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
|
||||
moduleUtil.addListener(this);
|
||||
repoLoader.addListener(this);
|
||||
updateModuleSummary();
|
||||
onModulesReloaded();
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
|
@ -214,23 +206,48 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
adapters.forEach(ModuleAdapter::refresh);
|
||||
forEachAdaptor(ModuleAdapter::refresh);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSingleModuleReloaded(ModuleUtil.InstalledModule module) {
|
||||
adapters.forEach(ModuleAdapter::refresh);
|
||||
forEachAdaptor(ModuleAdapter::refresh);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModulesReloaded() {
|
||||
adapters.forEach(ModuleAdapter::refresh);
|
||||
var users = moduleUtil.getUsers();
|
||||
if (users == null) return;
|
||||
|
||||
if (users.size() != 1) {
|
||||
binding.viewPager.setUserInputEnabled(true);
|
||||
binding.tabLayout.setVisibility(View.VISIBLE);
|
||||
binding.fab.show();
|
||||
} else {
|
||||
binding.viewPager.setUserInputEnabled(false);
|
||||
binding.tabLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
var tmp = new SparseArray<ModuleAdapter>(users.size());
|
||||
var snapshot = adapters;
|
||||
for (var user : users) {
|
||||
if (snapshot.indexOfKey(user.id) >= 0) {
|
||||
tmp.put(user.id, snapshot.get(user.id));
|
||||
} else {
|
||||
var adapter = new ModuleAdapter(user);
|
||||
adapter.setHasStableIds(true);
|
||||
tmp.put(user.id, adapter);
|
||||
}
|
||||
}
|
||||
adapters = tmp;
|
||||
forEachAdaptor(ModuleAdapter::refresh);
|
||||
runOnUiThread(pagerAdapter::notifyDataSetChanged);
|
||||
updateModuleSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepoLoaded() {
|
||||
adapters.forEach(ModuleAdapter::refresh);
|
||||
forEachAdaptor(ModuleAdapter::refresh);
|
||||
}
|
||||
|
||||
private void updateModuleSummary() {
|
||||
|
|
@ -261,6 +278,7 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
.show();
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
@Override
|
||||
public boolean onContextItemSelected(@NonNull MenuItem item) {
|
||||
if (selectedModule == null) {
|
||||
|
|
@ -348,9 +366,9 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
if (fragment == null || arguments == null) {
|
||||
return null;
|
||||
}
|
||||
int position = arguments.getInt("position");
|
||||
int userId = arguments.getInt("user_id");
|
||||
binding = SwiperefreshRecyclerviewBinding.inflate(getLayoutInflater(), container, false);
|
||||
adapter = fragment.adapters.get(position);
|
||||
adapter = fragment.adapters.get(userId);
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
binding.recyclerView.setLayoutManager(new LinearLayoutManager(requireActivity()));
|
||||
binding.swipeRefreshLayout.setOnRefreshListener(adapter::fullRefresh);
|
||||
|
|
@ -430,7 +448,7 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("position", position);
|
||||
bundle.putInt("user_id", adapters.keyAt(position));
|
||||
Fragment fragment = new ModuleListFragment();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
|
|
@ -443,7 +461,12 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
|
|||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
return adapters.keyAt(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsItem(long itemId) {
|
||||
return adapters.indexOfKey((int) itemId) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,11 +30,13 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import org.lsposed.lspd.models.UserInfo;
|
||||
import org.lsposed.manager.App;
|
||||
import org.lsposed.manager.ConfigManager;
|
||||
import org.lsposed.manager.repo.RepoLoader;
|
||||
import org.lsposed.manager.repo.model.OnlineModule;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
|
@ -50,6 +52,7 @@ public final class ModuleUtil {
|
|||
private final PackageManager pm;
|
||||
private final Set<ModuleListener> listeners = ConcurrentHashMap.newKeySet();
|
||||
private HashSet<String> enabledModules = new HashSet<>();
|
||||
private List<UserInfo> users = new ArrayList<>();
|
||||
private Map<Pair<String, Integer>, InstalledModule> installedModules = new HashMap<>();
|
||||
private boolean modulesLoaded = false;
|
||||
|
||||
|
|
@ -89,6 +92,7 @@ public final class ModuleUtil {
|
|||
}
|
||||
|
||||
Map<Pair<String, Integer>, InstalledModule> modules = new HashMap<>();
|
||||
var users = ConfigManager.getUsers();
|
||||
for (PackageInfo pkg : ConfigManager.getInstalledPackagesFromAllUsers(PackageManager.GET_META_DATA, false)) {
|
||||
ApplicationInfo app = pkg.applicationInfo;
|
||||
|
||||
|
|
@ -100,11 +104,18 @@ public final class ModuleUtil {
|
|||
|
||||
installedModules = modules;
|
||||
|
||||
this.users = users;
|
||||
|
||||
enabledModules = new HashSet<>(Arrays.asList(ConfigManager.getEnabledModules()));
|
||||
modulesLoaded = true;
|
||||
listeners.forEach(ModuleListener::onModulesReloaded);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<UserInfo> getUsers() {
|
||||
return modulesLoaded ? users : null;
|
||||
}
|
||||
|
||||
public InstalledModule reloadSingleModule(String packageName, int userId) {
|
||||
return reloadSingleModule(packageName, userId, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package org.lsposed.lspd.service;
|
|||
|
||||
import static org.lsposed.lspd.service.ServiceManager.TAG;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.IServiceConnection;
|
||||
|
|
@ -101,17 +102,16 @@ public class ActivityManagerService {
|
|||
return am.startUserInBackground(userId);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static Intent registerReceiver(String callerPackage,
|
||||
String callingFeatureId, IIntentReceiver receiver, IntentFilter filter,
|
||||
String requiredPermission, int userId, int flags) throws RemoteException {
|
||||
IActivityManager am = getActivityManager();
|
||||
if (am == null || thread == null) return null;
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S || (Build.VERSION.SDK_INT == Build.VERSION_CODES.R && Build.VERSION.PREVIEW_SDK_INT != 0))
|
||||
return am.registerReceiverWithFeature(thread, callerPackage, callingFeatureId, "null", receiver, filter, requiredPermission, userId, flags);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && Build.VERSION.PREVIEW_SDK_INT != 0))
|
||||
return am.registerReceiverWithFeature(thread, callerPackage, callingFeatureId, "null", receiver, filter, requiredPermission, userId, flags);
|
||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
return am.registerReceiverWithFeature(thread, callerPackage, callingFeatureId, receiver, filter, requiredPermission, userId, flags);
|
||||
} else {
|
||||
return am.registerReceiver(thread, callerPackage, receiver, filter, requiredPermission, userId, flags);
|
||||
|
|
|
|||
|
|
@ -252,13 +252,11 @@ public class LSPManagerService extends ILSPManagerService.Stub {
|
|||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
public static void broadcastIntent(String modulePackageName, int moduleUserId, boolean packageFullyRemoved) {
|
||||
Intent intent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
|
||||
public static void broadcastIntent(Intent inIntent) {
|
||||
var intent = new Intent("org.lsposed.manager.NOTIFICATION");
|
||||
intent.putExtra(Intent.EXTRA_INTENT, inIntent);
|
||||
intent.addFlags(0x01000000); //Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
|
||||
intent.addFlags(0x00400000); //Intent.FLAG_RECEIVER_FROM_SHELL
|
||||
intent.putExtra("android.intent.extra.PACKAGES", modulePackageName);
|
||||
intent.putExtra(Intent.EXTRA_USER, moduleUserId);
|
||||
intent.putExtra(Intent.ACTION_PACKAGE_FULLY_REMOVED, packageFullyRemoved);
|
||||
intent.setPackage(BuildConfig.MANAGER_INJECTED_PKG_NAME);
|
||||
try {
|
||||
ActivityManagerService.broadcastIntentWithFeature(null, intent,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ import java.util.Arrays;
|
|||
public class LSPosedService extends ILSPosedService.Stub {
|
||||
private static final int AID_NOBODY = 9999;
|
||||
private static final int USER_NULL = -10000;
|
||||
private static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
|
||||
public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
|
||||
private static final String EXTRA_USER_HANDLE = "android.intent.extra.user_handle";
|
||||
private static final String EXTRA_REMOVED_FOR_ALL_USERS = "android.intent.extra.REMOVED_FOR_ALL_USERS";
|
||||
|
||||
@Override
|
||||
public ILSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) {
|
||||
|
|
@ -79,7 +83,7 @@ public class LSPosedService extends ILSPosedService.Stub {
|
|||
if (uid == AID_NOBODY || uid <= 0) return;
|
||||
int userId = intent.getIntExtra("android.intent.extra.user_handle", USER_NULL);
|
||||
var intentAction = intent.getAction();
|
||||
var allUsers = intent.getBooleanExtra("android.intent.extra.REMOVED_FOR_ALL_USERS", false);
|
||||
var allUsers = intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false);
|
||||
if (userId == USER_NULL) userId = uid % PER_USER_RANGE;
|
||||
Uri uri = intent.getData();
|
||||
String moduleName = (uri != null) ? uri.getSchemeSpecificPart() : ConfigManager.getInstance().getModule(uid);
|
||||
|
|
@ -102,8 +106,8 @@ public class LSPosedService extends ILSPosedService.Stub {
|
|||
// because we only care about when the apk is gone
|
||||
if (moduleName != null && allUsers)
|
||||
if (ConfigManager.getInstance().removeModule(moduleName)) {
|
||||
broadcastOrShowNotification(moduleName, userId, intent);
|
||||
isXposedModule = true;
|
||||
broadcastAndShowNotification(moduleName, userId, intent, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -115,8 +119,8 @@ public class LSPosedService extends ILSPosedService.Stub {
|
|||
if (components != null && !Arrays.stream(components).reduce(false, (p, c) -> p || c.equals(moduleName), Boolean::logicalOr)) {
|
||||
return;
|
||||
}
|
||||
broadcastAndShowNotification(moduleName, userId, intent, isXposedModule);
|
||||
if (isXposedModule) {
|
||||
broadcastOrShowNotification(moduleName, userId, intent);
|
||||
// When installing a new Xposed module, we update the apk path to mark it as a
|
||||
// module to send a broadcast when modules that have not been activated are
|
||||
// uninstalled.
|
||||
|
|
@ -132,8 +136,8 @@ public class LSPosedService extends ILSPosedService.Stub {
|
|||
case Intent.ACTION_UID_REMOVED: {
|
||||
// when a package is removed (rather than hide) for a single user
|
||||
// (apk may still be there because of multi-user)
|
||||
broadcastAndShowNotification(moduleName, userId, intent, isXposedModule);
|
||||
if (isXposedModule) {
|
||||
broadcastOrShowNotification(moduleName, userId, intent);
|
||||
// it will automatically remove obsolete scope from database
|
||||
ConfigManager.getInstance().updateCache();
|
||||
} else if (ConfigManager.getInstance().isUidHooked(uid)) {
|
||||
|
|
@ -159,18 +163,34 @@ public class LSPosedService extends ILSPosedService.Stub {
|
|||
}
|
||||
}
|
||||
|
||||
private void broadcastOrShowNotification(String moduleName, int userId, Intent intent) {
|
||||
Log.d(TAG, "module " + moduleName + " changed, dispatching to manager");
|
||||
var internAction = intent.getAction();
|
||||
var allUsers = intent.getBooleanExtra("android.intent.extra.REMOVED_FOR_ALL_USERS", false);
|
||||
LSPManagerService.broadcastIntent(moduleName, userId, allUsers);
|
||||
var enabledModules = ConfigManager.getInstance().enabledModules();
|
||||
var scope = ConfigManager.getInstance().getModuleScope(moduleName);
|
||||
boolean systemModule = scope != null &&
|
||||
scope.parallelStream().anyMatch(app -> app.packageName.equals("android"));
|
||||
boolean enabled = Arrays.asList(enabledModules).contains(moduleName);
|
||||
if (!(Intent.ACTION_UID_REMOVED.equals(internAction) || Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(internAction) || allUsers))
|
||||
LSPManagerService.showNotification(moduleName, userId, enabled, systemModule);
|
||||
private void broadcastAndShowNotification(String packageName, int userId, Intent intent, boolean isXposedModule) {
|
||||
Log.d(TAG, "package " + packageName + " changed, dispatching to manager");
|
||||
var action = intent.getAction();
|
||||
var allUsers = intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false);
|
||||
intent.putExtra("android.intent.extra.PACKAGES", packageName);
|
||||
intent.putExtra(Intent.EXTRA_USER, userId);
|
||||
intent.putExtra("isXposedModule", isXposedModule);
|
||||
LSPManagerService.broadcastIntent(intent);
|
||||
if (isXposedModule) {
|
||||
var enabledModules = ConfigManager.getInstance().enabledModules();
|
||||
var scope = ConfigManager.getInstance().getModuleScope(packageName);
|
||||
boolean systemModule = scope != null &&
|
||||
scope.parallelStream().anyMatch(app -> app.packageName.equals("android"));
|
||||
boolean enabled = Arrays.asList(enabledModules).contains(packageName);
|
||||
if (!(Intent.ACTION_UID_REMOVED.equals(action) || Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action) || allUsers))
|
||||
LSPManagerService.showNotification(packageName, userId, enabled, systemModule);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public void dispatchUserChanged(Intent intent) {
|
||||
if (intent == null) return;
|
||||
int uid = intent.getIntExtra(EXTRA_USER_HANDLE, AID_NOBODY);
|
||||
if (uid == AID_NOBODY || uid <= 0) return;
|
||||
try {
|
||||
LSPManagerService.broadcastIntent(intent);
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "dispatch user info changed", e);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public void dispatchUserUnlocked(Intent intent) {
|
||||
|
|
@ -335,6 +355,31 @@ public class LSPosedService extends ILSPosedService.Stub {
|
|||
Log.d(TAG, "registered boot receiver");
|
||||
}
|
||||
|
||||
private void registerUserChangeReceiver() {
|
||||
try {
|
||||
IntentFilter userFilter = new IntentFilter();
|
||||
userFilter.addAction(ACTION_USER_ADDED);
|
||||
userFilter.addAction(ACTION_USER_REMOVED);
|
||||
|
||||
var receiver = new IIntentReceiver.Stub() {
|
||||
@Override
|
||||
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
|
||||
getExecutorService().submit(() -> dispatchUserChanged(intent));
|
||||
try {
|
||||
ActivityManagerService.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "finish receiver", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ActivityManagerService.registerReceiver("android", null, receiver, userFilter, null, -1, 0);
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "register user info change receiver", e);
|
||||
}
|
||||
Log.d(TAG, "registered user info change receiver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchSystemServerContext(IBinder activityThread, IBinder activityToken, String api) {
|
||||
Log.d(TAG, "received system context");
|
||||
|
|
@ -345,6 +390,7 @@ public class LSPosedService extends ILSPosedService.Stub {
|
|||
registerConfigurationReceiver();
|
||||
registerSecretCodeReceiver();
|
||||
registerBootCompleteReceiver();
|
||||
registerUserChangeReceiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Reference in New Issue