feat(settings): optional "Calendar" launcher name (#44)
Add a Settings → Appearance toggle that switches the app's launcher label between "Calendula" and "Calendar", for users on launchers that can't rename apps themselves. The launcher entry moves off MainActivity onto two <activity-alias> components (DefaultNameAlias / CalendarNameAlias); exactly one is enabled at a time via PackageManager.setComponentEnabledSetting. MainActivity keeps every other intent filter; the android.app.shortcuts meta-data moves onto both aliases so the long-press shortcut still publishes. Component-enabled state is the single source of truth — no persisted preference. The ComponentName uses the applicationId for the package (carrying the .debug/.releasetest suffix) and the namespace for the class, since manifest ".Alias" names resolve against the namespace; switching to Calendar enables the target alias before disabling the other to avoid a zero-entry launcher transient. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
package de.jeanlucmakiola.calendula.data.appname
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
/**
|
||||
* Pure decision logic behind the app-name toggle (issue #44). The framework seam
|
||||
* ([LauncherNameManager.set]/[current], which call `PackageManager`) is covered
|
||||
* on-device; these tests pin the read interpretation and the write ordering.
|
||||
*/
|
||||
class LauncherNameManagerTest {
|
||||
|
||||
@Test
|
||||
fun `enabled calendar alias reads as CALENDAR`() {
|
||||
assertThat(launcherNameFor(PackageManager.COMPONENT_ENABLED_STATE_ENABLED))
|
||||
.isEqualTo(LauncherName.CALENDAR)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `default and disabled calendar alias read as CALENDULA`() {
|
||||
assertThat(launcherNameFor(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT))
|
||||
.isEqualTo(LauncherName.CALENDULA)
|
||||
assertThat(launcherNameFor(PackageManager.COMPONENT_ENABLED_STATE_DISABLED))
|
||||
.isEqualTo(LauncherName.CALENDULA)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `write plan enables the target alias before disabling the other`() {
|
||||
val toCalendar = aliasWritePlan(LauncherName.CALENDAR)
|
||||
assertThat(toCalendar).containsExactly(
|
||||
AliasStateChange(LauncherAlias.CALENDAR, enabled = true),
|
||||
AliasStateChange(LauncherAlias.DEFAULT, enabled = false),
|
||||
).inOrder()
|
||||
|
||||
val toCalendula = aliasWritePlan(LauncherName.CALENDULA)
|
||||
assertThat(toCalendula).containsExactly(
|
||||
AliasStateChange(LauncherAlias.DEFAULT, enabled = true),
|
||||
AliasStateChange(LauncherAlias.CALENDAR, enabled = false),
|
||||
).inOrder()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `write plan never disables both aliases in the same step`() {
|
||||
// The first step is always an enable, so the launcher can never observe a
|
||||
// zero-entry transient regardless of switch direction.
|
||||
for (target in LauncherName.entries) {
|
||||
assertThat(aliasWritePlan(target).first().enabled).isTrue()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user