├── .gitignore
├── .idea
├── .gitignore
├── .name
├── compiler.xml
└── misc.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── assets
│ │ └── xposed_init
│ │ ├── ic_launcher-playstore.png
│ │ ├── java
│ │ └── balti
│ │ │ └── xposed
│ │ │ └── pixelifyplus
│ │ │ ├── ActivityMain.kt
│ │ │ ├── Constants.kt
│ │ │ ├── DeviceProps.kt
│ │ │ ├── DeviceSpoofer.kt
│ │ │ ├── FeatureCustomize.kt
│ │ │ ├── FeatureSpoofer.kt
│ │ │ └── Utils.kt
│ │ └── res
│ │ ├── drawable
│ │ ├── ic_game.png
│ │ ├── ic_info.xml
│ │ ├── ic_launcher_background.xml
│ │ └── ic_open.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── feature_customize.xml
│ │ ├── menu
│ │ └── menu_activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── module_scope.xml
│ │ ├── strings.xml
│ │ └── themes.xml
└── version.properties
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── update_info.json
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | ### Android template
17 | # Built application files
18 | *.apk
19 | *.aar
20 | *.ap_
21 | *.aab
22 |
23 | # Files for the ART/Dalvik VM
24 | *.dex
25 |
26 | # Java class files
27 | *.class
28 |
29 | # Generated files
30 | bin/
31 | gen/
32 | out/
33 | # Uncomment the following line in case you need and you don't have the release build type files in your app
34 | # release/
35 |
36 | # Gradle files
37 | .gradle/
38 | build/
39 |
40 | # Local configuration file (sdk path, etc)
41 | local.properties
42 |
43 | # Proguard folder generated by Eclipse
44 | proguard/
45 |
46 | # Log Files
47 | *.log
48 |
49 | # Android Studio Navigation editor temp files
50 | .navigation/
51 |
52 | # Android Studio captures folder
53 | captures/
54 |
55 | # IntelliJ
56 | *.iml
57 | .idea/workspace.xml
58 | .idea/tasks.xml
59 | .idea/gradle.xml
60 | .idea/assetWizardSettings.xml
61 | .idea/dictionaries
62 | .idea/libraries
63 | # Android Studio 3 in .gitignore file.
64 | .idea/caches
65 | .idea/modules.xml
66 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
67 | .idea/navEditor.xml
68 |
69 | # Keystore files
70 | # Uncomment the following lines if you do not want to check your keystore files in.
71 | #*.jks
72 | #*.keystore
73 |
74 | # External native build folder generated in Android Studio 2.2 and later
75 | .externalNativeBuild
76 | .cxx/
77 |
78 | # Google Services (e.g. APIs or Firebase)
79 | # google-services.json
80 |
81 | # Freeline
82 | freeline.py
83 | freeline/
84 | freeline_project_description.json
85 |
86 | # fastlane
87 | fastlane/report.xml
88 | fastlane/Preview.html
89 | fastlane/screenshots
90 | fastlane/test_output
91 | fastlane/readme.md
92 |
93 | # Version control
94 | vcs.xml
95 |
96 | # lint
97 | lint/intermediates/
98 | lint/generated/
99 | lint/outputs/
100 | lint/tmp/
101 | # lint/reports/
102 |
103 | # Android Profiling
104 | *.hprof
105 |
106 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Pixelify+
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 BaltiApps
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pixelify+
2 | LSPosed module to add Google Pixel features on Google Photos and spoof some games for any device.
3 |
4 | Based on:
5 |
6 | [LSPosed module repo](https://github.com/Xposed-Modules-Repo/balti.xposed.pixelifygooglephotos.git)
7 | [Development repo](https://github.com/BaltiApps/Pixelify-Google-Photos.git)
8 |
9 | [Telegram group link](https://t.me/pixelifyGooglePhotos)
10 |
11 | ### Steps to use:
12 | 1. Install Magisk canary and enable Zygisk, [LSPosed](https://github.com/LSPosed/LSPosed).
13 | 2. Install the apk of this app (available from [Releases](https://github.com/althafvly/Pixelifyplus/releases) page.)
14 | 3. Open LSPosed app and enable the module. Google Photos will be automatically selected.
15 | 4. Reboot. Enjoy. (If needed, you might need to clear data of Google Photos app).
16 |
17 | ### How does this module work?
18 | It simply hooks on to `hasSystemFeature()` method under `android.app.ApplicationPackageManager` class.
19 | Then when Google Photos checks the relevant features which are expected only on Pixel devices, the module passes `true`.
20 | Thus Google Photos enables Pixel-Exclusive features.
21 | The features being "spoofed" can be found from:
22 | [Dot OS sources](https://github.com/DotOS/android_vendor_dot/blob/55f1c26bb6dbb1175d96cf538ae113618caf7d06/prebuilt/common/etc/pixel_2016_exclusive.xml)
23 | [PixelFeatureDrops magisk module](https://github.com/ayush5harma/PixelFeatureDrops/tree/master/system/etc/sysconfig)
24 | This module can also spoof some of the `build.prop` information like `BRAND`, `MANUFACTURER`, `MODEL`, `FINGERPRINT` of some Pixel devices.
25 |
26 | ### Disclaimer!!
27 | The user takes sole responsibility for any damage that might arise due to use of this module.
28 | This includes physical damage (to device), injury, data loss, and also legal matters.
29 | This project was made as a learning initiative and the developer cannot be held liable in any way for the use of it.
30 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdk 31
8 |
9 | def getVersionName = { ->
10 | def versionPropsFile = file('version.properties')
11 | if (versionPropsFile.canRead()) {
12 | Properties versionProps = new Properties()
13 | versionProps.load(new FileInputStream(versionPropsFile))
14 |
15 | def value = 0
16 |
17 | def runTasks = gradle.startParameter.taskNames
18 | if ('assemble' in runTasks || 'assembleRelease' in runTasks || 'aR' in runTasks) {
19 | value = 1;
20 | }
21 |
22 | def versionMajor = 1
23 | def versionMinor = 3
24 | def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
25 | def versionNumber = versionProps['VERSION_NUMBER'].toInteger() + value
26 |
27 | versionProps['VERSION_BUILD'] = versionBuild.toString()
28 | versionProps['VERSION_NUMBER'] = versionNumber.toString()
29 |
30 | versionProps.store(versionPropsFile.newWriter(), null)
31 |
32 | return "${versionMajor}.${versionMinor}-${versionBuild}"
33 | } else {
34 | throw new GradleException("Could not read version.properties!")
35 | }
36 | }
37 |
38 | defaultConfig {
39 | applicationId "balti.xposed.pixelifyplus"
40 | minSdk 21
41 | targetSdk 31
42 | versionCode 5
43 | versionName getVersionName()
44 | }
45 |
46 | buildTypes {
47 | release {
48 | minifyEnabled false
49 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
50 | }
51 | }
52 | compileOptions {
53 | sourceCompatibility JavaVersion.VERSION_1_8
54 | targetCompatibility JavaVersion.VERSION_1_8
55 | }
56 | kotlinOptions {
57 | jvmTarget = '1.8'
58 | }
59 | applicationVariants.all { variant ->
60 | variant.outputs.all { output ->
61 | def formattedDate = new Date().format('yyyy-MM-dd')
62 | outputFileName = new File("Pixelify+_" + variant.versionName + "_" + formattedDate + ".apk");
63 | }
64 | }
65 | }
66 |
67 | dependencies {
68 |
69 | implementation 'androidx.core:core-ktx:1.7.0'
70 | implementation 'androidx.appcompat:appcompat:1.4.0'
71 | implementation 'com.google.android.material:material:1.4.0'
72 |
73 | // Xposed API
74 | compileOnly 'de.robv.android.xposed:api:82'
75 | compileOnly 'de.robv.android.xposed:api:82:sources'
76 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
22 |
25 |
28 |
31 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | balti.xposed.pixelifygooglephotos.FeatureSpoofer
2 | balti.xposed.pixelifygooglephotos.DeviceSpoofer
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/althafvly/Pixelifyplus/ac807f6f6871580f5018e6c5708c29a7afeba217/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/balti/xposed/pixelifyplus/ActivityMain.kt:
--------------------------------------------------------------------------------
1 | package balti.xposed.pixelifyplus
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.graphics.Paint
7 | import android.net.Uri
8 | import android.os.AsyncTask
9 | import android.os.Bundle
10 | import android.view.*
11 | import android.widget.*
12 | import androidx.activity.result.contract.ActivityResultContracts
13 | import androidx.appcompat.app.AlertDialog
14 | import androidx.appcompat.app.AppCompatActivity
15 | import androidx.appcompat.widget.SwitchCompat
16 | import balti.xposed.pixelifyplus.Constants.FIELD_LATEST_VERSION_CODE
17 | import balti.xposed.pixelifyplus.Constants.PREF_DEVICE_SUPPORT_HIGH_REFRESH_RATE
18 | import balti.xposed.pixelifyplus.Constants.PREF_DEVICE_TO_SPOOF
19 | import balti.xposed.pixelifyplus.Constants.PREF_DEVICE_TO_SPOOF_GAME
20 | import balti.xposed.pixelifyplus.Constants.PREF_LAST_VERSION
21 | import balti.xposed.pixelifyplus.Constants.PREF_OVERRIDE_ROM_FEATURE_LEVELS
22 | import balti.xposed.pixelifyplus.Constants.PREF_SPOOF_FEATURES_LIST
23 | import balti.xposed.pixelifyplus.Constants.PREF_STRICTLY_CHECK_GOOGLE_PHOTOS
24 | import balti.xposed.pixelifyplus.Constants.RELEASES_URL
25 | import balti.xposed.pixelifyplus.Constants.SHARED_PREF_FILE_NAME
26 | import balti.xposed.pixelifyplus.Constants.TELEGRAM_GROUP
27 | import balti.xposed.pixelifyplus.Constants.UPDATE_INFO_URL
28 | import com.google.android.material.snackbar.Snackbar
29 | import org.json.JSONObject
30 | import java.io.ByteArrayOutputStream
31 | import java.net.URL
32 | import kotlin.math.roundToInt
33 |
34 |
35 | class ActivityMain: AppCompatActivity(R.layout.activity_main) {
36 |
37 | /**
38 | * Normally [MODE_WORLD_READABLE] causes a crash.
39 | * But if "xposedsharedprefs" flag is present in AndroidManifest,
40 | * then the file is accordingly taken care by lsposed framework.
41 | *
42 | * If an exception is thrown, means module is not enabled,
43 | * hence Android throws a security exception.
44 | */
45 | private val pref by lazy {
46 | try {
47 | getSharedPreferences(SHARED_PREF_FILE_NAME, MODE_WORLD_READABLE)
48 | } catch (_: Exception){
49 | null
50 | }
51 | }
52 |
53 | private fun showRebootSnack(isPhotos: Boolean = true){
54 | if (pref == null) return // don't display snackbar if module not active.
55 | val rootView = findViewById(R.id.root_view_for_snackbar)
56 | if (isPhotos) {
57 | Snackbar.make(rootView, R.string.please_force_stop_google_photos, Snackbar.LENGTH_SHORT).show()
58 | } else {
59 | Snackbar.make(rootView, R.string.please_force_stop, Snackbar.LENGTH_SHORT).show()
60 | }
61 | }
62 |
63 | /**
64 | * Update TextView according to refresh rate.
65 | */
66 | private fun updateTextView() {
67 | val gameSpooferSpinner = findViewById(R.id.game_spoofer_spinner)
68 | val deviceSpooferDesc = findViewById(R.id.device_spoofer_desc)
69 | if (!hasHighRefreshRate()) {
70 | deviceSpooferDesc.setText(R.string.refresh_rate_desc)
71 | gameSpooferSpinner.isEnabled = false
72 | } else {
73 | deviceSpooferDesc.setText(R.string.spoofs_games)
74 | gameSpooferSpinner.isEnabled = true
75 | }
76 | pref?.edit()?.run {
77 | putBoolean(PREF_DEVICE_SUPPORT_HIGH_REFRESH_RATE, hasHighRefreshRate())
78 | apply()
79 | }
80 | }
81 |
82 | /**
83 | * Animate the "Feature flags changed" textview and hide it after showing for sometime.
84 | */
85 | private fun peekFeatureFlagsChanged(textView: TextView){
86 | textView.run {
87 | alpha = 1.0f
88 | animate().alpha(0.0f).apply {
89 | duration = 1000
90 | startDelay = 3000
91 | }.start()
92 | }
93 | }
94 |
95 | private val utils by lazy { Utils() }
96 |
97 | /**
98 | * Activity launcher for [FeatureCustomize] activity.
99 | * If user presses "Save" on [FeatureCustomize] activity, then result code is RESULT_OK.
100 | * Then show prompt to force stop Google Photos.
101 | */
102 | private val childActivityLauncher =
103 | registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
104 | if (it.resultCode == Activity.RESULT_OK) {
105 | showRebootSnack()
106 | }
107 | }
108 |
109 | override fun onCreate(savedInstanceState: Bundle?) {
110 | super.onCreate(savedInstanceState)
111 |
112 | /**
113 | * Check if [pref] is not null. If it is, then module is not enabled.
114 | */
115 | if (pref == null){
116 | AlertDialog.Builder(this)
117 | .setMessage(R.string.module_not_enabled)
118 | .setPositiveButton(R.string.close) {_, _ ->
119 | finish()
120 | }
121 | .setCancelable(false)
122 | .show()
123 | }
124 |
125 | /**
126 | * Link to xml views.
127 | */
128 | val resetSettings = findViewById