Skip to content

Commit

Permalink
Merge pull request orgzly-revived#244 from amberin/api-31-alarms-and-…
Browse files Browse the repository at this point in the history
…reminders-permission

Handle the SCHEDULE_EXACT_ALARM permission
  • Loading branch information
amberin authored May 10, 2024
2 parents 61374c5 + d19a353 commit a4a8e72
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 34 deletions.
17 changes: 10 additions & 7 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ on:
jobs:
test:
runs-on: ubuntu-latest
# TODO: Use strategy.matrix and always run on lowest and highest supported API
strategy:
matrix:
# TODO: Run on lowest and highest supported API
api-level: [29, 34]
steps:
- name: checkout
uses: actions/checkout@v4
Expand All @@ -29,7 +32,7 @@ jobs:
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Restore/create Gradle cache
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: AVD cache
Expand All @@ -39,14 +42,14 @@ jobs:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-29
key: avd-${{ matrix.api-level }}
save-always: true

- name: create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 29
api-level: ${{ matrix.api-level }}
arch: x86_64
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
Expand All @@ -62,7 +65,7 @@ jobs:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-29
key: avd-${{ matrix.api-level }}

- name: Add Dropbox API credentials
shell: bash
Expand All @@ -73,10 +76,10 @@ jobs:
- name: Run tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 29
api-level: ${{ matrix.api-level }}
arch: x86_64
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -metrics-collection
disable-animations: true
disable-spellchecker: true
profile: Nexus 6
Expand Down
9 changes: 8 additions & 1 deletion app/src/androidTest/java/com/orgzly/android/OrgzlyTest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.orgzly.android;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import android.Manifest;
import android.app.Activity;
import android.app.UiAutomation;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
Expand All @@ -17,6 +20,7 @@
import com.orgzly.android.repos.RepoFactory;
import com.orgzly.android.util.UserTimeFormatter;
import com.orgzly.org.datetime.OrgDateTime;
import com.orgzly.test.BuildConfig;

