Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e80322d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Allow DND events rule to choose custom calendars"

parents 0cd4db47 833119a4
Loading
Loading
Loading
Loading
+59 −48
Original line number Diff line number Diff line
@@ -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,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()]));
@@ -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);
        }
    }
}
+5 −4
Original line number Diff line number Diff line
@@ -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;
+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;
        }
    }
}