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

Commit 5bc5d8e3 authored by Matías Hernández's avatar Matías Hernández Committed by Android (Google) Code Review
Browse files

Merge "Use full day names in the a11y version of schedules in mode tile subtitles" into main

parents 6cac0bca 4336a6bf
Loading
Loading
Loading
Loading
+0 −22
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.service.notification.SystemZenRules.getTriggerDescriptionForScheduleEvent;
import static android.service.notification.SystemZenRules.getTriggerDescriptionForScheduleTime;
import static android.service.notification.ZenModeConfig.tryParseCountdownConditionId;
import static android.service.notification.ZenModeConfig.tryParseEventConditionId;
import static android.service.notification.ZenModeConfig.tryParseScheduleConditionId;

@@ -224,27 +223,6 @@ public class ZenMode implements Parcelable {
        return mRule.getTriggerDescription();
    }

    /**
     * Returns a "dynamic" trigger description. For some modes (such as manual Do Not Disturb)
     * when activated, we know when (and if) the mode is expected to end on its own; this dynamic
     * description reflects that. In other cases, returns {@link #getTriggerDescription}.
     */
    @Nullable
    public String getDynamicDescription(Context context) {
        if (isManualDnd() && isActive()) {
            long countdownEndTime = tryParseCountdownConditionId(mRule.getConditionId());
            if (countdownEndTime > 0) {
                CharSequence formattedTime = ZenModeConfig.getFormattedTime(context,
                        countdownEndTime, ZenModeConfig.isToday(countdownEndTime),
                        context.getUserId());
                return context.getString(com.android.internal.R.string.zen_mode_until,
                        formattedTime);
            }
        }

        return getTriggerDescription();
    }

    /**
     * Returns the {@link ZenIcon.Key} corresponding to the icon resource for this mode. This can be
     * either app-provided (via {@link AutomaticZenRule#setIconResId}, user-chosen (via the icon
+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.settingslib.notification.modes;

import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
import static android.service.notification.ZenModeConfig.tryParseCountdownConditionId;

import android.content.Context;
import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.common.base.Strings;

public final class ZenModeDescriptions {

    private final Context mContext;

    public ZenModeDescriptions(@NonNull Context context) {
        mContext = context;
    }

    /**
     * Returns a version of the mode's trigger description that might be "dynamic".
     *
     * <p>For some modes (such as manual Do Not Disturb) when activated, we know when (and if) the
     * mode is expected to end on its own; this description reflects that. In other cases,
     * returns {@link ZenMode#getTriggerDescription}.
     */
    @Nullable
    public String getTriggerDescription(@NonNull ZenMode mode) {
        if (mode.isManualDnd() && mode.isActive()) {
            long countdownEndTime = tryParseCountdownConditionId(mode.getRule().getConditionId());
            if (countdownEndTime > 0) {
                CharSequence formattedTime = ZenModeConfig.getFormattedTime(mContext,
                        countdownEndTime, ZenModeConfig.isToday(countdownEndTime),
                        mContext.getUserId());
                return mContext.getString(com.android.internal.R.string.zen_mode_until,
                        formattedTime);
            }
        }

        return Strings.emptyToNull(mode.getTriggerDescription());
    }

    /**
     * Returns a version of the {@link ZenMode} trigger description that is suitable for
     * accessibility (for example, where abbreviations are expanded to full words).
     *
     * <p>Returns {@code null} If the standard trigger description (returned by
     * {@link #getTriggerDescription}) is sufficient.
     */
    @Nullable
    public String getTriggerDescriptionForAccessibility(@NonNull ZenMode mode) {
        // Only one special case: time-based schedules, where we want to use full day names.
        if (mode.isSystemOwned() && mode.getType() == TYPE_SCHEDULE_TIME) {
            ZenModeConfig.ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(
                    mode.getRule().getConditionId());
            if (schedule != null) {
                String fullDaysSummary = SystemZenRules.getDaysOfWeekFull(mContext, schedule);
                if (fullDaysSummary != null) {
                    return fullDaysSummary + ", " + SystemZenRules.getTimeSummary(mContext,
                            schedule);
                }
            }
        }

        return null;
    }
}
+60 −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.settingslib.notification.modes;

import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
import static android.service.notification.SystemZenRules.PACKAGE_ANDROID;

import static com.google.common.truth.Truth.assertThat;

import android.service.notification.ZenModeConfig;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;

import java.util.Calendar;

@RunWith(RobolectricTestRunner.class)
public class ZenModeDescriptionsTest {

    private final ZenModeDescriptions mDescriptions = new ZenModeDescriptions(
            RuntimeEnvironment.getApplication());

