From 5111321526b174dccf322e190081ec318a79ba0a Mon Sep 17 00:00:00 2001 From: Dev4Mod Date: Sat, 11 May 2024 20:57:58 -0300 Subject: [PATCH] Add function to inject wallpaper in home screen --- .../java/com/wmods/wppenhacer/FilePicker.java | 62 ++++++++++++++++ .../com/wmods/wppenhacer/MainActivity.java | 21 +++--- .../preference/FileSelectPreference.java | 65 +++++++++++++++++ .../ui/fragments/MediaFragment.java | 2 +- .../wmods/wppenhacer/utils/RealPathUtil.java | 70 ++++++++++++++++++- .../wmods/wppenhacer/views/WallpaperView.java | 54 ++++++++++++++ .../features/customization/CustomTheme.java | 48 ++++++++++++- app/src/main/res/values/arrays.xml | 5 ++ app/src/main/res/values/attrs.xml | 4 ++ app/src/main/res/values/strings.xml | 10 +++ .../main/res/xml/fragment_customization.xml | 47 +++++++++---- 11 files changed, 357 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/com/wmods/wppenhacer/FilePicker.java create mode 100644 app/src/main/java/com/wmods/wppenhacer/preference/FileSelectPreference.java create mode 100644 app/src/main/java/com/wmods/wppenhacer/views/WallpaperView.java diff --git a/app/src/main/java/com/wmods/wppenhacer/FilePicker.java b/app/src/main/java/com/wmods/wppenhacer/FilePicker.java new file mode 100644 index 00000000..77cb407d --- /dev/null +++ b/app/src/main/java/com/wmods/wppenhacer/FilePicker.java @@ -0,0 +1,62 @@ +package com.wmods.wppenhacer; + +import android.net.Uri; +import android.util.Log; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.appcompat.app.AppCompatActivity; + +import com.wmods.wppenhacer.utils.RealPathUtil; + +import java.io.File; + +public class FilePicker { + + private static OnFilePickedListener mOnFilePickedListener; + private static AppCompatActivity mActivity; + public static ActivityResultLauncher fileSalve; + private static OnUriPickedListener mOnUriPickedListener; + public static ActivityResultLauncher fileCapture; + + public static void registerFilePicker(AppCompatActivity activity) { + mActivity = activity; + fileCapture = activity.registerForActivityResult(new ActivityResultContracts.OpenDocument(), FilePicker::setFile); + fileSalve = activity.registerForActivityResult(new ActivityResultContracts.CreateDocument("*/*"), FilePicker::setFile); + } + + private static void setFile(Uri uri) { + if (uri == null) return; + + if (mOnFilePickedListener == null) { + mOnUriPickedListener.onUriPicked(uri); + mOnUriPickedListener = null; + } + + if (mOnFilePickedListener != null) { + var realPath = RealPathUtil.getRealFilePath(mActivity, uri); + if (realPath == null) return; + mOnFilePickedListener.onFilePicked(new File(realPath)); + mOnFilePickedListener = null; + } + } + + + + public static void setOnFilePickedListener(OnFilePickedListener onFilePickedListener) { + mOnFilePickedListener = onFilePickedListener; + } + + public static void setOnUriPickedListener(OnUriPickedListener onFilePickedListener) { + mOnUriPickedListener = onFilePickedListener; + } + + public interface OnFilePickedListener { + void onFilePicked(File file); + } + + public interface OnUriPickedListener { + void onUriPicked(Uri uri); + } + +} diff --git a/app/src/main/java/com/wmods/wppenhacer/MainActivity.java b/app/src/main/java/com/wmods/wppenhacer/MainActivity.java index 7ccec327..498393cc 100644 --- a/app/src/main/java/com/wmods/wppenhacer/MainActivity.java +++ b/app/src/main/java/com/wmods/wppenhacer/MainActivity.java @@ -1,26 +1,18 @@ package com.wmods.wppenhacer; -import android.content.res.Resources; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; +import android.Manifest; +import android.content.pm.PackageManager; import android.os.Bundle; -import android.view.Window; -import com.google.android.material.bottomnavigation.BottomNavigationView; - -import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.app.AppCompatDelegate; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; import androidx.navigation.NavController; -import androidx.navigation.Navigation; import androidx.navigation.fragment.NavHostFragment; -import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.NavigationUI; import com.wmods.wppenhacer.databinding.ActivityMainBinding; -import rikka.material.app.MaterialActivity; - public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; @@ -42,11 +34,14 @@ protected void onCreate(Bundle savedInstanceState) { NavController navController = navHostFragment.getNavController(); var nav = binding.navView; NavigationUI.setupWithNavController(nav, navController); + if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_MEDIA_IMAGES}, 0); + } + FilePicker.registerFilePicker(this); } public static boolean isXposedEnabled() { return false; } - } \ No newline at end of file diff --git a/app/src/main/java/com/wmods/wppenhacer/preference/FileSelectPreference.java b/app/src/main/java/com/wmods/wppenhacer/preference/FileSelectPreference.java new file mode 100644 index 00000000..475a7e6d --- /dev/null +++ b/app/src/main/java/com/wmods/wppenhacer/preference/FileSelectPreference.java @@ -0,0 +1,65 @@ +package com.wmods.wppenhacer.preference; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; + +import androidx.activity.result.PickVisualMediaRequest; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceManager; + +import com.wmods.wppenhacer.FilePicker; +import com.wmods.wppenhacer.R; + +import java.io.File; +import java.util.Arrays; + +public class FileSelectPreference extends Preference implements Preference.OnPreferenceClickListener, FilePicker.OnFilePickedListener { + + private String[] mineTypes; + + public FileSelectPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context,attrs); + } + + public FileSelectPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context,attrs); + } + + public FileSelectPreference(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(context,attrs); + } + + public void init(Context context, AttributeSet attrs) { + setOnPreferenceClickListener(this); + var typedArray = context.getTheme().obtainStyledAttributes( + attrs, R.styleable.FileSelectPreference, + 0, 0 + ); + var attrsArray = typedArray.getTextArray(R.styleable.FileSelectPreference_android_entryValues); + mineTypes = Arrays.stream(attrsArray).map(String::valueOf).toArray(String[]::new); + var prefs = PreferenceManager.getDefaultSharedPreferences(context); + var keyValue = prefs.getString(this.getKey(),null); + setSummary(keyValue); + } + + + @Override + public boolean onPreferenceClick(@NonNull Preference preference) { + FilePicker.setOnFilePickedListener(this); + FilePicker.fileCapture.launch(mineTypes); + return false; + } + + @Override + public void onFilePicked(File file) { + getSharedPreferences().edit().putString(getKey(),file.getAbsolutePath()).apply(); + setSummary(file.getAbsolutePath()); + } +} diff --git a/app/src/main/java/com/wmods/wppenhacer/ui/fragments/MediaFragment.java b/app/src/main/java/com/wmods/wppenhacer/ui/fragments/MediaFragment.java index 535877ab..ac0c63b9 100644 --- a/app/src/main/java/com/wmods/wppenhacer/ui/fragments/MediaFragment.java +++ b/app/src/main/java/com/wmods/wppenhacer/ui/fragments/MediaFragment.java @@ -24,7 +24,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContract = registerForActivityResult(new ActivityResultContracts.OpenDocumentTree(), result -> { if (result == null) return; - var realPath = RealPathUtil.getRealPathFromURI_API19(getContext(), result); + var realPath = RealPathUtil.getRealFolderPath(getContext(), result); Preference preference = findPreference("localdownload"); if (preference != null) { preference.setSummary(realPath); diff --git a/app/src/main/java/com/wmods/wppenhacer/utils/RealPathUtil.java b/app/src/main/java/com/wmods/wppenhacer/utils/RealPathUtil.java index fff1cf59..5b8058bb 100644 --- a/app/src/main/java/com/wmods/wppenhacer/utils/RealPathUtil.java +++ b/app/src/main/java/com/wmods/wppenhacer/utils/RealPathUtil.java @@ -23,7 +23,75 @@ public class RealPathUtil { * @author paulburke */ @SuppressLint("NewApi") - public static String getRealPathFromURI_API19(final Context context, final Uri uri) { + public static String getRealFilePath(final Context context, final Uri uri) { + + // DocumentProvider + if (DocumentsContract.isDocumentUri(context,uri)) { + // ExternalStorageProvider + if (isExternalStorageDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + if ("primary".equalsIgnoreCase(type)) { + return Environment.getExternalStorageDirectory() + "/" + split[1]; + } + + // TODO handle non-primary volumes + } + // DownloadsProvider + else if (isDownloadsDocument(uri)) { + + final String id = DocumentsContract.getDocumentId(uri); + final Uri contentUri = ContentUris.withAppendedId( + Uri.parse("content://downloads/public_downloads"), Long.parseLong(id)); + + return getDataColumn(context, contentUri, null, null); + } + // MediaProvider + else if (isMediaDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + Uri contentUri; + if ("image".equals(type)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } else { + contentUri = MediaStore.Files.getContentUri("external"); + } + + final String selection = "_id=?"; + final String[] selectionArgs = new String[]{ + split[1] + }; + + return getDataColumn(context, contentUri, selection, selectionArgs); + } + } + // MediaStore (and general) + else if ("content".equalsIgnoreCase(uri.getScheme())) { + + // Return the remote address + if (isGooglePhotosUri(uri)) + return uri.getLastPathSegment(); + + return getDataColumn(context, uri, null, null); + } + // File + else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } + + return null; + } + + @SuppressLint("NewApi") + public static String getRealFolderPath(final Context context, final Uri uri) { // DocumentProvider if (DocumentsContract.isTreeUri(uri)) { diff --git a/app/src/main/java/com/wmods/wppenhacer/views/WallpaperView.java b/app/src/main/java/com/wmods/wppenhacer/views/WallpaperView.java new file mode 100644 index 00000000..0fa721b4 --- /dev/null +++ b/app/src/main/java/com/wmods/wppenhacer/views/WallpaperView.java @@ -0,0 +1,54 @@ +package com.wmods.wppenhacer.views; + +import static de.robv.android.xposed.XposedBridge.log; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import androidx.annotation.NonNull; + +import java.io.File; + +import de.robv.android.xposed.XSharedPreferences; + +public class WallpaperView extends FrameLayout { + private final XSharedPreferences prefs; + private ImageView imageView; + private float mAlpha = 1f; + + public WallpaperView(@NonNull Context context, XSharedPreferences preferences) { + super(context); + this.prefs = preferences; + init(context); + } + + private void init(Context context) { + imageView = new android.widget.ImageView(context); + imageView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + imageView.setAdjustViewBounds(false); + try { + Bitmap bitmap = BitmapFactory.decodeFile(prefs.getString("wallpaper_file", "")); + Drawable drawable = new BitmapDrawable(getResources(), bitmap); + imageView.setImageDrawable(drawable); + this.mAlpha = (100 - prefs.getInt("wallpaper_alpha", 30)) / 100f; + addView(imageView); + }catch (Exception e){ + log(e.toString()); + } + } + + @Override + public void addView(View child) { + if (child != imageView) + child.setAlpha(mAlpha); + super.addView(child); + } +} diff --git a/app/src/main/java/com/wmods/wppenhacer/xposed/features/customization/CustomTheme.java b/app/src/main/java/com/wmods/wppenhacer/xposed/features/customization/CustomTheme.java index d5d946e1..dec6e428 100644 --- a/app/src/main/java/com/wmods/wppenhacer/xposed/features/customization/CustomTheme.java +++ b/app/src/main/java/com/wmods/wppenhacer/xposed/features/customization/CustomTheme.java @@ -5,8 +5,10 @@ import static com.wmods.wppenhacer.utils.IColors.colors; import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; +import android.Manifest; import android.app.Activity; import android.app.Notification; +import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.graphics.Paint; import android.graphics.drawable.ColorDrawable; @@ -18,13 +20,17 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import com.wmods.wppenhacer.utils.IColors; +import com.wmods.wppenhacer.views.WallpaperView; import com.wmods.wppenhacer.xposed.core.Feature; import com.wmods.wppenhacer.xposed.core.Unobfuscator; import org.xmlpull.v1.XmlPullParser; +import java.util.ArrayList; + import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XSharedPreferences; import de.robv.android.xposed.XposedHelpers; @@ -40,6 +46,25 @@ public CustomTheme(ClassLoader loader, XSharedPreferences preferences) { @Override public void doHook() throws Exception { + hookWallpaper(); + hookColors(); + } + + private void hookWallpaper() { + if (!prefs.getBoolean("wallpaper", false)) return; + var clazz = XposedHelpers.findClass("com.whatsapp.HomeActivity", loader); + XposedHelpers.findAndHookMethod(clazz.getSuperclass(), "onCreate", Bundle.class, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + var activity = (Activity) param.thisObject; + if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + injectWallpaper(activity.findViewById(android.R.id.content)); + } + } + }); + } + + private void hookColors() throws Exception { if (!prefs.getBoolean("changecolor", false)) return; var customDrawable1 = Unobfuscator.loadExpandableWidgetClass(loader); @@ -52,10 +77,10 @@ public void doHook() throws Exception { var primaryColorInt = prefs.getInt("primary_color", 0); var secondaryColorInt = prefs.getInt("secondary_color", 0); - var backgroundColorInt = prefs.getInt("background_color", 0); + var backgroundColorInt = prefs.getInt("background_color", 0); - var primaryColor = primaryColorInt == 0 ? "0" : String.format("#%08X", primaryColorInt); - var secondaryColor = secondaryColorInt == 0 ? "0" : String.format("#%08X", secondaryColorInt); + var primaryColor = primaryColorInt == 0 ? "0" : String.format("#%08X", primaryColorInt); + var secondaryColor = secondaryColorInt == 0 ? "0" : String.format("#%08X", secondaryColorInt); var backgroundColor = backgroundColorInt == 0 ? "0" : String.format("#%08X", backgroundColorInt); for (var c : colors.keySet()) { @@ -94,6 +119,9 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { } }); + + + var intBgHook = new IntBgColorHook(); findAndHookMethod(Paint.class.getName(), loader, "setColor", int.class, intBgHook); findAndHookMethod(View.class.getName(), loader, "setBackgroundColor", int.class, intBgHook); @@ -129,7 +157,21 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); } }); + } + private void injectWallpaper(View view) { + var content = (ViewGroup) view; + var rootView = (ViewGroup)content.getChildAt(0); + var views = new ArrayList(); + while (rootView.getChildCount() > 0) { + views.add(rootView.getChildAt(0)); + rootView.removeView(rootView.getChildAt(0)); + } + var frameLayout = new WallpaperView(rootView.getContext(),prefs); + for (var v : views) { + frameLayout.addView(v); + } + rootView.addView(frameLayout); } @NonNull diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index b568201f..681180aa 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -75,4 +75,9 @@ 2.24.9.80 + + + image/* + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index f2f75c1a..441144af 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -22,6 +22,10 @@ + + + +