Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash on preview of card added to dynamic deck #5756

Closed
mikehardy opened this issue Feb 16, 2020 · 22 comments · Fixed by #5757 or #5842
Closed

Crash on preview of card added to dynamic deck #5756

mikehardy opened this issue Feb 16, 2020 · 22 comments · Fixed by #5757 or #5842
Assignees
Labels
Accepted Maintainers welcome a PR implementing this feature Bug
Milestone

Comments

@mikehardy
Copy link
Member

Saw our first google auto-test-lab-on-new-release crash report in a long time

https://play.google.com/apps/publish/?account=5338425030304417978&pli=1#PreLaunchReportPlace:p=com.ichi2.anki&plrtab=CRASH&plrvc=21000136

Reproduction Steps
  1. create a dynamic deck based on previewing ahead 1 day
  2. click the FAB button to add a note (should go to current / dynamic deck)
  3. in note editor click the the cards button at bottom to open template editor
  4. in template editor click the eyeball at the top to open the preview
Expected Result

You should see a preview

Actual Result
2020-02-16 15:01:38.837 16674-16674/com.ichi2.anki E/AbstractFlashcardViewer: Unable to restoreCollectionPreferences
    org.json.JSONException: No value for rev
        at org.json.JSONObject.get(JSONObject.java:392)
        at org.json.JSONObject.getJSONObject(JSONObject.java:612)
        at com.ichi2.anki.AbstractFlashcardViewer.restoreCollectionPreferences(AbstractFlashcardViewer.java:1782)
        at com.ichi2.anki.AbstractFlashcardViewer.onCollectionLoaded(AbstractFlashcardViewer.java:844)
        at com.ichi2.anki.Previewer.onCollectionLoaded(Previewer.java:65)
        at com.ichi2.anki.AnkiActivity.startLoadingCollection(AnkiActivity.java:261)
        at com.ichi2.anki.Previewer.onCreate(Previewer.java:60)

So here's the questions:

  1. is it legal to add a card to a dynamic deck? seems like no? If no, should the FAB / add card actions toast that you can't add to a dynamic deck?
Debug info

Refer to the support page if you are unsure where to get the "debug info".

Research

Enter an [ x ] character to confirm the points below:

[ ] I have read the support page and am reporting a bug or enhancement request specific to AnkiDroid

[ ] I have checked the manual and the FAQ and could not find a solution to my issue

[ ] I have searched for similar existing issues here and on the user forum

@mikehardy mikehardy added Bug Accepted Maintainers welcome a PR implementing this feature labels Feb 16, 2020
mikehardy added a commit to mikehardy/Anki-Android that referenced this issue Feb 16, 2020
@timrae
Copy link
Member

timrae commented Feb 16, 2020

Step 2 in your reproduction steps seems incorrect to me. It should (and does for me) go to the default deck by default if you try to open the add note dialog with a filtered deck. We don't allow users to add cards to filtered decks.

@timrae
Copy link
Member

timrae commented Feb 16, 2020

To me it seems the real bug here is that the previewer is trying to use the currently selected libanki deck instead of the deck selected in the note editor. Probably it's a bug introduced ages ago by me when we removed the guarantee that the deck selected in libanki is the same as the deck selected in the note editor.

@mikehardy
Copy link
Member Author

okay - so the critical thing here is that we shouldn't be able to add notes to dynamic decks. I'll hunt through things from that perspective.

@Arthur-Milchior
Copy link
Member

I had a similar problem, where clicking on a filtered deck crashed.
This led to the error message:

2020-02-18 02:12:42.153 15759-15759/com.ichi2.anki E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ichi2.anki, PID: 15759
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ichi2.anki/com.ichi2.anki.Reviewer}: java.lang.RuntimeException: org.json.JSONException: No value for rev
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3135)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3278)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1969)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7124)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
Caused by: java.lang.RuntimeException: org.json.JSONException: No value for rev
at com.ichi2.anki.AbstractFlashcardViewer.restoreCollectionPreferences(AbstractFlashcardViewer.java:1789)
at com.ichi2.anki.AbstractFlashcardViewer.onCollectionLoaded(AbstractFlashcardViewer.java:844)
at com.ichi2.anki.Reviewer.onCollectionLoaded(Reviewer.java:164)
at com.ichi2.anki.AnkiActivity.startLoadingCollection(AnkiActivity.java:261)
at com.ichi2.anki.Reviewer.onCreate(Reviewer.java:103)
at android.app.Activity.performCreate(Activity.java:7335)
at android.app.Activity.performCreate(Activity.java:7326)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1275)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3115)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3278)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1969)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7124)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
Caused by: org.json.JSONException: No value for rev
at org.json.JSONObject.get(JSONObject.java:392)
at org.json.JSONObject.getJSONObject(JSONObject.java:612)
at com.ichi2.anki.AbstractFlashcardViewer.restoreCollectionPreferences(AbstractFlashcardViewer.java:1782)
at com.ichi2.anki.AbstractFlashcardViewer.onCollectionLoaded(AbstractFlashcardViewer.java:844)
at com.ichi2.anki.Reviewer.onCollectionLoaded(Reviewer.java:164)
at com.ichi2.anki.AnkiActivity.startLoadingCollection(AnkiActivity.java:261)
at com.ichi2.anki.Reviewer.onCreate(Reviewer.java:103)
at android.app.Activity.performCreate(Activity.java:7335)
at android.app.Activity.performCreate(Activity.java:7326)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1275)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3115)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3278)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1969)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7124)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)

