Boot Manager framework rev

This commit is contained in:
Hamza Rizwan
2022-12-19 00:18:31 +05:30
parent 3aac546b05
commit b26b2a936d
6 changed files with 182 additions and 109 deletions

View File

@@ -334,4 +334,8 @@ object PackageUtils {
}
return ArrayUtils.deepCopy(packageInfoList)
}
fun getIntentFilter(s: String): Intent {
return Intent(s)
}
}

View File

@@ -290,6 +290,9 @@ abstract class ScopedFragment : Fragment(), SharedPreferences.OnSharedPreference
}
}
/**
* @param manualOverride if true, loader can be shown from anywhere
*/
open fun showLoader(manualOverride: Boolean = false) {
if (requireArguments().getBoolean(BundleConstants.loading)) {
loader = Loader.newInstance()

View File

@@ -0,0 +1,9 @@
package app.simple.inure.interfaces.utils;
public interface Copyable <T> {
T copy();
T createForCopy();
void copyTo(T dest);
}

View File

@@ -1,19 +1,18 @@
package app.simple.inure.models;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
import java.util.ArrayList;
import app.simple.inure.interfaces.utils.Copyable;
public class BootManagerModel implements Parcelable {
public class BootManagerModel implements Copyable <BootManagerModel> {
private String packageName;
private ArrayList <String> disabledComponents = new ArrayList <>();
private ArrayList <String> enabledComponents = new ArrayList <>();
private ArraySet <String> disabledComponents = new ArraySet <>();
private ArraySet <String> enabledComponents = new ArraySet <>();
private String name;
private boolean enabled;
public BootManagerModel(String packageName, ArrayList <String> disabledComponents, ArrayList <String> enabledComponents, String name, boolean enabled) {
public BootManagerModel(String packageName, ArraySet <String> disabledComponents, ArraySet <String> enabledComponents, String name, boolean enabled) {
this.packageName = packageName;
this.disabledComponents = disabledComponents;
this.enabledComponents = enabledComponents;
@@ -24,40 +23,6 @@ public class BootManagerModel implements Parcelable {
public BootManagerModel() {
}
protected BootManagerModel(Parcel in) {
packageName = in.readString();
disabledComponents = in.createStringArrayList();
enabledComponents = in.createStringArrayList();
name = in.readString();
enabled = in.readByte() != 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(packageName);
dest.writeStringList(disabledComponents);
dest.writeStringList(enabledComponents);
dest.writeString(name);
dest.writeByte((byte) (enabled ? 1 : 0));
}
@Override
public int describeContents() {
return 0;
}
public static final Creator <BootManagerModel> CREATOR = new Creator <>() {
@Override
public BootManagerModel createFromParcel(Parcel in) {
return new BootManagerModel(in);
}
@Override
public BootManagerModel[] newArray(int size) {
return new BootManagerModel[size];
}
};
public String getPackageName() {
return packageName;
}
@@ -66,11 +31,11 @@ public class BootManagerModel implements Parcelable {
this.packageName = packageName;
}
public ArrayList <String> getDisabledComponents() {
public ArraySet <String> getDisabledComponents() {
return disabledComponents;
}
public void setDisabledComponents(ArrayList <String> disabledComponents) {
public void setDisabledComponents(ArraySet <String> disabledComponents) {
this.disabledComponents = disabledComponents;
}
@@ -78,16 +43,16 @@ public class BootManagerModel implements Parcelable {
try {
this.disabledComponents.add(disabledComponent);
} catch (NullPointerException e) {
this.disabledComponents = new ArrayList <>();
this.disabledComponents = new ArraySet <>();
this.disabledComponents.add(disabledComponent);
}
}
public ArrayList <String> getEnabledComponents() {
public ArraySet <String> getEnabledComponents() {
return enabledComponents;
}
public void setEnabledComponents(ArrayList <String> enabledComponents) {
public void setEnabledComponents(ArraySet <String> enabledComponents) {
this.enabledComponents = enabledComponents;
}
@@ -95,7 +60,7 @@ public class BootManagerModel implements Parcelable {
try {
this.enabledComponents.add(component);
} catch (NullPointerException e) {
this.enabledComponents = new ArrayList <>();
this.enabledComponents = new ArraySet <>();
this.enabledComponents.add(component);
}
}
@@ -126,4 +91,23 @@ public class BootManagerModel implements Parcelable {
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Override
public BootManagerModel copy() {
return new BootManagerModel(packageName, disabledComponents, enabledComponents, name, enabled);
}
@Override
public BootManagerModel createForCopy() {
return new BootManagerModel();
}
@Override
public void copyTo(BootManagerModel dest) {
dest.setPackageName(packageName);
dest.setDisabledComponents(disabledComponents);
dest.setEnabledComponents(enabledComponents);
dest.setName(name);
dest.setEnabled(enabled);
}
}

View File

@@ -43,20 +43,17 @@ class BootManager : ScopedFragment() {
override fun onBootComponentClicked(view: View, bootManagerModel: BootManagerModel, position: Int) {
PopupBootManager(view).setOnPopupBootManagerCallbacks(object : PopupBootManager.Companion.PopupBootManagerCallbacks {
override fun onEnableAllClicked() {
bootManagerViewModel?.enableAllComponents(bootManagerModel, position)
showLoader(manualOverride = true).also {
bootManagerViewModel?.enableAllComponents(bootManagerModel.copy(), position)
}
}
override fun onDisableAllClicked() {
bootManagerViewModel?.disableAllComponents(bootManagerModel, position)
}
}).also {
bootManagerViewModel?.getBootManagerModelData()?.observe(viewLifecycleOwner) {
if (it.isNotNull()) {
adapterBootManager?.updateItem(it.first, it.second)
bootManagerViewModel?.clearBootManagerModelData()
showLoader(manualOverride = true).also {
bootManagerViewModel?.disableAllComponents(bootManagerModel.copy(), position)
}
}
}
})
}
})
@@ -66,6 +63,12 @@ class BootManager : ScopedFragment() {
startPostponedEnterTransition()
}
}
bootManagerViewModel?.getBootManagerModelData()?.observe(viewLifecycleOwner) {
adapterBootManager?.updateItem(it.first, it.second)
bootManagerViewModel?.clearBootManagerModelData()
hideLoader()
}
}
companion object {

View File

@@ -1,6 +1,8 @@
package app.simple.inure.viewmodels.panels
import android.app.Application
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
@@ -18,6 +20,17 @@ import java.util.stream.Collectors
class BootManagerViewModel(application: Application) : RootViewModel(application) {
private val command = "pm query-receivers --components -a android.intent.action.BOOT_COMPLETED"
private val bootCompletedIntent = "android.intent.action.BOOT_COMPLETED"
private val resolveInfoFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
PackageManager.MATCH_DIRECT_BOOT_AWARE or PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS or
PackageManager.GET_RECEIVERS
} else {
@Suppress("DEPRECATION")
PackageManager.GET_RECEIVERS or PackageManager.GET_DISABLED_COMPONENTS or
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
}
private val bootComponentData: MutableLiveData<ArrayList<BootManagerModel>> by lazy {
MutableLiveData<ArrayList<BootManagerModel>>()
@@ -46,86 +59,143 @@ class BootManagerViewModel(application: Application) : RootViewModel(application
private fun loadBootComponents() {
viewModelScope.launch(Dispatchers.IO) {
Shell.cmd(command).exec().let { result ->
if (result.isSuccess) {
val packageNames = result.out.map { it.split("/")[0] }.stream().distinct().collect(Collectors.toList())
val bootManagerModelArrayList = ArrayList<BootManagerModel>()
packageNames.forEach { packageName ->
val bootManagerModel = BootManagerModel()
bootManagerModel.packageName = packageName
bootManagerModel.name = PackageUtils.getApplicationName(applicationContext(), bootManagerModel.packageName)
bootManagerModel.isEnabled = packageManager.isPackageInstalledAndEnabled(bootManagerModel.packageName)
result.out.forEach {
if (it.startsWith(bootManagerModel.packageName)) {
val componentName = bootManagerModel.packageName + it.substringAfter("/")
if (ReceiversUtils.isEnabled(applicationContext(), bootManagerModel.packageName, componentName)) {
bootManagerModel.addEnabledComponent(componentName)
} else {
bootManagerModel.addDisabledComponent(componentName)
}
}
}
bootManagerModelArrayList.add(bootManagerModel)
}
bootManagerModelArrayList.sortBy {
it.name
}
bootComponentData.postValue(bootManagerModelArrayList)
val list = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.queryBroadcastReceivers(PackageUtils.getIntentFilter(bootCompletedIntent), PackageManager.ResolveInfoFlags.of(resolveInfoFlags.toLong()))
} else {
Log.d("BootManagerViewModel", "loadBootComponents: ${result.err}")
@Suppress("DEPRECATION")
packageManager.queryBroadcastReceivers(PackageUtils.getIntentFilter(bootCompletedIntent), resolveInfoFlags)
}
} else {
@Suppress("DEPRECATION")
packageManager.queryBroadcastReceivers(PackageUtils.getIntentFilter(bootCompletedIntent), resolveInfoFlags)
}
val bootManagerModelArrayList = ArrayList<BootManagerModel>()
val packageNames = list.stream().map { it.activityInfo.packageName }.collect(Collectors.toList()).distinct()
packageNames.forEach { packageName ->
val bootManagerModel = BootManagerModel()
bootManagerModel.packageName = packageName
bootManagerModel.name = PackageUtils.getApplicationName(applicationContext(), bootManagerModel.packageName)
bootManagerModel.isEnabled = packageManager.isPackageInstalledAndEnabled(bootManagerModel.packageName)
list.forEach { resolveInfo ->
if (resolveInfo.activityInfo.packageName.equals(bootManagerModel.packageName)) {
val componentName = resolveInfo.activityInfo.name
if (ReceiversUtils.isEnabled(applicationContext(), bootManagerModel.packageName, componentName)) {
bootManagerModel.addEnabledComponent(componentName)
} else {
bootManagerModel.addDisabledComponent(componentName)
}
}
}
bootManagerModelArrayList.add(bootManagerModel)
}
bootManagerModelArrayList.sortBy {
it.name
}
bootComponentData.postValue(bootManagerModelArrayList)
// This method is also valid but it's not as efficient as the above method
//
// Shell.cmd(command).exec().let { result ->
// if (result.isSuccess) {
// val packageNames = result.out.map { it.split("/")[0] }.stream().distinct().collect(Collectors.toList())
//
// val bootManagerModelArrayList = ArrayList<BootManagerModel>()
// packageNames.forEach { packageName ->
// val bootManagerModel = BootManagerModel()
// bootManagerModel.packageName = packageName
// bootManagerModel.name = PackageUtils.getApplicationName(applicationContext(), bootManagerModel.packageName)
// bootManagerModel.isEnabled = packageManager.isPackageInstalledAndEnabled(bootManagerModel.packageName)
//
// result.out.forEach {
// if (it.startsWith(bootManagerModel.packageName)) {
// val componentName = it.substringAfter("/")
// if (ReceiversUtils.isEnabled(applicationContext(), bootManagerModel.packageName, componentName)) {
// bootManagerModel.addEnabledComponent(componentName)
// } else {
// bootManagerModel.addDisabledComponent(componentName)
// }
// }
// }
//
// bootManagerModelArrayList.add(bootManagerModel)
// }
//
// bootManagerModelArrayList.sortBy {
// it.name
// }
//
// bootComponentData.postValue(bootManagerModelArrayList)
// } else {
// Log.d("BootManagerViewModel", "loadBootComponents: ${result.err}")
// }
// }
}
}
fun enableAllComponents(bootManagerModel: BootManagerModel, position: Int) {
viewModelScope.launch(Dispatchers.IO) {
var err = 0
bootManagerModel.disabledComponents.forEach { disabledComponent -> // Unnecessary but just to be sure :D
Shell.cmd("pm enable $disabledComponent").submit {
if (it.isSuccess) {
bootManagerModel.enabledComponents.add(disabledComponent)
(bootManagerModel.enabledComponents + bootManagerModel.disabledComponents).forEach { component ->
Shell.cmd("pm enable ${bootManagerModel.packageName}/$component").exec().let { result ->
if (result.isSuccess) {
Log.d("BootManagerViewModel", "enableAllComponents: $component")
} else {
err++
Log.e("BootManagerViewModel", "enableAllComponents: ${result.err}")
}
}
}.also {
if (err == 0) {
bootManagerModel.disabledComponents.clear()
bootManagerModelData.postValue(Pair(bootManagerModel, position))
}
// Verify if all components are enabled ----------------------------------------------------------------------- |
(bootManagerModel.enabledComponents + bootManagerModel.disabledComponents).forEach { component ->
if (ReceiversUtils.isEnabled(applicationContext(), bootManagerModel.packageName, component)) {
bootManagerModel.addEnabledComponent(component)
bootManagerModel.disabledComponents.remove(component)
} else {
bootManagerModel.addDisabledComponent(component)
bootManagerModel.enabledComponents.remove(component)
}
}
bootManagerModelData.postValue(Pair(bootManagerModel, position))
}
}
fun disableAllComponents(bootManagerModel: BootManagerModel, position: Int) {
viewModelScope.launch(Dispatchers.IO) {
var err = 0
bootManagerModel.enabledComponents.forEach { enabledComponent ->
Shell.cmd("pm disable $enabledComponent").submit {
(bootManagerModel.enabledComponents + bootManagerModel.disabledComponents).forEach { component ->
Shell.cmd("pm disable ${bootManagerModel.packageName}/$component").submit {
if (it.isSuccess) {
bootManagerModel.disabledComponents.add(enabledComponent)
Log.d("BootManagerViewModel", "disabledComponent: $component")
} else {
err++
Log.e("BootManagerViewModel", "disabledComponent: ${it.err}")
}
}
}.also {
if (err == 0) {
bootManagerModel.enabledComponents.clear()
bootManagerModelData.postValue(Pair(bootManagerModel, position))
}
// Verify if all components are disabled ----------------------------------------------------------------------- |
(bootManagerModel.enabledComponents + bootManagerModel.disabledComponents).forEach { component ->
if (ReceiversUtils.isEnabled(applicationContext(), bootManagerModel.packageName, component)) {
bootManagerModel.addEnabledComponent(component)
bootManagerModel.disabledComponents.remove(component)
} else {
bootManagerModel.addDisabledComponent(component)
bootManagerModel.enabledComponents.remove(component)
}
}
bootManagerModelData.postValue(Pair(bootManagerModel, position))
}
}
fun clearBootManagerModelData() {
bootManagerModelData.postValue(null)
bootManagerModelData.value = null
}
}