Skip to content

Commit

Permalink
Sched: Enable New Timezone Handling Code
Browse files Browse the repository at this point in the history
Copied from Anki at commit 131d37dca52c29033432e0149052093ab1c79461
Except one line in Collection which accepts data if server == true.

https://github.com/ankitects/anki/blob/131d37dca52c29033432e0149052093ab1c79461/pylib/anki/collection.py
https://github.com/ankitects/anki/blob/131d37dca52c29033432e0149052093ab1c79461/pylib/anki/schedv2.py

* Bumps SYNC_VERSION to 10 if using Rust
* Add local_minutes_west and sched_timing_today to Backend
* Add "New timezone handling" preference
* Set "localOffset" preference if using SchedV2 under Rust
* Fix SchedV2:_updateCutoff to better handle timezones

We will calculate this information in the Rust in V2 of the Rust Conversion

We can't do this yet as we're still on V11 of the database schema

Fixes 5805
  • Loading branch information
david-allison committed Jan 28, 2021
1 parent 7459828 commit c12a438
Show file tree
Hide file tree
Showing 15 changed files with 323 additions and 12 deletions.
29 changes: 29 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
import com.ichi2.compat.CompatHelper;
import com.ichi2.libanki.Collection;
import com.ichi2.libanki.Utils;
import com.ichi2.libanki.backend.exception.BackendNotSupportedException;
import com.ichi2.libanki.sched.AbstractSched;
import com.ichi2.preferences.NumberRangePreference;
import com.ichi2.themes.Themes;
import com.ichi2.ui.AppCompatPreferenceActivity;
Expand Down Expand Up @@ -586,6 +588,14 @@ private void initPreference(android.preference.Preference pref) {
Calendar calendar = col.crtGregorianCalendar();
((SeekBarPreference)pref).setValue(calendar.get(Calendar.HOUR_OF_DAY));
break;
case "newTimezoneHandling":
android.preference.CheckBoxPreference checkBox = (android.preference.CheckBoxPreference) pref;
checkBox.setChecked(col.getSched()._new_timezone_enabled());
if (col.schedVer() <= 1 || !col.isUsingRustBackend()) {
Timber.d("Disabled 'newTimezoneHandling' box");
checkBox.setEnabled(false);
}
break;
case "schedVer":
((android.preference.CheckBoxPreference)pref).setChecked(conf.optInt("schedVer", 1) == 2);
}
Expand Down Expand Up @@ -722,6 +732,25 @@ private void updatePreference(SharedPreferences prefs, String key, PreferenceCon
pm.setComponentEnabledSetting(providerName, state, PackageManager.DONT_KILL_APP);
break;
}
case "newTimezoneHandling" : {
if (getCol().schedVer() != 1 && getCol().isUsingRustBackend()) {
AbstractSched sched = getCol().getSched();
boolean was_enabled = sched._new_timezone_enabled();
boolean is_enabled = ((android.preference.CheckBoxPreference) pref).isChecked();
if (was_enabled != is_enabled) {
if (is_enabled) {
try {
sched.set_creation_offset();
} catch (BackendNotSupportedException e) {
throw e.alreadyUsingRustBackend();
}
} else {
sched.clear_creation_offset();
}
}
}
break;
}
case "schedVer": {
boolean wantNew = ((android.preference.CheckBoxPreference) pref).isChecked();
boolean haveNew = getCol().schedVer() == 2;
Expand Down
9 changes: 8 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/libanki/Collection.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabaseLockedException;
import android.os.Build;
import android.text.TextUtils;
import android.util.Pair;

Expand All @@ -37,6 +36,7 @@
import com.ichi2.libanki.backend.DroidBackend;
import com.ichi2.async.ProgressSender;
import com.ichi2.async.TaskManager;
import com.ichi2.libanki.backend.exception.BackendNotSupportedException;
import com.ichi2.libanki.exception.NoSuchDeckException;
import com.ichi2.libanki.exception.UnknownDatabaseVersionException;
import com.ichi2.libanki.hooks.ChessFilter;
Expand Down Expand Up @@ -246,6 +246,13 @@ private void _loadScheduler() {
mSched = new Sched(this);
} else if (ver == 2) {
mSched = new SchedV2(this);
if (!getServer() && isUsingRustBackend()) {
try {
getConf().put("localOffset", getSched()._current_timezone_offset());
} catch (BackendNotSupportedException e) {
throw e.alreadyUsingRustBackend();
}
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/libanki/Consts.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
****************************************************************************************/

package com.ichi2.libanki;
import net.ankiweb.rsdroid.RustCleanup;

import java.lang.annotation.Retention;

import androidx.annotation.IntDef;
Expand Down Expand Up @@ -124,7 +126,9 @@ public class Consts {
public static final int SYNC_ZIP_COUNT = 25;
public static final String SYNC_BASE = "https://sync%s.ankiweb.net/";
public static final Integer DEFAULT_HOST_NUM = null;
public static final int SYNC_VER = 9;
/* Note: 10 if using Rust backend, 9 if using Java. Set in BackendFactory.getInstance */
@RustCleanup("Use 10")
public static int SYNC_VER = 9;

public static final String HELP_SITE = "http://ankisrs.net/docs/manual.html";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package com.ichi2.libanki.backend;

import com.ichi2.libanki.DB;
import com.ichi2.libanki.backend.exception.BackendNotSupportedException;
import com.ichi2.libanki.backend.model.SchedTimingToday;

import androidx.annotation.VisibleForTesting;

Expand All @@ -34,4 +36,27 @@ public interface DroidBackend {

@VisibleForTesting(otherwise = VisibleForTesting.NONE)
void debugEnsureNoOpenPointers();

/**
* Obtains Timing information for the current day.
*
* @param createdSecs A UNIX timestamp of the collection creation time
* @param createdMinsWest The offset west of UTC at the time of creation (eg UTC+10 hours is -600)
* @param nowSecs timestamp of the current time
* @param nowMinsWest The current offset west of UTC
* @param rolloverHour The hour of the day the rollover happens (eg 4 for 4am)
* @return Timing information for the current day. See {@link SchedTimingToday}.
*/
SchedTimingToday sched_timing_today(long createdSecs, int createdMinsWest, long nowSecs, int nowMinsWest, int rolloverHour) throws BackendNotSupportedException;

/**
* For the given timestamp, return minutes west of UTC in the local timezone.<br/><br/>
*
* eg, Australia at +10 hours is -600.<br/>
* Includes the daylight savings offset if applicable.
*
* @param timestampSeconds The timestamp in seconds
* @return minutes west of UTC in the local timezone
*/
int local_minutes_west(long timestampSeconds) throws BackendNotSupportedException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package com.ichi2.libanki.backend;

import com.ichi2.anki.AnkiDroidApp;
import com.ichi2.libanki.Consts;

import net.ankiweb.rsdroid.BackendFactory;
import net.ankiweb.rsdroid.RustBackendFailedException;
import net.ankiweb.rsdroid.RustCleanup;

import androidx.annotation.Nullable;
import timber.log.Timber;
Expand All @@ -36,6 +38,7 @@ private DroidBackendFactory() {
* Obtains an instance of a {@link DroidBackend}.
* Each call to this method will generate a separate instance which can handle a new Anki collection
*/
@RustCleanup("Change back to a constant SYNC_VER")
public static DroidBackend getInstance(boolean useBackend) {

BackendFactory backendFactory = null;
Expand All @@ -47,7 +50,11 @@ public static DroidBackend getInstance(boolean useBackend) {
AnkiDroidApp.sendExceptionReport(e, "DroidBackendFactory::getInstance");
}
}
return getInstance(backendFactory);

DroidBackend instance = getInstance(backendFactory);
// Update the Sync version if we can load the Rust
Consts.SYNC_VER = backendFactory == null ? 9 : 10;
return instance;
}

private static DroidBackend getInstance(@Nullable BackendFactory backendFactory) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package com.ichi2.libanki.backend;

import com.ichi2.libanki.DB;
import com.ichi2.libanki.backend.exception.BackendNotSupportedException;
import com.ichi2.libanki.backend.model.SchedTimingToday;

import net.ankiweb.rsdroid.RustCleanup;

Expand Down Expand Up @@ -56,4 +58,16 @@ public boolean isUsingRustBackend() {
public void debugEnsureNoOpenPointers() {
// no-op
}


@Override
public SchedTimingToday sched_timing_today(long createdSecs, int createdMinsWest, long nowSecs, int nowMinsWest, int rolloverHour) throws BackendNotSupportedException {
throw new BackendNotSupportedException();
}


@Override
public int local_minutes_west(long timestampSeconds) throws BackendNotSupportedException {
throw new BackendNotSupportedException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
package com.ichi2.libanki.backend;

import com.ichi2.libanki.DB;
import com.ichi2.libanki.backend.model.SchedTimingToday;
import com.ichi2.libanki.backend.model.SchedTimingTodayProto;

import net.ankiweb.rsdroid.BackendFactory;
import net.ankiweb.rsdroid.BackendUtils;

import BackendProto.AdBackend;
import timber.log.Timber;

/** The Backend in Rust */
public class RustDroidBackend implements DroidBackend {
Expand Down Expand Up @@ -69,4 +69,16 @@ public void debugEnsureNoOpenPointers() {
throw new IllegalStateException("Contained unclosed sequence numbers: " + numbers);
}
}

@Override
public SchedTimingToday sched_timing_today(long createdSecs, int createdMinsWest, long nowSecs, int nowMinsWest, int rolloverHour) {
AdBackend.SchedTimingTodayOut2 res = mBackend.getBackend().schedTimingTodayLegacy(createdSecs, createdMinsWest, nowSecs, nowMinsWest, rolloverHour);
return new SchedTimingTodayProto(res);
}


@Override
public int local_minutes_west(long timestampSeconds) {
return mBackend.getBackend().localMinutesWest(timestampSeconds).getVal();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2021 David Allison <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.ichi2.libanki.backend.exception;

import net.ankiweb.rsdroid.RustCleanup;

@RustCleanup("All of these should be removed when JavaBackend is removed")
public class BackendNotSupportedException extends Exception {
public RuntimeException alreadyUsingRustBackend() {
return new RuntimeException("A BackendNotSupportedException should not occur when using Rust backend", this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2021 David Allison <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.ichi2.libanki.backend.model;

public interface SchedTimingToday {
/** The number of days that have passed since the collection was created.<br/>
* uint32 upstream */
int days_elapsed();
/**
* Timestamp of the next day rollover.<br/>
* int64 upstream */
long next_day_at();
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2021 David Allison <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.ichi2.libanki.backend.model;

import BackendProto.AdBackend;

/**
* Adapter for SchedTimingTodayOut2 result from Rust
*/
public class SchedTimingTodayProto implements SchedTimingToday {

private final AdBackend.SchedTimingTodayOut2 mData;

public SchedTimingTodayProto(AdBackend.SchedTimingTodayOut2 data) {
mData = data;
}


@Override
public int days_elapsed() {
return mData.getDaysElapsed();
}


@Override
public long next_day_at() {
return mData.getNextDayAt();
}
}
14 changes: 12 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/libanki/sched/AbstractSched.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.ichi2.libanki.Deck;
import com.ichi2.libanki.DeckConfig;
import com.ichi2.libanki.Collection;
import com.ichi2.libanki.backend.exception.BackendNotSupportedException;

import java.lang.ref.WeakReference;
import java.util.List;
Expand All @@ -23,8 +24,6 @@
import androidx.annotation.VisibleForTesting;
import timber.log.Timber;

import androidx.annotation.NonNull;

/**
* In this documentation, I will call "normal use" the fact that between two successive calls to `getCard`, either the
* result of the first `getCard` is sent to `answerCard` or the scheduler is reset (through `reset` or `defer
Expand Down Expand Up @@ -518,4 +517,15 @@ protected static void leech(@NonNull Card card, @Nullable Activity activity) {
* @return The number of revlog in the collection
*/
public abstract int logCount();

public abstract int _current_timezone_offset() throws BackendNotSupportedException;

public abstract boolean _new_timezone_enabled();
/**
* Save the UTC west offset at the time of creation into the DB.
* Once stored, this activates the new timezone handling code.
*/
public abstract void set_creation_offset() throws BackendNotSupportedException;

public abstract void clear_creation_offset();
}
Loading

0 comments on commit c12a438

Please sign in to comment.