Note that the only reason why I obtained the last part is because of PR #5762 (the version of the code I'm running is 1c4ca85)

So, it seems that the method is looking for the property used for rescheduling revision in a filtered deck's option. The problem is that the filtered deck option is itself, and it has no "rev" value.

I just checked, there is no card directly in the filtered deck, so that's not the problem.

@Arthur-Milchior
Copy link
Member

This particular bug was introduced in 3a7bea5 by PR #5733 of @correia55.
@correia55 do you think you can correct it, please ? I don't know what you code does exactly and would prefer not to try to understand what it should do for filtered deck

@mikehardy
Copy link
Member Author

I'll revert that if we can't figure it out quickly. It's not a huge PR so it should possible to figure it out but crashing is obviously not good

@mikehardy
Copy link
Member Author

I think I've got this figured out in #5757 - Going to merge it and push it out as a fix and release 2.9.4
Pending further commentary I may revise the fix but I'm 99% it is right and it definitely fixes current crashes

@mikehardy
Copy link
Member Author

As for Tim's comment - the card addition is actually going to the default deck, which is what should happen, it's just the preview is happening in the "current deck", which is the filtered deck and because of the assumption all decks (including dynamic) have deck rev options in #5733 the previewer crashes. That's unexpected but by not assuming dynamic decks have rev options everything is fine again

@timrae
Copy link
Member

timrae commented Feb 18, 2020

I think you intended to keep this open, until we confirm that we're not (temporarily) adding cards to dynamic decks when previewing.

@timrae timrae reopened this Feb 18, 2020
@mikehardy
Copy link
Member Author

No - I can't see how this is related. I can't even see how the patch that blew up AbstractCardViewer affected it. I think it was latent, so I opened #5765 as a very focused - full-steps-to-reproduce-the-test issue. But this can stay open too now that they're cross-linked

@timrae
Copy link
Member

timrae commented Feb 18, 2020

#5765 is a non-issue as far as I can tell... If you think it's necessary to check it then please feel free to re-open. But what I want is an understanding of the root cause of this crash. I have been assuming the card added here was incorrectly added to a dynamic deck. On quick inspection of the code I'm not so sure about that anymore, but then the question is why was this code path crashing?

@mikehardy
Copy link
Member Author

I'm not exactly sure of course - I thought #5765 would tickle it during inspection. My quick inspection did not lead me to believe it would actually add the card to the deck but proof is needed and it's an opportunity to learn more about the template editor which will serve me well for the mega-patch there anyway.

Without saying it's a root cause, all I know for sure is that after adding deck-specific auto-review settings, AbstractCardReviewer could crash if the current deck was dynamic. Why was the CardTemplateEditor pulling up the dynamic deck (selected in deck list) as the thing to preview (causing the crash) vs the deck in the spinner? Unsure.

@timrae
Copy link
Member

timrae commented Feb 18, 2020

Most likely the problem is not actually that the dummy card is added to a dynamic deck, but rather AbstractFlashcardViewer is assuming the card being reviewed (in this case a dummy card) is in the currently selected deck (which happens to be a dynamic deck). In fact the dummy card used in the previewer is always in the default deck, not the currently selected deck.

So the real underlying problem is that any code that wants to know something about the deck that the card is in, probably needs to go in the Reviewer class instead of the AbstractFlashcardViewer class.

@mikehardy
Copy link
Member Author

That seems right based on what I know and is easy to confirm, I'll follow that path when I get back if you don't beat me to it

@mikehardy mikehardy added this to the 2.10 release milestone Mar 6, 2020
@mikehardy mikehardy self-assigned this Mar 8, 2020
@mikehardy
Copy link
Member Author

@david-allison-1 your recent commits may have closed this one, or it may be that the hand-off between card editor -> card template editor -> previewer is not selecting the right deck for preview somehow?

@david-allison
Copy link
Member

