Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ java_defaults { "SettingsLibSettingsTheme", "SystemUI-statsd", "styleprotoslite", "androidx.lifecycle_lifecycle-livedata-ktx", "androidx.lifecycle_lifecycle-runtime-ktx", "androidx.lifecycle_lifecycle-viewmodel-ktx", "androidx.recyclerview_recyclerview", Loading src/com/android/customization/model/mode/DarkModeSectionController.java +7 −1 Original line number Diff line number Diff line Loading @@ -59,12 +59,17 @@ public class DarkModeSectionController implements private Context mContext; private DarkModeSectionView mDarkModeSectionView; private final DarkModeSnapshotRestorer mSnapshotRestorer; public DarkModeSectionController(Context context, Lifecycle lifecycle) { public DarkModeSectionController( Context context, Lifecycle lifecycle, DarkModeSnapshotRestorer snapshotRestorer) { mContext = context; mLifecycle = lifecycle; mPowerManager = context.getSystemService(PowerManager.class); mLifecycle.addObserver(this); mSnapshotRestorer = snapshotRestorer; } @OnLifecycleEvent(Lifecycle.Event.ON_START) Loading Loading @@ -132,6 +137,7 @@ public class DarkModeSectionController implements mDarkModeSectionView.announceForAccessibility( context.getString(R.string.mode_changed)); uiModeManager.setNightModeActivated(viewActivated); mSnapshotRestorer.store(viewActivated); }, /* delayMillis= */ shortDelay); } Loading src/com/android/customization/model/mode/DarkModeSnapshotRestorer.kt 0 → 100644 +101 −0 Original line number Diff line number Diff line /* * 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.model.mode import android.app.UiModeManager import android.content.Context import android.content.res.Configuration import androidx.annotation.VisibleForTesting import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext class DarkModeSnapshotRestorer : SnapshotRestorer { private val backgroundDispatcher: CoroutineDispatcher private val isActive: () -> Boolean private val setActive: suspend (Boolean) -> Unit private lateinit var store: SnapshotStore constructor( context: Context, manager: UiModeManager, backgroundDispatcher: CoroutineDispatcher, ) : this( backgroundDispatcher = backgroundDispatcher, isActive = { context.applicationContext.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_YES != 0 }, setActive = { isActive -> manager.setNightModeActivated(isActive) }, ) @VisibleForTesting constructor( backgroundDispatcher: CoroutineDispatcher, isActive: () -> Boolean, setActive: suspend (Boolean) -> Unit, ) { this.backgroundDispatcher = backgroundDispatcher this.isActive = isActive this.setActive = setActive } override suspend fun setUpSnapshotRestorer(store: SnapshotStore): RestorableSnapshot { this.store = store return snapshot( isActivated = isActive(), ) } override suspend fun restoreToSnapshot(snapshot: RestorableSnapshot) { val isActivated = snapshot.args[KEY]?.toBoolean() == true withContext(backgroundDispatcher) { setActive(isActivated) } } fun store( isActivated: Boolean, ) { store.store( snapshot( isActivated = isActivated, ), ) } private fun snapshot( isActivated: Boolean, ): RestorableSnapshot { return RestorableSnapshot( args = buildMap { put( KEY, isActivated.toString(), ) } ) } companion object { private const val KEY = "is_activated" } } src/com/android/customization/model/themedicon/ThemedIconSectionController.java +26 −7 Original line number Diff line number Diff line Loading @@ -20,11 +20,13 @@ import android.os.Bundle; import android.view.LayoutInflater; import androidx.annotation.Nullable; import androidx.lifecycle.Observer; import com.android.customization.model.themedicon.domain.interactor.ThemedIconInteractor; import com.android.customization.model.themedicon.domain.interactor.ThemedIconSnapshotRestorer; import com.android.customization.picker.themedicon.ThemedIconSectionView; import com.android.wallpaper.R; import com.android.wallpaper.model.CustomizationSectionController; import com.android.wallpaper.model.WorkspaceViewModel; /** The {@link CustomizationSectionController} for themed icon section. */ public class ThemedIconSectionController implements Loading @@ -33,16 +35,26 @@ public class ThemedIconSectionController implements private static final String KEY_THEMED_ICON_ENABLED = "SAVED_THEMED_ICON_ENABLED"; private final ThemedIconSwitchProvider mThemedIconOptionsProvider; private final WorkspaceViewModel mWorkspaceViewModel; private final ThemedIconInteractor mInteractor; private final ThemedIconSnapshotRestorer mSnapshotRestorer; private final Observer<Boolean> mIsActivatedChangeObserver; private ThemedIconSectionView mThemedIconSectionView; private boolean mSavedThemedIconEnabled = false; public ThemedIconSectionController(ThemedIconSwitchProvider themedIconOptionsProvider, WorkspaceViewModel workspaceViewModel, @Nullable Bundle savedInstanceState) { public ThemedIconSectionController( ThemedIconSwitchProvider themedIconOptionsProvider, ThemedIconInteractor interactor, @Nullable Bundle savedInstanceState, ThemedIconSnapshotRestorer snapshotRestorer) { mThemedIconOptionsProvider = themedIconOptionsProvider; mWorkspaceViewModel = workspaceViewModel; mInteractor = interactor; mSnapshotRestorer = snapshotRestorer; mIsActivatedChangeObserver = isActivated -> { if (mThemedIconSectionView.isAttachedToWindow()) { mThemedIconSectionView.getSwitch().setChecked(isActivated); } }; if (savedInstanceState != null) { mSavedThemedIconEnabled = savedInstanceState.getBoolean( Loading @@ -64,15 +76,22 @@ public class ThemedIconSectionController implements mThemedIconSectionView.getSwitch().setChecked(mSavedThemedIconEnabled); mThemedIconOptionsProvider.fetchThemedIconEnabled( enabled -> mThemedIconSectionView.getSwitch().setChecked(enabled)); mInteractor.isActivatedAsLiveData().observeForever(mIsActivatedChangeObserver); return mThemedIconSectionView; } @Override public void release() { mInteractor.isActivatedAsLiveData().removeObserver(mIsActivatedChangeObserver); } private void onViewActivated(Context context, boolean viewActivated) { if (context == null) { return; } mThemedIconOptionsProvider.setThemedIconEnabled(viewActivated); mWorkspaceViewModel.getUpdateWorkspace().setValue(viewActivated); mInteractor.setActivated(viewActivated); mSnapshotRestorer.store(viewActivated); } @Override Loading src/com/android/customization/model/themedicon/ThemedIconSwitchProvider.java +1 −1 Original line number Diff line number Diff line Loading @@ -118,7 +118,7 @@ public class ThemedIconSwitchProvider { * * <p>The value would also be stored in SharedPreferences. */ protected void setThemedIconEnabled(boolean enabled) { public void setThemedIconEnabled(boolean enabled) { mExecutorService.submit(() -> { ContentValues values = new ContentValues(); values.put(COL_ICON_THEMED_VALUE, enabled); Loading Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ java_defaults { "SettingsLibSettingsTheme", "SystemUI-statsd", "styleprotoslite", "androidx.lifecycle_lifecycle-livedata-ktx", "androidx.lifecycle_lifecycle-runtime-ktx", "androidx.lifecycle_lifecycle-viewmodel-ktx", "androidx.recyclerview_recyclerview", Loading
src/com/android/customization/model/mode/DarkModeSectionController.java +7 −1 Original line number Diff line number Diff line Loading @@ -59,12 +59,17 @@ public class DarkModeSectionController implements private Context mContext; private DarkModeSectionView mDarkModeSectionView; private final DarkModeSnapshotRestorer mSnapshotRestorer; public DarkModeSectionController(Context context, Lifecycle lifecycle) { public DarkModeSectionController( Context context, Lifecycle lifecycle, DarkModeSnapshotRestorer snapshotRestorer) { mContext = context; mLifecycle = lifecycle; mPowerManager = context.getSystemService(PowerManager.class); mLifecycle.addObserver(this); mSnapshotRestorer = snapshotRestorer; } @OnLifecycleEvent(Lifecycle.Event.ON_START) Loading Loading @@ -132,6 +137,7 @@ public class DarkModeSectionController implements mDarkModeSectionView.announceForAccessibility( context.getString(R.string.mode_changed)); uiModeManager.setNightModeActivated(viewActivated); mSnapshotRestorer.store(viewActivated); }, /* delayMillis= */ shortDelay); } Loading
src/com/android/customization/model/mode/DarkModeSnapshotRestorer.kt 0 → 100644 +101 −0 Original line number Diff line number Diff line /* * 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.model.mode import android.app.UiModeManager import android.content.Context import android.content.res.Configuration import androidx.annotation.VisibleForTesting import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext class DarkModeSnapshotRestorer : SnapshotRestorer { private val backgroundDispatcher: CoroutineDispatcher private val isActive: () -> Boolean private val setActive: suspend (Boolean) -> Unit private lateinit var store: SnapshotStore constructor( context: Context, manager: UiModeManager, backgroundDispatcher: CoroutineDispatcher, ) : this( backgroundDispatcher = backgroundDispatcher, isActive = { context.applicationContext.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_YES != 0 }, setActive = { isActive -> manager.setNightModeActivated(isActive) }, ) @VisibleForTesting constructor( backgroundDispatcher: CoroutineDispatcher, isActive: () -> Boolean, setActive: suspend (Boolean) -> Unit, ) { this.backgroundDispatcher = backgroundDispatcher this.isActive = isActive this.setActive = setActive } override suspend fun setUpSnapshotRestorer(store: SnapshotStore): RestorableSnapshot { this.store = store return snapshot( isActivated = isActive(), ) } override suspend fun restoreToSnapshot(snapshot: RestorableSnapshot) { val isActivated = snapshot.args[KEY]?.toBoolean() == true withContext(backgroundDispatcher) { setActive(isActivated) } } fun store( isActivated: Boolean, ) { store.store( snapshot( isActivated = isActivated, ), ) } private fun snapshot( isActivated: Boolean, ): RestorableSnapshot { return RestorableSnapshot( args = buildMap { put( KEY, isActivated.toString(), ) } ) } companion object { private const val KEY = "is_activated" } }
src/com/android/customization/model/themedicon/ThemedIconSectionController.java +26 −7 Original line number Diff line number Diff line Loading @@ -20,11 +20,13 @@ import android.os.Bundle; import android.view.LayoutInflater; import androidx.annotation.Nullable; import androidx.lifecycle.Observer; import com.android.customization.model.themedicon.domain.interactor.ThemedIconInteractor; import com.android.customization.model.themedicon.domain.interactor.ThemedIconSnapshotRestorer; import com.android.customization.picker.themedicon.ThemedIconSectionView; import com.android.wallpaper.R; import com.android.wallpaper.model.CustomizationSectionController; import com.android.wallpaper.model.WorkspaceViewModel; /** The {@link CustomizationSectionController} for themed icon section. */ public class ThemedIconSectionController implements Loading @@ -33,16 +35,26 @@ public class ThemedIconSectionController implements private static final String KEY_THEMED_ICON_ENABLED = "SAVED_THEMED_ICON_ENABLED"; private final ThemedIconSwitchProvider mThemedIconOptionsProvider; private final WorkspaceViewModel mWorkspaceViewModel; private final ThemedIconInteractor mInteractor; private final ThemedIconSnapshotRestorer mSnapshotRestorer; private final Observer<Boolean> mIsActivatedChangeObserver; private ThemedIconSectionView mThemedIconSectionView; private boolean mSavedThemedIconEnabled = false; public ThemedIconSectionController(ThemedIconSwitchProvider themedIconOptionsProvider, WorkspaceViewModel workspaceViewModel, @Nullable Bundle savedInstanceState) { public ThemedIconSectionController( ThemedIconSwitchProvider themedIconOptionsProvider, ThemedIconInteractor interactor, @Nullable Bundle savedInstanceState, ThemedIconSnapshotRestorer snapshotRestorer) { mThemedIconOptionsProvider = themedIconOptionsProvider; mWorkspaceViewModel = workspaceViewModel; mInteractor = interactor; mSnapshotRestorer = snapshotRestorer; mIsActivatedChangeObserver = isActivated -> { if (mThemedIconSectionView.isAttachedToWindow()) { mThemedIconSectionView.getSwitch().setChecked(isActivated); } }; if (savedInstanceState != null) { mSavedThemedIconEnabled = savedInstanceState.getBoolean( Loading @@ -64,15 +76,22 @@ public class ThemedIconSectionController implements mThemedIconSectionView.getSwitch().setChecked(mSavedThemedIconEnabled); mThemedIconOptionsProvider.fetchThemedIconEnabled( enabled -> mThemedIconSectionView.getSwitch().setChecked(enabled)); mInteractor.isActivatedAsLiveData().observeForever(mIsActivatedChangeObserver); return mThemedIconSectionView; } @Override public void release() { mInteractor.isActivatedAsLiveData().removeObserver(mIsActivatedChangeObserver); } private void onViewActivated(Context context, boolean viewActivated) { if (context == null) { return; } mThemedIconOptionsProvider.setThemedIconEnabled(viewActivated); mWorkspaceViewModel.getUpdateWorkspace().setValue(viewActivated); mInteractor.setActivated(viewActivated); mSnapshotRestorer.store(viewActivated); } @Override Loading
src/com/android/customization/model/themedicon/ThemedIconSwitchProvider.java +1 −1 Original line number Diff line number Diff line Loading @@ -118,7 +118,7 @@ public class ThemedIconSwitchProvider { * * <p>The value would also be stored in SharedPreferences. */ protected void setThemedIconEnabled(boolean enabled) { public void setThemedIconEnabled(boolean enabled) { mExecutorService.submit(() -> { ContentValues values = new ContentValues(); values.put(COL_ICON_THEMED_VALUE, enabled); Loading