Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bc30c1d
Revert "Fork Update"
krmanik Jun 25, 2020
6a3339c
Update fork
krmanik Jun 26, 2020
c8181c3
Merge branch 'master' of https://github.com/ankidroid/Anki-Android
krmanik Jun 28, 2020
0d37a81
Merge branch 'master' of https://github.com/ankidroid/Anki-Android
krmanik Jun 30, 2020
6184bef
api versioning
krmanik Jun 21, 2020
7254e0b
Updated AbstractFlashcardViewer.java, 02-strings.xml
krmanik Jun 24, 2020
939e6c1
Added Vesrion Compare using Comparable
krmanik Jun 27, 2020
638512e
Added Java SemVer for JS API
krmanik Jun 28, 2020
ef8cdcb
Updated AbstractFlashcardViewer.java, 02-strings.xml
krmanik Jul 1, 2020
474b616
Updated 02-strings.xml
krmanik Jul 4, 2020
d8b7c41
Updated 02-strings.xml
krmanik Jul 4, 2020
6544a1e
Updated 02-strings.xml
krmanik Jul 4, 2020
e3571aa
Merge branch 'master' into js-api-version
krmanik Jul 4, 2020
75dc239
Updated 02-strings.xml
krmanik Jul 5, 2020
e68e5a5
Updated AbstractFlashcardViewer.java
krmanik Jul 5, 2020
fe482d7
Updated AbstractFlashcardViewer.java
krmanik Jul 5, 2020
80079d9
Handle when API not initialised
krmanik Jul 5, 2020
e2f068a
Update JS API
krmanik Jul 25, 2020
401cddc
Update js api
krmanik Jul 26, 2020
1399b90
Merge branch 'master' of https://github.com/ankidroid/Anki-Android in…
krmanik Aug 4, 2020
7204912
Update 02-strings.xml
krmanik Aug 4, 2020
793063e
Update AbstractFlashcardViewer.java
krmanik Aug 4, 2020
c055f95
init js api
krmanik Aug 5, 2020
6a2b548
Updated
krmanik Aug 6, 2020
c0ff6c3
Updated
krmanik Aug 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions AnkiDroid/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -266,4 +266,7 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'org.smali:dexlib2:2.4.0'

//For AnkiDroid JS API Versioning
implementation "com.github.zafarkhaja:java-semver:0.9.0"
}
159 changes: 158 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

import androidx.annotation.CheckResult;
import androidx.annotation.IdRes;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
Expand Down Expand Up @@ -84,6 +85,8 @@

import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.util.TypefaceHelper;
import com.google.android.material.snackbar.Snackbar;
import com.google.gson.Gson;
import com.ichi2.anim.ActivityTransitionAnimation;
import com.ichi2.anim.ViewAnimation;
import com.ichi2.anki.dialogs.TagsDialog;
Expand Down Expand Up @@ -123,9 +126,12 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
Expand All @@ -142,6 +148,8 @@
import static com.ichi2.anki.reviewer.CardMarker.*;
import static com.ichi2.async.CollectionTask.TASK_TYPE.*;

import com.github.zafarkhaja.semver.Version;