import org.junit.After;
import org.junit.Before;
Expand Down Expand Up @@ -56,9 +60,12 @@ public class OrgzlyTest {
public GrantPermissionRule grantPermissionRule;

public OrgzlyTest() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
this.grantPermissionRule =
GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
} else {
getInstrumentation().getUiAutomation().grantRuntimePermission(App.getProcessName(),
Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(App.getProcessName(),
Expand Down
4 changes: 4 additions & 0 deletions app/src/androidTest/java/com/orgzly/android/RetryTestRule.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.orgzly.android

import android.util.Log
import org.junit.AssumptionViolatedException
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
Expand Down Expand Up @@ -29,6 +30,9 @@ class RetryTestRule(val retryCount: Int = 3) : TestRule {
return
} catch (t: Throwable) {
caughtThrowable = t
if (caughtThrowable is AssumptionViolatedException) {
throw caughtThrowable
}
Log.e(TAG, description.displayName + ": run " + (i + 1) + " failed")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import com.orgzly.R;
import com.orgzly.android.OrgzlyTest;
import com.orgzly.android.espresso.util.EspressoUtils;
import com.orgzly.android.prefs.AppPreferences;
import com.orgzly.android.ui.main.MainActivity;

Expand Down Expand Up @@ -163,6 +164,7 @@ public void testRangeTaskMarkedDone() {

@Test
public void testMoveTaskWithRepeaterToTomorrow() {
EspressoUtils.grantAlarmsAndRemindersPermission();
DateTime tomorrow = DateTime.now().withTimeAtStartOfDay().plusDays(1);
scenario = defaultSetUp();
searchForTextCloseKeyboard(".it.done ad.7");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

import com.orgzly.R;
import com.orgzly.android.OrgzlyTest;
import com.orgzly.android.RetryTestRule;
import com.orgzly.android.ui.main.MainActivity;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.Rule;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.Espresso.pressBack;
Expand All @@ -34,6 +36,9 @@ public class CreatedAtPropertyTest extends OrgzlyTest {

private ActivityScenario<MainActivity> scenario;

@Rule
public RetryTestRule mRetryTestRule = new RetryTestRule();

@Before
public void setUp() throws Exception {
super.setUp();
Expand Down
20 changes: 10 additions & 10 deletions app/src/androidTest/java/com/orgzly/android/espresso/MiscTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.matchesPattern;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertTrue;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.SystemClock;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.DatePicker;
import android.widget.TimePicker;
Expand All @@ -51,6 +51,7 @@
import com.orgzly.android.OrgzlyTest;
import com.orgzly.android.RetryTestRule;
import com.orgzly.android.db.entity.NotePosition;
import com.orgzly.android.espresso.util.EspressoUtils;
import com.orgzly.android.repos.RepoType;
import com.orgzly.android.ui.main.MainActivity;
import com.orgzly.android.ui.repos.ReposActivity;
Expand All @@ -59,15 +60,12 @@
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;

import java.util.Calendar;
import java.util.GregorianCalendar;

public class MiscTest extends OrgzlyTest {

@Rule
public TestRule mRetryTestRule = new RetryTestRule();
public RetryTestRule mRetryTestRule = new RetryTestRule();

@Test
public void testLftRgt() {
Expand Down Expand Up @@ -191,6 +189,7 @@ public void testSchedulingMultipleNotes() {
"*** DONE Note #5.\n" +
"CLOSED: [2014-06-03 Tue 13:34]\n" +
"");
EspressoUtils.grantAlarmsAndRemindersPermission();
try (ActivityScenario<MainActivity> ignored = ActivityScenario.launch(MainActivity.class)) {
onView(allOf(withText("book-name"), isDisplayed())).perform(click());

Expand Down Expand Up @@ -246,6 +245,7 @@ public void testNewBookDialogShouldSurviveScreenRotation() {
scenario.onActivity(activity ->
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT));

SystemClock.sleep(1000);
onView(withId(R.id.dialog_new_book_container)).check(matches(isDisplayed()));
onView(withId(R.id.dialog_input)).perform(replaceTextCloseKeyboard("notebook"));
onView(withText(R.string.create)).perform(click());
Expand All @@ -272,6 +272,7 @@ public void testBookTitleMustBeDisplayedWhenOpeningBookFromDrawer() {

@Test
public void testTimestampDialogTimeButtonValueWhenToggling() {
EspressoUtils.grantAlarmsAndRemindersPermission();
testUtils.setupBook("book-name", "Sample book used for tests\n" +
"* TODO Note #1.\n" +
"SCHEDULED: <2015-01-18 04:05 +6d>\n" +
Expand All @@ -282,15 +283,14 @@ public void testTimestampDialogTimeButtonValueWhenToggling() {

onNoteInBook(1).perform(click());

Calendar cal = new GregorianCalendar(2015, 0, 18, 4, 5);
String s = DateFormat.getTimeFormat(context).format(cal.getTime());
String regex = "4:05\\sAM";

onView(withId(R.id.scheduled_button)).perform(click());
onView(withId(R.id.time_picker_button)).check(matches(withText(containsString(s))));
onView(withId(R.id.time_picker_button)).check(matches(withText(matchesPattern(regex))));
onView(withId(R.id.time_used_checkbox)).perform(scroll(), click());
onView(withId(R.id.time_picker_button)).check(matches(withText(containsString(s))));
onView(withId(R.id.time_picker_button)).check(matches(withText(matchesPattern(regex))));
onView(withId(R.id.time_used_checkbox)).perform(click());
onView(withId(R.id.time_picker_button)).check(matches(withText(containsString(s))));
onView(withId(R.id.time_picker_button)).check(matches(withText(matchesPattern(regex))));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static com.orgzly.android.espresso.util.EspressoUtils.contextualToolbarOverflowMenu;
import static com.orgzly.android.espresso.util.EspressoUtils.grantAlarmsAndRemindersPermission;
import static com.orgzly.android.espresso.util.EspressoUtils.onActionItemClick;
import static com.orgzly.android.espresso.util.EspressoUtils.onBook;
import static com.orgzly.android.espresso.util.EspressoUtils.onNoteInBook;
Expand Down Expand Up @@ -256,6 +257,7 @@ public void testClickingNote() {
@Test
public void testSchedulingNote() {
defaultSetUp();
grantAlarmsAndRemindersPermission();

onView(withId(R.id.drawer_layout)).perform(open());
onView(withText("Scheduled")).perform(click());
Expand All @@ -266,6 +268,7 @@ public void testSchedulingNote() {
onView(withId(R.id.date_picker_button)).perform(click());
onView(withClassName(equalTo(DatePicker.class.getName()))).perform(setDate(2014, 4, 1));
onView(withText(android.R.string.ok)).perform(click());
SystemClock.sleep(500);
onView(isRoot()).perform(waitId(R.id.time_picker_button, 5000));
onView(withId(R.id.time_picker_button)).perform(scroll(), click());
onView(withClassName(equalTo(TimePicker.class.getName()))).perform(setTime(9, 15));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static com.orgzly.android.espresso.util.EspressoUtils.contextualToolbarOverflowMenu;
import static com.orgzly.android.espresso.util.EspressoUtils.onActionItemClick;
import static com.orgzly.android.espresso.util.EspressoUtils.onSavedSearch;
import static com.orgzly.android.espresso.util.EspressoUtils.onSnackbar;
import static com.orgzly.android.espresso.util.EspressoUtils.replaceTextCloseKeyboard;
import static com.orgzly.android.espresso.util.EspressoUtils.waitId;
import static org.hamcrest.Matchers.allOf;

import android.app.Activity;
Expand Down Expand Up @@ -75,9 +77,8 @@ public void testNewSameNameSavedSearch() {
public void testUpdateSameNameSavedSearch() {
onView(withId(R.id.fragment_saved_searches_flipper)).check(matches(isDisplayed()));
onSavedSearch(0).perform(click());
SystemClock.sleep(500);
onView(withId(R.id.fragment_saved_search_flipper)).check(matches(isDisplayed()));
onView(withId(R.id.fragment_saved_search_query)).perform(typeText(" edited"));
onView(withId(R.id.fragment_saved_search_query)).perform(replaceTextCloseKeyboard(" edited"));
onView(withId(R.id.done)).perform(click()); // Saved search done
onView(withId(R.id.fragment_saved_searches_flipper)).check(matches(isDisplayed()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import com.orgzly.BuildConfig;
import com.orgzly.R;
import com.orgzly.android.OrgzlyTest;
import com.orgzly.android.RetryTestRule;
import com.orgzly.android.db.entity.Repo;
import com.orgzly.android.repos.RepoType;
import com.orgzly.android.sync.BookSyncStatus;
Expand All @@ -47,17 +48,18 @@
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;

import java.io.IOException;

@SuppressWarnings("unchecked")
public class SyncingTest extends OrgzlyTest {
/**
* Utility method for starting sync using drawer button.
*/
private ActivityScenario<MainActivity> scenario;

@Rule
public RetryTestRule mRetryTestRule = new RetryTestRule();

@After
@Override
public void tearDown() throws Exception {
Expand All @@ -67,6 +69,9 @@ public void tearDown() throws Exception {
}
}

/**
* Utility method for starting sync using drawer button.
*/
private void sync() {
onView(withId(R.id.drawer_layout)).perform(open());
onView(withId(R.id.sync_button_container)).perform(click());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.Matchers.anything;

import android.content.res.Resources;
import android.os.Build;
import android.os.SystemClock;
import android.text.Spanned;
import android.text.style.ClickableSpan;
Expand All @@ -43,7 +45,6 @@
import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.espresso.util.HumanReadables;
import androidx.test.espresso.util.TreeIterables;
import androidx.test.platform.app.InstrumentationRegistry;

import com.orgzly.R;
import com.orgzly.android.ui.SpanUtils;
Expand Down Expand Up @@ -187,6 +188,7 @@ public static ViewInteraction onSavedSearch(int position) {
}

public static ViewInteraction onRecyclerViewItem(@IdRes int recyclerView, int position, @IdRes int childView) {
SystemClock.sleep(100);
onView(isRoot()).perform(waitId(recyclerView, 5000));
onView(withId(recyclerView)).perform(RecyclerViewActions.scrollToPosition(position));
return onView(new EspressoRecyclerViewMatcher(recyclerView)
Expand Down Expand Up @@ -297,7 +299,7 @@ public static void onActionItemClick(int id, int resourceId) {

// Open the overflow menu OR open the options menu,
// depending on if the device has a hardware or software overflow menu button.
openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getInstrumentation().getTargetContext());
openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());
onView(withText(resourceId)).perform(click());
}
}
Expand Down Expand Up @@ -337,7 +339,10 @@ public static ViewInteraction contextualToolbarOverflowMenu() {
}

public static void searchForTextCloseKeyboard(String str) {
SystemClock.sleep(100);
onView(isRoot()).perform(waitId(R.id.search_view, 5000));
onView(allOf(withId(R.id.search_view), isDisplayed())).perform(click());
onView(isRoot()).perform(waitId(R.id.search_src_text, 5000));
onView(withId(R.id.search_src_text)).perform(replaceText(str), pressKey(KeyEvent.KEYCODE_ENTER));
closeSoftKeyboardWithDelay();
}
Expand Down Expand Up @@ -501,4 +506,11 @@ public void perform(final UiController uiController, final View view) {
}
};
}

public static void grantAlarmsAndRemindersPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
String shellCmd = "appops set --uid com.orgzlyrevived SCHEDULE_EXACT_ALARM allow";
getInstrumentation().getUiAutomation().executeShellCommand(shellCmd);
}
}
}
3 changes: 1 addition & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

Expand Down
Loading

0 comments on commit a4a8e72

Please sign in to comment.