Merge "Import translations. DO NOT MERGE ANYWHERE" into tm-qpr-dev
diff --git a/res/drawable/keyguard_quick_affordance_icon_container_background_selected.xml b/res/drawable/keyguard_quick_affordance_icon_container_background_selected.xml
index 93a80eb..6b1ab28 100644
--- a/res/drawable/keyguard_quick_affordance_icon_container_background_selected.xml
+++ b/res/drawable/keyguard_quick_affordance_icon_container_background_selected.xml
@@ -13,22 +13,36 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<shape
+<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle" >
+ >
- <stroke
- android:width="2dp"
- android:color="@color/text_color_primary" />
+ <item
+ android:left="6dp"
+ android:top="6dp"
+ android:right="6dp"
+ android:bottom="6dp"
+ >
+ <shape
+ android:layout_width="wrap_content"
+ android:shape="rectangle">
- <solid android:color="@color/color_surface_variant" />
+ <solid android:color="@color/color_surface_variant" />
- <corners android:radius="20dp" />
+ <corners android:radius="14dp" />
- <padding
- android:left="5dp"
- android:top="5dp"
- android:right="5dp"
- android:bottom="5dp" />
+ </shape>
+ </item>
-</shape>
+ <item>
+ <shape android:shape="rectangle" >
+
+ <stroke
+ android:width="2dp"
+ android:color="@color/text_color_primary" />
+
+ <corners android:radius="20dp" />
+
+ </shape>
+ </item>
+</layer-list>
diff --git a/res/drawable/picker_fragment_tab_background.xml b/res/drawable/picker_fragment_tab_background.xml
index 3fbced3..3dad344 100644
--- a/res/drawable/picker_fragment_tab_background.xml
+++ b/res/drawable/picker_fragment_tab_background.xml
@@ -15,6 +15,6 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <corners android:radius="50dp" />
+ <corners android:radius="12dp" />
<solid android:color="@color/keyguard_quick_affordance_slot_tab_background_color" />
</shape>
diff --git a/res/layout/clock_section_view.xml b/res/layout/clock_section_view.xml
index 4a651ca..dfd015e 100644
--- a/res/layout/clock_section_view.xml
+++ b/res/layout/clock_section_view.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.customization.picker.clock.ClockSectionView
+<com.android.customization.picker.clock.ui.view.ClockSectionView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -51,4 +51,4 @@
android:src="@drawable/ic_clock_24px"
android:background="@drawable/option_border_color"
android:contentDescription="@string/clock_picker_entry_content_description" />
-</com.android.customization.picker.clock.ClockSectionView>
\ No newline at end of file
+</com.android.customization.picker.clock.ui.view.ClockSectionView>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index af8dfe1..5da2c33 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -272,18 +272,18 @@
<string name="adaptive_color_title">Dynamic</string>
<!--
- Name of the slot on the "start" side of the bottom of the lock screen, where quick affordance
- buttons can be added to the lock screen. In left-to-right languages, this is the left-hand side
- button. In right-to-left languages, this is the right-hand side button. [CHAR LIMIT=16].
+ Name of the slot on the "start" side of the bottom of the lock screen, where lock screen
+ shortcuts can be added to the lock screen. In left-to-right languages, this is the left-hand
+ side button. In right-to-left languages, this is the right-hand side button. [CHAR LIMIT=16].
-->
- <string name="keyguard_slot_name_bottom_start">Left</string>
+ <string name="keyguard_slot_name_bottom_start">Left shortcut</string>
<!--
- Name of the slot on the "end" side of the bottom of the lock screen, where quick affordance
- buttons can be added to the lock screen. In left-to-right languages, this is the right-hand side
- button. In right-to-left languages, this is the left-hand side button. [CHAR LIMIT=16].
+ Name of the slot on the "end" side of the bottom of the lock screen, where lock screen shortcuts
+ can be added to the lock screen. In left-to-right languages, this is the right-hand side button.
+ In right-to-left languages, this is the left-hand side button. [CHAR LIMIT=16].
-->
- <string name="keyguard_slot_name_bottom_end">Right</string>
+ <string name="keyguard_slot_name_bottom_end">Right shortcut</string>
<!--
Name for an option to have no quick affordance selected for one of the sides of the lock
diff --git a/src/com/android/customization/module/CustomizationInjector.kt b/src/com/android/customization/module/CustomizationInjector.kt
index 2772e56..6194e11 100644
--- a/src/com/android/customization/module/CustomizationInjector.kt
+++ b/src/com/android/customization/module/CustomizationInjector.kt
@@ -20,8 +20,10 @@
import com.android.customization.model.theme.OverlayManagerCompat
import com.android.customization.model.theme.ThemeBundleProvider
import com.android.customization.model.theme.ThemeManager
+import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
+import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
+import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
-import com.android.systemui.plugins.PluginManager
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.wallpaper.module.Injector
@@ -39,7 +41,15 @@
context: Context
): KeyguardQuickAffordancePickerInteractor
- fun getClockRegistry(context: Context): ClockRegistry
+ fun getClockRegistryProvider(context: Context): ClockRegistryProvider
- fun getPluginManager(context: Context): PluginManager
+ fun getClockPickerInteractor(
+ context: Context,
+ clockRegistry: ClockRegistry
+ ): ClockPickerInteractor
+
+ fun getClockSectionViewModel(
+ context: Context,
+ clockRegistry: ClockRegistry
+ ): ClockSectionViewModel
}
diff --git a/src/com/android/customization/module/ThemePickerInjector.kt b/src/com/android/customization/module/ThemePickerInjector.kt
index b448283..9723326 100644
--- a/src/com/android/customization/module/ThemePickerInjector.kt
+++ b/src/com/android/customization/module/ThemePickerInjector.kt
@@ -15,21 +15,20 @@
*/
package com.android.customization.module
-import android.app.NotificationManager
-import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
-import android.os.Handler
-import android.os.UserHandle
-import android.view.LayoutInflater
import androidx.activity.ComponentActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.android.customization.model.theme.OverlayManagerCompat
import com.android.customization.model.theme.ThemeBundleProvider
import com.android.customization.model.theme.ThemeManager
+import com.android.customization.picker.clock.data.repository.ClockPickerRepositoryImpl
+import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
+import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
+import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
import com.android.customization.picker.notifications.data.repository.NotificationsRepository
import com.android.customization.picker.notifications.domain.interactor.NotificationsInteractor
import com.android.customization.picker.notifications.ui.viewmodel.NotificationSectionViewModel
@@ -37,18 +36,9 @@
import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordanceSnapshotRestorer
import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordancePickerViewModel
-import com.android.systemui.plugins.Plugin
-import com.android.systemui.plugins.PluginManager
import com.android.systemui.shared.clocks.ClockRegistry
-import com.android.systemui.shared.clocks.DefaultClockProvider
import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
-import com.android.systemui.shared.plugins.PluginActionManager
-import com.android.systemui.shared.plugins.PluginEnabler
-import com.android.systemui.shared.plugins.PluginInstance
-import com.android.systemui.shared.plugins.PluginManagerImpl
-import com.android.systemui.shared.plugins.PluginPrefs
-import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager_Factory
import com.android.wallpaper.model.LiveWallpaperInfo
import com.android.wallpaper.model.WallpaperInfo
import com.android.wallpaper.module.CustomizationSections
@@ -61,7 +51,6 @@
import com.android.wallpaper.picker.LivePreviewFragment
import com.android.wallpaper.picker.PreviewFragment
import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
-import java.util.concurrent.Executors
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
@@ -78,8 +67,9 @@
private var fragmentFactory: FragmentFactory? = null
private var keyguardQuickAffordanceSnapshotRestorer: KeyguardQuickAffordanceSnapshotRestorer? =
null
- private var clockRegistry: ClockRegistry? = null
- private var pluginManager: PluginManager? = null
+ private var clockRegistryProvider: ClockRegistryProvider? = null
+ private var clockPickerInteractor: ClockPickerInteractor? = null
+ private var clockSectionViewModel: ClockSectionViewModel? = null
private var notificationsInteractor: NotificationsInteractor? = null
private var notificationSectionViewModelFactory: NotificationSectionViewModel.Factory? = null
@@ -182,7 +172,6 @@
?: KeyguardQuickAffordancePickerViewModel.Factory(
context,
getKeyguardQuickAffordancePickerInteractor(context),
- getUndoInteractor(context),
getCurrentWallpaperInfoFactory(context),
) { intent ->
context.startActivity(intent)
@@ -230,78 +219,29 @@
.also { keyguardQuickAffordanceSnapshotRestorer = it }
}
- override fun getClockRegistry(context: Context): ClockRegistry {
- return clockRegistry
- ?: ClockRegistry(
- context,
- getPluginManager(context),
- Handler.getMain(),
- isEnabled = true,
- userHandle = UserHandle.USER_SYSTEM,
- DefaultClockProvider(context, LayoutInflater.from(context), context.resources)
- )
- .also { clockRegistry = it }
+ override fun getClockRegistryProvider(context: Context): ClockRegistryProvider {
+ return clockRegistryProvider
+ ?: ClockRegistryProvider(context).also { clockRegistryProvider = it }
}
- override fun getPluginManager(context: Context): PluginManager {
- return pluginManager ?: createPluginManager(context).also { pluginManager = it }
- }
-
- private fun createPluginManager(context: Context): PluginManager {
- val privilegedPlugins = listOf<String>()
- val isDebugDevice = true
-
- val instanceFactory =
- PluginInstance.Factory(
- this::class.java.classLoader,
- PluginInstance.InstanceFactory<Plugin>(),
- PluginInstance.VersionChecker(),
- privilegedPlugins,
- isDebugDevice,
- )
-
- /*
- * let SystemUI handle plugin, in this class assume plugins are enabled
- */
- val pluginEnabler =
- object : PluginEnabler {
- override fun setEnabled(component: ComponentName) = Unit
-
- override fun setDisabled(
- component: ComponentName,
- @PluginEnabler.DisableReason reason: Int
- ) = Unit
-
- override fun isEnabled(component: ComponentName): Boolean {
- return true
- }
-
- @PluginEnabler.DisableReason
- override fun getDisableReason(componentName: ComponentName): Int {
- return PluginEnabler.ENABLED
- }
+ override fun getClockPickerInteractor(
+ context: Context,
+ clockRegistry: ClockRegistry,
+ ): ClockPickerInteractor {
+ return clockPickerInteractor
+ ?: ClockPickerInteractor(ClockPickerRepositoryImpl(clockRegistry)).also {
+ clockPickerInteractor = it
}
+ }
- val pluginActionManager =
- PluginActionManager.Factory(
- context,
- context.packageManager,
- context.mainExecutor,
- Executors.newSingleThreadExecutor(),
- context.getSystemService(NotificationManager::class.java),
- pluginEnabler,
- privilegedPlugins,
- instanceFactory,
- )
- return PluginManagerImpl(
- context,
- pluginActionManager,
- isDebugDevice,
- UncaughtExceptionPreHandlerManager_Factory.create().get(),
- pluginEnabler,
- PluginPrefs(context),
- listOf(),
- )
+ override fun getClockSectionViewModel(
+ context: Context,
+ clockRegistry: ClockRegistry,
+ ): ClockSectionViewModel {
+ return clockSectionViewModel
+ ?: ClockSectionViewModel(getClockPickerInteractor(context, clockRegistry)).also {
+ clockSectionViewModel = it
+ }
}
protected fun getNotificationsInteractor(
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
index 52c2430..f160a3d 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt
@@ -14,48 +14,15 @@
* limitations under the License.
*
*/
-
package com.android.customization.picker.clock.data.repository
-import android.util.Log
import com.android.customization.picker.clock.shared.model.ClockMetadataModel
-import com.android.systemui.plugins.ClockMetadata
-import com.android.systemui.shared.clocks.ClockRegistry
-import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.callbackFlow
/**
* Repository for accessing application clock settings, as well as selecting and configuring custom
* clocks.
*/
-class ClockPickerRepository(registry: ClockRegistry) {
-
- /** The currently-selected clock. */
- val selectedClock: Flow<ClockMetadataModel?> = callbackFlow {
- fun send() {
- val model =
- registry
- .getClocks()
- .find { clockMetadata -> clockMetadata.clockId == registry.currentClockId }
- ?.toModel()
- if (model == null) {
- Log.e(TAG, "Currently selected clock ID is not one of the available clocks.")
- }
- trySend(model)
- }
-
- val listener = ClockRegistry.ClockChangeListener { send() }
- registry.registerClockChangeListener(listener)
- send()
- awaitClose { registry.unregisterClockChangeListener(listener) }
- }
-
- private fun ClockMetadata.toModel(): ClockMetadataModel {
- return ClockMetadataModel(clockId = clockId, name = name)
- }
-
- companion object {
- private const val TAG = "ClockPickerRepository"
- }
+interface ClockPickerRepository {
+ val selectedClock: Flow<ClockMetadataModel?>
}
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
new file mode 100644
index 0000000..c307ca6
--- /dev/null
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.android.customization.picker.clock.data.repository
+
+import android.util.Log
+import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import com.android.systemui.plugins.ClockMetadata
+import com.android.systemui.shared.clocks.ClockRegistry
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+
+/** Implementation of [ClockPickerRepository], using [ClockRegistry]. */
+class ClockPickerRepositoryImpl(registry: ClockRegistry) : ClockPickerRepository {
+
+ /** The currently-selected clock. */
+ override val selectedClock: Flow<ClockMetadataModel?> = callbackFlow {
+ fun send() {
+ val model =
+ registry
+ .getClocks()
+ .find { clockMetadata -> clockMetadata.clockId == registry.currentClockId }
+ ?.toModel()
+ if (model == null) {
+ Log.e(TAG, "Currently selected clock ID is not one of the available clocks.")
+ }
+ trySend(model)
+ }
+
+ val listener = ClockRegistry.ClockChangeListener { send() }
+ registry.registerClockChangeListener(listener)
+ send()
+ awaitClose { registry.unregisterClockChangeListener(listener) }
+ }
+
+ private fun ClockMetadata.toModel(): ClockMetadataModel {
+ return ClockMetadataModel(clockId = clockId, name = name)
+ }
+
+ companion object {
+ private const val TAG = "ClockPickerRepositoryImpl"
+ }
+}
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
new file mode 100644
index 0000000..2529958
--- /dev/null
+++ b/src/com/android/customization/picker/clock/data/repository/ClockRegistryProvider.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.clock.data.repository
+
+import android.app.NotificationManager
+import android.content.ComponentName
+import android.content.Context
+import android.os.Handler
+import android.os.UserHandle
+import android.view.LayoutInflater
+import com.android.systemui.plugins.ClockProviderPlugin
+import com.android.systemui.plugins.Plugin
+import com.android.systemui.plugins.PluginListener
+import com.android.systemui.plugins.PluginManager
+import com.android.systemui.shared.clocks.ClockRegistry
+import com.android.systemui.shared.clocks.DefaultClockProvider
+import com.android.systemui.shared.plugins.PluginActionManager
+import com.android.systemui.shared.plugins.PluginEnabler
+import com.android.systemui.shared.plugins.PluginInstance
+import com.android.systemui.shared.plugins.PluginManagerImpl
+import com.android.systemui.shared.plugins.PluginPrefs
+import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager_Factory
+import java.util.concurrent.Executors
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+/**
+ * Provide the [ClockRegistry] singleton. Note that we need to make sure that the [PluginManager]
+ * needs to be connected before [ClockRegistry] is ready to use.
+ */
+class ClockRegistryProvider(
+ private val context: Context,
+) {
+ private val pluginManager: PluginManager by lazy { createPluginManager(context) }
+ private val clockRegistry: ClockRegistry by lazy {
+ ClockRegistry(
+ context,
+ pluginManager,
+ Handler.getMain(),
+ isEnabled = true,
+ userHandle = UserHandle.USER_SYSTEM,
+ DefaultClockProvider(context, LayoutInflater.from(context), context.resources)
+ )
+ }
+
+ suspend fun get(): ClockRegistry {
+ return suspendCancellableCoroutine { continuation ->
+ val pluginListener =
+ object : PluginListener<ClockProviderPlugin> {
+ var hasConnected = false
+ override fun onPluginConnected(
+ plugin: ClockProviderPlugin?,
+ pluginContext: Context?
+ ) {
+ if (!hasConnected) {
+ pluginManager.removePluginListener(this)
+ hasConnected = true
+ continuation.resumeWith(Result.success(clockRegistry))
+ }
+ }
+ }
+ pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java, true)
+ continuation.invokeOnCancellation { pluginManager.removePluginListener(pluginListener) }
+ }
+ }
+
+ private fun createPluginManager(context: Context): PluginManager {
+ val privilegedPlugins = listOf<String>()
+ val isDebugDevice = true
+
+ val instanceFactory =
+ PluginInstance.Factory(
+ this::class.java.classLoader,
+ PluginInstance.InstanceFactory<Plugin>(),
+ PluginInstance.VersionChecker(),
+ privilegedPlugins,
+ isDebugDevice,
+ )
+
+ /*
+ * let SystemUI handle plugin, in this class assume plugins are enabled
+ */
+ val pluginEnabler =
+ object : PluginEnabler {
+ override fun setEnabled(component: ComponentName) = Unit
+
+ override fun setDisabled(
+ component: ComponentName,
+ @PluginEnabler.DisableReason reason: Int
+ ) = Unit
+
+ override fun isEnabled(component: ComponentName): Boolean {
+ return true
+ }
+
+ @PluginEnabler.DisableReason
+ override fun getDisableReason(componentName: ComponentName): Int {
+ return PluginEnabler.ENABLED
+ }
+ }
+
+ val pluginActionManager =
+ PluginActionManager.Factory(
+ context,
+ context.packageManager,
+ context.mainExecutor,
+ Executors.newSingleThreadExecutor(),
+ context.getSystemService(NotificationManager::class.java),
+ pluginEnabler,
+ privilegedPlugins,
+ instanceFactory,
+ )
+ return PluginManagerImpl(
+ context,
+ pluginActionManager,
+ isDebugDevice,
+ UncaughtExceptionPreHandlerManager_Factory.create().get(),
+ pluginEnabler,
+ PluginPrefs(context),
+ listOf(),
+ )
+ }
+}
diff --git a/src/com/android/customization/picker/clock/ClockCustomDemoFragment.kt b/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt
similarity index 73%
rename from src/com/android/customization/picker/clock/ClockCustomDemoFragment.kt
rename to src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt
index 4f65080..4aa5de4 100644
--- a/src/com/android/customization/picker/clock/ClockCustomDemoFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragment.kt
@@ -1,4 +1,4 @@
-package com.android.customization.picker.clock
+package com.android.customization.picker.clock.ui.fragment
import android.content.Context
import android.os.Bundle
@@ -13,43 +13,23 @@
import android.widget.TextView
import android.widget.Toast
import androidx.core.view.setPadding
+import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.customization.module.ThemePickerInjector
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.plugins.ClockMetadata
-import com.android.systemui.plugins.ClockProviderPlugin
-import com.android.systemui.plugins.PluginListener
-import com.android.systemui.plugins.PluginManager
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.wallpaper.R
import com.android.wallpaper.module.InjectorProvider
import com.android.wallpaper.picker.AppbarFragment
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
class ClockCustomDemoFragment : AppbarFragment() {
- @VisibleForTesting lateinit var clockRegistry: ClockRegistry
@VisibleForTesting lateinit var recyclerView: RecyclerView
- lateinit var pluginManager: PluginManager
- @VisibleForTesting
- val pluginListener =
- object : PluginListener<ClockProviderPlugin> {
- override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) {
- val listInUse = clockRegistry.getClocks().filter { "NOT_IN_USE" !in it.clockId }
- recyclerView.adapter =
- ClockRecyclerAdapter(listInUse, context) {
- clockRegistry.currentClockId = it.clockId
- Toast.makeText(context, "${it.name} selected", Toast.LENGTH_SHORT).show()
- }
- }
- }
-
- override fun onAttach(context: Context) {
- super.onAttach(context)
- val injector = InjectorProvider.getInjector() as ThemePickerInjector
- pluginManager = injector.getPluginManager(context)
- clockRegistry = injector.getClockRegistry(context)
- pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java, true)
- }
+ @VisibleForTesting lateinit var clockRegistry: ClockRegistry
override fun onCreateView(
inflater: LayoutInflater,
@@ -58,6 +38,20 @@
): View {
val view = inflater.inflate(R.layout.fragment_clock_custom_picker_demo, container, false)
setUpToolbar(view)
+ lifecycleScope.launch {
+ clockRegistry =
+ withContext(Dispatchers.IO) {
+ (InjectorProvider.getInjector() as ThemePickerInjector)
+ .getClockRegistryProvider(requireContext())
+ .get()
+ }
+ val listInUse = clockRegistry.getClocks().filter { "NOT_IN_USE" !in it.clockId }
+ recyclerView.adapter =
+ ClockRecyclerAdapter(listInUse, requireContext()) {
+ clockRegistry.currentClockId = it.clockId
+ Toast.makeText(context, "${it.name} selected", Toast.LENGTH_SHORT).show()
+ }
+ }
return view
}
diff --git a/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt b/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt
index 748fa17..052d0f5 100644
--- a/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt
+++ b/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt
@@ -18,21 +18,27 @@
import android.content.Context
import android.view.LayoutInflater
import androidx.lifecycle.LifecycleOwner
-import com.android.customization.picker.clock.ClockCustomDemoFragment
-import com.android.customization.picker.clock.ClockSectionView
+import androidx.lifecycle.lifecycleScope
+import com.android.customization.module.ThemePickerInjector
+import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
import com.android.customization.picker.clock.ui.binder.ClockSectionViewBinder
-import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
+import com.android.customization.picker.clock.ui.fragment.ClockCustomDemoFragment
+import com.android.customization.picker.clock.ui.view.ClockSectionView
import com.android.wallpaper.R
import com.android.wallpaper.config.BaseFlags
import com.android.wallpaper.model.CustomizationSectionController
import com.android.wallpaper.model.CustomizationSectionController.CustomizationSectionNavigationController
+import com.android.wallpaper.module.InjectorProvider
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/** A [CustomizationSectionController] for clock customization. */
class ClockSectionController(
private val navigationController: CustomizationSectionNavigationController,
- private val viewModel: ClockSectionViewModel,
private val lifecycleOwner: LifecycleOwner,
private val flag: BaseFlags,
+ private val clockRegistryProvider: ClockRegistryProvider,
) : CustomizationSectionController<ClockSectionView?> {
override fun isAvailable(context: Context?): Boolean {
@@ -46,11 +52,16 @@
R.layout.clock_section_view,
null,
) as ClockSectionView
- ClockSectionViewBinder.bind(
- view = view,
- viewModel = viewModel,
- lifecycleOwner = lifecycleOwner
- ) { navigationController.navigateTo(ClockCustomDemoFragment()) }
+ lifecycleOwner.lifecycleScope.launch {
+ val registry = withContext(Dispatchers.IO) { clockRegistryProvider.get() }
+ ClockSectionViewBinder.bind(
+ view = view,
+ viewModel =
+ (InjectorProvider.getInjector() as ThemePickerInjector)
+ .getClockSectionViewModel(context, registry),
+ lifecycleOwner = lifecycleOwner
+ ) { navigationController.navigateTo(ClockCustomDemoFragment()) }
+ }
return view
}
}
diff --git a/src/com/android/customization/picker/clock/ClockSectionView.kt b/src/com/android/customization/picker/clock/ui/view/ClockSectionView.kt
similarity index 93%
rename from src/com/android/customization/picker/clock/ClockSectionView.kt
rename to src/com/android/customization/picker/clock/ui/view/ClockSectionView.kt
index fac975a..cca107c 100644
--- a/src/com/android/customization/picker/clock/ClockSectionView.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockSectionView.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.customization.picker.clock
+package com.android.customization.picker.clock.ui.view
import android.content.Context
import android.util.AttributeSet
diff --git a/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt b/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
index 57e9401..30372fe 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/binder/KeyguardQuickAffordancePickerBinder.kt
@@ -54,12 +54,12 @@
slotTabView.adapter = slotTabAdapter
slotTabView.layoutManager =
LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false)
- slotTabView.addItemDecoration(ItemSpacing())
+ slotTabView.addItemDecoration(ItemSpacing(SLOT_TAB_ITEM_SPACING_DP))
val affordancesAdapter = AffordancesAdapter()
affordancesView.adapter = affordancesAdapter
affordancesView.layoutManager =
LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false)
- affordancesView.addItemDecoration(ItemSpacing())
+ affordancesView.addItemDecoration(ItemSpacing(AFFORDANCE_ITEM_SPACING_DP))
var dialog: Dialog? = null
@@ -74,6 +74,16 @@
launch {
viewModel.quickAffordances.collect { affordances ->
affordancesAdapter.setItems(affordances)
+
+ // Scroll the view to show the first selected affordance.
+ val selectedPosition = affordances.indexOfFirst { it.isSelected }
+ if (selectedPosition != -1) {
+ // We use "post" because we need to give the adapter item a pass to
+ // update the view.
+ affordancesView.post {
+ affordancesView.smoothScrollToPosition(selectedPosition)
+ }
+ }
}
}
@@ -108,27 +118,29 @@
)
}
- private class ItemSpacing : RecyclerView.ItemDecoration() {
+ private class ItemSpacing(
+ private val itemSpacingDp: Int,
+ ) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, itemPosition: Int, parent: RecyclerView) {
val addSpacingToStart = itemPosition > 0
val addSpacingToEnd = itemPosition < (parent.adapter?.itemCount ?: 0) - 1
val isRtl = parent.layoutManager?.layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL
val density = parent.context.resources.displayMetrics.density
+ val halfItemSpacingPx = itemSpacingDp.toPx(density) / 2
if (!isRtl) {
- outRect.left = if (addSpacingToStart) ITEM_SPACING_DP.toPx(density) else 0
- outRect.right = if (addSpacingToEnd) ITEM_SPACING_DP.toPx(density) else 0
+ outRect.left = if (addSpacingToStart) halfItemSpacingPx else 0
+ outRect.right = if (addSpacingToEnd) halfItemSpacingPx else 0
} else {
- outRect.left = if (addSpacingToEnd) ITEM_SPACING_DP.toPx(density) else 0
- outRect.right = if (addSpacingToStart) ITEM_SPACING_DP.toPx(density) else 0
+ outRect.left = if (addSpacingToEnd) halfItemSpacingPx else 0
+ outRect.right = if (addSpacingToStart) halfItemSpacingPx else 0
}
}
private fun Int.toPx(density: Float): Int {
return (this * density).toInt()
}
-
- companion object {
- private const val ITEM_SPACING_DP = 8
- }
}
+
+ private const val SLOT_TAB_ITEM_SPACING_DP = 12
+ private const val AFFORDANCE_ITEM_SPACING_DP = 8
}
diff --git a/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt b/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt
index 51b98ef..8d8a517 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/fragment/KeyguardQuickAffordancePickerFragment.kt
@@ -30,7 +30,6 @@
import com.android.wallpaper.R
import com.android.wallpaper.module.InjectorProvider
import com.android.wallpaper.picker.AppbarFragment
-import com.android.wallpaper.picker.undo.ui.binder.RevertToolbarButtonBinder
import kotlinx.coroutines.ExperimentalCoroutinesApi
@OptIn(ExperimentalCoroutinesApi::class)
@@ -62,12 +61,6 @@
injector.getKeyguardQuickAffordancePickerViewModelFactory(requireContext()),
)
.get()
- setUpToolbarMenu(R.menu.undoable_customization_menu)
- RevertToolbarButtonBinder.bind(
- view = view.requireViewById(toolbarId),
- viewModel = viewModel.undo,
- lifecycleOwner = this,
- )
KeyguardQuickAffordancePreviewBinder.bind(
activity = requireActivity(),
diff --git a/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt b/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt
index b5954e5..92917ed 100644
--- a/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt
+++ b/src/com/android/customization/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModel.kt
@@ -38,8 +38,6 @@
import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
import com.android.wallpaper.picker.customization.ui.viewmodel.ScreenPreviewViewModel
-import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor
-import com.android.wallpaper.picker.undo.ui.viewmodel.UndoViewModel
import com.android.wallpaper.util.PreviewUtils
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -57,7 +55,6 @@
private constructor(
context: Context,
private val quickAffordanceInteractor: KeyguardQuickAffordancePickerInteractor,
- undoInteractor: UndoInteractor,
private val wallpaperInfoFactory: CurrentWallpaperInfoFactory,
activityStarter: (Intent) -> Unit,
) : ViewModel() {
@@ -94,11 +91,6 @@
},
)
- val undo: UndoViewModel =
- UndoViewModel(
- interactor = undoInteractor,
- )
-
private val _selectedSlotId = MutableStateFlow<String?>(null)
val selectedSlotId: StateFlow<String?> = _selectedSlotId.asStateFlow()
@@ -390,7 +382,6 @@
class Factory(
private val context: Context,
private val quickAffordanceInteractor: KeyguardQuickAffordancePickerInteractor,
- private val undoInteractor: UndoInteractor,
private val wallpaperInfoFactory: CurrentWallpaperInfoFactory,
private val activityStarter: (Intent) -> Unit,
) : ViewModelProvider.Factory {
@@ -399,7 +390,6 @@
return KeyguardQuickAffordancePickerViewModel(
context = context,
quickAffordanceInteractor = quickAffordanceInteractor,
- undoInteractor = undoInteractor,
wallpaperInfoFactory = wallpaperInfoFactory,
activityStarter = activityStarter,
)
diff --git a/tests/robotests/src/com/android/customization/picker/clock/ClockCustomDemoFragmentTest.kt b/tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt
similarity index 93%
rename from tests/robotests/src/com/android/customization/picker/clock/ClockCustomDemoFragmentTest.kt
rename to tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt
index ad3dd1c..430dd27 100644
--- a/tests/robotests/src/com/android/customization/picker/clock/ClockCustomDemoFragmentTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/clock/ui/fragment/ClockCustomDemoFragmentTest.kt
@@ -1,4 +1,4 @@
-package com.android.customization.picker.clock
+package com.android.customization.picker.clock.ui.fragment
import android.os.Handler
import android.os.UserHandle
@@ -9,7 +9,6 @@
import com.android.systemui.plugins.ClockId
import com.android.systemui.plugins.ClockMetadata
import com.android.systemui.plugins.ClockProvider
-import com.android.systemui.plugins.ClockProviderPlugin
import com.android.systemui.plugins.PluginManager
import com.android.systemui.shared.clocks.ClockRegistry
import org.junit.Assert
@@ -32,7 +31,6 @@
private lateinit var registry: ClockRegistry
@Mock private lateinit var mockPluginManager: PluginManager
@Mock private lateinit var mockHandler: Handler
- @Mock private lateinit var fakePlugin: ClockProviderPlugin
@Mock private lateinit var defaultClockProvider: ClockProvider
private var settingValue: String = ""
@@ -74,7 +72,6 @@
mClockCustomDemoFragment!!.recyclerView = RecyclerView(mActivity)
mClockCustomDemoFragment!!.recyclerView.layoutManager =
LinearLayoutManager(mActivity, RecyclerView.VERTICAL, false)
- mClockCustomDemoFragment!!.pluginListener.onPluginConnected(fakePlugin, mActivity)
}
@Test
diff --git a/tests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt b/tests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt
index 85d5e3b..fd03285 100644
--- a/tests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt
+++ b/tests/src/com/android/customization/model/picker/quickaffordance/ui/viewmodel/KeyguardQuickAffordancePickerViewModelTest.kt
@@ -34,9 +34,6 @@
import com.android.wallpaper.module.InjectorProvider
import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon
import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
-import com.android.wallpaper.picker.undo.data.repository.UndoRepository
-import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor
-import com.android.wallpaper.testing.FAKE_RESTORERS
import com.android.wallpaper.testing.FakeSnapshotStore
import com.android.wallpaper.testing.TestCurrentWallpaperInfoFactory
import com.android.wallpaper.testing.TestInjector
@@ -96,17 +93,10 @@
.apply { runBlocking { setUpSnapshotRestorer(FakeSnapshotStore()) } }
},
)
- val undoInteractor =
- UndoInteractor(
- scope = testScope.backgroundScope,
- repository = UndoRepository(),
- restorerByOwnerId = FAKE_RESTORERS,
- )
underTest =
KeyguardQuickAffordancePickerViewModel.Factory(
context = context,
quickAffordanceInteractor = quickAffordanceInteractor,
- undoInteractor = undoInteractor,
wallpaperInfoFactory = TestCurrentWallpaperInfoFactory(context),
activityStarter = { intent -> latestStartedActivityIntent = intent },
)
diff --git a/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt b/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
new file mode 100644
index 0000000..ea97c9a
--- /dev/null
+++ b/tests/src/com/android/customization/picker/clock/data/repository/FakeClockPickerRepository.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.clock.data.repository
+
+import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeClockPickerRepository : ClockPickerRepository {
+
+ override val selectedClock: Flow<ClockMetadataModel?> = MutableStateFlow(null)
+}
diff --git a/tests/src/com/android/customization/testing/TestCustomizationInjector.kt b/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
index afc7131..735ba8e 100644
--- a/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
+++ b/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
@@ -1,9 +1,6 @@
package com.android.customization.testing
import android.content.Context
-import android.os.Handler
-import android.os.UserHandle
-import android.view.LayoutInflater
import androidx.fragment.app.FragmentActivity
import com.android.customization.model.theme.OverlayManagerCompat
import com.android.customization.model.theme.ThemeBundleProvider
@@ -11,12 +8,14 @@
import com.android.customization.module.CustomizationInjector
import com.android.customization.module.CustomizationPreferences
import com.android.customization.module.ThemesUserEventLogger
+import com.android.customization.picker.clock.data.repository.ClockRegistryProvider
+import com.android.customization.picker.clock.data.repository.FakeClockPickerRepository
+import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
+import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
import com.android.customization.picker.quickaffordance.data.repository.KeyguardQuickAffordancePickerRepository
import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordanceSnapshotRestorer
-import com.android.systemui.plugins.PluginManager
import com.android.systemui.shared.clocks.ClockRegistry
-import com.android.systemui.shared.clocks.DefaultClockProvider
import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
import com.android.wallpaper.config.BaseFlags
@@ -25,7 +24,6 @@
import com.android.wallpaper.module.UserEventLogger
import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
import com.android.wallpaper.testing.TestInjector
-import java.util.HashMap
import kotlinx.coroutines.Dispatchers.IO
/** Test implementation of the dependency injector. */
@@ -41,8 +39,9 @@
private var customizationProviderClient: CustomizationProviderClient? = null
private var keyguardQuickAffordanceSnapshotRestorer: KeyguardQuickAffordanceSnapshotRestorer? =
null
- private var clockRegistry: ClockRegistry? = null
- private var pluginManager: PluginManager? = null
+ private var clockRegistryProvider: ClockRegistryProvider? = null
+ private var clockPickerInteractor: ClockPickerInteractor? = null
+ private var clockSectionViewModel: ClockSectionViewModel? = null
override fun getCustomizationPreferences(context: Context): CustomizationPreferences {
return customizationPreferences
@@ -128,21 +127,29 @@
.also { keyguardQuickAffordanceSnapshotRestorer = it }
}
- override fun getClockRegistry(context: Context): ClockRegistry {
- return clockRegistry
- ?: ClockRegistry(
- context,
- getPluginManager(context),
- Handler.getMain(),
- isEnabled = true,
- userHandle = UserHandle.USER_SYSTEM,
- DefaultClockProvider(context, LayoutInflater.from(context), context.resources)
- )
- .also { clockRegistry = it }
+ override fun getClockRegistryProvider(context: Context): ClockRegistryProvider {
+ return clockRegistryProvider
+ ?: ClockRegistryProvider(context).also { clockRegistryProvider = it }
}
- override fun getPluginManager(context: Context): PluginManager {
- return pluginManager ?: TestPluginManager().also { pluginManager = it }
+ override fun getClockPickerInteractor(
+ context: Context,
+ clockRegistry: ClockRegistry
+ ): ClockPickerInteractor {
+ return clockPickerInteractor
+ ?: ClockPickerInteractor(FakeClockPickerRepository()).also {
+ clockPickerInteractor = it
+ }
+ }
+
+ override fun getClockSectionViewModel(
+ context: Context,
+ clockRegistry: ClockRegistry
+ ): ClockSectionViewModel {
+ return clockSectionViewModel
+ ?: ClockSectionViewModel(getClockPickerInteractor(context, clockRegistry)).also {
+ clockSectionViewModel = it
+ }
}
companion object {