Loading src/com/android/settings/notification/ZenModeEventRuleSettings.java +59 −48 Original line number Diff line number Diff line Loading @@ -27,11 +27,7 @@ import android.provider.Settings; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.EventInfo; import androidx.preference.DropDownPreference; import androidx.preference.Preference; import androidx.preference.Preference.OnPreferenceChangeListener; import androidx.preference.PreferenceScreen; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settingslib.core.AbstractPreferenceController; Loading @@ -40,6 +36,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Objects; import androidx.preference.DropDownPreference; import androidx.preference.Preference; import androidx.preference.Preference.OnPreferenceChangeListener; import androidx.preference.PreferenceScreen; public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { private static final String KEY_CALENDAR = "calendar"; Loading @@ -51,7 +53,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { private DropDownPreference mReply; private EventInfo mEvent; private List<CalendarInfo> mCalendars; private boolean mCreate; @Override Loading Loading @@ -91,23 +93,19 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { } private void reloadCalendar() { mCalendars = getCalendars(mContext); List<CalendarInfo> calendars = getCalendars(mContext); ArrayList<CharSequence> entries = new ArrayList<>(); ArrayList<CharSequence> values = new ArrayList<>(); entries.add(getString(R.string.zen_mode_event_rule_calendar_any)); values.add(key(0, null)); final String eventCalendar = mEvent != null ? mEvent.calendar : null; boolean found = false; for (CalendarInfo calendar : mCalendars) { values.add(key(0, null, "")); final String eventCalendar = mEvent != null ? mEvent.calName : null; for (CalendarInfo calendar : calendars) { entries.add(calendar.name); values.add(key(calendar)); if (eventCalendar != null && eventCalendar.equals(calendar.name)) { found = true; } if (eventCalendar != null && (mEvent.calendarId == null && eventCalendar.equals(calendar.name))) { mEvent.calendarId = calendar.calendarId; } if (eventCalendar != null && !found) { entries.add(eventCalendar); values.add(key(mEvent.userId, eventCalendar)); } mCalendar.setEntries(entries.toArray(new CharSequence[entries.size()])); mCalendar.setEntryValues(values.toArray(new CharSequence[values.size()])); Loading @@ -124,12 +122,10 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { public boolean onPreferenceChange(Preference preference, Object newValue) { final String calendarKey = (String) newValue; if (calendarKey.equals(key(mEvent))) return false; final int i = calendarKey.indexOf(':'); mEvent.userId = Integer.parseInt(calendarKey.substring(0, i)); mEvent.calendar = calendarKey.substring(i + 1); if (mEvent.calendar.isEmpty()) { mEvent.calendar = null; } String[] key = calendarKey.split(":", 3); mEvent.userId = Integer.parseInt(key[0]); mEvent.calendarId = key[1].equals("") ? null : Long.parseLong(key[1]); mEvent.calName = key[2].equals("") ? null : key[2]; updateRule(ZenModeConfig.toEventConditionId(mEvent)); return true; } Loading Loading @@ -172,18 +168,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { return MetricsEvent.NOTIFICATION_ZEN_MODE_EVENT_RULE; } public static CalendarInfo findCalendar(Context context, EventInfo event) { if (context == null || event == null) return null; final String eventKey = key(event); for (CalendarInfo calendar : getCalendars(context)) { if (eventKey.equals(key(calendar))) { return calendar; } } return null; } private static List<CalendarInfo> getCalendars(Context context) { private List<CalendarInfo> getCalendars(Context context) { final List<CalendarInfo> calendars = new ArrayList<>(); for (UserHandle user : UserManager.get(context).getUserProfiles()) { final Context userContext = getContextForUser(context, user); Loading @@ -203,11 +188,11 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { } } public static void addCalendars(Context context, List<CalendarInfo> outCalendars) { final String primary = "\"primary\""; final String[] projection = { Calendars._ID, Calendars.CALENDAR_DISPLAY_NAME, "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + primary }; final String selection = primary + " = 1"; private void addCalendars(Context context, List<CalendarInfo> outCalendars) { final String[] projection = { Calendars._ID, Calendars.CALENDAR_DISPLAY_NAME }; final String selection = Calendars.CALENDAR_ACCESS_LEVEL + " >= " + Calendars.CAL_ACCESS_CONTRIBUTOR + " AND " + Calendars.SYNC_EVENTS + " = 1"; Cursor cursor = null; try { cursor = context.getContentResolver().query(Calendars.CONTENT_URI, projection, Loading @@ -216,10 +201,8 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { return; } while (cursor.moveToNext()) { final CalendarInfo ci = new CalendarInfo(); ci.name = cursor.getString(1); ci.userId = context.getUserId(); outCalendars.add(ci); addCalendar(cursor.getLong(0), cursor.getString(1), context.getUserId(), outCalendars); } } finally { if (cursor != null) { Loading @@ -228,16 +211,29 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { } } @VisibleForTesting void addCalendar(long calendarId, String calName, int userId, List<CalendarInfo> outCalendars) { final CalendarInfo ci = new CalendarInfo(); ci.calendarId = calendarId; ci.name = calName; ci.userId = userId; if (!outCalendars.contains(ci)) { outCalendars.add(ci); } } private static String key(CalendarInfo calendar) { return key(calendar.userId, calendar.name); return key(calendar.userId, calendar.calendarId, calendar.name); } private static String key(EventInfo event) { return key(event.userId, event.calendar); return key(event.userId, event.calendarId, event.calName); } private static String key(int userId, String calendar) { return EventInfo.resolveUserId(userId) + ":" + (calendar == null ? "" : calendar); private static String key(int userId, Long calendarId, String displayName) { return EventInfo.resolveUserId(userId) + ":" + (calendarId == null ? "" : calendarId) + ":" + displayName; } private static final Comparator<CalendarInfo> CALENDAR_NAME = new Comparator<CalendarInfo>() { Loading @@ -250,5 +246,20 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { public static class CalendarInfo { public String name; public int userId; public Long calendarId; @Override public boolean equals(Object o) { if (!(o instanceof CalendarInfo)) return false; if (o == this) return true; final CalendarInfo other = (CalendarInfo) o; return Objects.equals(other.name, name) && Objects.equals(other.calendarId, calendarId); } @Override public int hashCode() { return Objects.hash(name, calendarId); } } } src/com/android/settings/notification/ZenRuleSelectionDialog.java +5 −4 Original line number Diff line number Diff line Loading @@ -36,9 +36,6 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.utils.ZenServiceListing; Loading @@ -49,6 +46,9 @@ import java.util.Comparator; import java.util.Set; import java.util.TreeSet; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; public class ZenRuleSelectionDialog extends InstrumentedDialogFragment { private static final String TAG = "ZenRuleSelectionDialog"; private static final boolean DEBUG = ZenModeSettings.DEBUG; Loading Loading @@ -170,7 +170,8 @@ public class ZenRuleSelectionDialog extends InstrumentedDialogFragment { private ZenRuleInfo defaultNewEvent() { final ZenModeConfig.EventInfo event = new ZenModeConfig.EventInfo(); event.calendar = null; // any calendar event.calName = null; // any calendar event.calendarId = null; event.reply = ZenModeConfig.EventInfo.REPLY_ANY_EXCEPT_NO; final ZenRuleInfo rt = new ZenRuleInfo(); rt.settingsAction = ZenModeEventRuleSettings.ACTION; Loading tests/robotests/src/com/android/settings/notification/ZenModeEventRuleSettingsTest.java 0 → 100644 +119 −0 Original line number Diff line number Diff line /* * 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 com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.RuntimeEnvironment.application; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowToast; import java.util.ArrayList; import java.util.List; import androidx.fragment.app.FragmentActivity; @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = SettingsShadowResources.SettingsShadowTheme.class) public class ZenModeEventRuleSettingsTest { @Mock private FragmentActivity mActivity; @Mock private Intent mIntent; @Mock private NotificationManager mNotificationManager; private TestFragment mFragment; private Context mContext; @Before public void setUp() { MockitoAnnotations.initMocks(this); ShadowApplication shadowApplication = ShadowApplication.getInstance(); shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); mContext = shadowApplication.getApplicationContext(); mFragment = spy(new TestFragment()); mFragment.onAttach(application); doReturn(mActivity).when(mFragment).getActivity(); Resources res = application.getResources(); doReturn(res).when(mFragment).getResources(); when(mActivity.getTheme()).thenReturn(res.newTheme()); when(mActivity.getIntent()).thenReturn(mIntent); when(mActivity.getResources()).thenReturn(res); when(mFragment.getContext()).thenReturn(mContext); } @Test public void onCreate_noRuleId_shouldToastAndFinishAndNoCrash() { final String expected = mContext.getString(R.string.zen_mode_rule_not_found_text); mFragment.onCreate(null); // verify the toast assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(expected); // verify the finish verify(mActivity).finish(); //should not crash } @Test public void testNoDuplicateCalendars() { List<ZenModeEventRuleSettings.CalendarInfo> calendarsList = new ArrayList<>(); mFragment.addCalendar(1234, "calName", 1, calendarsList); mFragment.addCalendar(1234, "calName", 2, calendarsList); mFragment.addCalendar(1234, "calName", 3, calendarsList); assertThat(calendarsList.size()).isEqualTo(1); } private static class TestFragment extends ZenModeEventRuleSettings { @Override protected Object getSystemService(final String name) { return null; } } } Loading
src/com/android/settings/notification/ZenModeEventRuleSettings.java +59 −48 Original line number Diff line number Diff line Loading @@ -27,11 +27,7 @@ import android.provider.Settings; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.EventInfo; import androidx.preference.DropDownPreference; import androidx.preference.Preference; import androidx.preference.Preference.OnPreferenceChangeListener; import androidx.preference.PreferenceScreen; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settingslib.core.AbstractPreferenceController; Loading @@ -40,6 +36,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Objects; import androidx.preference.DropDownPreference; import androidx.preference.Preference; import androidx.preference.Preference.OnPreferenceChangeListener; import androidx.preference.PreferenceScreen; public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { private static final String KEY_CALENDAR = "calendar"; Loading @@ -51,7 +53,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { private DropDownPreference mReply; private EventInfo mEvent; private List<CalendarInfo> mCalendars; private boolean mCreate; @Override Loading Loading @@ -91,23 +93,19 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { } private void reloadCalendar() { mCalendars = getCalendars(mContext); List<CalendarInfo> calendars = getCalendars(mContext); ArrayList<CharSequence> entries = new ArrayList<>(); ArrayList<CharSequence> values = new ArrayList<>(); entries.add(getString(R.string.zen_mode_event_rule_calendar_any)); values.add(key(0, null)); final String eventCalendar = mEvent != null ? mEvent.calendar : null; boolean found = false; for (CalendarInfo calendar : mCalendars) { values.add(key(0, null, "")); final String eventCalendar = mEvent != null ? mEvent.calName : null; for (CalendarInfo calendar : calendars) { entries.add(calendar.name); values.add(key(calendar)); if (eventCalendar != null && eventCalendar.equals(calendar.name)) { found = true; } if (eventCalendar != null && (mEvent.calendarId == null && eventCalendar.equals(calendar.name))) { mEvent.calendarId = calendar.calendarId; } if (eventCalendar != null && !found) { entries.add(eventCalendar); values.add(key(mEvent.userId, eventCalendar)); } mCalendar.setEntries(entries.toArray(new CharSequence[entries.size()])); mCalendar.setEntryValues(values.toArray(new CharSequence[values.size()])); Loading @@ -124,12 +122,10 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { public boolean onPreferenceChange(Preference preference, Object newValue) { final String calendarKey = (String) newValue; if (calendarKey.equals(key(mEvent))) return false; final int i = calendarKey.indexOf(':'); mEvent.userId = Integer.parseInt(calendarKey.substring(0, i)); mEvent.calendar = calendarKey.substring(i + 1); if (mEvent.calendar.isEmpty()) { mEvent.calendar = null; } String[] key = calendarKey.split(":", 3); mEvent.userId = Integer.parseInt(key[0]); mEvent.calendarId = key[1].equals("") ? null : Long.parseLong(key[1]); mEvent.calName = key[2].equals("") ? null : key[2]; updateRule(ZenModeConfig.toEventConditionId(mEvent)); return true; } Loading Loading @@ -172,18 +168,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { return MetricsEvent.NOTIFICATION_ZEN_MODE_EVENT_RULE; } public static CalendarInfo findCalendar(Context context, EventInfo event) { if (context == null || event == null) return null; final String eventKey = key(event); for (CalendarInfo calendar : getCalendars(context)) { if (eventKey.equals(key(calendar))) { return calendar; } } return null; } private static List<CalendarInfo> getCalendars(Context context) { private List<CalendarInfo> getCalendars(Context context) { final List<CalendarInfo> calendars = new ArrayList<>(); for (UserHandle user : UserManager.get(context).getUserProfiles()) { final Context userContext = getContextForUser(context, user); Loading @@ -203,11 +188,11 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { } } public static void addCalendars(Context context, List<CalendarInfo> outCalendars) { final String primary = "\"primary\""; final String[] projection = { Calendars._ID, Calendars.CALENDAR_DISPLAY_NAME, "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + primary }; final String selection = primary + " = 1"; private void addCalendars(Context context, List<CalendarInfo> outCalendars) { final String[] projection = { Calendars._ID, Calendars.CALENDAR_DISPLAY_NAME }; final String selection = Calendars.CALENDAR_ACCESS_LEVEL + " >= " + Calendars.CAL_ACCESS_CONTRIBUTOR + " AND " + Calendars.SYNC_EVENTS + " = 1"; Cursor cursor = null; try { cursor = context.getContentResolver().query(Calendars.CONTENT_URI, projection, Loading @@ -216,10 +201,8 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { return; } while (cursor.moveToNext()) { final CalendarInfo ci = new CalendarInfo(); ci.name = cursor.getString(1); ci.userId = context.getUserId(); outCalendars.add(ci); addCalendar(cursor.getLong(0), cursor.getString(1), context.getUserId(), outCalendars); } } finally { if (cursor != null) { Loading @@ -228,16 +211,29 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { } } @VisibleForTesting void addCalendar(long calendarId, String calName, int userId, List<CalendarInfo> outCalendars) { final CalendarInfo ci = new CalendarInfo(); ci.calendarId = calendarId; ci.name = calName; ci.userId = userId; if (!outCalendars.contains(ci)) { outCalendars.add(ci); } } private static String key(CalendarInfo calendar) { return key(calendar.userId, calendar.name); return key(calendar.userId, calendar.calendarId, calendar.name); } private static String key(EventInfo event) { return key(event.userId, event.calendar); return key(event.userId, event.calendarId, event.calName); } private static String key(int userId, String calendar) { return EventInfo.resolveUserId(userId) + ":" + (calendar == null ? "" : calendar); private static String key(int userId, Long calendarId, String displayName) { return EventInfo.resolveUserId(userId) + ":" + (calendarId == null ? "" : calendarId) + ":" + displayName; } private static final Comparator<CalendarInfo> CALENDAR_NAME = new Comparator<CalendarInfo>() { Loading @@ -250,5 +246,20 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase { public static class CalendarInfo { public String name; public int userId; public Long calendarId; @Override public boolean equals(Object o) { if (!(o instanceof CalendarInfo)) return false; if (o == this) return true; final CalendarInfo other = (CalendarInfo) o; return Objects.equals(other.name, name) && Objects.equals(other.calendarId, calendarId); } @Override public int hashCode() { return Objects.hash(name, calendarId); } } }
src/com/android/settings/notification/ZenRuleSelectionDialog.java +5 −4 Original line number Diff line number Diff line Loading @@ -36,9 +36,6 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.utils.ZenServiceListing; Loading @@ -49,6 +46,9 @@ import java.util.Comparator; import java.util.Set; import java.util.TreeSet; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; public class ZenRuleSelectionDialog extends InstrumentedDialogFragment { private static final String TAG = "ZenRuleSelectionDialog"; private static final boolean DEBUG = ZenModeSettings.DEBUG; Loading Loading @@ -170,7 +170,8 @@ public class ZenRuleSelectionDialog extends InstrumentedDialogFragment { private ZenRuleInfo defaultNewEvent() { final ZenModeConfig.EventInfo event = new ZenModeConfig.EventInfo(); event.calendar = null; // any calendar event.calName = null; // any calendar event.calendarId = null; event.reply = ZenModeConfig.EventInfo.REPLY_ANY_EXCEPT_NO; final ZenRuleInfo rt = new ZenRuleInfo(); rt.settingsAction = ZenModeEventRuleSettings.ACTION; Loading
tests/robotests/src/com/android/settings/notification/ZenModeEventRuleSettingsTest.java 0 → 100644 +119 −0 Original line number Diff line number Diff line /* * 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 com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.RuntimeEnvironment.application; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowToast; import java.util.ArrayList; import java.util.List; import androidx.fragment.app.FragmentActivity; @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = SettingsShadowResources.SettingsShadowTheme.class) public class ZenModeEventRuleSettingsTest { @Mock private FragmentActivity mActivity; @Mock private Intent mIntent; @Mock private NotificationManager mNotificationManager; private TestFragment mFragment; private Context mContext; @Before public void setUp() { MockitoAnnotations.initMocks(this); ShadowApplication shadowApplication = ShadowApplication.getInstance(); shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); mContext = shadowApplication.getApplicationContext(); mFragment = spy(new TestFragment()); mFragment.onAttach(application); doReturn(mActivity).when(mFragment).getActivity(); Resources res = application.getResources(); doReturn(res).when(mFragment).getResources(); when(mActivity.getTheme()).thenReturn(res.newTheme()); when(mActivity.getIntent()).thenReturn(mIntent); when(mActivity.getResources()).thenReturn(res); when(mFragment.getContext()).thenReturn(mContext); } @Test public void onCreate_noRuleId_shouldToastAndFinishAndNoCrash() { final String expected = mContext.getString(R.string.zen_mode_rule_not_found_text); mFragment.onCreate(null); // verify the toast assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(expected); // verify the finish verify(mActivity).finish(); //should not crash } @Test public void testNoDuplicateCalendars() { List<ZenModeEventRuleSettings.CalendarInfo> calendarsList = new ArrayList<>(); mFragment.addCalendar(1234, "calName", 1, calendarsList); mFragment.addCalendar(1234, "calName", 2, calendarsList); mFragment.addCalendar(1234, "calName", 3, calendarsList); assertThat(calendarsList.size()).isEqualTo(1); } private static class TestFragment extends ZenModeEventRuleSettings { @Override protected Object getSystemService(final String name) { return null; } } }