OSDN Git Service

Allow DND events rule to choose custom calendars
authorBeverly <beverlyt@google.com>
Fri, 5 Oct 2018 14:26:11 +0000 (10:26 -0400)
committerBeverly <beverlyt@google.com>
Fri, 5 Oct 2018 18:58:00 +0000 (14:58 -0400)
For the System DND Events rule, users can now select
custom calendars they are contributors to that are
synced to their device.

Test: atest /extra/master/packages/apps/Settings/tests/robotests/src/com/android/settings/notification/ZenModeEventRuleSettingsTest.java
Bug: 113368047
Change-Id: I1b81c528655b8f68867d881cee8125aa2b027eaa

src/com/android/settings/notification/ZenModeEventRuleSettings.java
src/com/android/settings/notification/ZenRuleSelectionDialog.java
tests/robotests/src/com/android/settings/notification/ZenModeEventRuleSettingsTest.java [new file with mode: 0644]

index e859cdd..c11a672 100644 (file)
@@ -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;
@@ -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";
@@ -51,7 +53,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
     private DropDownPreference mReply;
 
     private EventInfo mEvent;
-    private List<CalendarInfo> mCalendars;
+
     private boolean mCreate;
 
     @Override
@@ -91,24 +93,20 @@ 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()]));
     }
@@ -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;
             }
@@ -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);
@@ -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,
@@ -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) {
@@ -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>() {
@@ -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);
+        }
     }
 }
index b076dd0..abda376 100644 (file)
@@ -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;
@@ -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;
@@ -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;
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeEventRuleSettingsTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeEventRuleSettingsTest.java
new file mode 100644 (file)
index 0000000..5d8be5a
--- /dev/null
@@ -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;
+        }
+    }
+}