├── .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