diff --git a/res/drawable/ic_delete_x.xml b/res/drawable/ic_delete_x.xml new file mode 100644 index 00000000000..345daf03fe6 --- /dev/null +++ b/res/drawable/ic_delete_x.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/res/drawable/ic_lock_closed.xml b/res/drawable/ic_lock_closed.xml new file mode 100644 index 00000000000..cb0ea241246 --- /dev/null +++ b/res/drawable/ic_lock_closed.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/res/layout/bubble_conversation_remove_button.xml b/res/layout/bubble_conversation_remove_button.xml new file mode 100644 index 00000000000..6ec48dcbea8 --- /dev/null +++ b/res/layout/bubble_conversation_remove_button.xml @@ -0,0 +1,24 @@ + + + \ No newline at end of file diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 1649cb2ae0a..6e88b769bda 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -1148,14 +1148,14 @@ @string/zen_mode_from_anyone @string/zen_mode_from_contacts @string/zen_mode_from_starred - @string/zen_mode_from_none_messages + @string/zen_mode_none_messages @string/zen_mode_from_anyone @string/zen_mode_from_contacts @string/zen_mode_from_starred - @string/zen_mode_from_none_calls + @string/zen_mode_none_calls diff --git a/res/values/strings.xml b/res/values/strings.xml index cff3357f806..d4f3f7344ab 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8465,6 +8465,8 @@ Shows at top of conversation section and appears as a bubble. + %1$s does not support conversation-specific settings. + @@ -8976,6 +8978,8 @@ 1 other %d others + + None Messages @@ -8995,8 +8999,13 @@ All calls can reach you - - %d contacts + + None + + + 1 contact + %d contacts + Anyone @@ -9004,8 +9013,6 @@ Contacts Starred contacts - - None From starred contacts and repeat callers @@ -9015,9 +9022,9 @@ From repeat callers only - Don\u2019t allow any calls + None - Don\u2019t allow any messages + None Alarms diff --git a/res/xml/app_bubble_notification_settings.xml b/res/xml/app_bubble_notification_settings.xml index 3f52ad38153..976d9f0c48f 100644 --- a/res/xml/app_bubble_notification_settings.xml +++ b/res/xml/app_bubble_notification_settings.xml @@ -27,4 +27,12 @@ android:title="@string/notification_bubbles_title" settings:allowDividerBelow="false"/> + + + diff --git a/res/xml/conversation_notification_settings.xml b/res/xml/conversation_notification_settings.xml index c034eb5d6d8..65fdee5e9da 100644 --- a/res/xml/conversation_notification_settings.xml +++ b/res/xml/conversation_notification_settings.xml @@ -78,14 +78,14 @@ android:key="ringtone" android:title="@string/notification_channel_sound_title" android:dialogTitle="@string/notification_channel_sound_title" - android:icon="@drawable/ic_media_stream" + android:icon="@drawable/ic_notifications" android:showSilent="true" android:showDefault="true"/> diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index e8eb8baadb0..2391fe8cc40 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -57,6 +57,7 @@ import android.net.LinkProperties; import android.net.Network; import android.net.wifi.WifiManager; import android.os.BatteryManager; +import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.IBinder; @@ -1089,4 +1090,15 @@ public final class Utils extends com.android.settingslib.Utils { } return f; } + + /** + * Returns true if current binder uid is Settings Intelligence. + */ + public static boolean isSettingsIntelligence(Context context) { + final int callingUid = Binder.getCallingUid(); + final String callingPackage = context.getPackageManager().getPackagesForUid(callingUid)[0]; + final boolean isSettingsIntelligence = TextUtils.equals(callingPackage, + context.getString(R.string.config_settingsintelligence_package_name)); + return isSettingsIntelligence; + } } diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index becd4e78b02..f918046bc37 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -269,7 +269,7 @@ public class AccessibilitySettings extends DashboardFragment { final CharSequence serviceState; final int fragmentType = AccessibilityUtil.getAccessibilityServiceFragmentType(info); - if (fragmentType == AccessibilityServiceFragmentType.INVISIBLE) { + if (fragmentType == AccessibilityServiceFragmentType.INVISIBLE_TOGGLE) { final ComponentName componentName = new ComponentName( info.getResolveInfo().serviceInfo.packageName, info.getResolveInfo().serviceInfo.name); @@ -652,13 +652,16 @@ public class AccessibilitySettings extends DashboardFragment { } private String getAccessibilityServiceFragmentTypeName(AccessibilityServiceInfo info) { - switch (AccessibilityUtil.getAccessibilityServiceFragmentType( - info)) { - case AccessibilityServiceFragmentType.LEGACY: - return LegacyAccessibilityServicePreferenceFragment.class.getName(); - case AccessibilityServiceFragmentType.INVISIBLE: + // Shorten the name to avoid exceeding 100 characters in one line. + final String volumeShortcutToggleAccessibilityServicePreferenceFragment = + VolumeShortcutToggleAccessibilityServicePreferenceFragment.class.getName(); + + switch (AccessibilityUtil.getAccessibilityServiceFragmentType(info)) { + case AccessibilityServiceFragmentType.VOLUME_SHORTCUT_TOGGLE: + return volumeShortcutToggleAccessibilityServicePreferenceFragment; + case AccessibilityServiceFragmentType.INVISIBLE_TOGGLE: return InvisibleToggleAccessibilityServicePreferenceFragment.class.getName(); - case AccessibilityServiceFragmentType.INTUITIVE: + case AccessibilityServiceFragmentType.TOGGLE: return ToggleAccessibilityServicePreferenceFragment.class.getName(); default: // impossible status diff --git a/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java b/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java index 2bcb5b3b3cf..090e5d48493 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java +++ b/src/com/android/settings/accessibility/AccessibilitySettingsForSetupWizard.java @@ -16,7 +16,7 @@ package com.android.settings.accessibility; -import static com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType.LEGACY; +import static com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType.VOLUME_SHORTCUT_TOGGLE; import android.accessibilityservice.AccessibilityServiceInfo; import android.app.settings.SettingsEnums; @@ -102,10 +102,10 @@ public class AccessibilitySettingsForSetupWizard extends SettingsPreferenceFragm super.onResume(); updateAccessibilityServicePreference(mScreenReaderPreference, SCREEN_READER_PACKAGE_NAME, SCREEN_READER_SERVICE_NAME, - LegacyToggleScreenReaderPreferenceFragmentForSetupWizard.class.getName()); + VolumeShortcutToggleScreenReaderPreferenceFragmentForSetupWizard.class.getName()); updateAccessibilityServicePreference(mSelectToSpeakPreference, SELECT_TO_SPEAK_PACKAGE_NAME, SELECT_TO_SPEAK_SERVICE_NAME, - LegacyToggleSelectToSpeakPreferenceFragmentForSetupWizard.class.getName()); + VolumeShortcutToggleSelectToSpeakPreferenceFragmentForSetupWizard.class.getName()); configureMagnificationPreferenceIfNeeded(mDisplayMagnificationPreference); } @@ -147,7 +147,7 @@ public class AccessibilitySettingsForSetupWizard extends SettingsPreferenceFragm } private void updateAccessibilityServicePreference(Preference preference, - String packageName, String serviceName, String targetLegacyFragment) { + String packageName, String serviceName, String targetFragment) { final AccessibilityServiceInfo info = findService(packageName, serviceName); if (info == null) { getPreferenceScreen().removePreference(preference); @@ -159,8 +159,8 @@ public class AccessibilitySettingsForSetupWizard extends SettingsPreferenceFragm preference.setTitle(title); ComponentName componentName = new ComponentName(serviceInfo.packageName, serviceInfo.name); preference.setKey(componentName.flattenToString()); - if (AccessibilityUtil.getAccessibilityServiceFragmentType(info) == LEGACY) { - preference.setFragment(targetLegacyFragment); + if (AccessibilityUtil.getAccessibilityServiceFragmentType(info) == VOLUME_SHORTCUT_TOGGLE) { + preference.setFragment(targetFragment); } // Update the extras. diff --git a/src/com/android/settings/accessibility/AccessibilityUtil.java b/src/com/android/settings/accessibility/AccessibilityUtil.java index a0e3d81403e..eb202b5b044 100644 --- a/src/com/android/settings/accessibility/AccessibilityUtil.java +++ b/src/com/android/settings/accessibility/AccessibilityUtil.java @@ -46,22 +46,23 @@ final class AccessibilityUtil { /** * Annotation for different accessibilityService fragment UI type. * - * {@code LEGACY} for displaying appearance aligned with sdk version Q accessibility service - * page, but only hardware shortcut allowed. - * {@code INVISIBLE} for displaying appearance without switch bar. - * {@code INTUITIVE} for displaying appearance with new design. + * {@code VOLUME_SHORTCUT_TOGGLE} for displaying basic accessibility service fragment but + * only hardware shortcut allowed. + * {@code INVISIBLE_TOGGLE} for displaying basic accessibility service fragment without + * switch bar. + * {@code TOGGLE} for displaying basic accessibility service fragment. */ @Retention(RetentionPolicy.SOURCE) @IntDef({ - AccessibilityServiceFragmentType.LEGACY, - AccessibilityServiceFragmentType.INVISIBLE, - AccessibilityServiceFragmentType.INTUITIVE, + AccessibilityServiceFragmentType.VOLUME_SHORTCUT_TOGGLE, + AccessibilityServiceFragmentType.INVISIBLE_TOGGLE, + AccessibilityServiceFragmentType.TOGGLE, }) public @interface AccessibilityServiceFragmentType { - int LEGACY = 0; - int INVISIBLE = 1; - int INTUITIVE = 2; + int VOLUME_SHORTCUT_TOGGLE = 0; + int INVISIBLE_TOGGLE = 1; + int TOGGLE = 2; } // TODO(b/147021230): Will move common functions and variables to @@ -162,11 +163,11 @@ final class AccessibilityUtil { & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; if (targetSdk <= Build.VERSION_CODES.Q) { - return AccessibilityServiceFragmentType.LEGACY; + return AccessibilityServiceFragmentType.VOLUME_SHORTCUT_TOGGLE; } return requestA11yButton - ? AccessibilityServiceFragmentType.INVISIBLE - : AccessibilityServiceFragmentType.INTUITIVE; + ? AccessibilityServiceFragmentType.INVISIBLE_TOGGLE + : AccessibilityServiceFragmentType.TOGGLE; } /** diff --git a/src/com/android/settings/accessibility/LegacyAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/VolumeShortcutToggleAccessibilityServicePreferenceFragment.java similarity index 97% rename from src/com/android/settings/accessibility/LegacyAccessibilityServicePreferenceFragment.java rename to src/com/android/settings/accessibility/VolumeShortcutToggleAccessibilityServicePreferenceFragment.java index c5cede3453e..31f97a8f600 100644 --- a/src/com/android/settings/accessibility/LegacyAccessibilityServicePreferenceFragment.java +++ b/src/com/android/settings/accessibility/VolumeShortcutToggleAccessibilityServicePreferenceFragment.java @@ -34,7 +34,7 @@ import com.google.common.collect.ImmutableSet; * *

For accessibility services that target SDK <= Q. */ -public class LegacyAccessibilityServicePreferenceFragment extends +public class VolumeShortcutToggleAccessibilityServicePreferenceFragment extends ToggleAccessibilityServicePreferenceFragment { @Override diff --git a/src/com/android/settings/accessibility/LegacyToggleScreenReaderPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/VolumeShortcutToggleScreenReaderPreferenceFragmentForSetupWizard.java similarity index 91% rename from src/com/android/settings/accessibility/LegacyToggleScreenReaderPreferenceFragmentForSetupWizard.java rename to src/com/android/settings/accessibility/VolumeShortcutToggleScreenReaderPreferenceFragmentForSetupWizard.java index 1b37a42afb0..6e4a233c608 100644 --- a/src/com/android/settings/accessibility/LegacyToggleScreenReaderPreferenceFragmentForSetupWizard.java +++ b/src/com/android/settings/accessibility/VolumeShortcutToggleScreenReaderPreferenceFragmentForSetupWizard.java @@ -21,8 +21,8 @@ import android.os.Bundle; import android.view.View; /** For accessibility services that target SDK <= Q in setup wizard. */ -public class LegacyToggleScreenReaderPreferenceFragmentForSetupWizard - extends LegacyAccessibilityServicePreferenceFragment { +public class VolumeShortcutToggleScreenReaderPreferenceFragmentForSetupWizard + extends VolumeShortcutToggleAccessibilityServicePreferenceFragment { private boolean mToggleSwitchWasInitiallyChecked; diff --git a/src/com/android/settings/accessibility/LegacyToggleSelectToSpeakPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/VolumeShortcutToggleSelectToSpeakPreferenceFragmentForSetupWizard.java similarity index 91% rename from src/com/android/settings/accessibility/LegacyToggleSelectToSpeakPreferenceFragmentForSetupWizard.java rename to src/com/android/settings/accessibility/VolumeShortcutToggleSelectToSpeakPreferenceFragmentForSetupWizard.java index ffb363cd154..3dd648cd592 100644 --- a/src/com/android/settings/accessibility/LegacyToggleSelectToSpeakPreferenceFragmentForSetupWizard.java +++ b/src/com/android/settings/accessibility/VolumeShortcutToggleSelectToSpeakPreferenceFragmentForSetupWizard.java @@ -21,8 +21,8 @@ import android.os.Bundle; import android.view.View; /** For accessibility services that target SDK <= Q in setup wizard. */ -public class LegacyToggleSelectToSpeakPreferenceFragmentForSetupWizard - extends LegacyAccessibilityServicePreferenceFragment { +public class VolumeShortcutToggleSelectToSpeakPreferenceFragmentForSetupWizard + extends VolumeShortcutToggleAccessibilityServicePreferenceFragment { private boolean mToggleSwitchWasInitiallyChecked; diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java index 239ad2178e8..b417c3d6872 100644 --- a/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java +++ b/src/com/android/settings/datausage/DataUsageSummaryPreferenceController.java @@ -114,6 +114,7 @@ public class DataUsageSummaryPreferenceController extends TelephonyBasePreferenc */ public void init(int subscriptionId) { mSubId = subscriptionId; + mHasMobileData = DataUsageUtils.hasMobileData(mContext); mDataUsageController = null; } @@ -123,8 +124,6 @@ public class DataUsageSummaryPreferenceController extends TelephonyBasePreferenc context.getSystemService(NetworkPolicyManager.class); mPolicyEditor = new NetworkPolicyEditor(policyManager); - mHasMobileData = DataUsageUtils.hasMobileData(context); - mDataUsageController = new DataUsageController(context); mDataUsageController.setSubscriptionId(subscriptionId); mDataInfoController = new DataUsageInfoController(); @@ -210,6 +209,11 @@ public class DataUsageSummaryPreferenceController extends TelephonyBasePreferenc final DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(mDefaultTemplate); + long usageLevel = info.usageLevel; + if (usageLevel <= 0L) { + usageLevel = mDataUsageController.getHistoricalUsageLevel(mDefaultTemplate); + } + if (subInfo != null) { mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(mDefaultTemplate)); summaryPreference.setWifiMode(/* isWifiMode */ false, @@ -218,7 +222,7 @@ public class DataUsageSummaryPreferenceController extends TelephonyBasePreferenc summaryPreference.setWifiMode(/* isWifiMode */ true, /* usagePeriod */ info.period, /* isSingleWifi */ false); summaryPreference.setLimitInfo(null); - summaryPreference.setUsageNumbers(info.usageLevel, + summaryPreference.setUsageNumbers(usageLevel, /* dataPlanSize */ -1L, /* hasMobileData */ true); summaryPreference.setChartEnabled(false); @@ -231,6 +235,11 @@ public class DataUsageSummaryPreferenceController extends TelephonyBasePreferenc } refreshDataplanInfo(info, subInfo); + if ((mDataplanUse <= 0L) && (mSnapshotTime < 0)) { + Log.d(TAG, "Display data usage from history"); + mDataplanUse = usageLevel; + mSnapshotTime = -1L; + } if (info.warningLevel > 0 && info.limitLevel > 0) { summaryPreference.setLimitInfo(TextUtils.expandTemplate( diff --git a/src/com/android/settings/deviceinfo/StorageSettings.java b/src/com/android/settings/deviceinfo/StorageSettings.java index 7f2c645a3b5..de6394e61ea 100644 --- a/src/com/android/settings/deviceinfo/StorageSettings.java +++ b/src/com/android/settings/deviceinfo/StorageSettings.java @@ -70,6 +70,16 @@ import java.util.List; public class StorageSettings extends SettingsPreferenceFragment implements Indexable { static final String TAG = "StorageSettings"; + private static final String KEY_STORAGE_SETTINGS = "storage_settings"; + private static final String KEY_INTERNAL_STORAGE = "storage_settings_internal_storage"; + private static final String KEY_STORAGE_SETTINGS_VOLUME = "storage_settings_volume_"; + private static final String KEY_STORAGE_SETTINGS_MEMORY_SIZE = "storage_settings_memory_size"; + private static final String KEY_STORAGE_SETTINGS_MEMORY = "storage_settings_memory_available"; + private static final String KEY_STORAGE_SETTINGS_DCIM = "storage_settings_dcim_space"; + private static final String KEY_STORAGE_SETTINGS_MUSIC = "storage_settings_music_space"; + private static final String KEY_STORAGE_SETTINGS_MISC = "storage_settings_misc_space"; + private static final String KEY_STORAGE_SETTINGS_FREE_SPACE = "storage_settings_free_space"; + private static final String TAG_VOLUME_UNMOUNTED = "volume_unmounted"; private static final String TAG_DISK_INIT = "disk_init"; private static final int METRICS_CATEGORY = SettingsEnums.DEVICEINFO_STORAGE; @@ -551,14 +561,14 @@ public class StorageSettings extends SettingsPreferenceFragment implements Index SearchIndexableRaw data = new SearchIndexableRaw(context); data.title = context.getString(R.string.storage_settings); - data.key = "storage_settings"; + data.key = KEY_STORAGE_SETTINGS; data.screenTitle = context.getString(R.string.storage_settings); data.keywords = context.getString(R.string.keywords_storage_settings); result.add(data); data = new SearchIndexableRaw(context); data.title = context.getString(R.string.internal_storage); - data.key = "storage_settings_internal_storage"; + data.key = KEY_INTERNAL_STORAGE; data.screenTitle = context.getString(R.string.storage_settings); result.add(data); @@ -568,7 +578,7 @@ public class StorageSettings extends SettingsPreferenceFragment implements Index for (VolumeInfo vol : vols) { if (isInteresting(vol)) { data.title = storage.getBestVolumeDescription(vol); - data.key = "storage_settings_volume_" + vol.id; + data.key = KEY_STORAGE_SETTINGS_VOLUME + vol.id; data.screenTitle = context.getString(R.string.storage_settings); result.add(data); } @@ -576,37 +586,37 @@ public class StorageSettings extends SettingsPreferenceFragment implements Index data = new SearchIndexableRaw(context); data.title = context.getString(R.string.memory_size); - data.key = "storage_settings_memory_size"; + data.key = KEY_STORAGE_SETTINGS_MEMORY_SIZE; data.screenTitle = context.getString(R.string.storage_settings); result.add(data); data = new SearchIndexableRaw(context); data.title = context.getString(R.string.memory_available); - data.key = "storage_settings_memory_available"; + data.key = KEY_STORAGE_SETTINGS_MEMORY; data.screenTitle = context.getString(R.string.storage_settings); result.add(data); data = new SearchIndexableRaw(context); data.title = context.getString(R.string.memory_dcim_usage); - data.key = "storage_settings_dcim_space"; + data.key = KEY_STORAGE_SETTINGS_DCIM; data.screenTitle = context.getString(R.string.storage_settings); result.add(data); data = new SearchIndexableRaw(context); data.title = context.getString(R.string.memory_music_usage); - data.key = "storage_settings_music_space"; + data.key = KEY_STORAGE_SETTINGS_MUSIC; data.screenTitle = context.getString(R.string.storage_settings); result.add(data); data = new SearchIndexableRaw(context); data.title = context.getString(R.string.memory_media_misc_usage); - data.key = "storage_settings_misc_space"; + data.key = KEY_STORAGE_SETTINGS_MISC; data.screenTitle = context.getString(R.string.storage_settings); result.add(data); data = new SearchIndexableRaw(context); data.title = context.getString(R.string.storage_menu_free); - data.key = "storage_settings_free_space"; + data.key = KEY_STORAGE_SETTINGS_FREE_SPACE; data.screenTitle = context.getString(R.string.storage_menu_free); // We need to define all three in order for this to trigger properly. data.intentAction = StorageManager.ACTION_MANAGE_STORAGE; @@ -618,5 +628,69 @@ public class StorageSettings extends SettingsPreferenceFragment implements Index return result; } + + @Override + public List getNonIndexableKeys(Context context) { + final List niks = super.getNonIndexableKeys(context); + if (isExternalExist(context)) { + niks.add(KEY_STORAGE_SETTINGS); + niks.add(KEY_INTERNAL_STORAGE); + niks.add(KEY_STORAGE_SETTINGS_MEMORY_SIZE); + niks.add(KEY_STORAGE_SETTINGS_MEMORY); + niks.add(KEY_STORAGE_SETTINGS_DCIM); + niks.add(KEY_STORAGE_SETTINGS_MUSIC); + niks.add(KEY_STORAGE_SETTINGS_MISC); + niks.add(KEY_STORAGE_SETTINGS_FREE_SPACE); + + final StorageManager storage = context.getSystemService( + StorageManager.class); + final List vols = storage.getVolumes(); + for (VolumeInfo vol : vols) { + if (isInteresting(vol)) { + niks.add(KEY_STORAGE_SETTINGS_VOLUME + vol.id); + } + } + } + return niks; + } + + @Override + protected boolean isPageSearchEnabled(Context context) { + return !isExternalExist(context); + } + + private boolean isExternalExist(Context context) { + int internalCount = 0; + StorageManager storageManager = context.getSystemService(StorageManager.class); + final List volumes = storageManager.getVolumes(); + for (VolumeInfo vol : volumes) { + //External storage + if (vol.getType() == VolumeInfo.TYPE_PUBLIC + || vol.getType() == VolumeInfo.TYPE_STUB) { + return true; + } else if (vol.getType() == VolumeInfo.TYPE_PRIVATE) { + internalCount++; + } + } + + // Unsupported disks + final List disks = storageManager.getDisks(); + for (DiskInfo disk : disks) { + if (disk.volumeCount == 0 && disk.size > 0) { + return true; + } + } + + // Missing private volumes + final List recs = storageManager.getVolumeRecords(); + for (VolumeRecord rec : recs) { + if (rec.getType() == VolumeInfo.TYPE_PRIVATE + && storageManager.findVolumeByUuid(rec.getFsUuid()) == null) { + internalCount++; + } + } + + return (internalCount != 1); + } }; } diff --git a/src/com/android/settings/dream/CurrentDreamPreferenceController.java b/src/com/android/settings/dream/CurrentDreamPreferenceController.java index fee4826c5a9..a73898fdc0a 100644 --- a/src/com/android/settings/dream/CurrentDreamPreferenceController.java +++ b/src/com/android/settings/dream/CurrentDreamPreferenceController.java @@ -20,8 +20,10 @@ import android.content.Context; import androidx.preference.Preference; +import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settings.widget.GearPreference; +import com.android.settingslib.RestrictedPreference; import com.android.settingslib.dream.DreamBackend; import com.android.settingslib.dream.DreamBackend.DreamInfo; @@ -45,6 +47,7 @@ public class CurrentDreamPreferenceController extends BasePreferenceController { public void updateState(Preference preference) { super.updateState(preference); setGearClickListenerForPreference(preference); + setActiveDreamIcon(preference); } @Override @@ -78,4 +81,13 @@ public class CurrentDreamPreferenceController extends BasePreferenceController { .filter((info) -> info.isActive) .findFirst(); } + + private void setActiveDreamIcon(Preference preference) { + if (!(preference instanceof GearPreference)) { + return; + } + final GearPreference gearPref = (GearPreference) preference; + gearPref.setIconSize(RestrictedPreference.ICON_SIZE_SMALL); + Utils.setSafeIcon(gearPref, mBackend.getActiveIcon()); + } } diff --git a/src/com/android/settings/network/telephony/MobileDataSlice.java b/src/com/android/settings/network/telephony/MobileDataSlice.java index b76eb3814cf..c3b08d38bfa 100644 --- a/src/com/android/settings/network/telephony/MobileDataSlice.java +++ b/src/com/android/settings/network/telephony/MobileDataSlice.java @@ -96,15 +96,18 @@ public class MobileDataSlice implements CustomSliceable { ListBuilder.ICON_IMAGE, title); final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction, null /* actionTitle */, isMobileDataEnabled()); + final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder() + .setTitle(title) + .addEndItem(toggleSliceAction) + .setPrimaryAction(primarySliceAction); + if (!Utils.isSettingsIntelligence(mContext)) { + rowBuilder.setSubtitle(summary); + } final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY) .setAccentColor(color) - .addRow(new ListBuilder.RowBuilder() - .setTitle(title) - .setSubtitle(summary) - .addEndItem(toggleSliceAction) - .setPrimaryAction(primarySliceAction)); + .addRow(rowBuilder); return listBuilder.build(); } diff --git a/src/com/android/settings/notification/AppBubbleListPreferenceController.java b/src/com/android/settings/notification/AppBubbleListPreferenceController.java new file mode 100644 index 00000000000..457a61ce45b --- /dev/null +++ b/src/com/android/settings/notification/AppBubbleListPreferenceController.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2020 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; + +import static android.app.NotificationChannel.DEFAULT_ALLOW_BUBBLE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; + +import android.annotation.Nullable; +import android.app.NotificationChannel; +import android.app.NotificationChannelGroup; +import android.content.Context; +import android.content.pm.ShortcutInfo; +import android.graphics.drawable.Drawable; +import android.service.notification.ConversationChannelWrapper; +import android.view.View; +import android.widget.ImageView; + +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + +import com.android.settings.R; +import com.android.settings.notification.app.AppConversationListPreferenceController; +import com.android.settingslib.RestrictedLockUtils; + +import com.google.common.annotations.VisibleForTesting; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Displays a list of conversations that have either been selected or excluded from bubbling. + */ +public class AppBubbleListPreferenceController extends AppConversationListPreferenceController { + + private static final String KEY = "bubble_conversations"; + + public AppBubbleListPreferenceController(Context context, NotificationBackend backend) { + super(context, backend); + } + + @Override + public void onResume(NotificationBackend.AppRow appRow, + @Nullable NotificationChannel channel, @Nullable NotificationChannelGroup group, + Drawable conversationDrawable, + ShortcutInfo conversationInfo, + RestrictedLockUtils.EnforcedAdmin admin) { + super.onResume(appRow, channel, group, conversationDrawable, conversationInfo, admin); + // In case something changed in the foreground (e.g. via bubble button on notification) + loadConversationsAndPopulate(); + } + + @Override + public String getPreferenceKey() { + return KEY; + } + + @Override + public boolean isAvailable() { + if (!super.isAvailable()) { + return false; + } + if (mAppRow.bubblePreference == BUBBLE_PREFERENCE_NONE) { + return false; + } + return true; + } + + @VisibleForTesting + @Override + public List filterAndSortConversations( + List conversations) { + return conversations.stream() + .sorted(mConversationComparator) + .filter((c) -> { + if (mAppRow.bubblePreference == BUBBLE_PREFERENCE_SELECTED) { + return c.getNotificationChannel().canBubble(); + } else if (mAppRow.bubblePreference == BUBBLE_PREFERENCE_ALL) { + return c.getNotificationChannel().getAllowBubbles() == 0; + } + return false; + }) + .collect(Collectors.toList()); + } + + @Override + protected int getTitleResId() { + // TODO: possible to left align like mocks? + return mAppRow.bubblePreference == BUBBLE_PREFERENCE_SELECTED + ? R.string.bubble_app_setting_selected_conversation_title + : R.string.bubble_app_setting_excluded_conversation_title; + } + + @VisibleForTesting + @Override + public Preference createConversationPref(final ConversationChannelWrapper conversation) { + final ConversationPreference pref = new ConversationPreference(mContext); + populateConversationPreference(conversation, pref); + pref.setOnClickListener((v) -> { + conversation.getNotificationChannel().setAllowBubbles(DEFAULT_ALLOW_BUBBLE); + mBackend.updateChannel(mAppRow.pkg, mAppRow.uid, conversation.getNotificationChannel()); + mPreference.removePreference(pref); + if (mPreference.getPreferenceCount() == 0) { + mPreference.setVisible(false); + } + }); + return pref; + } + + /** Simple preference with a 'x' button at the end. */ + @VisibleForTesting + public static class ConversationPreference extends Preference implements View.OnClickListener { + + View.OnClickListener mOnClickListener; + + ConversationPreference(Context context) { + super(context); + setWidgetLayoutResource(R.layout.bubble_conversation_remove_button); + } + + @Override + public void onBindViewHolder(final PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + ImageView view = holder.itemView.findViewById(R.id.button); + view.setOnClickListener(mOnClickListener); + } + + public void setOnClickListener(View.OnClickListener listener) { + mOnClickListener = listener; + } + + @Override + public void onClick(View v) { + if (mOnClickListener != null) { + mOnClickListener.onClick(v); + } + } + } +} diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java index b172879b64e..6172268bd0b 100644 --- a/src/com/android/settings/notification/NotificationBackend.java +++ b/src/com/android/settings/notification/NotificationBackend.java @@ -268,6 +268,15 @@ public class NotificationBackend { } } + public boolean hasSentMessage(String pkg, int uid) { + try { + return sINM.hasSentMessage(pkg, uid); + } catch (Exception e) { + Log.w(TAG, "Error calling NoMan", e); + return false; + } + } + /** * Returns all notification channels associated with the package and uid that will bypass DND */ diff --git a/src/com/android/settings/notification/app/AppBubbleNotificationSettings.java b/src/com/android/settings/notification/app/AppBubbleNotificationSettings.java index 5026a26a52a..b1b126e56c0 100644 --- a/src/com/android/settings/notification/app/AppBubbleNotificationSettings.java +++ b/src/com/android/settings/notification/app/AppBubbleNotificationSettings.java @@ -22,6 +22,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.settings.R; +import com.android.settings.notification.AppBubbleListPreferenceController; import com.android.settings.notification.NotificationBackend; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; @@ -56,18 +57,20 @@ public class AppBubbleNotificationSettings extends NotificationSettings implemen @Override protected List createPreferenceControllers(Context context) { - mControllers = getPreferenceControllers(context, this); + mControllers = getPreferenceControllers(context, this, mDependentFieldListener); return new ArrayList<>(mControllers); } protected static List getPreferenceControllers( - Context context, AppBubbleNotificationSettings fragment) { + Context context, AppBubbleNotificationSettings fragment, + DependentFieldListener listener) { List controllers = new ArrayList<>(); controllers.add(new HeaderPreferenceController(context, fragment)); controllers.add(new BubblePreferenceController(context, fragment != null ? fragment.getChildFragmentManager() : null, - new NotificationBackend(), true /* isAppPage */)); + new NotificationBackend(), true /* isAppPage */, listener)); + controllers.add(new AppBubbleListPreferenceController(context, new NotificationBackend())); return controllers; } @@ -114,7 +117,7 @@ public class AppBubbleNotificationSettings extends NotificationSettings implemen public List createPreferenceControllers(Context context) { return new ArrayList<>(AppBubbleNotificationSettings.getPreferenceControllers( - context, null)); + context, null, null)); } }; } diff --git a/src/com/android/settings/notification/app/AppConversationListPreferenceController.java b/src/com/android/settings/notification/app/AppConversationListPreferenceController.java index 32278db907a..2fcd2b2059a 100644 --- a/src/com/android/settings/notification/app/AppConversationListPreferenceController.java +++ b/src/com/android/settings/notification/app/AppConversationListPreferenceController.java @@ -19,6 +19,7 @@ package com.android.settings.notification.app; import android.app.NotificationChannel; import android.app.settings.SettingsEnums; import android.content.Context; +import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.os.AsyncTask; import android.os.Bundle; @@ -33,6 +34,7 @@ import com.android.settings.applications.AppInfoBase; import com.android.settings.core.SubSettingLauncher; import com.android.settings.notification.NotificationBackend; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -42,8 +44,9 @@ public class AppConversationListPreferenceController extends NotificationPrefere private static final String KEY = "conversations"; public static final String ARG_FROM_SETTINGS = "fromSettings"; - private List mConversations; - private PreferenceCategory mPreference; + protected List mConversations = new ArrayList<>(); + protected PreferenceCategory mPreference; + private boolean mHasSentMsg; public AppConversationListPreferenceController(Context context, NotificationBackend backend) { super(context, backend); @@ -74,12 +77,23 @@ public class AppConversationListPreferenceController extends NotificationPrefere @Override public void updateState(Preference preference) { mPreference = (PreferenceCategory) preference; + loadConversationsAndPopulate(); + } + + protected void loadConversationsAndPopulate() { + if (mAppRow == null) { + return; + } // Load channel settings new AsyncTask() { @Override protected Void doInBackground(Void... unused) { - mConversations = mBackend.getConversations(mAppRow.pkg, mAppRow.uid).getList(); - Collections.sort(mConversations, mConversationComparator); + mHasSentMsg = mBackend.hasSentMessage(mAppRow.pkg, mAppRow.uid); + ParceledListSlice list = + mBackend.getConversations(mAppRow.pkg, mAppRow.uid); + if (list != null) { + mConversations = filterAndSortConversations(list.getList()); + } return null; } @@ -93,15 +107,35 @@ public class AppConversationListPreferenceController extends NotificationPrefere }.execute(); } + protected List filterAndSortConversations( + List conversations) { + Collections.sort(conversations, mConversationComparator); + return conversations; + } + + protected int getTitleResId() { + return R.string.conversations_category_title; + } + private void populateList() { + if (mPreference == null) { + return; + } // TODO: if preference has children, compare with newly loaded list mPreference.removeAll(); - mPreference.setTitle(R.string.conversations_category_title); - if (mConversations.isEmpty()) { - mPreference.setVisible(false); + if (mHasSentMsg) { + mPreference.setVisible(true); + Preference notSupportedPref = new Preference(mContext); + notSupportedPref.setSummary(mContext.getString( + R.string.convo_not_supported_summary, mAppRow.label)); + mPreference.addPreference(notSupportedPref); + } else { + mPreference.setVisible(false); + } } else { mPreference.setVisible(true); + mPreference.setTitle(getTitleResId()); populateConversations(); } } @@ -117,6 +151,12 @@ public class AppConversationListPreferenceController extends NotificationPrefere protected Preference createConversationPref(final ConversationChannelWrapper conversation) { Preference pref = new Preference(mContext); + populateConversationPreference(conversation, pref); + return pref; + } + + protected void populateConversationPreference(final ConversationChannelWrapper conversation, + final Preference pref) { ShortcutInfo si = conversation.getShortcutInfo(); pref.setTitle(si != null @@ -147,7 +187,6 @@ public class AppConversationListPreferenceController extends NotificationPrefere .setTitleText(pref.getTitle()) .setSourceMetricsCategory(SettingsEnums.NOTIFICATION_APP_NOTIFICATION) .toIntent()); - return pref; } protected Comparator mConversationComparator = diff --git a/src/com/android/settings/notification/app/BubblePreference.java b/src/com/android/settings/notification/app/BubblePreference.java index 679b663c8dd..7e071ff938a 100644 --- a/src/com/android/settings/notification/app/BubblePreference.java +++ b/src/com/android/settings/notification/app/BubblePreference.java @@ -52,6 +52,8 @@ public class BubblePreference extends Preference implements View.OnClickListener private ButtonViewHolder mBubbleSelectedButton; private ButtonViewHolder mBubbleNoneButton; + private boolean mSelectedVisible; + public BubblePreference(Context context) { this(context, null); } @@ -89,6 +91,11 @@ public class BubblePreference extends Preference implements View.OnClickListener } } + public void setSelectedVisibility(boolean visible) { + mSelectedVisible = visible; + notifyChanged(); + } + @Override public void onBindViewHolder(final PreferenceViewHolder holder) { super.onBindViewHolder(holder); @@ -122,7 +129,8 @@ public class BubblePreference extends Preference implements View.OnClickListener mSelectedPreference == BUBBLE_PREFERENCE_SELECTED); bubbleSelected.setTag(BUBBLE_PREFERENCE_SELECTED); bubbleSelected.setOnClickListener(this); - bubbleSelected.setVisibility(disabledByAdmin ? View.GONE : View.VISIBLE); + bubbleSelected.setVisibility((!mSelectedVisible || disabledByAdmin) + ? View.GONE : View.VISIBLE); View bubbleNone = holder.findViewById(R.id.bubble_none); ImageView bubbleNoneImage = (ImageView) holder.findViewById(R.id.bubble_none_icon); diff --git a/src/com/android/settings/notification/app/BubblePreferenceController.java b/src/com/android/settings/notification/app/BubblePreferenceController.java index 3255192a912..0ca2095d6ec 100644 --- a/src/com/android/settings/notification/app/BubblePreferenceController.java +++ b/src/com/android/settings/notification/app/BubblePreferenceController.java @@ -47,12 +47,17 @@ public class BubblePreferenceController extends NotificationPreferenceController private FragmentManager mFragmentManager; private boolean mIsAppPage; + private boolean mHasSentInvalidMsg; + private int mNumConversations; + private NotificationSettings.DependentFieldListener mListener; public BubblePreferenceController(Context context, @Nullable FragmentManager fragmentManager, - NotificationBackend backend, boolean isAppPage) { + NotificationBackend backend, boolean isAppPage, + @Nullable NotificationSettings.DependentFieldListener listener) { super(context, backend); mFragmentManager = fragmentManager; mIsAppPage = isAppPage; + mListener = listener; } @Override @@ -81,10 +86,14 @@ public class BubblePreferenceController extends NotificationPreferenceController @Override public void updateState(Preference preference) { if (mIsAppPage && mAppRow != null) { + mHasSentInvalidMsg = mBackend.hasSentMessage(mAppRow.pkg, mAppRow.uid); + mNumConversations = mBackend.getConversations( + mAppRow.pkg, mAppRow.uid).getList().size(); // We're on the app specific bubble page which displays a tri-state int backEndPref = mAppRow.bubblePreference; BubblePreference pref = (BubblePreference) preference; pref.setDisabledByAdmin(mAdmin); + pref.setSelectedVisibility(!mHasSentInvalidMsg || mNumConversations > 0); if (!isGloballyEnabled()) { pref.setSelectedPreference(BUBBLE_PREFERENCE_NONE); } else { @@ -122,6 +131,9 @@ public class BubblePreferenceController extends NotificationPreferenceController mBackend.setAllowBubbles(mAppRow.pkg, mAppRow.uid, value); } } + if (mListener != null) { + mListener.onFieldValueChanged(); + } } return true; } diff --git a/src/com/android/settings/notification/app/ConversationNotificationSettings.java b/src/com/android/settings/notification/app/ConversationNotificationSettings.java index 9ee4a2cf2e1..902c81c8996 100644 --- a/src/com/android/settings/notification/app/ConversationNotificationSettings.java +++ b/src/com/android/settings/notification/app/ConversationNotificationSettings.java @@ -92,7 +92,7 @@ public class ConversationNotificationSettings extends NotificationSettings { mControllers.add(new BadgePreferenceController(context, mBackend)); mControllers.add(new NotificationsOffPreferenceController(context)); mControllers.add(new BubblePreferenceController(context, getChildFragmentManager(), - mBackend, false /* isAppPage */)); + mBackend, false /* isAppPage */, null /* dependentFieldListener */)); mControllers.add(new ConversationDemotePreferenceController(context, this, mBackend)); mControllers.add(new BubbleCategoryPreferenceController(context)); mControllers.add(new BubbleLinkPreferenceController(context)); diff --git a/src/com/android/settings/notification/zen/ZenModeBackend.java b/src/com/android/settings/notification/zen/ZenModeBackend.java index b9b27c400f7..2f6a2b1b52e 100644 --- a/src/com/android/settings/notification/zen/ZenModeBackend.java +++ b/src/com/android/settings/notification/zen/ZenModeBackend.java @@ -287,13 +287,13 @@ public class ZenModeBackend { protected int getAlarmsTotalSilencePeopleSummary(int category) { if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) { - return R.string.zen_mode_from_none; + return R.string.zen_mode_none_messages; } else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS){ - return R.string.zen_mode_from_none; + return R.string.zen_mode_none_calls; } else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS) { return R.string.zen_mode_from_no_conversations; } - return R.string.zen_mode_from_none; + return R.string.zen_mode_from_no_conversations; } protected int getConversationSummary() { @@ -322,7 +322,7 @@ public class ZenModeBackend { return R.string.zen_mode_from_starred; case ZenPolicy.PEOPLE_TYPE_NONE: default: - return R.string.zen_mode_from_none; + return R.string.zen_mode_none_calls; } } @@ -337,7 +337,7 @@ public class ZenModeBackend { return R.string.zen_mode_from_starred; case ZenPolicy.PEOPLE_TYPE_NONE: default: - return R.string.zen_mode_from_none; + return R.string.zen_mode_none_messages; } } @@ -472,7 +472,7 @@ public class ZenModeBackend { List displayContacts = new ArrayList<>(); if (numStarredContacts == 0) { - displayContacts.add(context.getString(R.string.zen_mode_from_none)); + displayContacts.add(context.getString(R.string.zen_mode_starred_contacts_summary_none)); } else { for (int i = 0; i < 2 && i < numStarredContacts; i++) { displayContacts.add(starredContacts.get(i)); @@ -494,10 +494,11 @@ public class ZenModeBackend { String getContactsNumberSummary(Context context) { final int numContacts = queryAllContactsData().getCount(); if (numContacts == 0) { - return context.getResources().getString(R.string.zen_mode_from_none); + return context.getResources().getString( + R.string.zen_mode_contacts_count_none); } - return context.getResources().getString(R.string.zen_mode_contacts_senders_summary, - numContacts); + return context.getResources().getQuantityString(R.plurals.zen_mode_contacts_count, + numContacts, numContacts); } private Cursor queryStarredContactsData() { diff --git a/src/com/android/settings/notification/zen/ZenModePrioritySendersPreferenceController.java b/src/com/android/settings/notification/zen/ZenModePrioritySendersPreferenceController.java index 8fd59c39a6a..abf2cedd3dc 100644 --- a/src/com/android/settings/notification/zen/ZenModePrioritySendersPreferenceController.java +++ b/src/com/android/settings/notification/zen/ZenModePrioritySendersPreferenceController.java @@ -91,7 +91,9 @@ public class ZenModePrioritySendersPreferenceController makeRadioPreference(KEY_ANY, com.android.settings.R.string.zen_mode_from_anyone); makeRadioPreference(KEY_NONE, - com.android.settings.R.string.zen_mode_from_none); + mIsMessages + ? com.android.settings.R.string.zen_mode_none_messages + : com.android.settings.R.string.zen_mode_none_calls); updateSummaries(); } diff --git a/src/com/android/settings/notification/zen/ZenModeSendersImagePreferenceController.java b/src/com/android/settings/notification/zen/ZenModeSendersImagePreferenceController.java index e8cd40db63a..6a0cf7acc71 100644 --- a/src/com/android/settings/notification/zen/ZenModeSendersImagePreferenceController.java +++ b/src/com/android/settings/notification/zen/ZenModeSendersImagePreferenceController.java @@ -91,7 +91,10 @@ public class ZenModeSendersImagePreferenceController newImageRes = mIsMessages ? R.drawable.zen_messages_none : R.drawable.zen_calls_none; - newContentDescription = mContext.getString(R.string.zen_mode_from_none); + newContentDescription = + mContext.getString(mIsMessages + ? R.string.zen_mode_none_messages + : R.string.zen_mode_none_calls); } mImageView.setImageResource(newImageRes); diff --git a/src/com/android/settings/notification/zen/ZenModeSettings.java b/src/com/android/settings/notification/zen/ZenModeSettings.java index 3e59203a8b9..436a3990801 100644 --- a/src/com/android/settings/notification/zen/ZenModeSettings.java +++ b/src/com/android/settings/notification/zen/ZenModeSettings.java @@ -156,7 +156,7 @@ public class ZenModeSettings extends ZenModeSettingsBase { || PRIORITY_CATEGORY_REPEAT_CALLERS == category, true); int numCategories = enabledCategories.size(); if (numCategories == 0) { - return mContext.getString(R.string.zen_mode_from_none); + return mContext.getString(R.string.zen_mode_none_calls); } else if (numCategories == 1) { return mContext.getString(R.string.zen_mode_calls_summary_one, enabledCategories.get(0)); @@ -172,7 +172,7 @@ public class ZenModeSettings extends ZenModeSettingsBase { category -> PRIORITY_CATEGORY_MESSAGES == category, false); int numCategories = enabledCategories.size(); if (numCategories == 0) { - return mContext.getString(R.string.zen_mode_from_none); + return mContext.getString(R.string.zen_mode_none_messages); } else { return enabledCategories.get(0); } diff --git a/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java b/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java index fe1e20461e9..c9a203e2f4c 100644 --- a/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java +++ b/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java @@ -82,15 +82,18 @@ public class ZenModeSliceBuilder { final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction, null /* actionTitle */, isZenModeEnabled); + final RowBuilder rowBuilder = new RowBuilder() + .setTitle(title) + .addEndItem(toggleSliceAction) + .setPrimaryAction(primarySliceAction); + if (!Utils.isSettingsIntelligence(context)) { + rowBuilder.setSubtitle(subtitle); + } return new ListBuilder(context, CustomSliceRegistry.ZEN_MODE_SLICE_URI, ListBuilder.INFINITY) .setAccentColor(color) - .addRow(new RowBuilder() - .setTitle(title) - .setSubtitle(subtitle) - .addEndItem(toggleSliceAction) - .setPrimaryAction(primarySliceAction)) + .addRow(rowBuilder) .build(); } diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java index 34c0f1b5ff2..2d5b4aa39a2 100644 --- a/src/com/android/settings/slices/SliceBuilderUtils.java +++ b/src/com/android/settings/slices/SliceBuilderUtils.java @@ -241,16 +241,19 @@ public class SliceBuilderUtils { final SliceAction sliceAction = getToggleAction(context, sliceData, toggleController.isChecked()); final Set keywords = buildSliceKeywords(sliceData); + final RowBuilder rowBuilder = new RowBuilder() + .setTitle(sliceData.getTitle()) + .setPrimaryAction( + SliceAction.createDeeplink(contentIntent, icon, + ListBuilder.ICON_IMAGE, sliceData.getTitle())) + .addEndItem(sliceAction); + if (!Utils.isSettingsIntelligence(context)) { + rowBuilder.setSubtitle(subtitleText); + } return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY) .setAccentColor(color) - .addRow(new RowBuilder() - .setTitle(sliceData.getTitle()) - .setSubtitle(subtitleText) - .setPrimaryAction( - SliceAction.createDeeplink(contentIntent, icon, - ListBuilder.ICON_IMAGE, sliceData.getTitle())) - .addEndItem(sliceAction)) + .addRow(rowBuilder) .setKeywords(keywords) .build(); } @@ -262,16 +265,19 @@ public class SliceBuilderUtils { final CharSequence subtitleText = getSubtitleText(context, controller, sliceData); @ColorInt final int color = Utils.getColorAccentDefaultColor(context); final Set keywords = buildSliceKeywords(sliceData); + final RowBuilder rowBuilder = new RowBuilder() + .setTitle(sliceData.getTitle()) + .setPrimaryAction( + SliceAction.createDeeplink(contentIntent, icon, + ListBuilder.ICON_IMAGE, + sliceData.getTitle())); + if (!Utils.isSettingsIntelligence(context)) { + rowBuilder.setSubtitle(subtitleText); + } return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY) .setAccentColor(color) - .addRow(new RowBuilder() - .setTitle(sliceData.getTitle()) - .setSubtitle(subtitleText) - .setPrimaryAction( - SliceAction.createDeeplink(contentIntent, icon, - ListBuilder.ICON_IMAGE, - sliceData.getTitle()))) + .addRow(rowBuilder) .setKeywords(keywords) .build(); } @@ -301,7 +307,6 @@ public class SliceBuilderUtils { } final InputRangeBuilder inputRangeBuilder = new InputRangeBuilder() .setTitle(sliceData.getTitle()) - .setSubtitle(subtitleText) .setPrimaryAction(primaryAction) .setMax(sliderController.getMax()) .setMin(sliderController.getMin()) @@ -311,6 +316,9 @@ public class SliceBuilderUtils { inputRangeBuilder.setTitleItem(icon, ListBuilder.ICON_IMAGE); color = CustomSliceable.COLOR_NOT_TINTED; } + if (!Utils.isSettingsIntelligence(context)) { + inputRangeBuilder.setSubtitle(subtitleText); + } return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY) .setAccentColor(color) @@ -330,14 +338,17 @@ public class SliceBuilderUtils { final CharSequence subtitleText = getSubtitleText(context, controller, sliceData); @ColorInt final int color = Utils.getColorAccentDefaultColor(context); final Set keywords = buildSliceKeywords(sliceData); + final RowBuilder rowBuilder = new RowBuilder() + .setTitle(sliceData.getTitle()) + .setPrimaryAction(primaryAction) + .addEndItem(copyableAction); + if (!Utils.isSettingsIntelligence(context)) { + rowBuilder.setSubtitle(subtitleText); + } return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY) .setAccentColor(color) - .addRow(new RowBuilder() - .setTitle(sliceData.getTitle()) - .setSubtitle(subtitleText) - .setPrimaryAction(primaryAction) - .addEndItem(copyableAction)) + .addRow(rowBuilder) .setKeywords(keywords) .build(); } @@ -418,14 +429,17 @@ public class SliceBuilderUtils { final SliceAction primaryAction = SliceAction.createDeeplink( getContentPendingIntent(context, data), icon, ListBuilder.ICON_IMAGE, title); + final RowBuilder rowBuilder = new RowBuilder() + .setTitle(title) + .setTitleItem(icon, ListBuilder.ICON_IMAGE) + .setPrimaryAction(primaryAction); + if (!Utils.isSettingsIntelligence(context)) { + rowBuilder.setSubtitle(subtitle); + } return new ListBuilder(context, data.getUri(), ListBuilder.INFINITY) .setAccentColor(color) - .addRow(new RowBuilder() - .setTitle(title) - .setTitleItem(icon, ListBuilder.ICON_IMAGE) - .setSubtitle(subtitle) - .setPrimaryAction(primaryAction)) + .addRow(rowBuilder) .setKeywords(keywords) .build(); } diff --git a/src/com/android/settings/wifi/WifiSettings2.java b/src/com/android/settings/wifi/WifiSettings2.java index 9bf5c72037f..3b18f5a4fc7 100644 --- a/src/com/android/settings/wifi/WifiSettings2.java +++ b/src/com/android/settings/wifi/WifiSettings2.java @@ -544,14 +544,9 @@ public class WifiSettings2 extends RestrictedSettingsFragment final WifiEntry selectedEntry = ((LongPressWifiEntryPreference) preference).getWifiEntry(); - // If the clicked WiFi entry is never connected, launch Wi-Fi edit UI to edit password. - if (selectedEntry.getSecurity() != WifiEntry.SECURITY_NONE - && selectedEntry.getSecurity() != WifiEntry.SECURITY_OWE) { - final WifiConfiguration config = selectedEntry.getWifiConfiguration(); - if (config != null && !config.getNetworkSelectionStatus().hasEverConnected()) { - launchConfigNewNetworkFragment(selectedEntry); - return true; - } + if (selectedEntry.shouldEditBeforeConnect()) { + launchConfigNewNetworkFragment(selectedEntry); + return true; } connect(selectedEntry, true /* editIfNoConfig */, true /* fullScreenEdit */); diff --git a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java index 69adf55be9c..958db7ebd8d 100644 --- a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java +++ b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java @@ -269,14 +269,17 @@ public class WifiCallingSliceHelper { // Top row shows information on current preference state final ListBuilder listBuilder = new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) .setAccentColor(Utils.getColorAccentDefaultColor(mContext)); - listBuilder.setHeader(new ListBuilder.HeaderBuilder() + final ListBuilder.HeaderBuilder headerBuilder = new ListBuilder.HeaderBuilder() .setTitle(res.getText(R.string.wifi_calling_mode_title)) - .setSubtitle(getWifiCallingPreferenceSummary(currentWfcPref, subId)) .setPrimaryAction(SliceAction.createDeeplink( getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY), icon, ListBuilder.ICON_IMAGE, - res.getText(R.string.wifi_calling_mode_title)))); + res.getText(R.string.wifi_calling_mode_title))); + if (!Utils.isSettingsIntelligence(mContext)) { + headerBuilder.setSubtitle(getWifiCallingPreferenceSummary(currentWfcPref, subId)); + } + listBuilder.setHeader(headerBuilder); if (isWifiOnlySupported) { listBuilder.addRow(wifiPreferenceRowBuilder(listBuilder, @@ -458,14 +461,17 @@ public class WifiCallingSliceHelper { private Slice getNonActionableWifiCallingSlice(CharSequence title, CharSequence subtitle, Uri sliceUri, PendingIntent primaryActionIntent) { final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal); + final RowBuilder rowBuilder = new RowBuilder() + .setTitle(title) + .setPrimaryAction(SliceAction.createDeeplink( + primaryActionIntent, icon, ListBuilder.SMALL_IMAGE, + title)); + if (!Utils.isSettingsIntelligence(mContext)) { + rowBuilder.setSubtitle(subtitle); + } return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) .setAccentColor(Utils.getColorAccentDefaultColor(mContext)) - .addRow(new RowBuilder() - .setTitle(title) - .setSubtitle(subtitle) - .setPrimaryAction(SliceAction.createDeeplink( - primaryActionIntent, icon, ListBuilder.SMALL_IMAGE, - title))) + .addRow(rowBuilder) .build(); } diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java index 3d3aff46e69..2aa8418227f 100644 --- a/tests/robotests/src/com/android/settings/UtilsTest.java +++ b/tests/robotests/src/com/android/settings/UtilsTest.java @@ -29,7 +29,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActionBar; -import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; @@ -67,6 +66,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowBinder; import java.net.InetAddress; import java.util.ArrayList; @@ -281,4 +281,22 @@ public class UtilsTest { assertThat(actionBar.getElevation()).isEqualTo(0.f); } + + @Test + public void isSettingsIntelligence_IsSI_returnTrue() { + final String siPackageName = mContext.getString( + R.string.config_settingsintelligence_package_name); + ShadowBinder.setCallingUid(USER_ID); + when(mPackageManager.getPackagesForUid(USER_ID)).thenReturn(new String[]{siPackageName}); + + assertThat(Utils.isSettingsIntelligence(mContext)).isTrue(); + } + + @Test + public void isSettingsIntelligence_IsNotSI_returnFalse() { + ShadowBinder.setCallingUid(USER_ID); + when(mPackageManager.getPackagesForUid(USER_ID)).thenReturn(new String[]{PACKAGE_NAME}); + + assertThat(Utils.isSettingsIntelligence(mContext)).isFalse(); + } } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java index c6a7684dd8e..bf631306b10 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java @@ -130,8 +130,8 @@ public class AccessibilitySettingsTest { } @Test - public void getServiceSummary_invisibleType_shortcutDisabled_showsOffSummary() { - setInvisibleFragmentType(mServiceInfo); + public void getServiceSummary_invisibleToggle_shortcutDisabled_showsOffSummary() { + setInvisibleToggleFragmentType(mServiceInfo); doReturn(DEFAULT_SUMMARY).when(mServiceInfo).loadSummary(any()); final CharSequence summary = AccessibilitySettings.getServiceSummary(mContext, @@ -277,7 +277,7 @@ public class AccessibilitySettingsTest { when(mockInfo.getComponentName()).thenReturn(DUMMY_COMPONENT_NAME); } - private void setInvisibleFragmentType(AccessibilityServiceInfo info) { + private void setInvisibleToggleFragmentType(AccessibilityServiceInfo info) { info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java index b8936c4601e..ac3198ff546 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java @@ -102,36 +102,36 @@ public final class AccessibilityUtilTest { } @Test - public void getAccessibilityServiceFragmentType_targetSdkQ_legacyType() { + public void getAccessibilityServiceFragmentType_targetSdkQ_volumeShortcutType() { final AccessibilityServiceInfo info = getMockAccessibilityServiceInfo(); info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo( - AccessibilityUtil.AccessibilityServiceFragmentType.LEGACY); + AccessibilityUtil.AccessibilityServiceFragmentType.VOLUME_SHORTCUT_TOGGLE); } @Test - public void getAccessibilityServiceFragmentType_targetSdkR_HaveA11yButton_headlessType() { + public void getAccessibilityServiceFragmentType_targetSdkR_HaveA11yButton_invisibleType() { final AccessibilityServiceInfo info = getMockAccessibilityServiceInfo(); info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo( - AccessibilityUtil.AccessibilityServiceFragmentType.INVISIBLE); + AccessibilityUtil.AccessibilityServiceFragmentType.INVISIBLE_TOGGLE); } @Test - public void getAccessibilityServiceFragmentType_targetSdkR_NoA11yButton_intuitiveType() { + public void getAccessibilityServiceFragmentType_targetSdkR_NoA11yButton_toggleType() { final AccessibilityServiceInfo info = getMockAccessibilityServiceInfo(); info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; info.flags |= ~AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo( - AccessibilityUtil.AccessibilityServiceFragmentType.INTUITIVE); + AccessibilityUtil.AccessibilityServiceFragmentType.TOGGLE); } @Test diff --git a/tests/robotests/src/com/android/settings/notification/app/AppBubbleListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/AppBubbleListPreferenceControllerTest.java new file mode 100644 index 00000000000..d176827c08b --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/app/AppBubbleListPreferenceControllerTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2020 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.app; + +import static android.app.NotificationChannel.DEFAULT_ALLOW_BUBBLE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.content.pm.ParceledListSlice; +import android.content.pm.ShortcutInfo; +import android.os.UserManager; +import android.service.notification.ConversationChannelWrapper; + +import androidx.preference.PreferenceCategory; + +import com.android.settings.notification.AppBubbleListPreferenceController; +import com.android.settings.notification.NotificationBackend; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowApplication; + +import java.util.ArrayList; +import java.util.List; + + +@RunWith(RobolectricTestRunner.class) +public class AppBubbleListPreferenceControllerTest { + + private Context mContext; + @Mock + private NotificationBackend mBackend; + @Mock + private NotificationManager mNm; + @Mock + private UserManager mUm; + + private AppBubbleListPreferenceController mController; + private ParceledListSlice mConvoList; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm); + shadowApplication.setSystemService(Context.USER_SERVICE, mUm); + mContext = RuntimeEnvironment.application; + + List convoList = new ArrayList<>(); + convoList.add(getConvo(-1, "default")); + convoList.add(getConvo(1, "selected")); + convoList.add(getConvo(0, "excluded")); + mConvoList = new ParceledListSlice<>(convoList); + when(mBackend.getConversations(anyString(), anyInt())).thenReturn(mConvoList); + mController = new AppBubbleListPreferenceController(mContext, mBackend); + } + + ConversationChannelWrapper getConvo(int bubbleChannelPref, String channelId) { + ConversationChannelWrapper ccw = new ConversationChannelWrapper(); + NotificationChannel channel = mock(NotificationChannel.class); + when(channel.getId()).thenReturn(channelId); + when(channel.getAllowBubbles()).thenReturn(bubbleChannelPref); + when(channel.canBubble()).thenReturn(bubbleChannelPref == 1); + ccw.setNotificationChannel(channel); + ccw.setPkg("pkg"); + ccw.setUid(1); + ccw.setShortcutInfo(mock(ShortcutInfo.class)); + return ccw; + } + + @Test + public void isAvailable_BUBBLE_PREFERENCE_NONE_false() { + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.bubblePreference = BUBBLE_PREFERENCE_NONE; + mController.onResume(appRow, null, null, null, null, null); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_BUBBLE_PREFERENCE_SELECTED_true() { + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.bubblePreference = BUBBLE_PREFERENCE_SELECTED; + mController.onResume(appRow, null, null, null, null, null); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_BUBBLE_PREFERENCE_ALL_true() { + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.bubblePreference = BUBBLE_PREFERENCE_ALL; + mController.onResume(appRow, null, null, null, null, null); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void filterAndSortConversations_BUBBLE_PREFERENCE_SELECTED_filtersAllowedBubbles() { + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.bubblePreference = BUBBLE_PREFERENCE_SELECTED; + mController.onResume(appRow, null, null, null, null, null); + + List result = + mController.filterAndSortConversations(mConvoList.getList()); + assertThat(result.size()).isEqualTo(1); + assertThat(result.get(0).getNotificationChannel().getId()) + .isEqualTo("selected"); + } + + @Test + public void filterAndSortConversations_BUBBLE_PREFERENCE_ALL_filtersExcludedBubbles() { + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.bubblePreference = BUBBLE_PREFERENCE_ALL; + mController.onResume(appRow, null, null, null, null, null); + + List result = + mController.filterAndSortConversations(mConvoList.getList()); + assertThat(result.size()).isEqualTo(1); + assertThat(result.get(0).getNotificationChannel().getId()) + .isEqualTo("excluded"); + } + + @Test + public void clickConversationPref_updatesChannel() { + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.bubblePreference = BUBBLE_PREFERENCE_ALL; + appRow.pkg = "PKG"; + mController.onResume(appRow, null, null, null, null, null); + mController.mPreference = new PreferenceCategory(mContext); + + ConversationChannelWrapper ccw = mConvoList.getList().get(0); + AppBubbleListPreferenceController.ConversationPreference pref = + (AppBubbleListPreferenceController.ConversationPreference) + mController.createConversationPref(ccw); + pref.onClick(null); + + verify(ccw.getNotificationChannel()).setAllowBubbles(DEFAULT_ALLOW_BUBBLE); + verify(mBackend).updateChannel(anyString(), anyInt(), any(NotificationChannel.class)); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java index 0cf6dc67829..685bca9b119 100644 --- a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java @@ -80,6 +80,8 @@ public class BubblePreferenceControllerTest { private PreferenceScreen mScreen; @Mock private FragmentManager mFragmentManager; + @Mock + private NotificationSettings.DependentFieldListener mListener; private BubblePreferenceController mController; private BubblePreferenceController mAppPageController; @@ -93,9 +95,9 @@ public class BubblePreferenceControllerTest { mContext = RuntimeEnvironment.application; when(mFragmentManager.beginTransaction()).thenReturn(mock(FragmentTransaction.class)); mController = spy(new BubblePreferenceController(mContext, mFragmentManager, mBackend, - false /* isAppPage */)); + false /* isAppPage */, mListener)); mAppPageController = spy(new BubblePreferenceController(mContext, mFragmentManager, - mBackend, true /* isAppPage */)); + mBackend, true /* isAppPage */, mListener)); } @Test @@ -106,7 +108,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsAvailable_notIfAppBlocked() { + public void isAvailable_notIfAppBlocked() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.banned = true; @@ -115,7 +117,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsAvailable_notIfChannelBlocked() { + public void isAvailable_notIfChannelBlocked() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); NotificationChannel channel = mock(NotificationChannel.class); @@ -125,7 +127,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsAvailable_channel_yesIfAppOff() { + public void isAvailable_channel_yesIfAppOff() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.bubblePreference = BUBBLE_PREFERENCE_NONE; @@ -137,7 +139,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsNotAvailable_ifOffGlobally_app() { + public void isNotAvailable_ifOffGlobally_app() { NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); mController.onResume(appRow, null, null, null, null, null); Settings.Global.putInt(mContext.getContentResolver(), @@ -147,7 +149,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsAvailable_notIfOffGlobally_channel() { + public void isAvailable_notIfOffGlobally_channel() { NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); NotificationChannel channel = mock(NotificationChannel.class); when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH); @@ -159,7 +161,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsAvailable_app_evenIfOffGlobally() { + public void isAvailable_app_evenIfOffGlobally() { NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); mAppPageController.onResume(appRow, null, null, null, null, null); Settings.Global.putInt(mContext.getContentResolver(), @@ -169,7 +171,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsAvailable_app() { + public void isAvailable_app() { NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); mController.onResume(appRow, null, null, null, null, null); Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); @@ -178,7 +180,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsAvailable_defaultChannel() { + public void isAvailable_defaultChannel() { NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.bubblePreference = BUBBLE_PREFERENCE_ALL; NotificationChannel channel = mock(NotificationChannel.class); @@ -191,7 +193,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testIsAvailable_channel() { + public void isAvailable_channel() { NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.bubblePreference = BUBBLE_PREFERENCE_ALL; NotificationChannel channel = mock(NotificationChannel.class); @@ -203,7 +205,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testUpdateState_disabledByAdmin() { + public void updateState_disabledByAdmin() { NotificationChannel channel = mock(NotificationChannel.class); when(channel.getId()).thenReturn("something"); mController.onResume(new NotificationBackend.AppRow(), channel, null, @@ -216,7 +218,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testUpdateState_app_disabledByAdmin() { + public void updateState_app_disabledByAdmin() { NotificationChannel channel = mock(NotificationChannel.class); when(channel.getId()).thenReturn("something"); mAppPageController.onResume(new NotificationBackend.AppRow(), channel, null, @@ -229,7 +231,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testUpdateState_channel_channelNotBlockable() { + public void updateState_channel_channelNotBlockable() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); NotificationChannel channel = mock(NotificationChannel.class); @@ -243,7 +245,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testUpdateState_channel() { + public void updateState_channel() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); NotificationChannel channel = mock(NotificationChannel.class); @@ -263,7 +265,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testUpdateState_app() { + public void updateState_app() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.label = "App!"; @@ -288,7 +290,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testUpdateState_app_offGlobally() { + public void updateState_app_offGlobally() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_OFF); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); @@ -302,7 +304,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testOnPreferenceChange_on_channel() { + public void onPreferenceChange_on_channel() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.bubblePreference = BUBBLE_PREFERENCE_SELECTED; @@ -321,7 +323,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testOnPreferenceChange_off_channel() { + public void onPreferenceChange_off_channel() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.bubblePreference = BUBBLE_PREFERENCE_SELECTED; @@ -341,7 +343,7 @@ public class BubblePreferenceControllerTest { @Test - public void testOnPreferenceChange_app_all() { + public void onPreferenceChange_app_all() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.bubblePreference = BUBBLE_PREFERENCE_NONE; @@ -379,7 +381,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testOnPreferenceChange_app_selected() { + public void onPreferenceChange_app_selected() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.bubblePreference = BUBBLE_PREFERENCE_ALL; @@ -397,7 +399,7 @@ public class BubblePreferenceControllerTest { } @Test - public void testOnPreferenceChange_app_none() { + public void onPreferenceChange_app_none() { Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); appRow.bubblePreference = BUBBLE_PREFERENCE_ALL; @@ -413,4 +415,17 @@ public class BubblePreferenceControllerTest { assertEquals(BUBBLE_PREFERENCE_NONE, appRow.bubblePreference); verify(mBackend, times(1)).setAllowBubbles(any(), anyInt(), eq(BUBBLE_PREFERENCE_NONE)); } + + @Test + public void onPreferenceChange_dependentFieldListenerCalled() { + Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.bubblePreference = BUBBLE_PREFERENCE_ALL; + mAppPageController.onResume(appRow, null, null, null, null, null); + + BubblePreference pref = new BubblePreference(mContext); + mAppPageController.onPreferenceChange(pref, BUBBLE_PREFERENCE_NONE); + + verify(mListener, times(1)).onFieldValueChanged(); + } } diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java index fc82abb21f2..33bdc61cd85 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.app.settings.SettingsEnums; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -455,37 +454,6 @@ public class SliceBuilderUtilsTest { assertThat(actualIconResource).isEqualTo(settingsIcon); } - @Test - public void buildUnavailableSlice_customizeSubtitle_returnsSliceWithCustomizedSubtitle() { - final String subtitleOfUnavailableSlice = "subtitleOfUnavailableSlice"; - final SliceData data = getDummyData(FakeUnavailablePreferenceController.class, - SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, 0 /* icon */, - subtitleOfUnavailableSlice); - Settings.Global.putInt(mContext.getContentResolver(), - FakeUnavailablePreferenceController.AVAILABILITY_KEY, - BasePreferenceController.DISABLED_DEPENDENT_SETTING); - - final Slice slice = SliceBuilderUtils.buildSlice(mContext, data); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getSubtitle()).isEqualTo(subtitleOfUnavailableSlice); - } - - @Test - public void buildUnavailableSlice_notCustomizeSubtitle_returnsSliceWithDefaultSubtitle() { - final SliceData data = getDummyData(FakeUnavailablePreferenceController.class, - SliceData.SliceType.SWITCH); - Settings.Global.putInt(mContext.getContentResolver(), - FakeUnavailablePreferenceController.AVAILABILITY_KEY, - BasePreferenceController.DISABLED_DEPENDENT_SETTING); - - final Slice slice = SliceBuilderUtils.buildSlice(mContext, data); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getSubtitle()).isEqualTo( - mContext.getString(R.string.disabled_dependent_setting_summary)); - } - private SliceData getDummyData() { return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, ICON, null /* unavailableSliceSubtitle */);