• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.notification.modes;
18 
19 import android.app.settings.SettingsEnums;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 
24 import androidx.annotation.Nullable;
25 import androidx.annotation.VisibleForTesting;
26 import androidx.lifecycle.Lifecycle;
27 
28 import com.android.settings.R;
29 import com.android.settings.core.SubSettingLauncher;
30 import com.android.settings.notification.modes.ZenModesListAddModePreferenceController.ModeType;
31 import com.android.settings.notification.modes.ZenModesListAddModePreferenceController.OnAddModeListener;
32 import com.android.settings.search.BaseSearchIndexProvider;
33 import com.android.settingslib.core.AbstractPreferenceController;
34 import com.android.settingslib.notification.modes.ZenIconLoader;
35 import com.android.settingslib.notification.modes.ZenMode;
36 import com.android.settingslib.notification.modes.ZenModesBackend;
37 import com.android.settingslib.search.SearchIndexable;
38 
39 import com.google.common.collect.ImmutableList;
40 
41 import java.util.List;
42 import java.util.Optional;
43 
44 @SearchIndexable
45 public class ZenModesListFragment extends ZenModesFragmentBase {
46 
47     static final int REQUEST_NEW_MODE = 101;
48 
49     @Nullable private ComponentName mActivityInvokedForAddNew;
50     @Nullable private ImmutableList<String> mZenModeIdsBeforeAddNew;
51 
52     @Override
createPreferenceControllers(Context context)53     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
54         return buildPreferenceControllers(context, mBackend, this::onAvailableModeTypesForAdd);
55     }
56 
buildPreferenceControllers(Context context, ZenModesBackend backend, OnAddModeListener onAddModeListener)57     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
58             ZenModesBackend backend, OnAddModeListener onAddModeListener) {
59         return ImmutableList.of(
60                 new ZenModesListPreferenceController(context, backend, ZenIconLoader.getInstance()),
61                 new ZenModesListAddModePreferenceController(context, "add_mode", onAddModeListener)
62         );
63     }
64 
65     @Override
onUpdatedZenModeState()66     protected void onUpdatedZenModeState() {
67         // Preferences linking to individual rules do not need to be updated as part of onStart(),
68         // because DashboardFragment does that in onResume(). However, we force the update if we
69         // detect Modes changes in the background with the page open.
70         if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
71             forceUpdatePreferences();
72         }
73     }
74 
75     @Override
getPreferenceScreenResId()76     protected int getPreferenceScreenResId() {
77         return R.xml.modes_list_settings;
78     }
79 
80     @Override
getMetricsCategory()81     public int getMetricsCategory() {
82         return SettingsEnums.ZEN_PRIORITY_MODES_LIST;
83     }
84 
onAvailableModeTypesForAdd(List<ModeType> types)85     private void onAvailableModeTypesForAdd(List<ModeType> types) {
86         if (types.size() > 1) {
87             // Show dialog to choose the mode to be created. Continue once the user chooses.
88             ZenModesListAddModeTypeChooserDialog.show(this, this::onChosenModeTypeForAdd, types);
89         } else {
90             // Will be custom_manual.
91             onChosenModeTypeForAdd(types.get(0));
92         }
93     }
94 
95     @VisibleForTesting
onChosenModeTypeForAdd(ModeType type)96     void onChosenModeTypeForAdd(ModeType type) {
97         if (type.creationActivityIntent() != null) {
98             mActivityInvokedForAddNew = type.creationActivityIntent().getComponent();
99             mZenModeIdsBeforeAddNew = ImmutableList.copyOf(
100                     mBackend.getModes().stream().map(ZenMode::getId).toList());
101             startActivityForResult(type.creationActivityIntent(), REQUEST_NEW_MODE);
102         } else {
103             // Custom-manual mode -> "add a mode" screen.
104             new SubSettingLauncher(requireContext())
105                     .setDestination(ZenModeNewCustomFragment.class.getName())
106                     .setSourceMetricsCategory(SettingsEnums.ZEN_PRIORITY_MODES_LIST)
107                     .launch();
108         }
109     }
110 
111     @Override
onActivityResult(int requestCode, int resultCode, Intent data)112     public void onActivityResult(int requestCode, int resultCode, Intent data) {
113         super.onActivityResult(requestCode, resultCode, data);
114         // If coming back after starting a 3rd-party configuration activity to create a new mode,
115         // try to identify the created mode. Ideally this would be part of the resultCode/data, but
116         // the existing API doesn't work that way...
117         ComponentName activityInvoked = mActivityInvokedForAddNew;
118         ImmutableList<String> previousIds = mZenModeIdsBeforeAddNew;
119         mActivityInvokedForAddNew = null;
120         mZenModeIdsBeforeAddNew = null;
121         if (requestCode != REQUEST_NEW_MODE || previousIds == null || activityInvoked == null) {
122             return;
123         }
124 
125         // If we find a new mode owned by the same package, presumably that's it. Open its page.
126         Optional<ZenMode> createdZenMode = mBackend.getModes().stream()
127                 .filter(m -> !previousIds.contains(m.getId()))
128                 .filter(m -> activityInvoked.getPackageName().equals(m.getOwnerPackage()))
129                 .findFirst();
130         createdZenMode.ifPresent(
131                 mode ->
132                         ZenSubSettingLauncher.forModeFragment(mContext, ZenModeFragment.class,
133                                 mode.getId(), getMetricsCategory()).launch());
134     }
135 
136     /**
137      * For Search.
138      */
139     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
140             new BaseSearchIndexProvider(R.xml.modes_list_settings) {
141 
142                 @Override
143                 public List<String> getNonIndexableKeys(Context context) {
144                     final List<String> keys = super.getNonIndexableKeys(context);
145                     return keys;
146                 }
147 
148                 @Override
149                 public List<AbstractPreferenceController> createPreferenceControllers(
150                         Context context) {
151                     // We need to redefine ZenModesBackend here even though mBackend exists so that
152                     // SEARCH_INDEX_DATA_PROVIDER can be static.
153                     return buildPreferenceControllers(context, ZenModesBackend.getInstance(context),
154                             ignoredType -> {});
155                 }
156             };
157 }
158