mirror of
https://github.com/LittleChest/AppCloneEnabler.git
synced 2026-09-20 16:26:47 +08:00
Init 1.1
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,33 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "top.littlew.acer"
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "top.littlew.acer"
|
||||
minSdk = 34
|
||||
targetSdk = 36
|
||||
versionCode = 2
|
||||
versionName = "1.1"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("de.robv.android.xposed:api:82")
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="App Clone Enabler">
|
||||
<meta-data
|
||||
android:name="xposedmodule"
|
||||
android:value="true" />
|
||||
<meta-data
|
||||
android:name="xposeddescription"
|
||||
android:value="Enable App Clone for all or custom user apps." />
|
||||
<meta-data
|
||||
android:name="xposedminversion"
|
||||
android:value="93" />
|
||||
<meta-data
|
||||
android:name="xposedscope"
|
||||
android:resource="@array/xposed_scope" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1 @@
|
||||
top.littlew.acer.XposedInit
|
||||
@@ -0,0 +1,151 @@
|
||||
package top.littlew.acer;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import de.robv.android.xposed.IXposedHookLoadPackage;
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
public class XposedInit implements IXposedHookLoadPackage {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static Context mContext;
|
||||
|
||||
@Override
|
||||
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) {
|
||||
|
||||
if (lpparam.packageName.equals("com.android.settings")) {
|
||||
XposedHelpers.findAndHookMethod(XposedHelpers.findClass("com.android.settings.SettingsActivity", lpparam.classLoader), "onCreate", Bundle.class, new XC_MethodHook() {
|
||||
@Override
|
||||
protected void afterHookedMethod(MethodHookParam param) {
|
||||
mContext = (Context) param.thisObject;
|
||||
}
|
||||
});
|
||||
|
||||
Class<?> clonedAppsPreferenceControllerClass = XposedHelpers.findClass("com.android.settings.applications.ClonedAppsPreferenceController", lpparam.classLoader);
|
||||
|
||||
XposedHelpers.findAndHookMethod(clonedAppsPreferenceControllerClass, "getAvailabilityStatus", new XC_MethodHook() {
|
||||
@Override
|
||||
protected void beforeHookedMethod(MethodHookParam param) {
|
||||
param.setResult(0);
|
||||
}
|
||||
});
|
||||
|
||||
XposedHelpers.findAndHookMethod(clonedAppsPreferenceControllerClass, "updateSummary", int.class, int.class, new XC_MethodHook() {
|
||||
@SuppressLint({"QueryPermissionsNeeded", "DiscouragedApi"})
|
||||
@Override
|
||||
protected void beforeHookedMethod(MethodHookParam param) {
|
||||
if (mContext == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
|
||||
List<String> cloneableApps = getCloneableApps();
|
||||
|
||||
List<PackageInfo> primaryInstalledPackagesAsUser = (List<PackageInfo>) XposedHelpers.callMethod(pm, "getInstalledPackagesAsUser", 0, XposedHelpers.callStaticMethod(UserHandle.class, "myUserId"));
|
||||
|
||||
List<String> primaryUserApps = primaryInstalledPackagesAsUser.stream().map(x -> x.packageName).toList();
|
||||
|
||||
int availableAppsCount = (int) cloneableApps.stream().filter(primaryUserApps::contains).count();
|
||||
|
||||
int clonedUserId = (int) XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.android.settings.Utils", lpparam.classLoader), "getCloneUserId", mContext);
|
||||
int clonedAppsCount = 0;
|
||||
|
||||
if (!(clonedUserId == -1)) {
|
||||
List<PackageInfo> cloneProfileInstalledPackagesAsUser = (List<PackageInfo>) XposedHelpers.callMethod(pm, "getInstalledPackagesAsUser", 0, clonedUserId);
|
||||
|
||||
List<String> cloneProfileApps = cloneProfileInstalledPackagesAsUser.stream().map(x -> x.packageName).toList();
|
||||
|
||||
clonedAppsCount = (int) cloneableApps.stream().filter(cloneProfileApps::contains).count();
|
||||
}
|
||||
|
||||
Object mPreference = XposedHelpers.getObjectField(param.thisObject, "mPreference");
|
||||
if (mPreference != null) {
|
||||
XposedHelpers.callMethod(mPreference, "setSummary", String.format(mContext.getResources().getString(mContext.getResources().getIdentifier("cloned_apps_summary", "string", mContext.getPackageName())), clonedAppsCount, availableAppsCount - clonedAppsCount));
|
||||
}
|
||||
|
||||
param.setResult(null);
|
||||
}
|
||||
});
|
||||
|
||||
XposedHelpers.findAndHookMethod(XposedHelpers.findClass("com.android.settings.applications.AppStateClonedAppsBridge", lpparam.classLoader), "updateExtraInfo", XposedHelpers.findClass("com.android.settingslib.applications.ApplicationsState$AppEntry", lpparam.classLoader), String.class, int.class, new XC_MethodHook() {
|
||||
@Override
|
||||
protected void beforeHookedMethod(MethodHookParam param) {
|
||||
XposedHelpers.setObjectField(param.thisObject, "mAllowedApps", getCloneableApps());
|
||||
}
|
||||
});
|
||||
|
||||
XposedHelpers.findAndHookMethod(XposedHelpers.findClass("com.android.settings.applications.manageapplications.ManageApplications", lpparam.classLoader), "updateOptionsMenu", new XC_MethodHook() {
|
||||
@SuppressLint("DiscouragedApi")
|
||||
@Override
|
||||
protected void afterHookedMethod(MethodHookParam param) {
|
||||
if (XposedHelpers.getObjectField(param.thisObject, "mListType").equals(17) && (int) XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.android.settings.Utils", lpparam.classLoader), "getCloneUserId", mContext) > 0) {
|
||||
Menu mOptionsMenu = (Menu) XposedHelpers.getObjectField(param.thisObject, "mOptionsMenu");
|
||||
if (mOptionsMenu != null) {
|
||||
mOptionsMenu.findItem(mContext.getResources().getIdentifier("delete_all_app_clones", "id", mContext.getPackageName())).setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
XposedHelpers.findAndHookMethod(XposedHelpers.findClass("com.android.launcher3.allapps.ActivityAllAppsContainerView$AdapterHolder", lpparam.classLoader), "setup", View.class, Predicate.class, new XC_MethodHook() {
|
||||
@Override
|
||||
protected void beforeHookedMethod(MethodHookParam param) {
|
||||
if ((int) XposedHelpers.getObjectField(param.thisObject, "mType") == 0) {
|
||||
Object allAppsContainerView = XposedHelpers.getObjectField(param.thisObject, "this$0");
|
||||
|
||||
Predicate workProfileMatcher = (Predicate) XposedHelpers.callMethod(XposedHelpers.getObjectField(allAppsContainerView, "mWorkManager"), "getItemInfoMatcher");
|
||||
Predicate privateProfileMatcher = (Predicate) XposedHelpers.callMethod(XposedHelpers.getObjectField(allAppsContainerView, "mPrivateProfileManager"), "getItemInfoMatcher");
|
||||
|
||||
Predicate WorkOrPrivate = workProfileMatcher.or(privateProfileMatcher);
|
||||
|
||||
Predicate filter = WorkOrPrivate.negate();
|
||||
|
||||
param.args[1] = filter;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getCloneableApps() {
|
||||
if (mContext == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@SuppressLint("DiscouragedApi") List<String> cloneableApps = new ArrayList<>(Arrays.asList(mContext.getResources().getStringArray(mContext.getResources().getIdentifier("cloneable_apps", "array", "android"))));
|
||||
|
||||
SharedPreferences sharedPrefs = mContext.getSharedPreferences("cloneable_apps", Context.MODE_PRIVATE);
|
||||
List<String> newCloneableApps = new ArrayList<>(sharedPrefs.getStringSet("cloneable_apps", new HashSet<>()));
|
||||
|
||||
cloneableApps.addAll(newCloneableApps);
|
||||
|
||||
if (cloneableApps.isEmpty()) {
|
||||
List<PackageInfo> primaryInstalledPackagesAsUser = (List<PackageInfo>) XposedHelpers.callMethod(mContext.getPackageManager(), "getInstalledPackagesAsUser", 0, XposedHelpers.callStaticMethod(UserHandle.class, "myUserId"));
|
||||
|
||||
for (PackageInfo pkgInfo : primaryInstalledPackagesAsUser) {
|
||||
if ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
cloneableApps.add(pkgInfo.packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cloneableApps;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<group
|
||||
android:scaleX="0.4"
|
||||
android:scaleY="0.4"
|
||||
android:pivotX="480"
|
||||
android:pivotY="480">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M571,632L631,632L631,508L754,508L754,448L631,448L631,325L571,325L571,448L447,448L447,508L571,508L571,632ZM233,816Q128,774 64,682.74Q0,591.48 0,479.24Q0,367 64.5,276Q129,185 233,143L233,211Q154,247 107,319.7Q60,392.4 60,479Q60,567 107,639Q154,711 233,748L233,816ZM600,839Q525,839 459.5,810.5Q394,782 345.5,733.5Q297,685 268.5,619.5Q240,554 240,479Q240,404 268.5,338.5Q297,273 345.5,224.5Q394,176 459.5,147.5Q525,119 600,119Q675,119 740.5,147.5Q806,176 854.5,224.5Q903,273 931.5,338.5Q960,404 960,479Q960,554 931.5,619.5Q903,685 854.5,733.5Q806,782 740.5,810.5Q675,839 600,839ZM600,479Q600,479 600,479Q600,479 600,479Q600,479 600,479Q600,479 600,479Q600,479 600,479Q600,479 600,479Q600,479 600,479Q600,479 600,479ZM600.5,779Q725,779 812.5,691.68Q900,604.36 900,479Q900,355 812.68,267Q725.36,179 600,179Q476,179 388,267Q300,355 300,479Q300,604.36 388,691.68Q476,779 600.5,779Z"/>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background_color"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="xposed_scope">
|
||||
<item>com.android.settings</item>
|
||||
<item>com.android.launcher3</item>
|
||||
<item>com.google.android.apps.nexuslauncher</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<color name="ic_launcher_background_color">#FBBF24</color>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user