Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1a4abbc authored by Yuri Lin's avatar Yuri Lin
Browse files

Migrate "duration for quick settings" to new modes page.

This mostly continues to use the existing dialogs in settingslib (ZenDurationDialog, SettingsEnableZenModeDialog) and creates a controller to read from the settings value.

Also updates the "turn on / turn off" button to respect the preferred duration.

Flag: android.app.modes_ui
Bug: 343444249
Test: ZenModeButtonPreferenceControllerTest, ManualDurationPreferenceControllerTest
Change-Id: I2fd49a79d9a5807fefdd7ec310a6cc60d70f9bb1
parent 5653acd5
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -67,5 +67,9 @@
        <Preference
                android:key="mode_display_settings"
                android:title="@string/mode_display_settings_title" />

        <Preference
                android:key="mode_manual_duration"
                android:title="@string/zen_category_duration" />
    </PreferenceCategory>
</PreferenceScreen>
 No newline at end of file
+123 −0
Original line number Diff line number Diff line
/*
 * 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.Nullable;
import android.content.Context;
import android.database.ContentObserver;
import android.icu.text.MessageFormat;
import android.net.Uri;
import android.provider.Settings;

import androidx.annotation.NonNull;
import androidx.preference.Preference;

import com.android.settings.R;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * Class to contain shared utilities for reading and observing the Settings ZEN_DURATION value.
 */
class ManualDurationHelper {
    private Context mContext;

    ManualDurationHelper(@NonNull Context context) {
        mContext = context;
    }

