private static File getBackupDirectory() { SharedPreferences prefs = AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()); File directory = new File(prefs.getString("deckPath", AnkiDroidApp.getStorageDirectory()) + BACKUP_SUFFIX); if (!directory.isDirectory()) { directory.mkdirs(); } return directory; }
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(); }
@Override public void onCreate() { super.onCreate(); SharedPreferences prefs = AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()); String path = prefs.getString("lastWidgetDeck", ""); if (path != null && path.length() > 0 && AnkiDroidApp.isSdCardMounted()) { Log.i(AnkiDroidApp.TAG, "BigWidget: reloading deck " + path); mCol = Collection.currentCollection(); if (mCol != null) { mCurrentCard = mCol.getSched().getCard(); } } }
public static boolean initialize(Context context) { mContext = context; SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()); mDictionary = Integer.parseInt(preferences.getString("dictionary", Integer.toString(DICTIONARY_NONE))); switch (mDictionary) { case DICTIONARY_NONE: mIsDictionaryAvailable = false; break; case DICTIONARY_AEDICT: mDictionaryAction = "sk.baka.aedict.action.ACTION_SEARCH_EDICT"; mIsDictionaryAvailable = Utils.isIntentAvailable(mContext, mDictionaryAction); break; case DICTIONARY_LEO_WEB: case DICTIONARY_NCIKU_WEB: case DICTIONARY_EIJIRO_WEB: mDictionaryAction = "android.intent.action.VIEW"; mIsDictionaryAvailable = Utils.isIntentAvailable(mContext, mDictionaryAction); break; case DICTIONARY_LEO_APP: mDictionaryAction = "android.intent.action.SEND"; mIsDictionaryAvailable = Utils.isIntentAvailable( mContext, mDictionaryAction, new ComponentName("org.leo.android.dict", "org.leo.android.dict.LeoDict")); break; case DICTIONARY_COLORDICT: mDictionaryAction = "colordict.intent.action.SEARCH"; mIsDictionaryAvailable = Utils.isIntentAvailable(mContext, mDictionaryAction); break; case DICTIONARY_FORA: mDictionaryAction = "com.ngc.fora.action.LOOKUP"; mIsDictionaryAvailable = Utils.isIntentAvailable(mContext, mDictionaryAction); break; default: mIsDictionaryAvailable = false; break; } Log.i(AnkiDroidApp.TAG, "Is intent available = " + mIsDictionaryAvailable); return mIsDictionaryAvailable; }
@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(); }
/** * If collection has not been opened for a long time, we perform a backup here because Android * deleted sometimes corrupted decks */ public static boolean safetyBackupNeeded(String path, int days) { if (!AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()) .getBoolean("useBackup", true)) { return false; } File collectionFile = new File(path); File[] deckBackups = getBackups(collectionFile); int len = deckBackups.length; if (len == 0) { // no backup available return true; } else if (deckBackups[len - 1].lastModified() == collectionFile.lastModified()) { return false; } SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH-mm"); Calendar cal = new GregorianCalendar(); cal.setTimeInMillis(System.currentTimeMillis()); Date lastBackupDate = null; while (lastBackupDate == null && len > 0) { try { len--; lastBackupDate = df.parse( deckBackups[len] .getName() .replaceAll("^.*-(\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}).anki2$", "$1")); } catch (ParseException e) { lastBackupDate = null; } } if (lastBackupDate == null) { return true; } else if (lastBackupDate.getTime() + days * 24 * 3600000 < Utils.intNow(1000)) { return true; } else { return false; } }
/** * Convenience method for querying the database for an entire column. The column will be returned * as an ArrayList of the specified class. See Deck.initUndo() for a usage example. * * @param type The class of the column's data type. Example: int.class, String.class. * @param query The SQL query statement. * @param column The column id in the result set to return. * @return An ArrayList with the contents of the specified column. */ public <T> ArrayList<T> queryColumn(Class<T> type, String query, int column) { int nullExceptionCount = 0; InvocationTargetException nullException = null; // to catch the null exception for reporting ArrayList<T> results = new ArrayList<T>(); Cursor cursor = null; try { cursor = mDatabase.rawQuery(query, null); String methodName = getCursorMethodName(type.getSimpleName()); while (cursor.moveToNext()) { try { // The magical line. Almost as illegible as python code ;) results.add( type.cast(Cursor.class.getMethod(methodName, int.class).invoke(cursor, column))); } catch (InvocationTargetException e) { if (cursor.isNull(column)) { // null value encountered nullExceptionCount++; if (nullExceptionCount == 1) { // Toast and error report first time only nullException = e; Toast.makeText( AnkiDroidApp.getInstance().getBaseContext(), "Error report pending: unexpected null in database.", Toast.LENGTH_LONG) .show(); } continue; // attempt to skip this null record } else { throw new RuntimeException(e); } } } } catch (NoSuchMethodException e) { // This is really coding error, so it should be revealed if it ever happens throw new RuntimeException(e); } catch (IllegalArgumentException e) { // This is really coding error, so it should be revealed if it ever happens throw new RuntimeException(e); } catch (IllegalAccessException e) { // This is really coding error, so it should be revealed if it ever happens throw new RuntimeException(e); } finally { if (cursor != null) { cursor.close(); } if (nullExceptionCount > 0) { if (nullException != null) { StringBuilder sb = new StringBuilder(); sb.append("AnkiDb.queryColumn (column " + column + "): "); sb.append("Exception due to null. Query: " + query); sb.append(" Null occurrences during this query: " + nullExceptionCount); AnkiDroidApp.sendExceptionReport( nullException, "queryColumn_encounteredNull", sb.toString()); Timber.w(sb.toString()); } else { // nullException not properly initialized StringBuilder sb = new StringBuilder(); sb.append("AnkiDb.queryColumn(): Critical error -- "); sb.append("unable to pass in the actual exception to error reporting."); AnkiDroidApp.sendExceptionReport( new RuntimeException("queryColumn null"), "queryColumn_encounteredNull", sb.toString()); Timber.e(sb.toString()); } } } return results; }
public static void performBackup(String path, int interval, boolean force) { SharedPreferences prefs = AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()); if (!prefs.getBoolean("useBackup", true) && !force) { return; } File collectionFile = new File(path); File[] deckBackups = getBackups(collectionFile); int len = deckBackups.length; if (len > 0 && deckBackups[len - 1].lastModified() == collectionFile.lastModified()) { Log.i(AnkiDroidApp.TAG, "performBackup: No backup necessary due to no collection changes"); return; } SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH-mm"); Calendar cal = new GregorianCalendar(); cal.setTimeInMillis(System.currentTimeMillis()); Date lastBackupDate = null; while (lastBackupDate == null && len > 0) { try { len--; lastBackupDate = df.parse( deckBackups[len] .getName() .replaceAll("^.*-(\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}).anki2$", "$1")); } catch (ParseException e) { lastBackupDate = null; } } if (lastBackupDate != null && lastBackupDate.getTime() + interval * 3600000 > Utils.intNow(1000) && !force) { Log.i(AnkiDroidApp.TAG, "performBackup: No backup created. Last backup younger than 5 hours"); return; } String backupFilename; try { backupFilename = String.format( Utils.ENGLISH_LOCALE, collectionFile.getName().replace(".anki2", "") + "-%s.anki2", df.format(cal.getTime())); } catch (UnknownFormatConversionException e) { Log.e(AnkiDroidApp.TAG, "performBackup: error on creating backup filename: " + e); return; } File backupFile = new File(getBackupDirectory().getPath(), backupFilename); if (backupFile.exists()) { Log.i(AnkiDroidApp.TAG, "performBackup: No new backup created. File already exists"); return; } if (getFreeDiscSpace(collectionFile) < collectionFile.length() + (MIN_FREE_SPACE * 1024 * 1024)) { Log.e(AnkiDroidApp.TAG, "performBackup: Not enough space on sd card to backup."); prefs.edit().putBoolean("noSpaceLeft", true).commit(); return; } try { InputStream stream = new FileInputStream(collectionFile); Utils.writeToFile(stream, backupFile.getAbsolutePath()); stream.close(); // set timestamp of file in order to avoid creating a new backup unless its changed backupFile.setLastModified(collectionFile.lastModified()); } catch (IOException e) { Log.e(AnkiDroidApp.TAG, Log.getStackTraceString(e)); Log.e(AnkiDroidApp.TAG, "performBackup: Copying of file failed."); return; } // delete old backups deleteDeckBackups(path, prefs.getInt("backupMax", 3)); }