<!-- [CHAR LIMIT=20] Zen mode settings: Calls screen footer -->
<string name="zen_mode_calls_footer">When Do Not Disturb is on, incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
+ <!-- [CHAR LIMIT=50] Zen mode settings: Starred contacts preference title -->
+ <string name="zen_mode_starred_contacts_title">Starred contacts</string>
+
+ <!-- Zen mode settings: Starred contacts summary [CHAR LIMIT=NONE] -->
+ <plurals name="zen_mode_starred_contacts_summary_additional_contacts">
+ <item quantity="one">and 1 other</item>
+ <item quantity="other">and <xliff:g id="num_people" example="3">%d</xliff:g> others</item>
+ </plurals>
+
<!-- [CHAR LIMIT=20] Zen mode settings: Messages option -->
<string name="zen_mode_messages">Messages</string>
android:entries="@array/zen_mode_contacts_entries"
android:entryValues="@array/zen_mode_contacts_values"/>
- <!-- TODO: setting that links to contacts or placeholder for external app -->
+ <Preference
+ android:key="zen_mode_starred_contacts_callers"
+ android:title="@string/zen_mode_starred_contacts_title"/>
<!-- Repeat callers -->
<SwitchPreference
android:entries="@array/zen_mode_contacts_entries"
android:entryValues="@array/zen_mode_contacts_values"/>
+ <Preference
+ android:key="zen_mode_starred_contacts_messages"
+ android:title="@string/zen_mode_starred_contacts_title"/>
+
<!-- Reminders -->
<SwitchPreference
android:key="zen_mode_reminders"
package com.android.settings.notification;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
+
import android.content.Context;
import android.provider.SearchIndexableResource;
Lifecycle lifecycle) {
List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new ZenModeCallsPreferenceController(context, lifecycle));
- // TODO: is a controller needed for a pref that just launches an external activity?
- // or can the contacts app insert this setting themselves?
+ controllers.add(new ZenModeStarredContactsPreferenceController(context, lifecycle,
+ PRIORITY_CATEGORY_CALLS, "zen_mode_starred_contacts_callers"));
controllers.add(new ZenModeRepeatCallersPreferenceController(context, lifecycle,
context.getResources().getInteger(com.android.internal.R.integer
.config_zen_repeat_callers_threshold)));
package com.android.settings.notification;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES;
+
import android.content.Context;
import android.provider.SearchIndexableResource;
controllers.add(new ZenModeEventsPreferenceController(context, lifecycle));
controllers.add(new ZenModeRemindersPreferenceController(context, lifecycle));
controllers.add(new ZenModeMessagesPreferenceController(context, lifecycle));
+ controllers.add(new ZenModeStarredContactsPreferenceController(context, lifecycle,
+ PRIORITY_CATEGORY_MESSAGES, "zen_mode_starred_contacts_messages"));
controllers.add(new ZenModeBehaviorFooterPreferenceController(context, lifecycle,
R.string.zen_msg_event_reminder_footer));
return controllers;
--- /dev/null
+/*
+ * Copyright (C) 2018 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.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES;
+import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.icu.text.ListFormatter;
+import android.provider.Contacts;
+import android.provider.ContactsContract;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ZenModeStarredContactsPreferenceController extends
+ AbstractZenModePreferenceController implements Preference.OnPreferenceClickListener {
+
+ protected static String KEY;
+ private Preference mPreference;
+ private final int mPriorityCategory;
+ private final PackageManager mPackageManager;
+
+ @VisibleForTesting
+ Intent mStarredContactsIntent;
+ @VisibleForTesting
+ Intent mFallbackIntent;
+
+ public ZenModeStarredContactsPreferenceController(Context context, Lifecycle lifecycle, int
+ priorityCategory, String key) {
+ super(context, key, lifecycle);
+ KEY = key;
+
+ mPriorityCategory = priorityCategory;
+ mPackageManager = mContext.getPackageManager();
+
+ mStarredContactsIntent = new Intent(Contacts.Intents.UI.LIST_STARRED_ACTION);
+
+ mFallbackIntent = new Intent(Intent.ACTION_MAIN);
+ mFallbackIntent.addCategory(Intent.CATEGORY_APP_CONTACTS);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(KEY);
+ mPreference.setOnPreferenceClickListener(this);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ if (mPriorityCategory == PRIORITY_CATEGORY_CALLS) {
+ return mBackend.isPriorityCategoryEnabled(PRIORITY_CATEGORY_CALLS)
+ && mBackend.getPriorityCallSenders() == PRIORITY_SENDERS_STARRED
+ && isIntentValid();
+ } else if (mPriorityCategory == PRIORITY_CATEGORY_MESSAGES) {
+ return mBackend.isPriorityCategoryEnabled(PRIORITY_CATEGORY_MESSAGES)
+ && mBackend.getPriorityMessageSenders() == PRIORITY_SENDERS_STARRED
+ && isIntentValid();
+ } else {
+ // invalid category
+ return false;
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+
+ List<String> starredContacts = getStarredContacts();
+ int numStarredContacts = starredContacts.size();
+
+ List<String> displayContacts = new ArrayList<>();
+
+ if (numStarredContacts == 0) {
+ displayContacts.add(mContext.getString(R.string.zen_mode_from_none));
+ } else {
+ for (int i = 0; i < 2 && i < numStarredContacts; i++) {
+ displayContacts.add(starredContacts.get(i));
+ }
+
+ if (numStarredContacts == 3) {
+ displayContacts.add(starredContacts.get(2));
+ } else if (numStarredContacts > 2) {
+ displayContacts.add(mContext.getResources().getQuantityString(
+ R.plurals.zen_mode_starred_contacts_summary_additional_contacts,
+ numStarredContacts - 2, numStarredContacts - 2));
+ }
+ }
+
+ mPreference.setSummary(ListFormatter.getInstance().format(displayContacts));
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ if (mStarredContactsIntent.resolveActivity(mPackageManager) != null) {
+ mContext.startActivity(mStarredContactsIntent);
+ } else {
+ mContext.startActivity(mFallbackIntent);
+ }
+ return true;
+ }
+
+ private List<String> getStarredContacts() {
+ List<String> starredContacts = new ArrayList<>();
+
+ Cursor cursor = mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
+ new String[]{ContactsContract.Contacts.DISPLAY_NAME_PRIMARY},
+ ContactsContract.Data.STARRED + "=1", null,
+ ContactsContract.Data.TIMES_CONTACTED);
+
+ if (cursor.moveToFirst()) {
+ do {
+ starredContacts.add(cursor.getString(0));
+ } while (cursor.moveToNext());
+ }
+ return starredContacts;
+ }
+
+ private boolean isIntentValid() {
+ return mStarredContactsIntent.resolveActivity(mPackageManager) != null
+ || mFallbackIntent.resolveActivity(mPackageManager) != null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 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.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ZenModeStarredContactsPreferenceControllerTest {
+
+ private ZenModeStarredContactsPreferenceController mCallsController;
+ private ZenModeStarredContactsPreferenceController mMessagesController;
+
+ @Mock
+ private ZenModeBackend mBackend;
+ @Mock
+ private NotificationManager mNotificationManager;
+ @Mock
+ private Preference mockPref;
+ @Mock
+ private NotificationManager.Policy mPolicy;
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private Intent testIntent;
+ @Mock
+ private ComponentName mComponentName;
+ private Context mContext;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ ShadowApplication shadowApplication = ShadowApplication.getInstance();
+ shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+ mContext = shadowApplication.getApplicationContext();
+ when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
+ when(testIntent.resolveActivity(any())).thenReturn(mComponentName);
+
+ mCallsController = new ZenModeStarredContactsPreferenceController(
+ mContext, mock(Lifecycle.class), PRIORITY_CATEGORY_CALLS,
+ "zen_mode_starred_contacts_callers");
+ ReflectionHelpers.setField(mCallsController, "mBackend", mBackend);
+ ReflectionHelpers.setField(mCallsController, "mStarredContactsIntent", testIntent);
+ when(mPreferenceScreen.findPreference(mCallsController.getPreferenceKey()))
+ .thenReturn(mockPref);
+ mCallsController.displayPreference(mPreferenceScreen);
+
+ mMessagesController = new ZenModeStarredContactsPreferenceController(
+ mContext, mock(Lifecycle.class), PRIORITY_CATEGORY_MESSAGES,
+ "zen_mode_starred_contacts_messages");
+ ReflectionHelpers.setField(mMessagesController, "mBackend", mBackend);
+ ReflectionHelpers.setField(mMessagesController, "mStarredContactsIntent", testIntent);
+ when(mPreferenceScreen.findPreference(mMessagesController.getPreferenceKey()))
+ .thenReturn(mockPref);
+ mMessagesController.displayPreference(mPreferenceScreen);
+ }
+
+ @Test
+ public void isAvailable_noCallers() {
+ when(mBackend.isPriorityCategoryEnabled(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS))
+ .thenReturn(false);
+ assertThat(mCallsController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_anyCallers() {
+ when(mBackend.isPriorityCategoryEnabled(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS))
+ .thenReturn(true);
+ when(mBackend.getPriorityCallSenders())
+ .thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_ANY);
+
+
+ assertThat(mCallsController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_starredCallers() {
+ when(mBackend.isPriorityCategoryEnabled(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS))
+ .thenReturn(true);
+ when(mBackend.getPriorityCallSenders())
+ .thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_STARRED);
+
+ assertThat(mCallsController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_noMessages() {
+ when(mBackend.isPriorityCategoryEnabled(
+ NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)).thenReturn(false);
+ assertThat(mMessagesController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_anyMessages() {
+ when(mBackend.isPriorityCategoryEnabled(
+ NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)).thenReturn(true);
+ when(mBackend.getPriorityMessageSenders())
+ .thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_ANY);
+
+ assertThat(mMessagesController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_starredMessageContacts() {
+ when(mBackend.isPriorityCategoryEnabled(
+ NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)).thenReturn(true);
+ when(mBackend.getPriorityMessageSenders())
+ .thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_STARRED);
+
+ assertThat(mMessagesController.isAvailable()).isTrue();
+ }
+}