    @Test
    public void getTriggerDescriptionForAccessibility_scheduleTime_usesFullDays() {
        ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
        scheduleInfo.days = new int[] { Calendar.MONDAY };
        scheduleInfo.startHour = 11;
        scheduleInfo.endHour = 15;
        ZenMode mode = new TestModeBuilder()
                .setPackage(PACKAGE_ANDROID)
                .setType(TYPE_SCHEDULE_TIME)
                .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo))
                .build();

        assertThat(mDescriptions.getTriggerDescriptionForAccessibility(mode))
                .isEqualTo("Monday, 11:00 AM - 3:00 PM");
    }

    @Test
    public void getTriggerDescriptionForAccessibility_otherMode_isNull() {
        ZenMode mode = new TestModeBuilder().setTriggerDescription("When December ends").build();
        assertThat(mDescriptions.getTriggerDescriptionForAccessibility(mode)).isNull();
    }
}
+31 −2
Original line number Diff line number Diff line
@@ -18,9 +18,12 @@

package com.android.systemui.statusbar.policy.ui.dialog.viewmodel

import android.app.AutomaticZenRule
import android.content.Intent
import android.content.applicationContext
import android.provider.Settings
import android.service.notification.SystemZenRules
import android.service.notification.ZenModeConfig
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.notification.modes.TestModeBuilder
@@ -35,6 +38,7 @@ import com.android.systemui.statusbar.policy.ui.dialog.mockModesDialogDelegate
import com.android.systemui.statusbar.policy.ui.dialog.mockModesDialogEventLogger
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import java.util.Calendar
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.test.runCurrent
@@ -60,6 +64,8 @@ class ModesDialogViewModelTest : SysuiTestCase() {

    private lateinit var underTest: ModesDialogViewModel

    private lateinit var timeScheduleMode: ZenMode

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
@@ -71,6 +77,21 @@ class ModesDialogViewModelTest : SysuiTestCase() {
                kosmos.mockModesDialogDelegate,
                kosmos.mockModesDialogEventLogger,
            )

        val scheduleInfo = ZenModeConfig.ScheduleInfo()
        scheduleInfo.days = intArrayOf(Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY)
        scheduleInfo.startHour = 11
        scheduleInfo.endHour = 15
        timeScheduleMode =
            TestModeBuilder()
                .setPackage(SystemZenRules.PACKAGE_ANDROID)
                .setType(AutomaticZenRule.TYPE_SCHEDULE_TIME)
                .setManualInvocationAllowed(true)
                .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo))
                .setTriggerDescription(
                    SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, scheduleInfo)
                )
                .build()
    }

    @Test
@@ -325,17 +346,19 @@ class ModesDialogViewModelTest : SysuiTestCase() {
                        .setTriggerDescription(null)
                        .setEnabled(false, /* byUser= */ false)
                        .build(),
                    timeScheduleMode,
                )
            )
            runCurrent()

            assertThat(tiles!!).hasSize(6)
            assertThat(tiles!!).hasSize(7)
            assertThat(tiles!![0].subtext).isEqualTo("When the going gets tough")
            assertThat(tiles!![1].subtext).isEqualTo("On • When in Rome")
            assertThat(tiles!![2].subtext).isEqualTo("Not set")
            assertThat(tiles!![3].subtext).isEqualTo("Off")
            assertThat(tiles!![4].subtext).isEqualTo("On")
            assertThat(tiles!![5].subtext).isEqualTo("Not set")
            assertThat(tiles!![6].subtext).isEqualTo("Mon - Wed, 11:00 AM - 3:00 PM")
        }

    @Test
@@ -381,11 +404,12 @@ class ModesDialogViewModelTest : SysuiTestCase() {
                        .setTriggerDescription(null)
                        .setEnabled(false, /* byUser= */ false)
                        .build(),
                    timeScheduleMode,
                )
            )
            runCurrent()

            assertThat(tiles!!).hasSize(6)
            assertThat(tiles!!).hasSize(7)
            with(tiles?.elementAt(0)!!) {
                assertThat(this.stateDescription).isEqualTo("Off")
                assertThat(this.subtextDescription).isEqualTo("When the going gets tough")
@@ -410,6 +434,11 @@ class ModesDialogViewModelTest : SysuiTestCase() {
                assertThat(this.stateDescription).isEqualTo("Off")
                assertThat(this.subtextDescription).isEqualTo("Not set")
            }
            with(tiles?.elementAt(6)!!) {
                assertThat(this.stateDescription).isEqualTo("Off")
                assertThat(this.subtextDescription)
                    .isEqualTo("Monday to Wednesday, 11:00 AM - 3:00 PM")
            }

            // All tiles have the same long click info
            tiles!!.forEach { assertThat(it.onLongClickLabel).isEqualTo("Open settings") }
+1 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ data class ModeTileViewModel(
    val icon: Icon,
    val text: String,
    val subtext: String,
    val subtextDescription: String, // version of subtext without "on"/"off" for screen readers
    val subtextDescription: String, // version of subtext (without "on"/"off") for screen readers
    val enabled: Boolean,
    val stateDescription: String, // "on"/"off" state of the tile, for screen readers
    val onClick: () -> Unit,
Loading