First bits of "add a mode"

* Preference below the modes list.
* Temporarily triggers addition of a mode with default name and type=SCHEDULE_TIME (type will be "manual only" later).
* Fixed sorting of modes in the list when refreshing (new modes were added at the bottom instead of where they should, the same would've happened for renamed modes).
* Minor polishes (extracted fragment launch to helper class, renamed item controller class for clarity).

Test: atest com.android.settings.notification.modes
Bug: 326442408
Fixes: 347198709
Flag: android.app.modes_ui
Change-Id: Ie276c92181c5374faf74592433595e7e15a5efc0
This commit is contained in:
Matías Hernández
2024-06-14 15:46:51 +02:00
parent 16f9205fb6
commit 8409c39d94
9 changed files with 263 additions and 40 deletions

View File

@@ -30,6 +30,8 @@ import android.provider.ContactsContract;
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.SystemZenRules;
import android.service.notification.ZenAdapters;
import android.service.notification.ZenModeConfig;
import android.util.Log;
@@ -242,4 +244,32 @@ class ZenModesBackend {
}
mNotificationManager.removeAutomaticZenRule(mode.getId(), /* fromUser= */ true);
}
/**
* Creates a new custom mode with the provided {@code name}. The mode will be "manual" (i.e.
* not have a schedule), this can be later updated by the user in the mode settings page.
*
* @return the created mode. Only {@code null} if creation failed due to an internal error
*/
@Nullable
ZenMode addCustomMode(String name) {
ZenModeConfig.ScheduleInfo schedule = new ZenModeConfig.ScheduleInfo();
schedule.days = ZenModeConfig.ALL_DAYS;
schedule.startHour = 22;
schedule.endHour = 7;
// TODO: b/326442408 - Create as "manual" (i.e. no trigger) instead of schedule-time.
AutomaticZenRule rule = new AutomaticZenRule.Builder(name,
ZenModeConfig.toScheduleConditionId(schedule))
.setPackage(ZenModeConfig.getScheduleConditionProvider().getPackageName())
.setType(AutomaticZenRule.TYPE_SCHEDULE_CALENDAR)
.setOwner(ZenModeConfig.getScheduleConditionProvider())
.setTriggerDescription(SystemZenRules.getTriggerDescriptionForScheduleTime(
mContext, schedule))
.setManualInvocationAllowed(true)
.build();
String ruleId = mNotificationManager.addAutomaticZenRule(rule);
return getMode(ruleId);
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.preference.Preference;
import com.android.settings.utils.ZenServiceListing;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.Random;
class ZenModesListAddModePreferenceController extends AbstractPreferenceController {
private final ZenModesBackend mBackend;
private final ZenServiceListing mServiceListing;
ZenModesListAddModePreferenceController(Context context, ZenModesBackend backend,
ZenServiceListing serviceListing) {
super(context);
mBackend = backend;
mServiceListing = serviceListing;
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return "add_mode";
}
@Override
public void updateState(Preference preference) {
preference.setOnPreferenceClickListener(pref -> {
// TODO: b/326442408 - Launch the proper mode creation flow (using mServiceListing).
ZenMode mode = mBackend.addCustomMode("New mode #" + new Random().nextInt(1000));
if (mode != null) {
ZenSubSettingLauncher.forMode(mContext, mode.getId()).launch();
}
return true;
});
}
}

View File

@@ -31,12 +31,14 @@ import com.android.settings.utils.ZenServiceListing;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import com.google.common.collect.ImmutableList;
import java.util.List;
@SearchIndexable
public class ZenModesListFragment extends ZenModesFragmentBase {
protected final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig();
private static final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig();
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
@@ -50,13 +52,11 @@ public class ZenModesListFragment extends ZenModesFragmentBase {
// We need to redefine ZenModesBackend here even though mBackend exists so that this method
// can be static; it must be static to be able to be used in SEARCH_INDEX_DATA_PROVIDER.
ZenModesBackend backend = ZenModesBackend.getInstance(context);
List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new ZenModesListPreferenceController(
context, parent, backend));
// TODO: b/326442408 - Add controller for "Add Mode" preference/flow, which is what uses
// the ZenServiceListing.
return controllers;
return ImmutableList.of(
new ZenModesListPreferenceController(context, parent, backend),
new ZenModesListAddModePreferenceController(context, backend, serviceListing)
);
}
@Override
@@ -77,7 +77,7 @@ public class ZenModesListFragment extends ZenModesFragmentBase {
return SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION;
}
protected static ManagedServiceSettings.Config getConditionProviderConfig() {
private static ManagedServiceSettings.Config getConditionProviderConfig() {
return new ManagedServiceSettings.Config.Builder()
.setTag(TAG)
.setIntentAction(ConditionProviderService.SERVICE_INTERFACE)
@@ -87,8 +87,6 @@ public class ZenModesListFragment extends ZenModesFragmentBase {
.build();
}
// TODO: b/322373473 - Add 3-dot options menu with capability to delete modes.
/**
* For Search.
*/

View File

@@ -15,24 +15,19 @@
*/
package com.android.settings.notification.modes;
import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.RestrictedPreference;
/**
* Preference representing a single mode item on the modes aggregator page. Clicking on this
* preference leads to an individual mode's configuration page.
*/
class ZenModeListPreference extends RestrictedPreference {
class ZenModesListItemPreference extends RestrictedPreference {
final Context mContext;
ZenMode mZenMode;
ZenModeListPreference(Context context, ZenMode zenMode) {
ZenModesListItemPreference(Context context, ZenMode zenMode) {
super(context);
mContext = context;
setZenMode(zenMode);
@@ -41,13 +36,7 @@ class ZenModeListPreference extends RestrictedPreference {
@Override
public void onClick() {
Bundle bundle = new Bundle();
bundle.putString(MODE_ID, mZenMode.getId());
new SubSettingLauncher(mContext)
.setDestination(ZenModeFragment.class.getName())
.setArguments(bundle)
.setSourceMetricsCategory(SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION)
.launch();
ZenSubSettingLauncher.forMode(mContext, mZenMode.getId()).launch();
}
public void setZenMode(ZenMode zenMode) {

View File

@@ -15,7 +15,6 @@
*/
package com.android.settings.notification.modes;
import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
import android.content.res.Resources;
@@ -74,24 +73,27 @@ class ZenModesListPreferenceController extends BasePreferenceController {
// category for each rule that exists.
PreferenceCategory category = (PreferenceCategory) preference;
Map<String, ZenModeListPreference> originalPreferences = new HashMap<>();
Map<String, ZenModesListItemPreference> originalPreferences = new HashMap<>();
for (int i = 0; i < category.getPreferenceCount(); i++) {
ZenModeListPreference pref = (ZenModeListPreference) category.getPreference(i);
ZenModesListItemPreference pref = (ZenModesListItemPreference) category.getPreference(
i);
originalPreferences.put(pref.getKey(), pref);
}
// Loop through each rule, either updating the existing rule or creating the rule's
// preference
for (ZenMode mode : mBackend.getModes()) {
if (originalPreferences.containsKey(mode.getId())) {
List<ZenMode> modes = mBackend.getModes();
for (ZenMode mode : modes) {
ZenModesListItemPreference modePreference = originalPreferences.get(mode.getId());
if (modePreference != null) {
// existing rule; update its info if it's changed since the last display
AutomaticZenRule rule = mode.getRule();
originalPreferences.get(mode.getId()).setZenMode(mode);
modePreference.setZenMode(mode);
} else {
// new rule; create a new ZenRulePreference & add it to the preference category
Preference pref = new ZenModeListPreference(mContext, mode);
category.addPreference(pref);
modePreference = new ZenModesListItemPreference(mContext, mode);
category.addPreference(modePreference);
}
modePreference.setOrder(modes.indexOf(mode));
originalPreferences.remove(mode.getId());
}

View File

@@ -0,0 +1,43 @@
/*
* 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.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import com.android.settings.core.SubSettingLauncher;
class ZenSubSettingLauncher {
static SubSettingLauncher forMode(Context context, String modeId) {
return forModeFragment(context, ZenModeFragment.class, modeId,
SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION);
}
private static SubSettingLauncher forModeFragment(Context context,
Class<? extends ZenModeFragmentBase> fragmentClass, String modeId,
int sourceMetricsCategory) {
Bundle bundle = new Bundle();
bundle.putString(ZenModeFragmentBase.MODE_ID, modeId);
return new SubSettingLauncher(context)
.setDestination(fragmentClass.getName())
.setArguments(bundle)
.setSourceMetricsCategory(sourceMetricsCategory);
}
}