@SuppressWarnings({"PMD.AvoidThrowingRawExceptionTypes","PMD.FieldDeclarationsShouldBeAtStartOfClass"})
public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity implements ReviewerUi, CommandProcessor {

Expand Down Expand Up @@ -189,6 +197,20 @@ public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity i

// ETA
private int eta;
// JavaScript Versioning
protected String mCardSuppliedApiVersion = "";
Comment thread
david-allison marked this conversation as resolved.
Outdated
protected String mCardSuppliedDeveloperContact = "";
Comment thread
david-allison marked this conversation as resolved.
Outdated
Comment thread
david-allison marked this conversation as resolved.
Outdated

private static final String sCurrentJsApiVersion = "0.0.1";
private static final String sMinimumJsApiVersion = "0.0.1";

// JS API ERROR CODE
private static final int ankiJsErrorCodeDefault = 0;
private static final int ankiJsErrorCodeMarkCard = 1;
private static final int ankiJsErrorCodeFlagCard = 2;

// JS api list enable/disable status
private HashMap<String, Boolean> mJsApiListMap = new HashMap<String, Boolean>();
Comment thread
david-allison marked this conversation as resolved.

private boolean isInFullscreen;

Expand Down Expand Up @@ -3189,11 +3211,28 @@ private boolean filterUrl(String url) {
}
// mark card using javascript
if (url.startsWith("signal:mark_current_card")) {
executeCommand(COMMAND_MARK);
if (isAnkiApiNull("markCard")) {
showDeveloperContact(ankiJsErrorCodeDefault);
return true;
} else if (mJsApiListMap.get("markCard")) {
Comment thread
david-allison marked this conversation as resolved.
executeCommand(COMMAND_MARK);
} else {
// see 02-string.xml
showDeveloperContact(ankiJsErrorCodeMarkCard);
}
return true;
}
// flag card (blue, green, orange, red) using javascript from AnkiDroid webview
if (url.startsWith("signal:flag_")) {
if (isAnkiApiNull("toggleFlag")) {
showDeveloperContact(ankiJsErrorCodeDefault);
return true;
} else if (!mJsApiListMap.get("toggleFlag")) {
// see 02-string.xml
showDeveloperContact(ankiJsErrorCodeFlagCard);
return true;
}

String mFlag = url.replaceFirst("signal:flag_","");
switch (mFlag) {
case "none": executeCommand(COMMAND_UNSET_FLAG);
Expand Down Expand Up @@ -3450,6 +3489,81 @@ void handleUrlFromJavascript(String url) {
}
}

// Check if value null
private boolean isAnkiApiNull(String api) {
if (mJsApiListMap.get(api) == null) {
Comment thread
david-allison marked this conversation as resolved.
Outdated
return true;
}
return false;
}

/*
* see 02-strings.xml
* Show Error code when mark card or flag card unsupported
* 1 - mark card
* 2 - flag card
*
* show developer contact if js api used in card is deprecated
*/
private void showDeveloperContact(int errorCode) {
Comment thread
david-allison marked this conversation as resolved.
String errorMsg = getString(R.string.anki_js_error_code, errorCode);

View parentLayout = findViewById(android.R.id.content);
String snackbarMsg;
snackbarMsg = getString(R.string.api_version_developer_contact, mCardSuppliedDeveloperContact, errorMsg);

Snackbar snackbar = Snackbar.make(parentLayout, snackbarMsg, Snackbar.LENGTH_LONG);
View snackbarView = snackbar.getView();
TextView snackTextView = snackbarView.findViewById(com.google.android.material.R.id.snackbar_text);
snackTextView.setTextColor(Color.WHITE);
snackTextView.setMaxLines(3);

snackbar.setActionTextColor(Color.MAGENTA)
.setAction(getString(R.string.reviewer_invalid_api_version_visit_documentation), view -> {
openUrl(Uri.parse("https://github.com/ankidroid/Anki-Android/wiki"));
});

snackbar.show();
}

/**
* Supplied api version must be equal to current api version to call mark card, toggle flag functions etc.
*/
private boolean requireApiVersion(String apiVer, String apiDevContact) {
try {

if (TextUtils.isEmpty(apiDevContact)) {
return false;
}

Version mVersionCurrent = Version.valueOf(sCurrentJsApiVersion);
Comment thread
david-allison marked this conversation as resolved.
Version mVersionSupplied = Version.valueOf(apiVer);

/*
* if api major version equals to supplied major version then return true and also check for minor version and patch version
* show toast for update and contact developer if need updates
* otherwise return false
*/
if (mVersionSupplied.equals(mVersionCurrent)) {
return true;
Comment thread
david-allison marked this conversation as resolved.
} else if (mVersionSupplied.lessThan(mVersionCurrent)) {
UIUtils.showThemedToast(AbstractFlashcardViewer.this, getString(R.string.update_js_api_version, mCardSuppliedDeveloperContact), false);

if (mVersionSupplied.greaterThanOrEqualTo(Version.valueOf(sMinimumJsApiVersion))) {
return true;
} else {
return false;
}
} else {
UIUtils.showThemedToast(AbstractFlashcardViewer.this, getString(R.string.valid_js_api_version, mCardSuppliedDeveloperContact), false);
return false;
}
} catch (Exception e) {
Timber.i(e, "requireApiVersion::exception");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Timber.i(e, "requireApiVersion::exception");
Timber.w(e, "requireApiVersion::exception");

}
return false;
}

@VisibleForTesting
void loadInitialCard() {
CollectionTask.launchCollectionTask(ANSWER_CARD, mAnswerCardHandler(false),
Expand Down Expand Up @@ -3498,6 +3612,49 @@ protected void showTagsDialog() {
*/
public class JavaScriptFunction {

private final Gson sGson = new Gson();
Comment thread
mikehardy marked this conversation as resolved.
Outdated
// list of api that can be accessed
private final String[] sApiList = {"toggleFlag", "markCard"};

// api disabled when valid api version not provided
private void disableJsApi() {
for (int i = 0; i < sApiList.length; i++) {
mJsApiListMap.put(sApiList[i], false);
}
}

// if supplied api version match then enable api
private void enableJsApi() {
for (int i = 0; i < sApiList.length; i++) {
mJsApiListMap.put(sApiList[i], true);
}
}

@JavascriptInterface
public String init(String jsonData) {
JSONObject data;
String apiStatusJson = "";

try {
data = new JSONObject(jsonData);
if (!(data == JSONObject.NULL)) {
mCardSuppliedApiVersion = data.optString("version", "");
mCardSuppliedDeveloperContact = data.optString("developer", "");

if (requireApiVersion(mCardSuppliedApiVersion, mCardSuppliedDeveloperContact)) {
enableJsApi();
} else {
disableJsApi();
}
apiStatusJson = sGson.toJson(mJsApiListMap);
}

} catch (JSONException j) {
UIUtils.showThemedToast(AbstractFlashcardViewer.this, getString(R.string.invalid_json_data, j.getLocalizedMessage()), false);
}
return String.valueOf(apiStatusJson);
}

@JavascriptInterface
public String ankiGetNewCardCount() {
return newCount.toString();
Expand Down
12 changes: 12 additions & 0 deletions AnkiDroid/src/main/res/values/02-strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,16 @@
<string name="white_board_image_saved">Whiteboard image saved to %s</string>

<string name="title_whiteboard_pen_color">Whiteboard pen color</string>

<string name="api_version_developer_contact">This card uses unsupported AnkiDroid features. Contact developer %s, or view the wiki. %s</string>
<string name="invalid_json_data">Card provided invalid data. %s</string>
<string name="valid_js_api_version">Invalid AnkiDroid JS API version. Contact developer %s, or view wiki</string>
<string name="update_js_api_version">AnkiDroid JS API update available. Contact developer %s, or view wiki</string>
<string name="reviewer_invalid_api_version_visit_documentation">View</string>
<string name="update_js_api_patch_version">AnkiDroid JS API patch update available. Contact developer %s, or view wiki.</string>
<string name="update_js_api_minor_version">AnkiDroid JS API minor update available. Contact developer %s, or view wiki.</string>
<string name="js_api_not_implemented">JS API not implemented to current deck. View wiki.</string>

<!-- Error codes for AnkiDroid JS API-->
<string name="anki_js_error_code">(Error Code:%d)</string>
Comment thread
david-allison marked this conversation as resolved.
Outdated
</resources>