diff --git a/res/values/strings.xml b/res/values/strings.xml index 00748369ab5..5c33e9c0700 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7928,6 +7928,15 @@ 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. + + Starred contacts + + + + and 1 other + and %d others + + Messages diff --git a/res/xml/zen_mode_calls_settings.xml b/res/xml/zen_mode_calls_settings.xml index d9e47f30538..62d9ef4490d 100644 --- a/res/xml/zen_mode_calls_settings.xml +++ b/res/xml/zen_mode_calls_settings.xml @@ -29,7 +29,9 @@ android:entries="@array/zen_mode_contacts_entries" android:entryValues="@array/zen_mode_contacts_values"/> - + + + 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)); controllers.add(new ZenModeRepeatCallersPreferenceController(context, lifecycle, context.getResources().getInteger(com.android.internal.R.integer .config_zen_repeat_callers_threshold))); diff --git a/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java b/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java index c2508e35286..95b9f7e30df 100644 --- a/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java +++ b/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java @@ -16,6 +16,8 @@ package com.android.settings.notification; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES; + import android.content.Context; import android.provider.SearchIndexableResource; @@ -42,6 +44,8 @@ public class ZenModeMsgEventReminderSettings extends ZenModeSettingsBase impleme 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)); controllers.add(new ZenModeBehaviorFooterPreferenceController(context, lifecycle, R.string.zen_msg_event_reminder_footer)); return controllers; diff --git a/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java new file mode 100644 index 00000000000..1b8a3d5261c --- /dev/null +++ b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java @@ -0,0 +1,151 @@ +/* + * 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 android.support.v7.preference.Preference; +import android.support.v7.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 final String KEY = "zen_mode_starred_contacts"; + 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) { + super(context, KEY, lifecycle); + 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 starredContacts = getStarredContacts(); + int numStarredContacts = starredContacts.size(); + + List 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 getStarredContacts() { + List 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; + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java new file mode 100644 index 00000000000..7a45d7f4829 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java @@ -0,0 +1,149 @@ +/* + * 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 android.support.v7.preference.ListPreference; +import android.support.v7.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 ListPreference 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); + 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); + 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(); + } +}