diff --git a/app/src/main/aidl/com/drdisagree/colorblendr/service/IShizukuConnection.aidl b/app/src/main/aidl/com/drdisagree/colorblendr/service/IShizukuConnection.aidl index eed180ff..0805809b 100644 --- a/app/src/main/aidl/com/drdisagree/colorblendr/service/IShizukuConnection.aidl +++ b/app/src/main/aidl/com/drdisagree/colorblendr/service/IShizukuConnection.aidl @@ -6,4 +6,7 @@ interface IShizukuConnection { void applyFabricatedColors(String jsonString) = 2; void removeFabricatedColors() = 3; String getCurrentSettings() = 4; + void applyFabricatedColorsSamsung(String paletteArray) = 5; + void applyThemedIconSamsung(boolean isThemed) = 6; + void removeFabricatedColorsSamsung() = 7; } \ No newline at end of file diff --git a/app/src/main/java/com/drdisagree/colorblendr/common/Const.kt b/app/src/main/java/com/drdisagree/colorblendr/common/Const.kt index 8bd5b25b..a6062356 100644 --- a/app/src/main/java/com/drdisagree/colorblendr/common/Const.kt +++ b/app/src/main/java/com/drdisagree/colorblendr/common/Const.kt @@ -1,7 +1,9 @@ package com.drdisagree.colorblendr.common +import android.os.Build import com.drdisagree.colorblendr.BuildConfig import com.drdisagree.colorblendr.config.RPrefs +import com.drdisagree.colorblendr.utils.RomUtil.isSamsung import com.drdisagree.colorblendr.utils.SystemUtil import com.google.gson.Gson import com.google.gson.reflect.TypeToken @@ -72,10 +74,21 @@ object Const { const val SHOW_PER_APP_THEME_WARN: String = "showPerAppThemeWarn" const val TINT_TEXT_COLOR: String = "tintTextColor" const val SHIZUKU_PERMISSION_REQUEST_ID: Int = 100 - const val THEME_CUSTOMIZATION_OVERLAY_PACKAGES: String = "theme_customization_overlay_packages" const val SHIZUKU_THEMING_ENABLED: String = "shizukuThemingEnabled" const val APP_LIST_FILTER_METHOD: String = "appListFilterMethod" val screenOrientation: AtomicInteger = AtomicInteger(-1) + val isSamsungDevice: Boolean = isSamsung + + // AOSP key + const val THEME_CUSTOMIZATION_OVERLAY_PACKAGES: String = "theme_customization_overlay_packages" + + // Samsung key + const val WALLPAPER_THEME_STATE: String = "wallpapertheme_state" + const val WALLPAPER_THEME_COLOR_IS_GRAY: String = "wallpapertheme_color_isgray" + const val LOCK_ADAPTIVE_COLOR: String = "lock_adaptive_color" + const val WALLPAPER_THEME_COLORS: String = "wallpapertheme_color" + const val WALLPAPER_THEME_COLORS_FOR_GOOGLE: String = "wallpapertheme_color_for_g" + const val COLOR_THEME_APP_ICON: String = "colortheme_app_icon" // Service preferences val GSON: Gson = Gson() @@ -151,4 +164,12 @@ object Const { LAUNCHABLE, ALL } + + val isRootMode: Boolean = workingMethod == Const.WorkMethod.ROOT + val isShizukuMode: Boolean = workingMethod == Const.WorkMethod.SHIZUKU + + val isAtleastA13 = !isShizukuMode || + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU + val isAtleastA14 = !isShizukuMode || + Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE } diff --git a/app/src/main/java/com/drdisagree/colorblendr/service/ShizukuConnection.kt b/app/src/main/java/com/drdisagree/colorblendr/service/ShizukuConnection.kt index 7b22bd15..6ad69cd5 100644 --- a/app/src/main/java/com/drdisagree/colorblendr/service/ShizukuConnection.kt +++ b/app/src/main/java/com/drdisagree/colorblendr/service/ShizukuConnection.kt @@ -4,7 +4,13 @@ import android.content.Context import android.os.Build import android.util.Log import androidx.annotation.Keep +import com.drdisagree.colorblendr.common.Const.COLOR_THEME_APP_ICON +import com.drdisagree.colorblendr.common.Const.LOCK_ADAPTIVE_COLOR import com.drdisagree.colorblendr.common.Const.THEME_CUSTOMIZATION_OVERLAY_PACKAGES +import com.drdisagree.colorblendr.common.Const.WALLPAPER_THEME_COLORS +import com.drdisagree.colorblendr.common.Const.WALLPAPER_THEME_COLORS_FOR_GOOGLE +import com.drdisagree.colorblendr.common.Const.WALLPAPER_THEME_COLOR_IS_GRAY +import com.drdisagree.colorblendr.common.Const.WALLPAPER_THEME_STATE import com.drdisagree.colorblendr.extension.ThemeOverlayPackage import com.topjohnwu.superuser.Shell import org.json.JSONException @@ -17,10 +23,12 @@ class ShizukuConnection : IShizukuConnection.Stub { private val TAG: String = ShizukuConnection::class.java.simpleName } + @Suppress("unused") constructor() { Log.i(TAG, "Constructed with no arguments") } + @Suppress("unused") @Keep constructor(context: Context) { Log.i(TAG, "Constructed with context: $context") @@ -40,6 +48,22 @@ class ShizukuConnection : IShizukuConnection.Stub { ).exec() } + override fun applyFabricatedColorsSamsung(paletteArray: String) { + Shell.cmd( + "settings put system $LOCK_ADAPTIVE_COLOR '3'", + "settings put system $WALLPAPER_THEME_COLORS '$paletteArray'", + "settings put system $WALLPAPER_THEME_COLORS_FOR_GOOGLE '$paletteArray'", + "settings put system $WALLPAPER_THEME_COLOR_IS_GRAY '0'", + "settings put system $WALLPAPER_THEME_STATE '1'", + ).exec() + } + + override fun applyThemedIconSamsung(isThemed: Boolean) { + Shell.cmd( + "settings put system $COLOR_THEME_APP_ICON '${if (isThemed) "1" else "0"}'" + ).exec() + } + override fun removeFabricatedColors() { try { applyFabricatedColors(originalSettings.toString()) @@ -48,6 +72,19 @@ class ShizukuConnection : IShizukuConnection.Stub { } } + override fun removeFabricatedColorsSamsung() { + try { + Shell.cmd( + "settings put system $WALLPAPER_THEME_STATE '0'", + "settings put system $LOCK_ADAPTIVE_COLOR '3'", + "settings put system $WALLPAPER_THEME_COLORS ''", + "settings put system $WALLPAPER_THEME_COLORS_FOR_GOOGLE ''" + ).exec() + } catch (e: Exception) { + Log.e(TAG, "removeFabricatedColorsSamsung: ", e) + } + } + override fun getCurrentSettings(): String { val currentSettings = Shell.cmd( "settings get secure $THEME_CUSTOMIZATION_OVERLAY_PACKAGES" diff --git a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ColorPaletteFragment.kt b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ColorPaletteFragment.kt index e56cfb4e..559bde7b 100644 --- a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ColorPaletteFragment.kt +++ b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ColorPaletteFragment.kt @@ -16,7 +16,6 @@ import android.widget.TextView import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import com.drdisagree.colorblendr.R -import com.drdisagree.colorblendr.common.Const import com.drdisagree.colorblendr.common.Const.MANUAL_OVERRIDE_COLORS import com.drdisagree.colorblendr.common.Const.MONET_ACCENT_SATURATION import com.drdisagree.colorblendr.common.Const.MONET_ACCURATE_SHADES @@ -25,7 +24,7 @@ import com.drdisagree.colorblendr.common.Const.MONET_BACKGROUND_SATURATION import com.drdisagree.colorblendr.common.Const.MONET_LAST_UPDATED import com.drdisagree.colorblendr.common.Const.MONET_PITCH_BLACK_THEME import com.drdisagree.colorblendr.common.Const.MONET_STYLE -import com.drdisagree.colorblendr.common.Const.workingMethod +import com.drdisagree.colorblendr.common.Const.isShizukuMode import com.drdisagree.colorblendr.config.RPrefs import com.drdisagree.colorblendr.config.RPrefs.clearPref import com.drdisagree.colorblendr.config.RPrefs.getBoolean @@ -56,7 +55,6 @@ class ColorPaletteFragment : Fragment() { private lateinit var colorTableRows: Array private lateinit var sharedViewModel: SharedViewModel private val colorNames: Array> = ColorUtil.colorNames - private val notShizukuMode: Boolean = workingMethod != Const.WorkMethod.SHIZUKU override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -87,7 +85,7 @@ class ColorPaletteFragment : Fragment() { ) // Warning message - val isOverrideAvailable: Boolean = notShizukuMode && + val isOverrideAvailable: Boolean = !isShizukuMode && getBoolean(MANUAL_OVERRIDE_COLORS, false) binding.warn.warningText.setText( @@ -211,7 +209,7 @@ class ColorPaletteFragment : Fragment() { Snackbar.LENGTH_INDEFINITE ) .setAction(snackbarButton) { - if (!manualOverride || !notShizukuMode) { + if (!manualOverride || isShizukuMode) { val clipboard: ClipboardManager = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip: ClipData = ClipData.newPlainText( diff --git a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ColorsFragment.kt b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ColorsFragment.kt index 955dc7c6..9074f48f 100644 --- a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ColorsFragment.kt +++ b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ColorsFragment.kt @@ -19,7 +19,7 @@ import com.drdisagree.colorblendr.common.Const.MONET_LAST_UPDATED import com.drdisagree.colorblendr.common.Const.MONET_SEED_COLOR import com.drdisagree.colorblendr.common.Const.MONET_SEED_COLOR_ENABLED import com.drdisagree.colorblendr.common.Const.WALLPAPER_COLOR_LIST -import com.drdisagree.colorblendr.common.Const.workingMethod +import com.drdisagree.colorblendr.common.Const.isShizukuMode import com.drdisagree.colorblendr.config.RPrefs import com.drdisagree.colorblendr.config.RPrefs.getBoolean import com.drdisagree.colorblendr.config.RPrefs.getInt @@ -50,7 +50,6 @@ class ColorsFragment : Fragment() { private lateinit var binding: FragmentColorsBinding private lateinit var monetSeedColor: IntArray private lateinit var sharedViewModel: SharedViewModel - private val notShizukuMode: Boolean = workingMethod != Const.WorkMethod.SHIZUKU private val wallpaperChangedReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { @@ -65,7 +64,7 @@ class ColorsFragment : Fragment() { sharedViewModel = ViewModelProvider(requireActivity())[SharedViewModel::class.java] - if (!notShizukuMode) { + if (isShizukuMode) { SettingsFragment.clearCustomColors() } } @@ -171,7 +170,7 @@ class ColorsFragment : Fragment() { PerAppThemeFragment() ) } - binding.perAppTheme.setEnabled(notShizukuMode) + binding.perAppTheme.setEnabled(!isShizukuMode) } private fun updateViewVisibility(visibilityStates: Map) { diff --git a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/SettingsAdvancedFragment.kt b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/SettingsAdvancedFragment.kt index e52be43a..4c2e6a7e 100644 --- a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/SettingsAdvancedFragment.kt +++ b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/SettingsAdvancedFragment.kt @@ -10,7 +10,6 @@ import android.view.ViewGroup import android.widget.CompoundButton import androidx.fragment.app.Fragment import com.drdisagree.colorblendr.R -import com.drdisagree.colorblendr.common.Const import com.drdisagree.colorblendr.common.Const.DARKER_LAUNCHER_ICONS import com.drdisagree.colorblendr.common.Const.FORCE_PITCH_BLACK_SETTINGS import com.drdisagree.colorblendr.common.Const.MODE_SPECIFIC_THEMES @@ -22,9 +21,9 @@ import com.drdisagree.colorblendr.common.Const.MONET_TERTIARY_COLOR import com.drdisagree.colorblendr.common.Const.PIXEL_LAUNCHER import com.drdisagree.colorblendr.common.Const.SCREEN_OFF_UPDATE_COLORS import com.drdisagree.colorblendr.common.Const.SEMI_TRANSPARENT_LAUNCHER_ICONS +import com.drdisagree.colorblendr.common.Const.isShizukuMode import com.drdisagree.colorblendr.common.Const.saveSelectedFabricatedApps import com.drdisagree.colorblendr.common.Const.selectedFabricatedApps -import com.drdisagree.colorblendr.common.Const.workingMethod import com.drdisagree.colorblendr.config.RPrefs.getBoolean import com.drdisagree.colorblendr.config.RPrefs.getInt import com.drdisagree.colorblendr.config.RPrefs.putBoolean @@ -45,7 +44,6 @@ import me.jfenn.colorpickerdialog.views.picker.ImagePickerView class SettingsAdvancedFragment : Fragment() { private lateinit var binding: FragmentSettingsAdvancedBinding - private val notShizukuMode: Boolean = workingMethod != Const.WorkMethod.SHIZUKU private val hasPixelLauncher: Boolean = SystemUtil.isAppInstalled(PIXEL_LAUNCHER) override fun onCreateView( @@ -60,7 +58,7 @@ class SettingsAdvancedFragment : Fragment() { // Secondary color var monetSecondaryColor = getInt(MONET_SECONDARY_COLOR, Color.WHITE) binding.secondaryColorPicker.isEnabled = - getBoolean(MONET_SEED_COLOR_ENABLED, false) && notShizukuMode + getBoolean(MONET_SEED_COLOR_ENABLED, false) && !isShizukuMode binding.secondaryColorPicker.previewColor = getInt(MONET_SECONDARY_COLOR, monetSecondaryColor) binding.secondaryColorPicker.setOnClickListener { @@ -84,7 +82,7 @@ class SettingsAdvancedFragment : Fragment() { // Tertiary color var monetTertiaryColor = getInt(MONET_TERTIARY_COLOR, Color.WHITE) binding.tertiaryColorPicker.isEnabled = - getBoolean(MONET_SEED_COLOR_ENABLED, false) && notShizukuMode + getBoolean(MONET_SEED_COLOR_ENABLED, false) && !isShizukuMode binding.tertiaryColorPicker.previewColor = monetTertiaryColor binding.tertiaryColorPicker.setOnClickListener { ColorPickerDialog() @@ -111,7 +109,7 @@ class SettingsAdvancedFragment : Fragment() { } // Mode specific themes - binding.modeSpecificThemes.isEnabled = notShizukuMode + binding.modeSpecificThemes.isEnabled = !isShizukuMode binding.modeSpecificThemes.isSwitchChecked = getBoolean(MODE_SPECIFIC_THEMES, false) binding.modeSpecificThemes.setSwitchChangeListener { _: CompoundButton?, isChecked: Boolean -> putBoolean(MODE_SPECIFIC_THEMES, isChecked) @@ -119,7 +117,7 @@ class SettingsAdvancedFragment : Fragment() { } // Darker launcher icons - binding.darkerLauncherIcons.isEnabled = notShizukuMode && hasPixelLauncher + binding.darkerLauncherIcons.isEnabled = !isShizukuMode && hasPixelLauncher binding.darkerLauncherIcons.isSwitchChecked = getBoolean(DARKER_LAUNCHER_ICONS, false) binding.darkerLauncherIcons.setSwitchChangeListener { _: CompoundButton?, isChecked: Boolean -> if (isChecked) { @@ -130,7 +128,7 @@ class SettingsAdvancedFragment : Fragment() { } // Semi-transparent launcher icons - binding.semitransparentLauncher.isEnabled = notShizukuMode && hasPixelLauncher + binding.semitransparentLauncher.isEnabled = !isShizukuMode && hasPixelLauncher binding.semitransparentLauncher.isSwitchChecked = getBoolean(SEMI_TRANSPARENT_LAUNCHER_ICONS, false) binding.semitransparentLauncher.setSwitchChangeListener { _: CompoundButton?, isChecked: Boolean -> @@ -143,7 +141,7 @@ class SettingsAdvancedFragment : Fragment() { // Semi-transparent launcher icons binding.pitchBlackSettingsWorkaround.isEnabled = - notShizukuMode && getBoolean(MONET_PITCH_BLACK_THEME, false) + !isShizukuMode && getBoolean(MONET_PITCH_BLACK_THEME, false) binding.pitchBlackSettingsWorkaround.visibility = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.UPSIDE_DOWN_CAKE) View.VISIBLE else View.GONE binding.pitchBlackSettingsWorkaround.isSwitchChecked = @@ -167,7 +165,7 @@ class SettingsAdvancedFragment : Fragment() { } private fun savePixelLauncherInPerAppTheme() { - if (!hasPixelLauncher || !notShizukuMode) { + if (!hasPixelLauncher || isShizukuMode) { return } diff --git a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/SettingsFragment.kt b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/SettingsFragment.kt index 39f333d6..62c34d1c 100644 --- a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/SettingsFragment.kt +++ b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/SettingsFragment.kt @@ -38,7 +38,7 @@ import com.drdisagree.colorblendr.common.Const.SHIZUKU_THEMING_ENABLED import com.drdisagree.colorblendr.common.Const.THEMING_ENABLED import com.drdisagree.colorblendr.common.Const.TINT_TEXT_COLOR import com.drdisagree.colorblendr.common.Const.WALLPAPER_COLOR_LIST -import com.drdisagree.colorblendr.common.Const.workingMethod +import com.drdisagree.colorblendr.common.Const.isShizukuMode import com.drdisagree.colorblendr.config.RPrefs import com.drdisagree.colorblendr.config.RPrefs.backupPrefs import com.drdisagree.colorblendr.config.RPrefs.clearPref @@ -71,7 +71,6 @@ class SettingsFragment : Fragment() { private lateinit var binding: FragmentSettingsBinding private var sharedViewModel: SharedViewModel? = null private var isMasterSwitchEnabled: Boolean = true - private val notShizukuMode: Boolean = workingMethod != Const.WorkMethod.SHIZUKU private val masterSwitch: CompoundButton.OnCheckedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView: CompoundButton, isChecked: Boolean -> @@ -150,7 +149,7 @@ class SettingsFragment : Fragment() { sharedViewModel!!.setBooleanState(MONET_ACCURATE_SHADES, isChecked) applyFabricatedColors() } - binding.accurateShades.setEnabled(notShizukuMode) + binding.accurateShades.setEnabled(!isShizukuMode) // Pitch black theme binding.pitchBlackTheme.isSwitchChecked = getBoolean(MONET_PITCH_BLACK_THEME, false) @@ -158,7 +157,7 @@ class SettingsFragment : Fragment() { putBoolean(MONET_PITCH_BLACK_THEME, isChecked) applyFabricatedColors() } - binding.pitchBlackTheme.setEnabled(notShizukuMode) + binding.pitchBlackTheme.setEnabled(!isShizukuMode) // Custom primary color binding.customPrimaryColor.isSwitchChecked = getBoolean(MONET_SEED_COLOR_ENABLED, false) @@ -186,7 +185,7 @@ class SettingsFragment : Fragment() { putBoolean(TINT_TEXT_COLOR, isChecked) applyFabricatedColors() } - binding.tintTextColor.setEnabled(notShizukuMode) + binding.tintTextColor.setEnabled(!isShizukuMode) // Override colors manually binding.overrideColorsManually.isSwitchChecked = getBoolean(MANUAL_OVERRIDE_COLORS, false) @@ -220,7 +219,7 @@ class SettingsFragment : Fragment() { } } } - binding.overrideColorsManually.setEnabled(notShizukuMode) + binding.overrideColorsManually.setEnabled(!isShizukuMode) binding.backupRestore.container.setOnClickListener { crossfade( diff --git a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/StylesFragment.kt b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/StylesFragment.kt index 03146f41..7fac0abf 100644 --- a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/StylesFragment.kt +++ b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/StylesFragment.kt @@ -1,6 +1,5 @@ package com.drdisagree.colorblendr.ui.fragments -import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.MenuItem @@ -9,11 +8,12 @@ import android.view.ViewGroup import androidx.annotation.StringRes import androidx.fragment.app.Fragment import com.drdisagree.colorblendr.R -import com.drdisagree.colorblendr.common.Const import com.drdisagree.colorblendr.common.Const.MONET_LAST_UPDATED import com.drdisagree.colorblendr.common.Const.MONET_STYLE import com.drdisagree.colorblendr.common.Const.MONET_STYLE_ORIGINAL_NAME -import com.drdisagree.colorblendr.common.Const.workingMethod +import com.drdisagree.colorblendr.common.Const.isAtleastA13 +import com.drdisagree.colorblendr.common.Const.isAtleastA14 +import com.drdisagree.colorblendr.common.Const.isShizukuMode import com.drdisagree.colorblendr.config.RPrefs import com.drdisagree.colorblendr.config.RPrefs.putLong import com.drdisagree.colorblendr.config.RPrefs.putString @@ -23,11 +23,6 @@ import com.drdisagree.colorblendr.utils.MiscUtil.setToolbarTitle class StylesFragment : Fragment() { private lateinit var binding: FragmentStylesBinding - private val notShizukuMode = workingMethod != Const.WorkMethod.SHIZUKU - private val isAtleastA13 = notShizukuMode || - Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU - private val isAtleastA14 = notShizukuMode || - Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE override fun onCreateView( inflater: LayoutInflater, @@ -108,7 +103,7 @@ class StylesFragment : Fragment() { putString(MONET_STYLE_ORIGINAL_NAME, getOriginalName(R.string.monet_fidelity)) binding.monetFidelity.applyColorScheme() } - binding.monetFidelity.isEnabled = notShizukuMode + binding.monetFidelity.isEnabled = !isShizukuMode binding.monetContent.isSelected = getString(R.string.monet_content) == selectedStyle binding.monetContent.setOnClickListener { @@ -118,7 +113,7 @@ class StylesFragment : Fragment() { putString(MONET_STYLE_ORIGINAL_NAME, getOriginalName(R.string.monet_content)) binding.monetContent.applyColorScheme() } - binding.monetContent.isEnabled = notShizukuMode + binding.monetContent.isEnabled = !isShizukuMode binding.monetFruitsalad.isSelected = getString(R.string.monet_fruitsalad) == selectedStyle binding.monetFruitsalad.setOnClickListener { diff --git a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ThemeFragment.kt b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ThemeFragment.kt index 5248c47d..d0d7fbb5 100644 --- a/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ThemeFragment.kt +++ b/app/src/main/java/com/drdisagree/colorblendr/ui/fragments/ThemeFragment.kt @@ -10,7 +10,6 @@ import android.widget.SeekBar import android.widget.SeekBar.OnSeekBarChangeListener import androidx.fragment.app.Fragment import com.drdisagree.colorblendr.R -import com.drdisagree.colorblendr.common.Const import com.drdisagree.colorblendr.common.Const.MONET_ACCENT_SATURATION import com.drdisagree.colorblendr.common.Const.MONET_ACCURATE_SHADES import com.drdisagree.colorblendr.common.Const.MONET_BACKGROUND_LIGHTNESS @@ -18,7 +17,7 @@ import com.drdisagree.colorblendr.common.Const.MONET_BACKGROUND_SATURATION import com.drdisagree.colorblendr.common.Const.MONET_LAST_UPDATED import com.drdisagree.colorblendr.common.Const.MONET_PITCH_BLACK_THEME import com.drdisagree.colorblendr.common.Const.MONET_STYLE -import com.drdisagree.colorblendr.common.Const.workingMethod +import com.drdisagree.colorblendr.common.Const.isShizukuMode import com.drdisagree.colorblendr.config.RPrefs import com.drdisagree.colorblendr.config.RPrefs.clearPref import com.drdisagree.colorblendr.config.RPrefs.getBoolean @@ -50,7 +49,6 @@ class ThemeFragment : Fragment() { getInt(MONET_BACKGROUND_LIGHTNESS, 100) ) private var wasDarkMode: Boolean = isDarkMode - private val notShizukuMode: Boolean = workingMethod != Const.WorkMethod.SHIZUKU override fun onCreateView( inflater: LayoutInflater, @@ -95,7 +93,7 @@ class ThemeFragment : Fragment() { applyFabricatedColors() true } - accentSaturation.setEnabled(notShizukuMode) + accentSaturation.setEnabled(!isShizukuMode) // Monet background saturation backgroundSaturation.seekbarProgress = getInt(MONET_BACKGROUND_SATURATION, 100) @@ -124,7 +122,7 @@ class ThemeFragment : Fragment() { applyFabricatedColors() true } - backgroundSaturation.setEnabled(notShizukuMode) + backgroundSaturation.setEnabled(!isShizukuMode) // Monet background lightness backgroundLightness.seekbarProgress = getInt(MONET_BACKGROUND_LIGHTNESS, 100) @@ -153,7 +151,7 @@ class ThemeFragment : Fragment() { applyFabricatedColors() true } - backgroundLightness.setEnabled(notShizukuMode) + backgroundLightness.setEnabled(!isShizukuMode) } return binding.getRoot() diff --git a/app/src/main/java/com/drdisagree/colorblendr/utils/OverlayManager.kt b/app/src/main/java/com/drdisagree/colorblendr/utils/OverlayManager.kt index 9e7193d0..7c5e3d50 100644 --- a/app/src/main/java/com/drdisagree/colorblendr/utils/OverlayManager.kt +++ b/app/src/main/java/com/drdisagree/colorblendr/utils/OverlayManager.kt @@ -21,6 +21,8 @@ import com.drdisagree.colorblendr.common.Const.MONET_BACKGROUND_SATURATION import com.drdisagree.colorblendr.common.Const.MONET_PITCH_BLACK_THEME import com.drdisagree.colorblendr.common.Const.MONET_STYLE import com.drdisagree.colorblendr.common.Const.SYSTEMUI_PACKAGE +import com.drdisagree.colorblendr.common.Const.isSamsungDevice +import com.drdisagree.colorblendr.common.Const.isShizukuMode import com.drdisagree.colorblendr.common.Const.selectedFabricatedApps import com.drdisagree.colorblendr.common.Const.workingMethod import com.drdisagree.colorblendr.config.RPrefs @@ -220,6 +222,7 @@ object OverlayManager { return } + val isDarkMode = SystemUtil.isDarkMode val style = ColorSchemeUtil.stringToEnumMonetStyle( context, RPrefs.getString(MONET_STYLE, context.getString(R.string.monet_tonalspot))!! @@ -252,14 +255,21 @@ object OverlayManager { isDark = true ) + if ( + applyFabricatedColorsNonRootSamsung( + context, + if (isDarkMode) paletteDark else paletteLight + ) + ) { + return + } + ArrayList().apply { add( FabricatedOverlayResource( FABRICATED_OVERLAY_NAME_SYSTEM, FRAMEWORK_PACKAGE ).also { frameworkOverlay -> - val isDarkMode = SystemUtil.isDarkMode - frameworkOverlay.apply { for (i in colorNames.indices) { for (j in colorNames[i].indices) { @@ -417,8 +427,8 @@ object OverlayManager { } } - private fun applyFabricatedColorsNonRoot(context: Context): Boolean { - if (workingMethod != Const.WorkMethod.SHIZUKU) { + private fun applyFabricatedColorsNonRoot(context: Context, force: Boolean = false): Boolean { + if (!isShizukuMode || (isSamsungDevice && !force)) { return false } @@ -452,8 +462,42 @@ object OverlayManager { return true } + private fun applyFabricatedColorsNonRootSamsung( + context: Context, + palette: ArrayList> + ): Boolean { + if (!isShizukuMode || !isSamsungDevice) { + return false + } + + if (!ShizukuUtil.isShizukuAvailable || !ShizukuUtil.hasShizukuPermission(context)) { + Log.w(TAG, "Shizuku permission not available") + return true + } + + if (mShizukuConnection == null) { + mShizukuConnection = shizukuConnection + + if (mShizukuConnection == null) { + Log.w(TAG, "Shizuku service connection is null") + return true + } + } + + try { + applyFabricatedColorsNonRoot(context, true) // Material app colors + mShizukuConnection!!.applyFabricatedColorsSamsung( + palette.flatten().toString() + ) // Samsung app colors + } catch (e: Exception) { + Log.d(TAG, "applyFabricatedColorsNonRootSamsung: ", e) + } + + return true + } + private fun removeFabricatedColorsNonRoot(context: Context): Boolean { - if (workingMethod != Const.WorkMethod.SHIZUKU) { + if (!isShizukuMode) { return false } @@ -473,6 +517,10 @@ object OverlayManager { try { mShizukuConnection!!.removeFabricatedColors() + + if (isSamsungDevice) { + mShizukuConnection!!.removeFabricatedColorsSamsung() + } } catch (e: Exception) { Log.d(TAG, "removeFabricatedColorsNonRoot: ", e) } diff --git a/app/src/main/java/com/drdisagree/colorblendr/utils/RomUtils.kt b/app/src/main/java/com/drdisagree/colorblendr/utils/RomUtils.kt new file mode 100644 index 00000000..ee6d67a2 --- /dev/null +++ b/app/src/main/java/com/drdisagree/colorblendr/utils/RomUtils.kt @@ -0,0 +1,409 @@ +package com.drdisagree.colorblendr.utils + +import android.annotation.SuppressLint +import android.os.Build +import android.os.Environment +import android.text.TextUtils +import com.topjohnwu.superuser.Shell +import java.io.File +import java.io.FileInputStream +import java.util.Locale +import java.util.Properties + +/** + * Source: [...](https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/RomUtils.java) + */ +@Suppress("unused") +object RomUtil { + + private val ROM_HUAWEI = arrayOf("huawei") + private val ROM_VIVO = arrayOf("vivo") + private val ROM_XIAOMI = arrayOf("xiaomi") + private val ROM_OPPO = arrayOf("oppo") + private val ROM_LEECO = arrayOf("leeco", "letv") + private val ROM_360 = arrayOf("360", "qiku") + private val ROM_ZTE = arrayOf("zte") + private val ROM_ONEPLUS = arrayOf("oneplus") + private val ROM_NUBIA = arrayOf("nubia") + private val ROM_COOLPAD = arrayOf("coolpad", "yulong") + private val ROM_LG = arrayOf("lg", "lge") + private val ROM_GOOGLE = arrayOf("google") + private val ROM_SAMSUNG = arrayOf("samsung") + private val ROM_MEIZU = arrayOf("meizu") + private val ROM_LENOVO = arrayOf("lenovo") + private val ROM_SMARTISAN = arrayOf("smartisan", "deltainno") + private val ROM_HTC = arrayOf("htc") + private val ROM_SONY = arrayOf("sony") + private val ROM_GIONEE = arrayOf("gionee", "amigo") + private val ROM_MOTOROLA = arrayOf("motorola") + + private const val VERSION_PROPERTY_HUAWEI = "ro.build.version.emui" + private const val VERSION_PROPERTY_VIVO = "ro.vivo.os.build.display.id" + private const val VERSION_PROPERTY_XIAOMI = "ro.build.version.incremental" + private const val VERSION_PROPERTY_OPPO = "ro.build.version.opporom" + private const val VERSION_PROPERTY_LEECO = "ro.letv.release.version" + private const val VERSION_PROPERTY_360 = "ro.build.uiversion" + private const val VERSION_PROPERTY_ZTE = "ro.build.MiFavor_version" + private const val VERSION_PROPERTY_ONEPLUS = "ro.rom.version" + private const val VERSION_PROPERTY_NUBIA = "ro.build.rom.id" + private const val UNKNOWN = "unknown" + + private var bean: RomInfo? = null + + val isHuawei: Boolean + /** + * Return whether the rom is made by huawei. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_HUAWEI[0] == romInfo!!.name + + val isVivo: Boolean + /** + * Return whether the rom is made by vivo. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_VIVO[0] == romInfo!!.name + + val isXiaomi: Boolean + /** + * Return whether the rom is made by xiaomi. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_XIAOMI[0] == romInfo!!.name + + val isOppo: Boolean + /** + * Return whether the rom is made by oppo. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_OPPO[0] == romInfo!!.name + + val isLeeco: Boolean + /** + * Return whether the rom is made by leeco. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_LEECO[0] == romInfo!!.name + + /** + * Return whether the rom is made by 360. + * + * @return `true`: yes

`false`: no + */ + fun is360(): Boolean { + return ROM_360[0] == romInfo!!.name + } + + val isZte: Boolean + /** + * Return whether the rom is made by zte. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_ZTE[0] == romInfo!!.name + + val isOneplus: Boolean + /** + * Return whether the rom is made by oneplus. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_ONEPLUS[0] == romInfo!!.name + + val isNubia: Boolean + /** + * Return whether the rom is made by nubia. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_NUBIA[0] == romInfo!!.name + + val isCoolpad: Boolean + /** + * Return whether the rom is made by coolpad. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_COOLPAD[0] == romInfo!!.name + + val isLg: Boolean + /** + * Return whether the rom is made by lg. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_LG[0] == romInfo!!.name + + val isGoogle: Boolean + /** + * Return whether the rom is made by google. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_GOOGLE[0] == romInfo!!.name + + val isSamsung: Boolean + /** + * Return whether the rom is made by samsung. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_SAMSUNG[0] == romInfo!!.name + + val isMeizu: Boolean + /** + * Return whether the rom is made by meizu. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_MEIZU[0] == romInfo!!.name + + val isLenovo: Boolean + /** + * Return whether the rom is made by lenovo. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_LENOVO[0] == romInfo!!.name + + val isSmartisan: Boolean + /** + * Return whether the rom is made by smartisan. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_SMARTISAN[0] == romInfo!!.name + + val isHtc: Boolean + /** + * Return whether the rom is made by htc. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_HTC[0] == romInfo!!.name + + val isSony: Boolean + /** + * Return whether the rom is made by sony. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_SONY[0] == romInfo!!.name + + val isGionee: Boolean + /** + * Return whether the rom is made by gionee. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_GIONEE[0] == romInfo!!.name + + val isMotorola: Boolean + /** + * Return whether the rom is made by motorola. + * + * @return `true`: yes

`false`: no + */ + get() = ROM_MOTOROLA[0] == romInfo!!.name + + val romInfo: RomInfo? + /** + * Return the ROM's information. + * + * @return the ROM's information + */ + get() { + if (bean != null) return bean + bean = RomInfo() + val brand = brand + val manufacturer = manufacturer + if (isRightRom(brand, manufacturer, *ROM_HUAWEI)) { + bean!!.name = ROM_HUAWEI[0] + val version = getRomVersion(VERSION_PROPERTY_HUAWEI) + val temp = + version.split("_".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + if (temp.size > 1) { + bean!!.version = temp[1] + } else { + bean!!.version = version + } + return bean + } + if (isRightRom(brand, manufacturer, *ROM_VIVO)) { + bean!!.name = ROM_VIVO[0] + bean!!.version = getRomVersion(VERSION_PROPERTY_VIVO) + return bean + } + if (isRightRom(brand, manufacturer, *ROM_XIAOMI)) { + bean!!.name = ROM_XIAOMI[0] + bean!!.version = getRomVersion(VERSION_PROPERTY_XIAOMI) + return bean + } + if (isRightRom(brand, manufacturer, *ROM_OPPO)) { + bean!!.name = ROM_OPPO[0] + bean!!.version = getRomVersion(VERSION_PROPERTY_OPPO) + return bean + } + if (isRightRom(brand, manufacturer, *ROM_LEECO)) { + bean!!.name = ROM_LEECO[0] + bean!!.version = getRomVersion(VERSION_PROPERTY_LEECO) + return bean + } + + if (isRightRom(brand, manufacturer, *ROM_360)) { + bean!!.name = ROM_360[0] + bean!!.version = getRomVersion(VERSION_PROPERTY_360) + return bean + } + if (isRightRom(brand, manufacturer, *ROM_ZTE)) { + bean!!.name = ROM_ZTE[0] + bean!!.version = getRomVersion(VERSION_PROPERTY_ZTE) + return bean + } + if (isRightRom(brand, manufacturer, *ROM_ONEPLUS)) { + bean!!.name = ROM_ONEPLUS[0] + bean!!.version = getRomVersion(VERSION_PROPERTY_ONEPLUS) + return bean + } + if (isRightRom(brand, manufacturer, *ROM_NUBIA)) { + bean!!.name = ROM_NUBIA[0] + bean!!.version = getRomVersion(VERSION_PROPERTY_NUBIA) + return bean + } + + if (isRightRom(brand, manufacturer, *ROM_COOLPAD)) { + bean!!.name = ROM_COOLPAD[0] + } else if (isRightRom(brand, manufacturer, *ROM_LG)) { + bean!!.name = ROM_LG[0] + } else if (isRightRom(brand, manufacturer, *ROM_GOOGLE)) { + bean!!.name = ROM_GOOGLE[0] + } else if (isRightRom(brand, manufacturer, *ROM_SAMSUNG)) { + bean!!.name = ROM_SAMSUNG[0] + } else if (isRightRom(brand, manufacturer, *ROM_MEIZU)) { + bean!!.name = ROM_MEIZU[0] + } else if (isRightRom(brand, manufacturer, *ROM_LENOVO)) { + bean!!.name = ROM_LENOVO[0] + } else if (isRightRom(brand, manufacturer, *ROM_SMARTISAN)) { + bean!!.name = ROM_SMARTISAN[0] + } else if (isRightRom(brand, manufacturer, *ROM_HTC)) { + bean!!.name = ROM_HTC[0] + } else if (isRightRom(brand, manufacturer, *ROM_SONY)) { + bean!!.name = ROM_SONY[0] + } else if (isRightRom(brand, manufacturer, *ROM_GIONEE)) { + bean!!.name = ROM_GIONEE[0] + } else if (isRightRom(brand, manufacturer, *ROM_MOTOROLA)) { + bean!!.name = ROM_MOTOROLA[0] + } else { + bean!!.name = manufacturer + } + bean!!.version = getRomVersion("") + return bean + } + + private fun isRightRom(brand: String, manufacturer: String, vararg names: String): Boolean { + for (name in names) { + if (brand.contains(name) || manufacturer.contains(name)) { + return true + } + } + return false + } + + private val manufacturer: String + get() { + try { + val manufacturer = Build.MANUFACTURER + if (!TextUtils.isEmpty(manufacturer)) { + return manufacturer.lowercase(Locale.getDefault()) + } + } catch (ignore: Throwable) { /**/ + } + return UNKNOWN + } + + private val brand: String + get() { + try { + val brand = Build.BRAND + if (!TextUtils.isEmpty(brand)) { + return brand.lowercase(Locale.getDefault()) + } + } catch (ignore: Throwable) { /**/ + } + return UNKNOWN + } + + private fun getRomVersion(propertyName: String): String { + var ret = "" + if (!TextUtils.isEmpty(propertyName)) { + ret = getSystemProperty(propertyName) + } + if (TextUtils.isEmpty(ret) || ret == UNKNOWN) { + try { + val display = Build.DISPLAY + if (!TextUtils.isEmpty(display)) { + ret = display.lowercase(Locale.getDefault()) + } + } catch (ignore: Throwable) { /**/ + } + } + if (TextUtils.isEmpty(ret)) { + return UNKNOWN + } + return ret + } + + private fun getSystemProperty(name: String): String { + val prop = getSystemPropertyByShell(name) + if (!TextUtils.isEmpty(prop)) { + return prop + } + return getSystemPropertyByStream(name) + } + + private fun getSystemPropertyByShell(propName: String): String { + return Shell.cmd("getprop $propName").exec().out[0] + } + + private fun getSystemPropertyByStream(key: String): String { + try { + val prop = Properties() + val `is` = FileInputStream( + File(Environment.getRootDirectory(), "build.prop") + ) + prop.load(`is`) + return prop.getProperty(key, "") + } catch (ignore: Exception) { /**/ + } + return "" + } + + private fun getSystemPropertyByReflect(key: String): String { + try { + @SuppressLint("PrivateApi") val clz = Class.forName("android.os.SystemProperties") + val getMethod = clz.getMethod( + "get", + String::class.java, + String::class.java + ) + return getMethod.invoke(clz, key, "") as String + } catch (e: Exception) { /**/ + } + return "" + } + + class RomInfo { + var name: String? = null + var version: String? = null + + override fun toString(): String { + return "RomInfo{name=" + name + + ", version=" + version + "}" + } + } +} \ No newline at end of file