@Override
        public void onClick(DialogInterface dialog, int which) {
          switch (which) {
            case CONTEXT_MENU_MARK:
              DeckTask.launchDeckTask(
                  DeckTask.TASK_TYPE_MARK_CARD,
                  mUpdateCardHandler,
                  new DeckTask.TaskData(
                      mCol.getSched(),
                      mCol.getCard(Long.parseLong(mCards.get(mPositionInCardsList).get("id"))),
                      0));
              return;

            case CONTEXT_MENU_SUSPEND:
              DeckTask.launchDeckTask(
                  DeckTask.TASK_TYPE_DISMISS_NOTE,
                  mSuspendCardHandler,
                  new DeckTask.TaskData(
                      mCol.getSched(),
                      mCol.getCard(Long.parseLong(mCards.get(mPositionInCardsList).get("id"))),
                      1));
              return;

            case CONTEXT_MENU_DELETE:
              Resources res = getResources();
              StyledDialog.Builder builder = new StyledDialog.Builder(CardBrowser.this);
              builder.setTitle(res.getString(R.string.delete_card_title));
              builder.setIcon(android.R.drawable.ic_dialog_alert);
              builder.setMessage(
                  res.getString(
                      R.string.delete_card_message, mCards.get(mPositionInCardsList).get("sfld")));
              builder.setPositiveButton(
                  res.getString(R.string.yes),
                  new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                      Card card =
                          mCol.getCard(Long.parseLong(mCards.get(mPositionInCardsList).get("id")));
                      deleteNote(card);
                      DeckTask.launchDeckTask(
                          DeckTask.TASK_TYPE_DISMISS_NOTE,
                          mDeleteNoteHandler,
                          new DeckTask.TaskData(mCol.getSched(), card, 3));
                    }
                  });
              builder.setNegativeButton(res.getString(R.string.no), null);
              builder.create().show();
              return;

            case CONTEXT_MENU_DETAILS:
              Card tempCard =
                  mCol.getCard(Long.parseLong(mCards.get(mPositionInCardsList).get("id")));
              Themes.htmlOkDialog(
                      CardBrowser.this,
                      getResources().getString(R.string.card_browser_card_details),
                      tempCard.getCardDetails(CardBrowser.this))
                  .show();
              return;
          }
        }
 private void deleteNote(Card card) {
   ArrayList<Card> cards = card.note().cards();
   for (Card c : cards) {
     mCards.remove(getPosition(mCards, c.getId()));
     mAllCards.remove(getPosition(mAllCards, c.getId()));
   }
   updateList();
 }
  /**
   * Test that query for the next card in the schedule returns a valid result WITH a deck selector
   */
  public void testQueryCardFromCertainDeck() {
    long deckToTest = mTestDeckIds[0];
    String deckSelector = "deckID=?";
    String deckArguments[] = {Long.toString(deckToTest)};
    Collection col;
    col = CollectionHelper.getInstance().getCol(getContext());
    Sched sched = col.getSched();
    long selectedDeckBeforeTest = col.getDecks().selected();
    col.getDecks().select(1); // select Default deck

    Cursor reviewInfoCursor =
        getContext()
            .getContentResolver()
            .query(
                FlashCardsContract.ReviewInfo.CONTENT_URI, null, deckSelector, deckArguments, null);
    assertNotNull(reviewInfoCursor);
    assertEquals("Check that we actually received one card", 1, reviewInfoCursor.getCount());
    try {
      reviewInfoCursor.moveToFirst();
      int cardOrd =
          reviewInfoCursor.getInt(
              reviewInfoCursor.getColumnIndex(FlashCardsContract.ReviewInfo.CARD_ORD));
      long noteID =
          reviewInfoCursor.getLong(
              reviewInfoCursor.getColumnIndex(FlashCardsContract.ReviewInfo.NOTE_ID));
      assertEquals("Check that the selected deck has not changed", 1, col.getDecks().selected());

      col.getDecks().select(deckToTest);
      Card nextCard = null;
      for (int i = 0;
          i < 10;
          i++) { // minimizing fails, when sched.reset() randomly chooses between multiple cards
        sched.reset();
        nextCard = sched.getCard();
        if (nextCard.note().getId() == noteID && nextCard.getOrd() == cardOrd) break;
      }
      assertNotNull("Check that there actually is a next scheduled card", nextCard);
      assertEquals(
          "Check that received card and actual card have same note id",
          nextCard.note().getId(),
          noteID);
      assertEquals(
          "Check that received card and actual card have same card ord",
          nextCard.getOrd(),
          cardOrd);
    } finally {
      reviewInfoCursor.close();
    }

    col.getDecks().select(selectedDeckBeforeTest);
  }
  /** Test giving the answer for a reviewed card */
  public void testAnswerCard() {
    Collection col;
    col = CollectionHelper.getInstance().getCol(getContext());
    Sched sched = col.getSched();
    long deckId = mTestDeckIds[0];
    col.getDecks().select(deckId);
    Card card = sched.getCard();

    ContentResolver cr = getContext().getContentResolver();
    Uri reviewInfoUri = FlashCardsContract.ReviewInfo.CONTENT_URI;
    ContentValues values = new ContentValues();
    long noteId = card.note().getId();
    int cardOrd = card.getOrd();
    int ease = AbstractFlashcardViewer.EASE_3; // <- insert real ease here

    values.put(FlashCardsContract.ReviewInfo.NOTE_ID, noteId);
    values.put(FlashCardsContract.ReviewInfo.CARD_ORD, cardOrd);
    values.put(FlashCardsContract.ReviewInfo.EASE, ease);
    int updateCount = cr.update(reviewInfoUri, values, null, null);

    assertEquals("Check if update returns 1", 1, updateCount);

    sched.reset();
    Card newCard = sched.getCard();
    if (newCard != null) {
      if (newCard.note().getId() == card.note().getId() && newCard.getOrd() == card.getOrd()) {
        fail("Next scheduled card has not changed");
      }
    } else {
      // We expected this
    }
  }
 public void setCard(Card card) {
   mCurrentCard = card;
   Long cardId = 0l;
   if (card != null) {
     cardId = card.getId();
   }
   AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext())
       .edit()
       .putLong("lastWidgetCard", cardId)
       .commit();
 }
  private void updateCardInList(Card card) {
    Note note = card.note();
    for (Card c : note.cards()) {
      int aPos = getPosition(mAllCards, c.getId());
      int pos = getPosition(mCards, c.getId());

      String sfld = note.getSFld();
      mAllCards.get(aPos).put("sfld", sfld);
      mCards.get(pos).put("sfld", sfld);

      if (mWholeCollection) {
        String deckName;
        try {
          deckName = mCol.getDecks().get(card.getDid()).getString("name");
        } catch (JSONException e) {
          throw new RuntimeException(e);
        }
        mAllCards.get(aPos).put("deck", deckName);
        mCards.get(pos).put("deck", deckName);
      }

      String flags =
          Integer.toString((c.getQueue() == -1 ? 1 : 0) + (note.hasTag("marked") ? 2 : 0));
      mAllCards.get(aPos).put("flags", flags);
      mCards.get(pos).put("flags", flags);
    }
    updateList();
  }
  /**
   * Test that query for the next card in the schedule returns a valid result without any deck
   * selector
   */
  public void testQueryNextCard() {
    Collection col;
    col = CollectionHelper.getInstance().getCol(getContext());
    Sched sched = col.getSched();

    Cursor reviewInfoCursor =
        getContext()
            .getContentResolver()
            .query(FlashCardsContract.ReviewInfo.CONTENT_URI, null, null, null, null);
    assertNotNull(reviewInfoCursor);
    assertEquals("Check that we actually received one card", 1, reviewInfoCursor.getCount());

    reviewInfoCursor.moveToFirst();
    int cardOrd =
        reviewInfoCursor.getInt(
            reviewInfoCursor.getColumnIndex(FlashCardsContract.ReviewInfo.CARD_ORD));
    long noteID =
        reviewInfoCursor.getLong(
            reviewInfoCursor.getColumnIndex(FlashCardsContract.ReviewInfo.NOTE_ID));

    Card nextCard = null;
    for (int i = 0;
        i < 10;
        i++) { // minimizing fails, when sched.reset() randomly chooses between multiple cards
      sched.reset();
      nextCard = sched.getCard();
      if (nextCard.note().getId() == noteID && nextCard.getOrd() == cardOrd) break;
    }
    assertNotNull("Check that there actually is a next scheduled card", nextCard);
    assertEquals(
        "Check that received card and actual card have same note id",
        nextCard.note().getId(),
        noteID);
    assertEquals(
        "Check that received card and actual card have same card ord", nextCard.getOrd(), cardOrd);
  }
 @Override
 public void onDestroy() {
   // // TODO: this does not seem to be reliably called
   // String path = "";
   long cardId = 0l;
   if (mCol != null) {
     // path = mLoadedDeck.getDeckPath();
     // DeckManager.closeDeck(path, DeckManager.REQUESTING_ACTIVITY_BIGWIDGET);
     if (mCurrentCard != null) {
       cardId = mCurrentCard.getId();
     }
   }
   // PrefSettings.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).edit().putString("lastWidgetDeck",
   // path).commit();
   AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext())
       .edit()
       .putLong("lastWidgetCard", cardId)
       .commit();
 }
        @Override
        public void onProgressUpdate(DeckTask.TaskData... values) {
          if (canceled) {
            return;
          }
          ArrayList<HashMap<String, String>> cards = values[0].getCards();
          if (cards == null) {
            Resources res = getResources();
            StyledDialog.Builder builder = new StyledDialog.Builder(CardBrowser.this);
            builder.setTitle(res.getString(R.string.error));
            builder.setIcon(android.R.drawable.ic_dialog_alert);
            builder.setMessage(res.getString(R.string.card_browser_cardloading_error));
            builder.setPositiveButton(
                res.getString(R.string.ok),
                new DialogInterface.OnClickListener() {
                  @Override
                  public void onClick(DialogInterface dialog, int which) {
                    closeCardBrowser();
                  }
                });
            builder.setOnCancelListener(
                new OnCancelListener() {
                  @Override
                  public void onCancel(DialogInterface dialog) {
                    closeCardBrowser();
                  }
                });
            builder.create().show();
          } else {
            if (mPrefFixArabic) {
              for (HashMap<String, String> entry : cards) {
                entry.put("sfld", ArabicUtilities.reshapeSentence(entry.get("sfld")));
              }
            }
            try {

              int field =
                  AnkiDroidApp.getSharedPrefs(getBaseContext()).getInt("cardBrowserField", 0);

              Card tempCard =
                  mCol.getCard(
                      Long.parseLong(
                          cards.get(0).get("id"))); // Long.parseLong(mCards.get(0).get("id"))

              ArrayList<String> uniqueFields = new ArrayList<String>();

              if (field > 0 && (mFields != null)) {
                for (HashMap<String, String> entry : cards) {
                  tempCard = mCol.getCard(Long.parseLong(entry.get("id")));
                  String item = tempCard.note().getitem(mFields[field]);
                  entry.put("sfld", item);

                  if (!uniqueFields.contains(item)) {
                    uniqueFields.add(item);
                    mAllCards.add(entry);
                    mCards.add(entry);
                  }
                }
              } else {
                mAllCards.addAll(cards);
                mCards.addAll(cards);
              }

              if (mOrder == CARD_ORDER_NONE) {
                updateCardsList();
                mProgressDialog.dismiss();
              } else {
                DeckTask.launchDeckTask(
                    DeckTask.TASK_TYPE_UPDATE_CARD_BROWSER_LIST,
                    mSortCardsHandler,
                    new DeckTask.TaskData(mAllCards, new HashMapCompare()));
              }
            } catch (OutOfMemoryError e) {
              Log.e(AnkiDroidApp.TAG, "CardBrowser: mLoadCardsHandler: OutOfMemoryError: " + e);
              Themes.showThemedToast(
                  CardBrowser.this,
                  getResources().getString(R.string.error_insufficient_memory),
                  false);
              closeCardBrowser();
            }
          }
        }