Initial changes
This commit is contained in:
committed by
Pun Butrach
parent
6bd7c85ab8
commit
ba62bdf380
@@ -0,0 +1,18 @@
|
||||
**I. Core Architectural Principles (The "Lawnchair Way")**
|
||||
|
||||
* **Pragmatic Modernization:** The primary architectural goal is to incrementally refactor the
|
||||
legacy AOSP codebase towards a modern, testable, and maintainable structure. We do not rewrite for
|
||||
the sake of rewriting.
|
||||
* **Decoupling & Abstraction:** New features and refactors must prioritize decoupling from the core
|
||||
`Launcher3` (`src`) module wherever possible. The preferred pattern is to create clean Kotlin
|
||||
interfaces (`lawnchair` package) that act as a bridge to legacy systems.
|
||||
* **Unidirectional Data Flow (UDF) for UI:** All new, complex UI screens (especially in Settings)
|
||||
are to be built using a ViewModel-centric UDF architecture. State should be exposed via
|
||||
`StateFlow` and consumed by "dumb" Jetpack Compose UI.
|
||||
* **Embrace Kotlin & Coroutines:** All new asynchronous code must use Kotlin Coroutines, preferably
|
||||
`Flow`. Legacy callbacks and `AsyncTask`-style patterns are to be eliminated during refactoring.
|
||||
* **Respect for Constraints:** The architecture must work within the project's real-world
|
||||
constraints:
|
||||
* **DI is a Service Locator:** We use a `MainThreadInitializedObject` singleton pattern, not
|
||||
Hilt/Dagger. Note that this pattern is slowly being migrated to use Hilt/Dagger (without the
|
||||
Android Gradle Plugin) by Google, so expect inconsistency.
|
||||
@@ -201,7 +201,6 @@ class AllAppsSearchInput(context: Context, attrs: AttributeSet?) :
|
||||
|
||||
// Sometimes the user has to click the input bar one more time
|
||||
// for the keyboard to show.
|
||||
input.showKeyboard()
|
||||
} else {
|
||||
setBackgroundVisibility(true, 1f)
|
||||
animateHintVisibility(false)
|
||||
|
||||
@@ -3,7 +3,7 @@ package app.lawnchair.data.iconoverride
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import app.lawnchair.icons.IconPickerItem
|
||||
import app.lawnchair.icons.picker.IconPickerItem
|
||||
import com.android.launcher3.util.ComponentKey
|
||||
|
||||
@Entity
|
||||
|
||||
@@ -2,7 +2,7 @@ package app.lawnchair.data.iconoverride
|
||||
|
||||
import android.content.Context
|
||||
import app.lawnchair.data.AppDatabase
|
||||
import app.lawnchair.icons.IconPickerItem
|
||||
import app.lawnchair.icons.picker.IconPickerItem
|
||||
import com.android.launcher3.LauncherAppState
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppComponent
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package app.lawnchair.icons
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
data class IconEntryWithDrawable(
|
||||
val entry: IconEntry,
|
||||
val drawable: Drawable,
|
||||
)
|
||||
@@ -14,95 +14,80 @@ import android.content.Intent.ACTION_TIME_CHANGED
|
||||
import android.content.Intent.ACTION_TIME_TICK
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ComponentInfo
|
||||
import android.content.pm.PackageItemInfo
|
||||
import android.content.res.Resources
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Handler
|
||||
import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.text.TextUtils
|
||||
import android.util.ArrayMap
|
||||
import android.util.Log
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import app.lawnchair.data.iconoverride.IconOverrideRepository
|
||||
import app.lawnchair.icons.iconpack.IconPack
|
||||
import app.lawnchair.icons.iconpack.IconPackProvider
|
||||
import app.lawnchair.icons.picker.IconEntry
|
||||
import app.lawnchair.icons.picker.IconType
|
||||
import app.lawnchair.preferences.PreferenceManager
|
||||
import app.lawnchair.util.Constants.LAWNICONS_PACKAGE_NAME
|
||||
import app.lawnchair.util.MultiSafeCloseable
|
||||
import app.lawnchair.util.getPackageVersionCode
|
||||
import app.lawnchair.util.isPackageInstalled
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.config.FeatureFlags
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.graphics.ThemeManager
|
||||
import com.android.launcher3.icons.IconProvider
|
||||
import com.android.launcher3.icons.LauncherIconProvider.ATTR_DRAWABLE
|
||||
import com.android.launcher3.icons.LauncherIconProvider.ATTR_PACKAGE
|
||||
import com.android.launcher3.icons.LauncherIconProvider.TAG_ICON
|
||||
import com.android.launcher3.icons.ClockDrawableWrapper
|
||||
import com.android.launcher3.icons.LauncherIconProvider
|
||||
import com.android.launcher3.icons.mono.ThemedIconDrawable
|
||||
import com.android.launcher3.util.ComponentKey
|
||||
import com.android.launcher3.util.SafeCloseable
|
||||
import javax.inject.Inject
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
|
||||
class LawnchairIconProvider @JvmOverloads constructor(
|
||||
private val context: Context,
|
||||
supportsIconTheme: Boolean = false,
|
||||
) : IconProvider(context) {
|
||||
|
||||
@LauncherAppSingleton
|
||||
class LawnchairIconProvider @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
val themeManager: ThemeManager,
|
||||
) : LauncherIconProvider(
|
||||
context,
|
||||
themeManager,
|
||||
) {
|
||||
private val prefs = PreferenceManager.getInstance(context)
|
||||
private val themedIconsEnabled = prefs.themedIcons.get()
|
||||
|
||||
private val iconPackPref = prefs.iconPackPackage
|
||||
private val themedIconPackPref = prefs.themedIconPackPackage
|
||||
private val themedIconSourcePref = prefs.themedIconPackPackage
|
||||
|
||||
private val iconPackProvider = IconPackProvider.INSTANCE.get(context)
|
||||
private val overrideRepo = IconOverrideRepository.INSTANCE.get(context)
|
||||
|
||||
private val iconPack
|
||||
get() = iconPackProvider.getIconPack(iconPackPref.get())?.apply { loadBlocking() }
|
||||
private val themedIconPack
|
||||
get() = iconPackProvider.getIconPack(themedIconPackPref.get())?.apply { loadBlocking() }
|
||||
|
||||
private var isOlderLawniconsInstalled = context.packageManager.getPackageVersionCode(LAWNICONS_PACKAGE_NAME) in 1..3
|
||||
|
||||
private var iconPackVersion = 0L
|
||||
private val themedIconSource
|
||||
get() = iconPackProvider.getIconPack(themedIconSourcePref.get())?.apply { loadBlocking() }
|
||||
|
||||
private var themeMapName: String = ""
|
||||
private var mThemedIconMap: Map<String, ThemeData>? = null
|
||||
|
||||
private val mThemeManager: ThemeManager? = null
|
||||
private var _themeMap: Map<String, ThemeData>? = null
|
||||
|
||||
val themeMap: Map<String, ThemeData>
|
||||
get() {
|
||||
if (!context.isThemedIconsEnabled()) {
|
||||
mThemedIconMap = DISABLED_MAP
|
||||
if (!themedIconsEnabled) {
|
||||
_themeMap = DISABLED_MAP
|
||||
}
|
||||
if (mThemedIconMap == null) {
|
||||
mThemedIconMap = createThemedIconMap()
|
||||
if (_themeMap == null) {
|
||||
_themeMap = getThemedIconMap()
|
||||
}
|
||||
if (isOlderLawniconsInstalled) {
|
||||
themeMapName = themedIconPackPref.get()
|
||||
mThemedIconMap = createThemedIconMap()
|
||||
if (themedIconSource != null && themeMapName == "") {
|
||||
_themeMap = super.getThemedIconMap()
|
||||
}
|
||||
if (themedIconPack != null && themeMapName != themedIconPack!!.packPackageName) {
|
||||
themeMapName = themedIconPack!!.packPackageName
|
||||
mThemedIconMap = createThemedIconMap()
|
||||
if (themedIconSource != null && themeMapName != themedIconSource!!.packPackageName) {
|
||||
themeMapName = themedIconSource!!.packPackageName
|
||||
_themeMap = getThemedIconMap()
|
||||
}
|
||||
return mThemedIconMap!!
|
||||
return _themeMap!!
|
||||
}
|
||||
private val supportsIconTheme get() = themeMap != DISABLED_MAP
|
||||
|
||||
init {
|
||||
setIconThemeSupported(supportsIconTheme)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables icon theme support (Lawnchair)
|
||||
* @see com.android.launcher3.icons.LauncherIconProvider.setIconThemeSupported
|
||||
*/
|
||||
fun setIconThemeSupported(isSupported: Boolean) {
|
||||
if (isSupported && isOlderLawniconsInstalled && FeatureFlags.USE_LOCAL_ICON_OVERRIDES.get()) {
|
||||
mThemedIconMap = null
|
||||
} else {
|
||||
mThemedIconMap = DISABLED_MAP
|
||||
}
|
||||
}
|
||||
val systemIconState = themeManager.iconState
|
||||
|
||||
private fun resolveIconEntry(componentName: ComponentName, user: UserHandle): IconEntry? {
|
||||
val componentKey = ComponentKey(componentName, user)
|
||||
@@ -112,7 +97,7 @@ class LawnchairIconProvider @JvmOverloads constructor(
|
||||
return overrideItem.toIconEntry()
|
||||
}
|
||||
|
||||
val iconPack = this.iconPack ?: return null
|
||||
val iconPack = iconPack ?: return null
|
||||
// then look for dynamic calendar
|
||||
val calendarEntry = iconPack.getCalendar(componentName)
|
||||
if (calendarEntry != null) {
|
||||
@@ -122,79 +107,136 @@ class LawnchairIconProvider @JvmOverloads constructor(
|
||||
return iconPack.getIcon(componentName)
|
||||
}
|
||||
|
||||
fun isThemeEnabled(): Boolean {
|
||||
return mThemedIconMap != DISABLED_MAP
|
||||
}
|
||||
override fun getIcon(
|
||||
info: PackageItemInfo,
|
||||
appInfo: ApplicationInfo,
|
||||
iconDpi: Int,
|
||||
): Drawable {
|
||||
val packageName = appInfo.packageName
|
||||
val componentName = context.packageManager.getLaunchIntentForPackage(packageName)?.component
|
||||
val user = UserHandle.getUserHandleForUid(appInfo.uid)
|
||||
|
||||
override fun getThemeDataForPackage(packageName: String?): ThemeData? {
|
||||
return getThemedIconMap().get(packageName)
|
||||
}
|
||||
|
||||
fun getThemedIconMap(): MutableMap<String, ThemeData> {
|
||||
if (mThemedIconMap != null) {
|
||||
return mThemedIconMap!!.toMutableMap() // Lawnchair-TODO: This feels cursed?
|
||||
var iconEntry: IconEntry? = null
|
||||
if (componentName != null) {
|
||||
iconEntry = resolveIconEntry(componentName, user)
|
||||
}
|
||||
val map = ArrayMap<String, ThemeData>()
|
||||
val res = mContext.getResources()
|
||||
try {
|
||||
res.getXml(R.xml.grayscale_icon_map).use { parser ->
|
||||
val depth = parser.getDepth()
|
||||
var type: Int
|
||||
while ((parser.next().also { type = it }) != XmlPullParser.START_TAG &&
|
||||
type != XmlPullParser.END_DOCUMENT
|
||||
);
|
||||
while ((
|
||||
(parser.next().also { type = it }) != XmlPullParser.END_TAG ||
|
||||
parser.getDepth() > depth
|
||||
) &&
|
||||
type != XmlPullParser.END_DOCUMENT
|
||||
) {
|
||||
if (type != XmlPullParser.START_TAG) {
|
||||
continue
|
||||
}
|
||||
if (TAG_ICON == parser.getName()) {
|
||||
val pkg = parser.getAttributeValue(null, ATTR_PACKAGE)
|
||||
val iconId = parser.getAttributeResourceValue(
|
||||
null,
|
||||
ATTR_DRAWABLE,
|
||||
0,
|
||||
|
||||
var iconPackEntry = iconEntry
|
||||
|
||||
val themeData = getThemeDataForPackage(packageName)
|
||||
var themedIcon: Drawable? = null
|
||||
|
||||
val themedColors = ThemedIconDrawable.getColors(context)
|
||||
|
||||
if (iconEntry != null) {
|
||||
val clock = iconPackProvider.getClockMetadata(iconEntry)
|
||||
|
||||
if (iconEntry.type == IconType.Calendar) {
|
||||
iconPackEntry = iconEntry.resolveDynamicCalendar(getDay())
|
||||
}
|
||||
|
||||
when {
|
||||
!themedIconsEnabled -> {
|
||||
// theming is disabled, don't populate theme data
|
||||
themedIcon = null
|
||||
}
|
||||
|
||||
clock != null -> {
|
||||
// the icon supports dynamic clock, use dynamic themed clock
|
||||
themedIcon =
|
||||
ClockDrawableWrapper.forPackage(mContext, mClock.packageName, iconDpi)
|
||||
.getMonochrome()
|
||||
}
|
||||
|
||||
packageName == mClock.packageName -> {
|
||||
// is clock app but icon might not be adaptive, fallback to static themed clock
|
||||
val clockThemedData =
|
||||
ThemeData(context.resources, R.drawable.themed_icon_static_clock)
|
||||
themedIcon = CustomAdaptiveIconDrawable(
|
||||
themedColors[0].toDrawable(),
|
||||
clockThemedData.loadPaddedDrawable().apply { setTint(themedColors[1]) },
|
||||
)
|
||||
}
|
||||
|
||||
packageName == mCalendar.packageName -> {
|
||||
// calendar app, apply the dynamic calendar icon
|
||||
themedIcon = loadCalendarDrawable(iconDpi, themeData)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// regular icon
|
||||
themedIcon = if (themeData != null) {
|
||||
CustomAdaptiveIconDrawable(
|
||||
themedColors[0].toDrawable(),
|
||||
themeData.loadPaddedDrawable().apply { setTint(themedColors[1]) },
|
||||
)
|
||||
if (iconId != 0 && !TextUtils.isEmpty(pkg)) {
|
||||
map.put(pkg, ThemeData(res, iconId))
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: java.lang.Exception) {
|
||||
Log.e(TAG, "Unable to parse icon map", e)
|
||||
}
|
||||
mThemedIconMap = map
|
||||
return mThemedIconMap!!.toMutableMap() // Lawnchair-TODO: This feels cursed?
|
||||
|
||||
val iconPackIcon = iconPackEntry?.let { iconPackProvider.getDrawable(it, iconDpi, user) }
|
||||
|
||||
return themedIcon ?: iconPackIcon ?: super.getIcon(info, appInfo, iconDpi)
|
||||
}
|
||||
|
||||
override fun getIcon(info: ComponentInfo?): Drawable {
|
||||
return CustomAdaptiveIconDrawable.wrapNonNull(super.getIcon(info))
|
||||
override fun getThemeDataForPackage(packageName: String?): ThemeData? {
|
||||
return themeMap[packageName]
|
||||
}
|
||||
|
||||
override fun getIcon(info: ComponentInfo?, iconDpi: Int): Drawable {
|
||||
return CustomAdaptiveIconDrawable.wrapNonNull(super.getIcon(info, iconDpi))
|
||||
}
|
||||
override fun getThemedIconMap(): MutableMap<String, ThemeData> {
|
||||
val themedIconMap = ArrayMap<String, ThemeData>()
|
||||
|
||||
override fun getIcon(info: ApplicationInfo?): Drawable {
|
||||
return CustomAdaptiveIconDrawable.wrapNonNull(super.getIcon(info))
|
||||
}
|
||||
fun ArrayMap<String, ThemeData>.updateFromResources(
|
||||
resources: Resources,
|
||||
packageName: String,
|
||||
) {
|
||||
try {
|
||||
@SuppressLint("DiscouragedApi")
|
||||
val xmlId = resources.getIdentifier("grayscale_icon_map", "xml", packageName)
|
||||
if (xmlId != 0) {
|
||||
val parser = resources.getXml(xmlId)
|
||||
val depth = parser.depth
|
||||
var type: Int
|
||||
while (
|
||||
(
|
||||
parser.next()
|
||||
.also { type = it } != XmlPullParser.END_TAG || parser.depth > depth
|
||||
) &&
|
||||
type != XmlPullParser.END_DOCUMENT
|
||||
) {
|
||||
if (type != XmlPullParser.START_TAG) continue
|
||||
if (TAG_ICON == parser.name) {
|
||||
val pkg = parser.getAttributeValue(null, ATTR_PACKAGE)
|
||||
val iconId = parser.getAttributeResourceValue(null, ATTR_DRAWABLE, 0)
|
||||
if (iconId != 0 && pkg.isNotEmpty()) {
|
||||
this[pkg] = ThemeData(resources, iconId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to parse icon map.", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getIcon(info: ApplicationInfo?, iconDpi: Int): Drawable {
|
||||
return CustomAdaptiveIconDrawable.wrapNonNull(super.getIcon(info, iconDpi))
|
||||
}
|
||||
// first, get Lawnchair's internal grayscale icon map
|
||||
themedIconMap.updateFromResources(
|
||||
resources = context.resources,
|
||||
packageName = context.packageName,
|
||||
)
|
||||
|
||||
override fun getIcon(info: PackageItemInfo?, appInfo: ApplicationInfo?, iconDpi: Int): Drawable {
|
||||
return CustomAdaptiveIconDrawable.wrapNonNull(super.getIcon(info, appInfo, iconDpi))
|
||||
}
|
||||
if (context.packageManager.isPackageInstalled(packageName = themeMapName)) {
|
||||
// get the grayscale icon map of the supported icon pack
|
||||
themedIconMap.updateFromResources(
|
||||
resources = context.packageManager.getResourcesForApplication(themeMapName),
|
||||
packageName = themeMapName,
|
||||
)
|
||||
}
|
||||
|
||||
override fun updateSystemState() {
|
||||
super.updateSystemState()
|
||||
mSystemState += "," + mThemeManager?.iconState?.toUniqueId()
|
||||
return themedIconMap
|
||||
}
|
||||
|
||||
override fun registerIconChangeListener(
|
||||
@@ -204,7 +246,7 @@ class LawnchairIconProvider @JvmOverloads constructor(
|
||||
return MultiSafeCloseable().apply {
|
||||
add(super.registerIconChangeListener(callback, handler))
|
||||
add(IconPackChangeReceiver(context, handler, callback))
|
||||
add(LawniconsChangeReceiver(context, handler, callback))
|
||||
add(LawniconsChangeReceiver(context, handler))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,12 +261,12 @@ class LawnchairIconProvider @JvmOverloads constructor(
|
||||
field?.close()
|
||||
field = value
|
||||
}
|
||||
private var iconState = mThemeManager?.iconState
|
||||
private var iconState = themeManager.iconState
|
||||
private val iconPackPref = PreferenceManager.getInstance(context).iconPackPackage
|
||||
private val themedIconPackPref = PreferenceManager.getInstance(context).themedIconPackPackage
|
||||
|
||||
private val subscription = iconPackPref.subscribeChanges {
|
||||
val newState = mThemeManager?.iconState
|
||||
val newState = themeManager.iconState
|
||||
if (iconState != newState) {
|
||||
iconState = newState
|
||||
updateSystemState()
|
||||
@@ -232,7 +274,7 @@ class LawnchairIconProvider @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
private val themedIconSubscription = themedIconPackPref.subscribeChanges {
|
||||
val newState = mThemeManager?.iconState
|
||||
val newState = themeManager.iconState
|
||||
if (iconState != newState) {
|
||||
iconState = newState
|
||||
updateSystemState()
|
||||
@@ -307,7 +349,6 @@ class LawnchairIconProvider @JvmOverloads constructor(
|
||||
private inner class LawniconsChangeReceiver(
|
||||
private val context: Context,
|
||||
handler: Handler,
|
||||
private val callback: IconChangeListener,
|
||||
) : BroadcastReceiver(),
|
||||
SafeCloseable {
|
||||
|
||||
@@ -321,9 +362,6 @@ class LawnchairIconProvider @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (isThemeEnabled()) {
|
||||
setIconThemeSupported(true)
|
||||
}
|
||||
updateSystemState()
|
||||
}
|
||||
|
||||
@@ -332,56 +370,7 @@ class LawnchairIconProvider @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createThemedIconMap(): MutableMap<String, ThemeData> {
|
||||
val map = ArrayMap<String, ThemeData>()
|
||||
|
||||
fun updateMapFromResources(resources: Resources, packageName: String) {
|
||||
try {
|
||||
@SuppressLint("DiscouragedApi")
|
||||
val xmlId = resources.getIdentifier("grayscale_icon_map", "xml", packageName)
|
||||
if (xmlId != 0) {
|
||||
val parser = resources.getXml(xmlId)
|
||||
val depth = parser.depth
|
||||
var type: Int
|
||||
while (
|
||||
(parser.next().also { type = it } != XmlPullParser.END_TAG || parser.depth > depth) &&
|
||||
type != XmlPullParser.END_DOCUMENT
|
||||
) {
|
||||
if (type != XmlPullParser.START_TAG) continue
|
||||
if (TAG_ICON == parser.name) {
|
||||
val pkg = parser.getAttributeValue(null, ATTR_PACKAGE)
|
||||
val iconId = parser.getAttributeResourceValue(null, ATTR_DRAWABLE, 0)
|
||||
if (iconId != 0 && !pkg.isNullOrEmpty()) {
|
||||
map[pkg] = ThemeData(resources, iconId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to parse icon map.", e)
|
||||
}
|
||||
}
|
||||
updateMapFromResources(
|
||||
resources = context.resources,
|
||||
packageName = context.packageName,
|
||||
)
|
||||
if (context.packageManager.isPackageInstalled(packageName = themeMapName)) {
|
||||
iconPackVersion = context.packageManager.getPackageVersionCode(themeMapName)
|
||||
updateMapFromResources(
|
||||
resources = context.packageManager.getResourcesForApplication(themeMapName),
|
||||
packageName = themeMapName,
|
||||
)
|
||||
if (isOlderLawniconsInstalled) {
|
||||
// updateMapWithDynamicIcons(context, map)
|
||||
}
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "LawnchairIconProvider"
|
||||
|
||||
val DISABLED_MAP = emptyMap<String, ThemeData>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package app.lawnchair.icons
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import app.lawnchair.icons.shape.IconShape
|
||||
import app.lawnchair.icons.shape.PathShapeDelegate
|
||||
import app.lawnchair.preferences2.PreferenceManager2
|
||||
import com.android.launcher3.LauncherPrefs
|
||||
import com.android.launcher3.concurrent.annotations.Ui
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.graphics.ThemeManager
|
||||
import com.android.launcher3.util.DaggerSingletonTracker
|
||||
import com.android.launcher3.util.LooperExecutor
|
||||
import com.patrykmichalik.opto.core.firstBlocking
|
||||
import javax.inject.Inject
|
||||
|
||||
@LauncherAppSingleton
|
||||
class LawnchairThemeManager
|
||||
@Inject
|
||||
constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
@Ui private val uiExecutor: LooperExecutor,
|
||||
private val prefs: LauncherPrefs,
|
||||
private val iconControllerFactory: IconControllerFactory,
|
||||
private val lifecycle: DaggerSingletonTracker,
|
||||
private val prefs2: PreferenceManager2,
|
||||
) : ThemeManager(
|
||||
context,
|
||||
uiExecutor,
|
||||
prefs,
|
||||
iconControllerFactory,
|
||||
lifecycle,
|
||||
) {
|
||||
override var iconState = parseIconStateV2(null)
|
||||
|
||||
override fun verifyIconState() {
|
||||
val newState = parseIconStateV2(iconState)
|
||||
if (newState == iconState) return
|
||||
iconState = newState
|
||||
|
||||
listeners.forEach { it.onThemeChanged() }
|
||||
}
|
||||
|
||||
private fun parseIconStateV2(oldState: IconState?): IconState {
|
||||
val currentShape: IconShape = try {
|
||||
prefs2.iconShape.firstBlocking()
|
||||
} catch (e: Exception) {
|
||||
Log.d(TAG, "Error getting icon shape", e)
|
||||
IconShape.Circle
|
||||
}
|
||||
|
||||
val shapePath = currentShape.getMaskPath()
|
||||
val shapeKey = currentShape.getHashString()
|
||||
|
||||
val iconShape =
|
||||
if (oldState != null && oldState.iconMask == shapeKey) {
|
||||
oldState.iconShape
|
||||
} else {
|
||||
PathShapeDelegate(shapePath)
|
||||
}
|
||||
|
||||
return IconState(
|
||||
iconMask = shapeKey,
|
||||
folderRadius = 1f,
|
||||
shapeRadius = 1f,
|
||||
themeController = iconControllerFactory.createThemeController(),
|
||||
iconShape = iconShape,
|
||||
folderShape = iconShape,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private const val TAG = "LawnchairThemeManager"
|
||||
@@ -0,0 +1,37 @@
|
||||
package app.lawnchair.icons
|
||||
|
||||
import android.content.Context
|
||||
import app.lawnchair.preferences2.PreferenceManager2
|
||||
import com.android.launcher3.LauncherPrefs
|
||||
import com.android.launcher3.concurrent.annotations.Ui
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.graphics.ThemeManager
|
||||
import com.android.launcher3.util.DaggerSingletonTracker
|
||||
import com.android.launcher3.util.LooperExecutor
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
||||
@Module
|
||||
class ThemeManagerModule {
|
||||
|
||||
@Provides
|
||||
@LauncherAppSingleton
|
||||
fun provideThemeManager(
|
||||
@ApplicationContext context: Context,
|
||||
@Ui uiExecutor: LooperExecutor,
|
||||
prefs: LauncherPrefs,
|
||||
lifecycle: DaggerSingletonTracker,
|
||||
iconControllerFactory: ThemeManager.IconControllerFactory,
|
||||
prefs2: PreferenceManager2,
|
||||
): ThemeManager {
|
||||
return LawnchairThemeManager(
|
||||
context = context,
|
||||
uiExecutor = uiExecutor,
|
||||
prefs = prefs,
|
||||
lifecycle = lifecycle,
|
||||
iconControllerFactory = iconControllerFactory,
|
||||
prefs2 = prefs2,
|
||||
)
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -1,4 +1,4 @@
|
||||
package app.lawnchair.icons
|
||||
package app.lawnchair.icons.iconpack
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ComponentName
|
||||
@@ -9,6 +9,12 @@ import android.content.res.Resources
|
||||
import android.content.res.XmlResourceParser
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.Xml
|
||||
import app.lawnchair.icons.ClockMetadata
|
||||
import app.lawnchair.icons.ExtendedBitmapDrawable
|
||||
import app.lawnchair.icons.picker.IconEntry
|
||||
import app.lawnchair.icons.picker.IconPickerCategory
|
||||
import app.lawnchair.icons.picker.IconPickerItem
|
||||
import app.lawnchair.icons.picker.IconType
|
||||
import com.android.launcher3.R
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
+5
-1
@@ -1,8 +1,12 @@
|
||||
package app.lawnchair.icons
|
||||
package app.lawnchair.icons.iconpack
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import app.lawnchair.icons.ClockMetadata
|
||||
import app.lawnchair.icons.picker.IconEntry
|
||||
import app.lawnchair.icons.picker.IconPickerCategory
|
||||
import app.lawnchair.icons.picker.IconPickerItem
|
||||
import com.android.launcher3.compat.AlphabeticIndexCompat
|
||||
import java.util.concurrent.Semaphore
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
+8
-40
@@ -1,17 +1,19 @@
|
||||
package app.lawnchair.icons
|
||||
package app.lawnchair.icons.iconpack
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.AdaptiveIconDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.os.Process
|
||||
import android.os.UserHandle
|
||||
import app.lawnchair.icons.ClockMetadata
|
||||
import app.lawnchair.icons.CustomAdaptiveIconDrawable
|
||||
import app.lawnchair.icons.picker.IconEntry
|
||||
import app.lawnchair.icons.shouldTransparentBGIcons
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppComponent
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.icons.ClockDrawableWrapper
|
||||
import com.android.launcher3.icons.IconProvider
|
||||
import com.android.launcher3.util.DaggerSingletonObject
|
||||
import com.android.launcher3.util.SafeCloseable
|
||||
import javax.inject.Inject
|
||||
@@ -49,26 +51,17 @@ class IconPackProvider @Inject constructor(
|
||||
fun getDrawable(iconEntry: IconEntry, iconDpi: Int, user: UserHandle): Drawable? {
|
||||
val iconPack = getIconPackOrSystem(iconEntry.packPackageName) ?: return null
|
||||
iconPack.loadBlocking()
|
||||
val packageManager = context.packageManager
|
||||
val drawable = iconPack.getIcon(iconEntry, iconDpi) ?: return null
|
||||
val shouldTintBackgrounds = context.shouldTintIconPackBackgrounds()
|
||||
val clockMetadata =
|
||||
if (user == Process.myUserHandle()) iconPack.getClock(iconEntry) else null
|
||||
try {
|
||||
if (clockMetadata != null) {
|
||||
val clockDrawable: ClockDrawableWrapper =
|
||||
ClockDrawableWrapper.forMeta(Build.VERSION.SDK_INT, clockMetadata) {
|
||||
if (shouldTintBackgrounds) {
|
||||
wrapThemedData(
|
||||
packageManager,
|
||||
iconEntry,
|
||||
drawable,
|
||||
)
|
||||
} else {
|
||||
drawable
|
||||
}
|
||||
drawable
|
||||
}
|
||||
return if (shouldTintBackgrounds && context.shouldTransparentBGIcons()) {
|
||||
|
||||
return if (context.shouldTransparentBGIcons()) {
|
||||
clockDrawable.foreground
|
||||
} else {
|
||||
CustomAdaptiveIconDrawable(
|
||||
@@ -81,31 +74,6 @@ class IconPackProvider @Inject constructor(
|
||||
// Ignore
|
||||
}
|
||||
|
||||
if (shouldTintBackgrounds) {
|
||||
return wrapThemedData(packageManager, iconEntry, drawable)
|
||||
}
|
||||
return drawable
|
||||
}
|
||||
|
||||
private fun wrapThemedData(
|
||||
packageManager: PackageManager,
|
||||
iconEntry: IconEntry,
|
||||
drawable: Drawable,
|
||||
): Drawable {
|
||||
val res = packageManager.getResourcesForApplication(iconEntry.packPackageName)
|
||||
val resId = res.getIdentifier(iconEntry.name, "drawable", iconEntry.packPackageName)
|
||||
val td = IconProvider.ThemeData(res, resId)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
||||
drawable is AdaptiveIconDrawable &&
|
||||
drawable.monochrome == null
|
||||
) {
|
||||
return AdaptiveIconDrawable(
|
||||
drawable.background,
|
||||
drawable.foreground,
|
||||
td.loadPaddedDrawable(),
|
||||
)
|
||||
}
|
||||
return drawable
|
||||
}
|
||||
|
||||
+6
-1
@@ -1,10 +1,15 @@
|
||||
package app.lawnchair.icons
|
||||
package app.lawnchair.icons.iconpack
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.LauncherApps
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Process
|
||||
import app.lawnchair.icons.ClockMetadata
|
||||
import app.lawnchair.icons.picker.IconEntry
|
||||
import app.lawnchair.icons.picker.IconPickerCategory
|
||||
import app.lawnchair.icons.picker.IconPickerItem
|
||||
import app.lawnchair.icons.picker.IconType
|
||||
import app.lawnchair.util.requireSystemService
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.pm.UserCache
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package app.lawnchair.icons
|
||||
package app.lawnchair.icons.picker
|
||||
|
||||
data class IconEntry(
|
||||
val packPackageName: String,
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package app.lawnchair.icons
|
||||
package app.lawnchair.icons.picker
|
||||
|
||||
data class IconPickerCategory(
|
||||
val title: String,
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package app.lawnchair.icons
|
||||
package app.lawnchair.icons.picker
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
@@ -83,6 +83,9 @@ open class IconShape(
|
||||
private val tmpPoint = PointF()
|
||||
open val windowTransitionRadius = 1f
|
||||
|
||||
/** The icon scale used by Launcher3 */
|
||||
open val iconScale = 1f
|
||||
|
||||
open fun getMaskPath(): Path {
|
||||
return Path().also { addToPath(it, 0f, 0f, 100f, 100f, 50f) }
|
||||
}
|
||||
@@ -594,6 +597,8 @@ open class IconShape(
|
||||
path.addPath(tempPath)
|
||||
}
|
||||
|
||||
override val iconScale = 72f / 83.4f
|
||||
|
||||
override fun toString(): String {
|
||||
return "foursidedcookie"
|
||||
}
|
||||
@@ -635,6 +640,8 @@ open class IconShape(
|
||||
path.addPath(tempPath)
|
||||
}
|
||||
|
||||
override val iconScale = 72f / 80f
|
||||
|
||||
override fun toString(): String {
|
||||
return "sevensidedcookie"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package app.lawnchair.icons.shape
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Path
|
||||
import android.graphics.Rect
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import com.android.launcher3.graphics.ShapeDelegate
|
||||
import com.android.launcher3.views.ClipPathView
|
||||
|
||||
/**
|
||||
* A ShapeDelegate that is initialized directly with a Path object,
|
||||
* bypassing SVG string conversion. The provided path is assumed to be
|
||||
* defined within a [0, 0, 100, 100] viewport.
|
||||
*/
|
||||
data class PathShapeDelegate(private val basePath: Path) : ShapeDelegate {
|
||||
|
||||
private val tmpPath = Path()
|
||||
private val tmpMatrix = Matrix()
|
||||
|
||||
override fun drawShape(
|
||||
canvas: Canvas,
|
||||
offsetX: Float,
|
||||
offsetY: Float,
|
||||
radius: Float,
|
||||
paint: Paint,
|
||||
) {
|
||||
tmpPath.reset()
|
||||
addToPath(tmpPath, offsetX, offsetY, radius, tmpMatrix)
|
||||
canvas.drawPath(tmpPath, paint)
|
||||
}
|
||||
|
||||
override fun addToPath(path: Path, offsetX: Float, offsetY: Float, radius: Float) {
|
||||
addToPath(path, offsetX, offsetY, radius, Matrix())
|
||||
}
|
||||
|
||||
private fun addToPath(
|
||||
path: Path,
|
||||
offsetX: Float,
|
||||
offsetY: Float,
|
||||
radius: Float,
|
||||
matrix: Matrix,
|
||||
) {
|
||||
// The base path is 100x100. We need to scale it to fit the desired 2 * radius.
|
||||
// The radius in ShapeDelegate is half the size of the icon.
|
||||
val scale = radius / 50f
|
||||
matrix.setScale(scale, scale)
|
||||
matrix.postTranslate(offsetX, offsetY)
|
||||
// Apply the transformation to our base path and add it to the destination path.
|
||||
basePath.transform(matrix, path)
|
||||
}
|
||||
|
||||
override fun <T> createRevealAnimator(
|
||||
target: T,
|
||||
startRect: Rect,
|
||||
endRect: Rect,
|
||||
endRadius: Float,
|
||||
isReversed: Boolean,
|
||||
): android.animation.ValueAnimator where T : View, T : ClipPathView {
|
||||
// This is complex to implement correctly without a proper morph.
|
||||
// For now, we can fall back to a simple Rect-based animation,
|
||||
// which is what would happen if a proper morph isn't possible anyway.
|
||||
// A more advanced implementation would use androidx.graphics.shapes.Morph.
|
||||
Log.w(
|
||||
"PathShapeDelegate",
|
||||
"createRevealAnimator is not fully implemented for custom paths.",
|
||||
)
|
||||
return ShapeDelegate.RoundedSquare(0f).createRevealAnimator(
|
||||
target,
|
||||
startRect,
|
||||
endRect,
|
||||
endRadius,
|
||||
isReversed,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import com.android.launcher3.InvariantDeviceProfile.INDEX_DEFAULT
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.dagger.LauncherAppComponent
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.graphics.ThemeManager
|
||||
import com.android.launcher3.model.DeviceGridState
|
||||
import com.android.launcher3.util.ComponentKey
|
||||
import com.android.launcher3.util.DaggerSingletonObject
|
||||
@@ -43,6 +44,7 @@ class PreferenceManager @Inject constructor(
|
||||
SafeCloseable {
|
||||
private val idp get() = InvariantDeviceProfile.INSTANCE.get(context)
|
||||
private val mRecentsModel get() = RecentsModel.INSTANCE.get(context)
|
||||
private val themeManager = ThemeManager.INSTANCE.get(context)
|
||||
private val reloadIcons: () -> Unit = { mRecentsModel.onThemeChanged() }
|
||||
private val reloadGrid: () -> Unit = { idp.onPreferencesChanged(context) }
|
||||
|
||||
|
||||
@@ -125,6 +125,9 @@ class PreferenceManager2 @Inject constructor(
|
||||
?: IconShapeManager.getSystemIconShape(context)
|
||||
},
|
||||
save = { it.toString() },
|
||||
onSet = {
|
||||
reloadHelper.reloadIcons()
|
||||
},
|
||||
)
|
||||
|
||||
val customIconShape = preference(
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package app.lawnchair.preferences2
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.Discouraged
|
||||
import app.lawnchair.LawnchairLauncher
|
||||
import com.android.launcher3.InvariantDeviceProfile
|
||||
import com.android.launcher3.LauncherAppState
|
||||
@@ -44,9 +43,8 @@ class ReloadHelper(private val context: Context) {
|
||||
recreate()
|
||||
}
|
||||
|
||||
@Discouraged("This literally reload the models like forceRefresh because the old code has been removed in L3")
|
||||
fun reloadIcons() {
|
||||
LauncherAppState.INSTANCE.get(context).model.forceReload()
|
||||
LauncherAppState.INSTANCE.get(context).iconCache.clearMemoryCache()
|
||||
}
|
||||
|
||||
fun reloadTaskbar() {
|
||||
|
||||
@@ -68,7 +68,6 @@ import app.lawnchair.ui.preferences.components.WallpaperPreview
|
||||
import app.lawnchair.ui.preferences.components.WithWallpaper
|
||||
import app.lawnchair.ui.preferences.components.controls.ListPreference
|
||||
import app.lawnchair.ui.preferences.components.controls.ListPreferenceEntry
|
||||
import app.lawnchair.ui.preferences.components.controls.SwitchPreference
|
||||
import app.lawnchair.ui.preferences.components.invariantDeviceProfile
|
||||
import app.lawnchair.ui.preferences.components.layout.Chip
|
||||
import app.lawnchair.ui.preferences.components.layout.NestedScrollStretch
|
||||
@@ -203,14 +202,6 @@ fun IconPackPreferences(
|
||||
adapter = iconPackAdapter,
|
||||
false,
|
||||
)
|
||||
PreferenceGroup {
|
||||
Item {
|
||||
SwitchPreference(
|
||||
adapter = prefs.tintIconPackBackgrounds.getAdapter(),
|
||||
label = stringResource(id = R.string.themed_icon_pack_tint),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1 -> {
|
||||
@@ -280,11 +271,7 @@ fun IconPackGrid(
|
||||
val lazyListState = rememberLazyListState()
|
||||
val padding = 12.dp
|
||||
|
||||
val iconPacksLocal = if (isThemedIconPack) {
|
||||
themedIconPacks.filter { it.packageName != "" }
|
||||
} else {
|
||||
iconPacks
|
||||
}
|
||||
val iconPacksLocal = iconPacks
|
||||
|
||||
val selectedPack = adapter.state.value
|
||||
LaunchedEffect(selectedPack) {
|
||||
|
||||
@@ -34,11 +34,11 @@ import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.lawnchair.icons.CustomIconPack
|
||||
import app.lawnchair.icons.IconPack
|
||||
import app.lawnchair.icons.IconPackProvider
|
||||
import app.lawnchair.icons.IconPickerItem
|
||||
import app.lawnchair.icons.filter
|
||||
import app.lawnchair.icons.iconpack.CustomIconPack
|
||||
import app.lawnchair.icons.iconpack.IconPack
|
||||
import app.lawnchair.icons.iconpack.IconPackProvider
|
||||
import app.lawnchair.icons.picker.IconPickerItem
|
||||
import app.lawnchair.icons.picker.filter
|
||||
import app.lawnchair.ui.OverflowMenu
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceGroupDescription
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceLazyColumn
|
||||
|
||||
@@ -12,7 +12,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.lawnchair.data.iconoverride.IconOverrideRepository
|
||||
import app.lawnchair.icons.IconPickerItem
|
||||
import app.lawnchair.icons.picker.IconPickerItem
|
||||
import app.lawnchair.ui.preferences.LocalNavController
|
||||
import app.lawnchair.ui.preferences.LocalPreferenceInteractor
|
||||
import app.lawnchair.ui.preferences.components.AppItem
|
||||
|
||||
@@ -19,13 +19,19 @@ package com.android.launcher3.dagger;
|
||||
|
||||
import com.android.quickstep.dagger.QuickstepBaseAppComponent;
|
||||
|
||||
import app.lawnchair.icons.ThemeManagerModule;
|
||||
import dagger.Component;
|
||||
|
||||
/**
|
||||
* Root component for Dagger injection for Launcher Quickstep.
|
||||
*/
|
||||
@LauncherAppSingleton
|
||||
@Component(modules = LauncherAppModule.class)
|
||||
@Component(
|
||||
modules = {
|
||||
LauncherAppModule.class,
|
||||
ThemeManagerModule.class
|
||||
}
|
||||
)
|
||||
public interface LauncherAppComponent extends QuickstepBaseAppComponent {
|
||||
/** Builder for quickstep LauncherAppComponent. */
|
||||
@Component.Builder
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
package com.android.launcher3
|
||||
|
||||
import android.content.Context
|
||||
import app.lawnchair.icons.LawnchairIconProvider
|
||||
import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.icons.IconCache
|
||||
import com.android.launcher3.icons.LauncherIconProvider
|
||||
import com.android.launcher3.util.DaggerSingletonObject
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
@@ -29,7 +29,7 @@ data class LauncherAppState
|
||||
@Inject
|
||||
constructor(
|
||||
@ApplicationContext val context: Context,
|
||||
val iconProvider: LauncherIconProvider,
|
||||
val iconProvider: LawnchairIconProvider,
|
||||
val iconCache: IconCache,
|
||||
val model: LauncherModel,
|
||||
val invariantDeviceProfile: InvariantDeviceProfile,
|
||||
|
||||
@@ -20,24 +20,6 @@ import android.content.Context;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.lawnchair.DeviceProfileOverrides;
|
||||
import app.lawnchair.HeadlessWidgetsManager;
|
||||
import app.lawnchair.NotificationManager;
|
||||
import app.lawnchair.data.folder.service.FolderService;
|
||||
import app.lawnchair.data.iconoverride.IconOverrideRepository;
|
||||
import app.lawnchair.data.wallpaper.service.WallpaperService;
|
||||
import app.lawnchair.font.FontCache;
|
||||
import app.lawnchair.font.FontManager;
|
||||
import app.lawnchair.font.googlefonts.GoogleFontsListing;
|
||||
import app.lawnchair.icons.IconPackProvider;
|
||||
import app.lawnchair.icons.shape.IconShapeManager;
|
||||
import app.lawnchair.preferences.PreferenceManager;
|
||||
import app.lawnchair.preferences2.PreferenceManager2;
|
||||
import app.lawnchair.smartspace.provider.SmartspaceProvider;
|
||||
import app.lawnchair.theme.ThemeProvider;
|
||||
import app.lawnchair.ui.preferences.components.colorpreference.ColorPreferenceModelList;
|
||||
import app.lawnchair.ui.preferences.data.liveinfo.LiveInformationManager;
|
||||
import app.lawnchair.util.LawnchairWindowManagerProxy;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherPrefs;
|
||||
@@ -73,10 +55,28 @@ import com.android.launcher3.widget.LauncherWidgetHolder.WidgetHolderFactory;
|
||||
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||
import com.android.launcher3.widget.util.WidgetSizeHandler;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import app.lawnchair.DeviceProfileOverrides;
|
||||
import app.lawnchair.HeadlessWidgetsManager;
|
||||
import app.lawnchair.NotificationManager;
|
||||
import app.lawnchair.data.folder.service.FolderService;
|
||||
import app.lawnchair.data.iconoverride.IconOverrideRepository;
|
||||
import app.lawnchair.data.wallpaper.service.WallpaperService;
|
||||
import app.lawnchair.font.FontCache;
|
||||
import app.lawnchair.font.FontManager;
|
||||
import app.lawnchair.font.googlefonts.GoogleFontsListing;
|
||||
import app.lawnchair.icons.iconpack.IconPackProvider;
|
||||
import app.lawnchair.icons.shape.IconShapeManager;
|
||||
import app.lawnchair.preferences.PreferenceManager;
|
||||
import app.lawnchair.preferences2.PreferenceManager2;
|
||||
import app.lawnchair.smartspace.provider.SmartspaceProvider;
|
||||
import app.lawnchair.theme.ThemeProvider;
|
||||
import app.lawnchair.ui.preferences.components.colorpreference.ColorPreferenceModelList;
|
||||
import app.lawnchair.ui.preferences.data.liveinfo.LiveInformationManager;
|
||||
import app.lawnchair.util.LawnchairWindowManagerProxy;
|
||||
import dagger.BindsInstance;
|
||||
|
||||
/**
|
||||
* Launcher base component for Dagger injection.
|
||||
*
|
||||
|
||||
@@ -42,7 +42,7 @@ import javax.inject.Inject
|
||||
|
||||
/** Centralized class for managing Launcher icon theming */
|
||||
@LauncherAppSingleton
|
||||
class ThemeManager
|
||||
open class ThemeManager
|
||||
@Inject
|
||||
constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
@@ -53,8 +53,8 @@ constructor(
|
||||
) {
|
||||
|
||||
/** Representation of the current icon state */
|
||||
var iconState = parseIconState(null)
|
||||
private set
|
||||
open var iconState = parseIconState(null)
|
||||
protected set
|
||||
|
||||
var isMonoThemeEnabled
|
||||
set(value) = prefs.put(THEMED_ICONS, value)
|
||||
@@ -72,7 +72,7 @@ constructor(
|
||||
val folderShape
|
||||
get() = iconState.folderShape
|
||||
|
||||
private val listeners = CopyOnWriteArrayList<ThemeChangeListener>()
|
||||
protected val listeners = CopyOnWriteArrayList<ThemeChangeListener>()
|
||||
|
||||
init {
|
||||
val receiver = SimpleBroadcastReceiver(
|
||||
@@ -93,7 +93,7 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun verifyIconState() {
|
||||
protected open fun verifyIconState() {
|
||||
val newState = parseIconState(iconState)
|
||||
if (newState == iconState) return
|
||||
iconState = newState
|
||||
@@ -105,7 +105,7 @@ constructor(
|
||||
|
||||
fun removeChangeListener(listener: ThemeChangeListener) = listeners.remove(listener)
|
||||
|
||||
private fun parseIconState(oldState: IconState?): IconState {
|
||||
protected open fun parseIconState(oldState: IconState?): IconState {
|
||||
val shapeModel =
|
||||
prefs.get(PREF_ICON_SHAPE).let { shapeOverride ->
|
||||
ShapesProvider.iconShapes.firstOrNull { it.key == shapeOverride }
|
||||
|
||||
@@ -22,7 +22,6 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
import static com.android.launcher3.util.LooperExecutor.CALLER_ICON_CACHE;
|
||||
import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
|
||||
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
|
||||
import android.content.ComponentName;
|
||||
@@ -87,6 +86,8 @@ import java.util.stream.Stream;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import app.lawnchair.icons.LawnchairIconProvider;
|
||||
|
||||
/**
|
||||
* Cache of application icons. Icons can be made from any thread.
|
||||
*/
|
||||
@@ -113,16 +114,14 @@ public class IconCache extends BaseIconCache {
|
||||
private final SparseArray<BitmapInfo> mWidgetCategoryBitmapInfos;
|
||||
|
||||
private int mPendingIconRequestCount = 0;
|
||||
|
||||
|
||||
@Inject
|
||||
public IconCache(
|
||||
@ApplicationContext Context context,
|
||||
InvariantDeviceProfile idp,
|
||||
@Nullable @Named("ICONS_DB") String dbFileName,
|
||||
UserCache userCache,
|
||||
LauncherIconProvider iconProvider,
|
||||
// TODO: Lawnchair stuff
|
||||
// IconProvider iconProvider,
|
||||
LawnchairIconProvider iconProvider,
|
||||
InstallSessionHelper installSessionHelper,
|
||||
LauncherIcons.IconPool iconPool,
|
||||
InstantAppResolver instantAppResolver,
|
||||
@@ -184,6 +183,7 @@ public class IconCache extends BaseIconCache {
|
||||
return mIconPool.obtain();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Updates the entries related to the given package in memory and persistent DB.
|
||||
*/
|
||||
|
||||
@@ -46,10 +46,10 @@ public class LauncherIconProvider extends IconProvider {
|
||||
public static final String ATTR_DRAWABLE = "drawable";
|
||||
public static final String ATTR_COMPONENT = "component";
|
||||
|
||||
private static final String TAG = "LIconProvider";
|
||||
private static final Map<String, ThemeData> DISABLED_MAP = Collections.emptyMap();
|
||||
protected static final String TAG = "LIconProvider";
|
||||
protected static final Map<String, ThemeData> DISABLED_MAP = Collections.emptyMap();
|
||||
|
||||
private Map<String, ThemeData> mThemedIconMap;
|
||||
protected Map<String, ThemeData> mThemedIconMap;
|
||||
|
||||
protected final ThemeManager mThemeManager;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class LauncherIconProvider extends IconProvider {
|
||||
mSystemState += "," + mThemeManager.getIconState().toUniqueId();
|
||||
}
|
||||
|
||||
private Map<String, ThemeData> getThemedIconMap() {
|
||||
protected Map<String, ThemeData> getThemedIconMap() {
|
||||
if (mThemedIconMap != null) {
|
||||
return mThemedIconMap;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.LauncherApps
|
||||
import android.content.pm.LauncherApps.ArchiveCompatibilityParams
|
||||
import app.lawnchair.icons.LawnchairIconProvider
|
||||
import com.android.launcher3.BuildConfigs
|
||||
import com.android.launcher3.Flags
|
||||
import com.android.launcher3.InvariantDeviceProfile
|
||||
@@ -31,7 +32,6 @@ import com.android.launcher3.dagger.ApplicationContext
|
||||
import com.android.launcher3.graphics.ThemeManager
|
||||
import com.android.launcher3.graphics.ThemeManager.ThemeChangeListener
|
||||
import com.android.launcher3.icons.IconCache
|
||||
import com.android.launcher3.icons.LauncherIconProvider
|
||||
import com.android.launcher3.icons.LauncherIcons.IconPool
|
||||
import com.android.launcher3.notification.NotificationListener
|
||||
import com.android.launcher3.pm.InstallSessionHelper
|
||||
@@ -57,7 +57,7 @@ constructor(
|
||||
private val themeManager: ThemeManager,
|
||||
private val userCache: UserCache,
|
||||
private val settingsCache: SettingsCache,
|
||||
private val iconProvider: LauncherIconProvider,
|
||||
private val iconProvider: LawnchairIconProvider,
|
||||
private val customWidgetManager: CustomWidgetManager,
|
||||
private val installSessionHelper: InstallSessionHelper,
|
||||
private val lifeCycle: DaggerSingletonTracker,
|
||||
|
||||
Reference in New Issue
Block a user