use of com.ichi2.anki.CollectionHelper in project AnkiChinaAndroid by ankichinateam.
the class DatabaseErrorDialog method onCreateDialog.
@Override
public MaterialDialog onCreateDialog(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int mType = getArguments().getInt("dialogType");
Resources res = getResources();
MaterialDialog.Builder builder = new MaterialDialog.Builder(getActivity());
builder.cancelable(true).title(getTitle());
boolean sqliteInstalled = false;
try {
sqliteInstalled = Runtime.getRuntime().exec("sqlite3 --version").waitFor() == 0;
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
switch(mType) {
case DIALOG_LOAD_FAILED:
{
// the activity
return builder.cancelable(false).content(getMessage()).iconAttr(R.attr.dialogErrorIcon).positiveText(res.getString(R.string.error_handling_options)).negativeText(res.getString(R.string.close)).onPositive((inner_dialog, which) -> ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_ERROR_HANDLING)).onNegative((inner_dialog, which) -> exit()).show();
}
case DIALOG_DB_ERROR:
{
// Database Check failed to execute successfully; give user the option of either choosing from repair
// options, submitting an error report, or closing the activity
MaterialDialog dialog = builder.cancelable(false).content(getMessage()).iconAttr(R.attr.dialogErrorIcon).positiveText(res.getString(R.string.error_handling_options)).negativeText(res.getString(R.string.answering_error_report)).neutralText(res.getString(R.string.close)).onPositive((inner_dialog, which) -> ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_ERROR_HANDLING)).onNegative((inner_dialog, which) -> {
((DeckPicker) getActivity()).sendErrorReport();
dismissAllDialogFragments();
}).onNeutral((inner_dialog, which) -> exit()).show();
dialog.getCustomView().findViewById(R.id.md_buttonDefaultNegative).setEnabled(((DeckPicker) getActivity()).hasErrorFiles());
return dialog;
}
case DIALOG_ERROR_HANDLING:
{
// The user has asked to see repair options; allow them to choose one of the repair options or go back
// to the previous dialog
ArrayList<String> options = new ArrayList<>();
ArrayList<Integer> values = new ArrayList<>();
if (!((AnkiActivity) getActivity()).colIsOpen()) {
// retry
options.add(res.getString(R.string.backup_retry_opening));
values.add(0);
} else {
// fix integrity
options.add(res.getString(R.string.check_db));
values.add(1);
}
// repair db with sqlite
if (sqliteInstalled) {
options.add(res.getString(R.string.backup_error_menu_repair));
values.add(2);
}
// // restore from backup
options.add(res.getString(R.string.backup_restore));
values.add(3);
// delete old collection and build new one
options.add(res.getString(R.string.backup_full_sync_from_server));
values.add(4);
// delete old collection and build new one
options.add(res.getString(R.string.backup_del_collection));
values.add(5);
String[] titles = new String[options.size()];
mRepairValues = new int[options.size()];
for (int i = 0; i < options.size(); i++) {
titles[i] = options.get(i);
mRepairValues[i] = values.get(i);
}
return builder.iconAttr(R.attr.dialogErrorIcon).negativeText(res.getString(R.string.dialog_cancel)).items(titles).itemsCallback((materialDialog, view, which, charSequence) -> {
switch(mRepairValues[which]) {
case 0:
((DeckPicker) getActivity()).restartActivity();
return;
case 1:
((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_CONFIRM_DATABASE_CHECK);
return;
case 2:
((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_REPAIR_COLLECTION);
return;
case 3:
((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_RESTORE_BACKUP);
return;
case 4:
((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_FULL_SYNC_FROM_SERVER);
return;
case 5:
((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_NEW_COLLECTION);
return;
default:
throw new RuntimeException("Unknown dialog selection: " + mRepairValues[which]);
}
}).show();
}
case DIALOG_REPAIR_COLLECTION:
{
// Allow user to run BackupManager.repairCollection()
return builder.content(getMessage()).iconAttr(R.attr.dialogErrorIcon).positiveText(res.getString(R.string.dialog_positive_repair)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> {
((DeckPicker) getActivity()).repairCollection();
dismissAllDialogFragments();
}).show();
}
case DIALOG_RESTORE_BACKUP:
{
// Allow user to restore one of the backups
String path = CollectionHelper.getInstance().getCollectionPath(getActivity());
File[] files = BackupManager.getBackups(new File(path));
mBackups = new File[files.length];
for (int i = 0; i < files.length; i++) {
mBackups[i] = files[files.length - 1 - i];
}
if (mBackups.length == 0) {
builder.title(res.getString(R.string.backup_restore)).content(getMessage()).positiveText(res.getString(R.string.dialog_ok)).onPositive((inner_dialog, which) -> ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_ERROR_HANDLING));
} else {
String[] dates = new String[mBackups.length];
for (int i = 0; i < mBackups.length; i++) {
dates[i] = mBackups[i].getName().replaceAll(".*-(\\d{4}-\\d{2}-\\d{2})-(\\d{2})-(\\d{2}).apkg", "$1 ($2:$3 h)");
}
builder.title(res.getString(R.string.backup_restore_select_title)).negativeText(res.getString(R.string.dialog_cancel)).onNegative((inner_dialog, which) -> dismissAllDialogFragments()).items(dates).itemsCallbackSingleChoice(dates.length, (materialDialog, view, which, charSequence) -> {
if (mBackups[which].length() > 0) {
// restore the backup if it's valid
((DeckPicker) getActivity()).restoreFromBackup(mBackups[which].getPath());
dismissAllDialogFragments();
} else {
// otherwise show an error dialog
new MaterialDialog.Builder(getActivity()).title(R.string.backup_error).content(R.string.backup_invalid_file_error).positiveText(R.string.dialog_ok).build().show();
}
return true;
});
}
MaterialDialog materialDialog = builder.build();
materialDialog.setOnKeyListener((dialog, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Timber.i("DIALOG_RESTORE_BACKUP caught hardware back button");
dismissAllDialogFragments();
return true;
}
return false;
});
return materialDialog;
}
case DIALOG_NEW_COLLECTION:
{
// Allow user to create a new empty collection
return builder.content(getMessage()).positiveText(res.getString(R.string.dialog_positive_create)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> {
CollectionHelper ch = CollectionHelper.getInstance();
Time time = ch.getTimeSafe(getContext());
ch.closeCollection(false, "DatabaseErrorDialog: Before Create New Collection");
String path1 = CollectionHelper.getCollectionPath(getActivity());
if (BackupManager.moveDatabaseToBrokenFolder(path1, false, time)) {
((DeckPicker) getActivity()).restartActivity();
} else {
((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_LOAD_FAILED);
}
}).show();
}
case DIALOG_CONFIRM_DATABASE_CHECK:
{
// Confirmation dialog for database check
return builder.content(getMessage()).positiveText(res.getString(R.string.dialog_ok)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> {
((DeckPicker) getActivity()).integrityCheck();
dismissAllDialogFragments();
}).show();
}
case DIALOG_CONFIRM_RESTORE_BACKUP:
{
// Confirmation dialog for backup restore
return builder.content(getMessage()).positiveText(res.getString(R.string.dialog_continue)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_RESTORE_BACKUP)).show();
}
case DIALOG_FULL_SYNC_FROM_SERVER:
{
// Allow user to do a full-sync from the server
return builder.content(getMessage()).positiveText(res.getString(R.string.dialog_positive_overwrite)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> {
((DeckPicker) getActivity()).sync("download");
dismissAllDialogFragments();
}).show();
}
case DIALOG_DB_LOCKED:
{
// If the database is locked, all we can do is ask the user to exit.
return builder.content(getMessage()).positiveText(res.getString(R.string.close)).cancelable(false).onPositive((inner_dialog, which) -> exit()).show();
}
default:
return null;
}
}
use of com.ichi2.anki.CollectionHelper in project AnkiChinaAndroid by ankichinateam.
the class ReminderService method onReceive.
@Override
public void onReceive(Context context, Intent intent) {
cancelDeckReminder(context, intent);
// 0 is not a valid dconf id.
final long dConfId = intent.getLongExtra(EXTRA_DECK_OPTION_ID, 0);
if (dConfId == 0) {
Timber.w("onReceive - dConfId 0, returning");
return;
}
CollectionHelper colHelper;
Collection col;
try {
colHelper = CollectionHelper.getInstance();
col = colHelper.getCol(context);
} catch (Throwable t) {
Timber.w("onReceive - unexpectedly unable to get collection. Returning.");
return;
}
if (null == col || !colHelper.colIsOpen()) {
Timber.w("onReceive - null or closed collection, unable to process reminders");
return;
}
if (col.getDecks().getConf(dConfId) == null) {
final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
final PendingIntent reminderIntent = PendingIntent.getBroadcast(context, (int) dConfId, new Intent(context, ReminderService.class).putExtra(EXTRA_DECK_OPTION_ID, dConfId), 0);
alarmManager.cancel(reminderIntent);
}
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
if (!notificationManager.areNotificationsEnabled()) {
Timber.v("onReceive - notifications disabled, returning");
return;
}
List<DeckDueTreeNode> decksDue = getDeckOptionDue(col, dConfId, true);
if (null == decksDue) {
Timber.v("onReceive - no decks due, returning");
return;
}
for (DeckDueTreeNode deckDue : decksDue) {
long deckId = deckDue.getDid();
final int total = deckDue.getRevCount() + deckDue.getLrnCount() + deckDue.getNewCount();
if (total <= 0) {
Timber.v("onReceive - no cards due in deck %d", deckId);
continue;
}
Timber.v("onReceive - deck '%s' due count %d", deckDue.getFullDeckName(), total);
final Notification notification = new NotificationCompat.Builder(context, NotificationChannels.getId(NotificationChannels.Channel.DECK_REMINDERS)).setCategory(NotificationCompat.CATEGORY_REMINDER).setContentTitle(context.getString(R.string.reminder_title)).setContentText(context.getResources().getQuantityString(R.plurals.reminder_text, total, deckDue.getFullDeckName(), total)).setSmallIcon(R.drawable.ic_stat_notify).setColor(ContextCompat.getColor(context, R.color.material_light_blue_700)).setContentIntent(PendingIntent.getActivity(context, (int) deckId, getReviewDeckIntent(context, deckId), PendingIntent.FLAG_UPDATE_CURRENT)).setAutoCancel(true).build();
notificationManager.notify((int) deckId, notification);
Timber.v("onReceive - notification state: %s", notification);
}
}
use of com.ichi2.anki.CollectionHelper in project AnkiChinaAndroid by ankichinateam.
the class Collection method load.
/**
* DB-related *************************************************************** ********************************
*/
public void load() {
Cursor cursor = null;
String deckConf = "";
try {
// Read in deck table columns
cursor = mDb.query("SELECT crt, mod, scm, dty, usn, ls, " + "conf, dconf, tags,ver FROM col");
if (!cursor.moveToFirst()) {
return;
}
mCrt = cursor.getLong(0);
mMod = cursor.getLong(1);
mScm = cursor.getLong(2);
// No longer used
mDty = cursor.getInt(3) == 1;
mUsn = cursor.getInt(4);
mLs = cursor.getLong(5);
mConf = new JSONObject(cursor.getString(6));
deckConf = cursor.getString(7);
mTagsJson = cursor.getString(8);
mTags.load(mTagsJson);
mVer = cursor.getInt(9);
} finally {
if (cursor != null) {
cursor.close();
}
}
// getModels().load(loadColumn("models")); This code has been
// moved to `CollectionHelper::loadLazyCollection` for
// efficiency Models are loaded lazily on demand. The
// application layer can asynchronously pre-fetch those parts;
// otherwise they get loaded when required.
Timber.i("load new collection");
mDecks.load(loadColumn("decks"), deckConf);
}
use of com.ichi2.anki.CollectionHelper in project AnkiChinaAndroid by ankichinateam.
the class RobolectricTest method tearDown.
@After
public void tearDown() {
// If you don't clean up your ActivityControllers you will get OOM errors
for (ActivityController controller : controllersForCleanup) {
Timber.d("Calling destroy on controller %s", controller.get().toString());
try {
controller.destroy();
} catch (Exception e) {
// Any exception here is likely because the test code already destroyed it, which is fine
// No exception here should halt test execution since tests are over anyway.
}
}
controllersForCleanup.clear();
// If you don't tear down the database you'll get unexpected IllegalStateExceptions related to connections
CollectionHelper.getInstance().closeCollection(false, "RoboelectricTest: End");
// After every test make sure the CollectionHelper is no longer overridden (done for null testing)
disableNullCollection();
// After every test, make sure the sqlite implementation is set back to default
DB.setSqliteOpenHelperFactory(null);
// called on each AnkiDroidApp.onCreate(), and spams the build
// there is no onDestroy(), so call it here.
Timber.uprootAll();
}
Aggregations