    int getZenDuration() {
        return Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ZEN_DURATION,
                0);
    }

    /**
     * Generates a summary of the duration that manual DND will be on when turned on from
     * quick settings, for example "Until you turn off" or "[number] hours", based on the given
     * setting value.
     */
    public String getSummary() {
        int zenDuration = getZenDuration();
        String summary;
        if (zenDuration < 0) {
            summary = mContext.getString(R.string.zen_mode_duration_summary_always_prompt);
        } else if (zenDuration == 0) {
            summary = mContext.getString(R.string.zen_mode_duration_summary_forever);
        } else {
            if (zenDuration >= 60) {
                MessageFormat msgFormat = new MessageFormat(
                        mContext.getString(R.string.zen_mode_duration_summary_time_hours),
                        Locale.getDefault());
                Map<String, Object> msgArgs = new HashMap<>();
                msgArgs.put("count", zenDuration / 60);
                summary = msgFormat.format(msgArgs);
            } else {
                MessageFormat msgFormat = new MessageFormat(
                        mContext.getString(R.string.zen_mode_duration_summary_time_minutes),
                        Locale.getDefault());
                Map<String, Object> msgArgs = new HashMap<>();
                msgArgs.put("count", zenDuration);
                summary = msgFormat.format(msgArgs);
            }
        }
        return summary;
    }

    SettingsObserver makeSettingsObserver(@NonNull AbstractZenModePreferenceController controller) {
        return new SettingsObserver(controller);
    }

    final class SettingsObserver extends ContentObserver {
        private static final Uri ZEN_MODE_DURATION_URI = Settings.Secure.getUriFor(
                Settings.Secure.ZEN_DURATION);

        private final AbstractZenModePreferenceController mPrefController;
        private Preference mPreference;

        /**
         * Create a settings observer attached to the provided PreferenceController, whose
         * updateState method should be called onChange.
         */
        SettingsObserver(@NonNull AbstractZenModePreferenceController prefController) {
            super(mContext.getMainExecutor(), 0);
            mPrefController = prefController;
        }

        void setPreference(Preference preference) {
            mPreference = preference;
        }

        public void register() {
            mContext.getContentResolver().registerContentObserver(ZEN_MODE_DURATION_URI, false,
                    this);
        }

        public void unregister() {
            mContext.getContentResolver().unregisterContentObserver(this);
        }

        @Override
        public void onChange(boolean selfChange, @Nullable Uri uri) {
            super.onChange(selfChange, uri);
            if (ZEN_MODE_DURATION_URI.equals(uri) && mPreference != null) {
                mPrefController.updateState(mPreference);
            }
        }
    }
}
+86 −0
Original line number Diff line number Diff line
/*
 * 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.content.Context;

import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;

import com.android.settings.notification.zen.SettingsZenDurationDialog;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;

public class ManualDurationPreferenceController extends AbstractZenModePreferenceController {
    private static final String TAG = "QsDurationPrefController";

    private final Fragment mParent;
    private final ManualDurationHelper mDurationHelper;
    private final ManualDurationHelper.SettingsObserver mSettingsObserver;

    ManualDurationPreferenceController(Context context, String key, Fragment parent,
            ZenModesBackend backend) {
        super(context, key, backend);
        mParent = parent;
        mDurationHelper = new ManualDurationHelper(context);
        mSettingsObserver = mDurationHelper.makeSettingsObserver(this);
    }

    @Override
    public boolean isAvailable(ZenMode zenMode) {
        if (!super.isAvailable(zenMode)) {
            return false;
        }
        return zenMode.isManualDnd();
    }

    // Called by parent fragment onAttach().
    void registerSettingsObserver() {
        mSettingsObserver.register();
    }

    // Called by parent fragment onDetach().
    void unregisterSettingsObserver() {
        mSettingsObserver.unregister();
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        Preference pref = screen.findPreference(getPreferenceKey());
        if (pref != null) {
            mSettingsObserver.setPreference(pref);
        }
    }

    @Override
    public void updateState(Preference preference, ZenMode unusedZenMode) {
        // This controller is a link between a Settings value (ZEN_DURATION) and the manual DND
        // mode. The status of the zen mode object itself doesn't affect the preference
        // value, as that comes from settings; that value from settings will determine the
        // condition that is attached to the mode on manual activation. Thus we ignore the actual
        // zen mode value provided here.
        preference.setSummary(mDurationHelper.getSummary());
        preference.setOnPreferenceClickListener(pref -> {
            // The new setting value is set by the dialog, so we don't need to do it here.
            final SettingsZenDurationDialog durationDialog = new SettingsZenDurationDialog();
            durationDialog.show(mParent.getParentFragmentManager(), TAG);
            return true;
        });
    }
}
+29 −2
Original line number Diff line number Diff line
@@ -18,21 +18,32 @@ package com.android.settings.notification.modes;

import android.annotation.NonNull;
import android.content.Context;
import android.provider.Settings;
import android.widget.Button;

import androidx.fragment.app.Fragment;
import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.notification.SettingsEnableZenModeDialog;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;

import java.time.Duration;

class ZenModeButtonPreferenceController extends AbstractZenModePreferenceController {
    private static final String TAG = "ZenModeButtonPrefController";

    private Button mZenButton;
    private Fragment mParent;
    private ManualDurationHelper mDurationHelper;

    public ZenModeButtonPreferenceController(Context context, String key, ZenModesBackend backend) {
    ZenModeButtonPreferenceController(Context context, String key, Fragment parent,
            ZenModesBackend backend) {
        super(context, key, backend);
        mParent = parent;
        mDurationHelper = new ManualDurationHelper(context);
    }

    @Override
@@ -49,7 +60,23 @@ class ZenModeButtonPreferenceController extends AbstractZenModePreferenceControl
            if (zenMode.isActive()) {
                mBackend.deactivateMode(zenMode);
            } else {
                if (zenMode.isManualDnd()) {
                    // if manual DND, potentially ask for or use desired duration
                    int zenDuration = mDurationHelper.getZenDuration();
                    switch (zenDuration) {
                        case Settings.Secure.ZEN_DURATION_PROMPT:
                            new SettingsEnableZenModeDialog().show(
                                    mParent.getParentFragmentManager(), TAG);
                            break;
                        case Settings.Secure.ZEN_DURATION_FOREVER:
                            mBackend.activateMode(zenMode, null);
                            break;
                        default:
                            mBackend.activateMode(zenMode, Duration.ofMinutes(zenDuration));
                    }
                } else {
                    mBackend.activateMode(zenMode, null);
                }
            }
        });
        if (zenMode.isActive()) {
+18 −2
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import java.util.ArrayList;
import java.util.List;

public class ZenModeFragment extends ZenModeFragmentBase {

    // for mode deletion menu
    private static final int DELETE_MODE = 1;

@@ -48,7 +47,8 @@ public class ZenModeFragment extends ZenModeFragmentBase {
    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
        List<AbstractPreferenceController> prefControllers = new ArrayList<>();
        prefControllers.add(new ZenModeHeaderController(context, "header", this, mBackend));
        prefControllers.add(new ZenModeButtonPreferenceController(context, "activate", mBackend));
        prefControllers.add(
                new ZenModeButtonPreferenceController(context, "activate", this, mBackend));
        prefControllers.add(new ZenModeActionsPreferenceController(context, "actions", mBackend));
        prefControllers.add(new ZenModePeopleLinkPreferenceController(
                context, "zen_mode_people", mBackend, mHelperBackend));
@@ -64,9 +64,19 @@ public class ZenModeFragment extends ZenModeFragmentBase {
                "zen_automatic_trigger_category", this, mBackend));
        prefControllers.add(new InterruptionFilterPreferenceController(
                context, "allow_filtering", mBackend));
        prefControllers.add(new ManualDurationPreferenceController(
                context, "mode_manual_duration", this, mBackend));
        return prefControllers;
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);

        // allow duration preference controller to listen for settings changes
        use(ManualDurationPreferenceController.class).registerSettingsObserver();
    }

    @Override
    public void onStart() {
        super.onStart();
@@ -78,6 +88,12 @@ public class ZenModeFragment extends ZenModeFragmentBase {
        }
    }

    @Override
    public void onDetach() {
        use(ManualDurationPreferenceController.class).unregisterSettingsObserver();
        super.onDetach();
    }

    @Override
    public int getMetricsCategory() {
        // TODO: b/332937635 - make this the correct metrics category
Loading