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