From b77b2ec7c88b8ad6322fb3d5e67676ec3440bebb Mon Sep 17 00:00:00 2001 From: Yuri Lin Date: Wed, 24 Apr 2024 18:53:41 -0400 Subject: [PATCH] Add flow for updating zen mode status on modes pages The main responsibility for updating stored ZenMode data when updated is the Settings page, which reloads mode data whenever any changes are detected. This change adds a process for that Settings page to then update the ZenMode data associated with all controllers on that page. Flag: android.app.modes_ui Bug: 335259054 Test: manual with toy implementations Change-Id: Ie1692da54d962c90378085d8bd8573e5b93f8eb6 --- .../AbstractZenModePreferenceController.java | 80 +++++++++ .../modes/ZenModeSettingsBase.java | 156 ++++++++++++++++++ .../modes/ZenModesRuleSettingsBase.java | 89 ---------- 3 files changed, 236 insertions(+), 89 deletions(-) create mode 100644 src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java create mode 100644 src/com/android/settings/notification/modes/ZenModeSettingsBase.java delete mode 100644 src/com/android/settings/notification/modes/ZenModesRuleSettingsBase.java diff --git a/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java b/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java new file mode 100644 index 00000000000..0c18be1b4a7 --- /dev/null +++ b/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024 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.settings.notification.modes; + +import android.app.AutomaticZenRule; +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; + +import com.android.settingslib.core.AbstractPreferenceController; + +/** + * Base class for any preference controllers pertaining to any single Zen mode. + */ +abstract class AbstractZenModePreferenceController extends AbstractPreferenceController { + + @Nullable + protected ZenModesBackend mBackend; + + @Nullable // only until updateZenMode() is called + private ZenMode mZenMode; + + @NonNull + final String mKey; + + // ZenModesBackend should only be passed in if the preference controller may set the user's + // policy for this zen mode. Otherwise, if the preference controller is essentially read-only + // and leads to a further Settings screen, backend should be null. + AbstractZenModePreferenceController(@NonNull Context context, @NonNull String key, + @Nullable ZenModesBackend backend) { + super(context); + mBackend = backend; + mKey = key; + } + + @Override + @NonNull + public String getPreferenceKey() { + return mKey; + } + + // Called by the parent Fragment onStart, which means it will happen before resume. + public void updateZenMode(@NonNull Preference preference, @NonNull ZenMode zenMode) { + mZenMode = zenMode; + updateState(preference); + } + + @Nullable + public ZenMode getMode() { + return mZenMode; + } + + @Nullable + public AutomaticZenRule getAZR() { + if (mZenMode == null || mZenMode.getRule() == null) { + return null; + } + return mZenMode.getRule(); + } + + /** Implementations of this class should override + * {@link AbstractPreferenceController#updateState(Preference)} to specify what should + * happen when the preference is updated */ +} diff --git a/src/com/android/settings/notification/modes/ZenModeSettingsBase.java b/src/com/android/settings/notification/modes/ZenModeSettingsBase.java new file mode 100644 index 00000000000..32288706f02 --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeSettingsBase.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2024 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.settings.notification.modes; + +import android.app.AutomaticZenRule; +import android.content.Context; +import android.os.Bundle; +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settingslib.core.AbstractPreferenceController; + +import java.util.List; + +/** + * Base class for Settings pages used to configure individual modes. + */ +abstract class ZenModeSettingsBase extends ZenModesSettingsBase { + static final String TAG = "ZenModeSettings"; + static final String MODE_ID = "MODE_ID"; + + @Nullable // only until reloadMode() is called + private ZenMode mZenMode; + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + + // TODO: b/322373473 - Update if modes page ends up using a different method of passing id + Bundle bundle = getArguments(); + if (bundle != null && bundle.containsKey(MODE_ID)) { + String id = bundle.getString(MODE_ID); + if (!reloadMode(id)) { + Log.d(TAG, "Mode id " + id + " not found"); + toastAndFinish(); + } + } else { + Log.d(TAG, "Mode id required to set mode config settings"); + toastAndFinish(); + } + } + + /** + * Refresh stored ZenMode data. + * @param id the mode ID + * @return whether we successfully got mode data from the backend. + */ + private boolean reloadMode(String id) { + mZenMode = mBackend.getMode(id); + if (mZenMode == null) { + return false; + } + return true; + } + + /** + * Refresh ZenMode data any time the system's zen mode state changes (either the zen mode value + * itself, or the config), and also (once updated) update the info for all controllers. + */ + @Override + protected void updateZenModeState() { + if (mZenMode == null) { + // This shouldn't happen, but guard against it in case + toastAndFinish(); + return; + } + String id = mZenMode.getId(); + if (!reloadMode(id)) { + Log.d(TAG, "Mode id=" + id + " not found"); + toastAndFinish(); + } + updateControllers(); + } + + private void updateControllers() { + if (getPreferenceControllers() == null || mZenMode == null) { + return; + } + + final PreferenceScreen screen = getPreferenceScreen(); + if (screen == null) { + Log.d(TAG, "PreferenceScreen not found"); + return; + } + for (List list : getPreferenceControllers()) { + for (AbstractPreferenceController controller : list) { + if (!controller.isAvailable()) { + continue; + } + + try { + // Find preference associated with controller + final String key = controller.getPreferenceKey(); + final Preference preference = screen.findPreference(key); + if (preference != null) { + AbstractZenModePreferenceController zenController = + (AbstractZenModePreferenceController) controller; + zenController.updateZenMode(preference, mZenMode); + } else { + Log.d(TAG, + String.format("Cannot find preference with key %s in Controller %s", + key, controller.getClass().getSimpleName())); + } + } catch (ClassCastException e) { + // Skip any controllers that aren't AbstractZenModePreferenceController. + Log.d(TAG, "Could not cast: " + controller.getClass().getSimpleName()); + } + } + } + } + + private void toastAndFinish() { + Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT) + .show(); + this.finish(); + } + + /** + * Get current mode data. + */ + @Nullable + public ZenMode getMode() { + return mZenMode; + } + + /** + * Get AutomaticZenRule associated with current mode data, or null if it doesn't exist. + */ + @Nullable + public AutomaticZenRule getAZR() { + if (mZenMode == null) { + return null; + } + return mZenMode.getRule(); + } +} diff --git a/src/com/android/settings/notification/modes/ZenModesRuleSettingsBase.java b/src/com/android/settings/notification/modes/ZenModesRuleSettingsBase.java deleted file mode 100644 index 3ddf70440a5..00000000000 --- a/src/com/android/settings/notification/modes/ZenModesRuleSettingsBase.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2024 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.settings.notification.modes; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.os.Bundle; -import android.util.Log; -import android.widget.Toast; - -import com.android.settings.R; - -/** - * Base class for Settings pages used to configure individual modes. - */ -abstract class ZenModesRuleSettingsBase extends ZenModesSettingsBase { - static final String TAG = "ZenModesRuleSettings"; - static final String MODE_ID = "MODE_ID"; - - @Nullable - protected ZenMode mZenMode; - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - - // TODO: b/322373473 - Update if modes page ends up using a different method of passing id - Bundle bundle = getArguments(); - if (bundle != null && bundle.containsKey(MODE_ID)) { - String id = bundle.getString(MODE_ID); - if (!reloadMode(id)) { - Log.d(TAG, "Mode id " + id + " not found"); - toastAndFinish(); - } - } else { - Log.d(TAG, "Mode id required to set mode config settings"); - toastAndFinish(); - } - } - - /** - * Refresh stored ZenMode data. - * @param id the mode ID - * @return whether we successfully got mode data from the backend. - */ - private boolean reloadMode(String id) { - mZenMode = mBackend.getMode(id); - return mZenMode != null; - } - - /** - * Refresh ZenMode data any time the system's zen mode state changes (either the zen mode value - * itself, or the config). - */ - @Override - protected void updateZenModeState() { - if (mZenMode == null) { - // This shouldn't happen, but guard against it in case - toastAndFinish(); - return; - } - String id = mZenMode.getId(); - if (!reloadMode(id)) { - Log.d(TAG, "Mode id=" + id + " not found"); - toastAndFinish(); - } - } - - private void toastAndFinish() { - Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT) - .show(); - this.finish(); - } -}