Merge "Allow DND events rule to choose custom calendars"
This commit is contained in:
committed by
Android (Google) Code Review
commit
1e80322df8
@@ -27,11 +27,7 @@ import android.provider.Settings;
|
|||||||
import android.service.notification.ZenModeConfig;
|
import android.service.notification.ZenModeConfig;
|
||||||
import android.service.notification.ZenModeConfig.EventInfo;
|
import android.service.notification.ZenModeConfig.EventInfo;
|
||||||
|
|
||||||
import androidx.preference.DropDownPreference;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import androidx.preference.Preference;
|
|
||||||
import androidx.preference.Preference.OnPreferenceChangeListener;
|
|
||||||
import androidx.preference.PreferenceScreen;
|
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
@@ -40,6 +36,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
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 {
|
public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
|
||||||
private static final String KEY_CALENDAR = "calendar";
|
private static final String KEY_CALENDAR = "calendar";
|
||||||
@@ -51,7 +53,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
|
|||||||
private DropDownPreference mReply;
|
private DropDownPreference mReply;
|
||||||
|
|
||||||
private EventInfo mEvent;
|
private EventInfo mEvent;
|
||||||
private List<CalendarInfo> mCalendars;
|
|
||||||
private boolean mCreate;
|
private boolean mCreate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,24 +93,20 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void reloadCalendar() {
|
private void reloadCalendar() {
|
||||||
mCalendars = getCalendars(mContext);
|
List<CalendarInfo> calendars = getCalendars(mContext);
|
||||||
ArrayList<CharSequence> entries = new ArrayList<>();
|
ArrayList<CharSequence> entries = new ArrayList<>();
|
||||||
ArrayList<CharSequence> values = new ArrayList<>();
|
ArrayList<CharSequence> values = new ArrayList<>();
|
||||||
entries.add(getString(R.string.zen_mode_event_rule_calendar_any));
|
entries.add(getString(R.string.zen_mode_event_rule_calendar_any));
|
||||||
values.add(key(0, null));
|
values.add(key(0, null, ""));
|
||||||
final String eventCalendar = mEvent != null ? mEvent.calendar : null;
|
final String eventCalendar = mEvent != null ? mEvent.calName : null;
|
||||||
boolean found = false;
|
for (CalendarInfo calendar : calendars) {
|
||||||
for (CalendarInfo calendar : mCalendars) {
|
|
||||||
entries.add(calendar.name);
|
entries.add(calendar.name);
|
||||||
values.add(key(calendar));
|
values.add(key(calendar));
|
||||||
if (eventCalendar != null && eventCalendar.equals(calendar.name)) {
|
if (eventCalendar != null && (mEvent.calendarId == null
|
||||||
found = true;
|
&& 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.setEntries(entries.toArray(new CharSequence[entries.size()]));
|
||||||
mCalendar.setEntryValues(values.toArray(new CharSequence[values.size()]));
|
mCalendar.setEntryValues(values.toArray(new CharSequence[values.size()]));
|
||||||
}
|
}
|
||||||
@@ -124,12 +122,10 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
|
|||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
final String calendarKey = (String) newValue;
|
final String calendarKey = (String) newValue;
|
||||||
if (calendarKey.equals(key(mEvent))) return false;
|
if (calendarKey.equals(key(mEvent))) return false;
|
||||||
final int i = calendarKey.indexOf(':');
|
String[] key = calendarKey.split(":", 3);
|
||||||
mEvent.userId = Integer.parseInt(calendarKey.substring(0, i));
|
mEvent.userId = Integer.parseInt(key[0]);
|
||||||
mEvent.calendar = calendarKey.substring(i + 1);
|
mEvent.calendarId = key[1].equals("") ? null : Long.parseLong(key[1]);
|
||||||
if (mEvent.calendar.isEmpty()) {
|
mEvent.calName = key[2].equals("") ? null : key[2];
|
||||||
mEvent.calendar = null;
|
|
||||||
}
|
|
||||||
updateRule(ZenModeConfig.toEventConditionId(mEvent));
|
updateRule(ZenModeConfig.toEventConditionId(mEvent));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -172,18 +168,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
|
|||||||
return MetricsEvent.NOTIFICATION_ZEN_MODE_EVENT_RULE;
|
return MetricsEvent.NOTIFICATION_ZEN_MODE_EVENT_RULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CalendarInfo findCalendar(Context context, EventInfo event) {
|
private List<CalendarInfo> getCalendars(Context context) {
|
||||||
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) {
|
|
||||||
final List<CalendarInfo> calendars = new ArrayList<>();
|
final List<CalendarInfo> calendars = new ArrayList<>();
|
||||||
for (UserHandle user : UserManager.get(context).getUserProfiles()) {
|
for (UserHandle user : UserManager.get(context).getUserProfiles()) {
|
||||||
final Context userContext = getContextForUser(context, user);
|
final Context userContext = getContextForUser(context, user);
|
||||||
@@ -203,11 +188,11 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addCalendars(Context context, List<CalendarInfo> outCalendars) {
|
private void addCalendars(Context context, List<CalendarInfo> outCalendars) {
|
||||||
final String primary = "\"primary\"";
|
final String[] projection = { Calendars._ID, Calendars.CALENDAR_DISPLAY_NAME };
|
||||||
final String[] projection = { Calendars._ID, Calendars.CALENDAR_DISPLAY_NAME,
|
final String selection = Calendars.CALENDAR_ACCESS_LEVEL + " >= "
|
||||||
"(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + primary };
|
+ Calendars.CAL_ACCESS_CONTRIBUTOR
|
||||||
final String selection = primary + " = 1";
|
+ " AND " + Calendars.SYNC_EVENTS + " = 1";
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
try {
|
try {
|
||||||
cursor = context.getContentResolver().query(Calendars.CONTENT_URI, projection,
|
cursor = context.getContentResolver().query(Calendars.CONTENT_URI, projection,
|
||||||
@@ -216,10 +201,8 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
final CalendarInfo ci = new CalendarInfo();
|
addCalendar(cursor.getLong(0), cursor.getString(1),
|
||||||
ci.name = cursor.getString(1);
|
context.getUserId(), outCalendars);
|
||||||
ci.userId = context.getUserId();
|
|
||||||
outCalendars.add(ci);
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
@@ -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) {
|
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) {
|
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) {
|
private static String key(int userId, Long calendarId, String displayName) {
|
||||||
return EventInfo.resolveUserId(userId) + ":" + (calendar == null ? "" : calendar);
|
return EventInfo.resolveUserId(userId) + ":" + (calendarId == null ? "" : calendarId)
|
||||||
|
+ ":" + displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Comparator<CalendarInfo> CALENDAR_NAME = new Comparator<CalendarInfo>() {
|
private static final Comparator<CalendarInfo> CALENDAR_NAME = new Comparator<CalendarInfo>() {
|
||||||
@@ -250,5 +246,20 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
|
|||||||
public static class CalendarInfo {
|
public static class CalendarInfo {
|
||||||
public String name;
|
public String name;
|
||||||
public int userId;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,9 +36,6 @@ import android.widget.ImageView;
|
|||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
import com.android.settings.utils.ZenServiceListing;
|
import com.android.settings.utils.ZenServiceListing;
|
||||||
@@ -49,6 +46,9 @@ import java.util.Comparator;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
|
public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
|
||||||
private static final String TAG = "ZenRuleSelectionDialog";
|
private static final String TAG = "ZenRuleSelectionDialog";
|
||||||
private static final boolean DEBUG = ZenModeSettings.DEBUG;
|
private static final boolean DEBUG = ZenModeSettings.DEBUG;
|
||||||
@@ -170,7 +170,8 @@ public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
|
|||||||
|
|
||||||
private ZenRuleInfo defaultNewEvent() {
|
private ZenRuleInfo defaultNewEvent() {
|
||||||
final ZenModeConfig.EventInfo event = new ZenModeConfig.EventInfo();
|
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;
|
event.reply = ZenModeConfig.EventInfo.REPLY_ANY_EXCEPT_NO;
|
||||||
final ZenRuleInfo rt = new ZenRuleInfo();
|
final ZenRuleInfo rt = new ZenRuleInfo();
|
||||||
rt.settingsAction = ZenModeEventRuleSettings.ACTION;
|
rt.settingsAction = ZenModeEventRuleSettings.ACTION;
|
||||||
|
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user