@mikehardy Nope, happy to take this on though.

@david-allison
Copy link
Member

Oh wow, I didn't realise Cards was a link

@david-allison
Copy link
Member

david-allison commented Mar 20, 2020

Based on Anki Desktop, placing {{Deck}} in the preview, it looks like we're using odid ?? did to select the deck to preview cards with

Not exactly
https://github.com/ankitects/anki/blob/244326c130111619877c44cdc56115fc6e6362c6/pylib/anki/template.py#L155

@mikehardy
Copy link
Member Author

Oh wow, I didn't realise Cards was a link

Then just for fun you'll love scanning #5151 😮

@david-allison
Copy link
Member

@mikehardy I'll bet you've been wanting me to look at that for a few days now 😉.


I've skimmed, but I'm not sure you'll like the answer.

My first impressions are:

  • We want the feature, we have a lot of problems with speculative persistence
  • Fixing the issue (corruption) should take priority over this, as it's a small targeted change in check database
  • We've already corrupted databases, so getting this in won't help users in a bad state.
  • For a bug fix, it's too complex.
  • For a new feature, it's not well specified enough for the amount of code changed.

Practicalities:

  • Go with targeted recovery first, let users get past the issue without a DB restore, even if it's not ideal. Hopefully anyone editing a template isn't a new user and understands.
  • I've reviewed and seen much larger PRs go through. Although it was a slog, it was necessary.
  • I'd like to see it in
  • I'll leave it ticking over in the back of my mind
  • I haven't looked through the pre-PR code yet, so I've got some work to do to get up to speed.
  • Let's set a calendar reminder (21st April?) to get this looked at in detail.

All the above is honest thoughts/opinions, you're maintaining the project and the change, and I'll take your lead on solutions/strategies to get to this.

david-allison added a commit to david-allison/Anki-Android that referenced this issue Mar 21, 2020
Previewing a card currently performs displayAnswerBottomBar which
requires an ease calculation.

The ease calculation depends on the current deck, and is not necessary
in the previewer as we don't show ease buttons, we get a crash as the
scheduler is pointed at the wrong deck, so don't calculate either.

Note: This only fixes the crash, it doesn't touch the root cause:
We rely on libAnki to get cards for previews, which relies on the
current deck for setting certain data.

This information is neither required, nor correct when previewing.

We can't change the scheduler while previewing as we may be previewing
during a review session, which would cause a scheduler reset.
@mikehardy
Copy link
Member Author

If you're talking about #5151 it was actually split into separate items as you mention prior but guidance at the time was to combine, so it's in the current state based on that. There's actually only one outstanding item left pre-merge for that one, and then I'm going to merge it. It's not the most fantastic but it works well and has nearly 100% coverage (in fact, most of the testing infrastructure was co-developed at the time in order to make sure I didn't bungle it...)

@mikehardy mikehardy modified the milestones: 2.10 release, 2.9.6 Release Mar 21, 2020
mikehardy pushed a commit that referenced this issue Mar 21, 2020
* NF: Rename showEaseButtons

to displayAnswerBottomBar

* #5756 - Fix Dynamic Card Preview Crash

Previewing a card currently performs displayAnswerBottomBar which
requires an ease calculation.

The ease calculation depends on the current deck, and is not necessary
in the previewer as we don't show ease buttons, we get a crash as the
scheduler is pointed at the wrong deck, so don't calculate either.

Note: This only fixes the crash, it doesn't touch the root cause:
We rely on libAnki to get cards for previews, which relies on the
current deck for setting certain data.

This information is neither required, nor correct when previewing.

We can't change the scheduler while previewing as we may be previewing
during a review session, which would cause a scheduler reset.
@mikehardy
Copy link
Member Author

2.10alpha54 released just now has this whenever google delivers it to you

mikehardy pushed a commit that referenced this issue Mar 26, 2020
* NF: Rename showEaseButtons

to displayAnswerBottomBar

* #5756 - Fix Dynamic Card Preview Crash

Previewing a card currently performs displayAnswerBottomBar which
requires an ease calculation.

The ease calculation depends on the current deck, and is not necessary
in the previewer as we don't show ease buttons, we get a crash as the
scheduler is pointed at the wrong deck, so don't calculate either.

Note: This only fixes the crash, it doesn't touch the root cause:
We rely on libAnki to get cards for previews, which relies on the
current deck for setting certain data.

This information is neither required, nor correct when previewing.

We can't change the scheduler while previewing as we may be previewing
during a review session, which would cause a scheduler reset.
Apochens added a commit to Apochens/Anki-Android that referenced this issue Sep 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Accepted Maintainers welcome a PR implementing this feature Bug
Projects
None yet
4 participants