use of com.ichi2.libanki.utils.Time in project AnkiChinaAndroid by ankichinateam.
the class BackupManager method repairCollection.
/**
* Run the sqlite3 command-line-tool (if it exists) on the collection to dump to a text file
* and reload as a new database. Recently this command line tool isn't available on many devices
*
* @param col Collection
* @return whether the repair was successful
*/
public static boolean repairCollection(Collection col) {
String deckPath = col.getPath();
File deckFile = new File(deckPath);
Time time = col.getTime();
Timber.i("BackupManager - RepairCollection - Closing Collection");
col.close();
// repair file
String execString = "sqlite3 " + deckPath + " .dump | sqlite3 " + deckPath + ".tmp";
Timber.i("repairCollection - Execute: %s", execString);
try {
String[] cmd = { "/system/bin/sh", "-c", execString };
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
if (!new File(deckPath + ".tmp").exists()) {
Timber.e("repairCollection - dump to " + deckPath + ".tmp failed");
return false;
}
if (!moveDatabaseToBrokenFolder(deckPath, false, time)) {
Timber.e("repairCollection - could not move corrupt file to broken folder");
return false;
}
Timber.i("repairCollection - moved corrupt file to broken folder");
File repairedFile = new File(deckPath + ".tmp");
return repairedFile.renameTo(deckFile);
} catch (IOException | InterruptedException e) {
Timber.e(e, "repairCollection - error");
}
return false;
}
use of com.ichi2.libanki.utils.Time in project AnkiChinaAndroid by ankichinateam.
the class CardBrowser method onCollectionLoaded.
// Finish initializing the activity after the collection has been correctly loaded
@Override
protected void onCollectionLoaded(Collection col) {
super.onCollectionLoaded(col);
Timber.d("onCollectionLoaded()");
registerExternalStorageListener();
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext());
// Load reference to action bar title
mActionBarTitle = (TextView) findViewById(R.id.toolbar_title);
// Add drop-down menu to select deck to action bar.
mDropDownDecks = getCol().getDecks().allSorted();
mDropDownAdapter = new DeckDropDownAdapter(this, mDropDownDecks, R.layout.dropdown_deck_selected_item, this);
Toolbar toolbar = findViewById(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
// enable ActionBar app icon to behave as action to toggle nav drawer
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
// Decide which action to take when the navigation button is tapped.
toolbar.setNavigationOnClickListener(v -> finishActivityWithFade(this, ActivityTransitionAnimation.RIGHT));
}
ActionBar mActionBar = getSupportActionBar();
if (mActionBar != null) {
mActionBar.setDisplayShowTitleEnabled(false);
}
mActionBarSpinner = (Spinner) findViewById(R.id.toolbar_spinner);
mActionBarSpinner.setAdapter(mDropDownAdapter);
mActionBarSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
deckDropDownItemChanged(position);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// do nothing
}
});
mActionBarSpinner.setVisibility(View.VISIBLE);
mOrder = CARD_ORDER_NONE;
String colOrder = getCol().getConf().getString("sortType");
for (int c = 0; c < fSortTypes.length; ++c) {
if (fSortTypes[c].equals(colOrder)) {
mOrder = c;
break;
}
}
if (mOrder == 1 && preferences.getBoolean("cardBrowserNoSorting", false)) {
mOrder = 0;
}
// This upgrade should already have been done during
// setConf. However older version of AnkiDroid didn't call
// upgradeJSONIfNecessary during setConf, which means the
// conf saved may still have this bug.
mOrderAsc = Upgrade.upgradeJSONIfNecessary(getCol(), getCol().getConf(), "sortBackwards", false);
mCards = new ArrayList<>();
mCardsListView = (ListView) findViewById(R.id.card_browser_list);
// Create a spinner for column1
Spinner cardsColumn1Spinner = (Spinner) findViewById(R.id.browser_column1_spinner);
ArrayAdapter<CharSequence> column1Adapter = ArrayAdapter.createFromResource(this, R.array.browser_column1_headings, android.R.layout.simple_spinner_item);
column1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
cardsColumn1Spinner.setAdapter(column1Adapter);
mColumn1Index = AnkiDroidApp.getSharedPrefs(getBaseContext()).getInt("cardBrowserColumn1", 0);
cardsColumn1Spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
// If a new column was selected then change the key used to map from mCards to the column TextView
if (pos != mColumn1Index) {
mColumn1Index = pos;
AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).edit().putInt("cardBrowserColumn1", mColumn1Index).commit();
Column[] fromMap = mCardsAdapter.getFromMapping();
fromMap[0] = COLUMN1_KEYS[mColumn1Index];
mCardsAdapter.setFromMapping(fromMap);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Do Nothing
}
});
// Load default value for column2 selection
mColumn2Index = AnkiDroidApp.getSharedPrefs(getBaseContext()).getInt("cardBrowserColumn2", 0);
// Setup the column 2 heading as a spinner so that users can easily change the column type
Spinner cardsColumn2Spinner = (Spinner) findViewById(R.id.browser_column2_spinner);
ArrayAdapter<CharSequence> column2Adapter = ArrayAdapter.createFromResource(this, R.array.browser_column2_headings, android.R.layout.simple_spinner_item);
column2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
cardsColumn2Spinner.setAdapter(column2Adapter);
// Create a new list adapter with updated column map any time the user changes the column
cardsColumn2Spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
// If a new column was selected then change the key used to map from mCards to the column TextView
if (pos != mColumn2Index) {
mColumn2Index = pos;
AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).edit().putInt("cardBrowserColumn2", mColumn2Index).commit();
Column[] fromMap = mCardsAdapter.getFromMapping();
fromMap[1] = COLUMN2_KEYS[mColumn2Index];
mCardsAdapter.setFromMapping(fromMap);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Do Nothing
}
});
// get the font and font size from the preferences
int sflRelativeFontSize = preferences.getInt("relativeCardBrowserFontSize", DEFAULT_FONT_SIZE_RATIO);
String sflCustomFont = preferences.getString("browserEditorFont", "");
Column[] columnsContent = { COLUMN1_KEYS[mColumn1Index], COLUMN2_KEYS[mColumn2Index] };
// make a new list adapter mapping the data in mCards to column1 and column2 of R.layout.card_item_browser
mCardsAdapter = new MultiColumnListAdapter(this, R.layout.card_item_browser, columnsContent, new int[] { R.id.card_sfld, R.id.card_column2 }, sflRelativeFontSize, sflCustomFont);
// link the adapter to the main mCardsListView
mCardsListView.setAdapter(mCardsAdapter);
// make the items (e.g. question & answer) render dynamically when scrolling
mCardsListView.setOnScrollListener(new RenderOnScroll());
// set the spinner index
cardsColumn1Spinner.setSelection(mColumn1Index);
cardsColumn2Spinner.setSelection(mColumn2Index);
mCardsListView.setOnItemClickListener(new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mInMultiSelectMode) {
// click on whole cell triggers select
CheckBox cb = (CheckBox) view.findViewById(R.id.card_checkbox);
cb.toggle();
onCheck(position, view);
} else {
// load up the card selected on the list
long clickedCardId = getCards().get(position).getId();
openNoteEditorForCard(clickedCardId);
}
}
});
mCardsListView.setOnItemLongClickListener(new ListView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, final int position, long id) {
mLastSelectedPosition = position;
loadMultiSelectMode();
// click on whole cell triggers select
CheckBox cb = (CheckBox) view.findViewById(R.id.card_checkbox);
cb.toggle();
onCheck(position, view);
recenterListView(view);
mCardsAdapter.notifyDataSetChanged();
return true;
}
});
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
// If a valid value for last deck exists then use it, otherwise use libanki selected deck
if (getLastDeckId() != null && getLastDeckId() == ALL_DECKS_ID) {
selectAllDecks();
} else if (getLastDeckId() != null && getCol().getDecks().get(getLastDeckId(), false) != null) {
selectDeckById(getLastDeckId());
} else {
selectDeckById(getCol().getDecks().selected());
}
}
use of com.ichi2.libanki.utils.Time in project AnkiChinaAndroid by ankichinateam.
the class AnkiActivity method showImportDialog.
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void showImportDialog(int id, String message) {
// On API19+ we only use import dialog to confirm, otherwise we use it the whole time
if ((CompatHelper.getSdkVersion() < 19) || (id == ImportDialog.DIALOG_IMPORT_ADD_CONFIRM) || (id == ImportDialog.DIALOG_IMPORT_REPLACE_CONFIRM)) {
Timber.d("showImportDialog() delegating to ImportDialog");
AsyncDialogFragment newFragment = ImportDialog.newInstance(id, message, this);
showAsyncDialogFragment(newFragment);
} else {
Timber.d("showImportDialog() delegating to file picker intent");
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra("android.content.extra.SHOW_ADVANCED", true);
intent.putExtra("android.content.extra.FANCY", true);
intent.putExtra("android.content.extra.SHOW_FILESIZE", true);
startActivityForResultWithoutAnimation(intent, PICK_APKG_FILE);
}
}
use of com.ichi2.libanki.utils.Time in project AnkiChinaAndroid by ankichinateam.
the class OverView method loadDataBuilder.
public void loadDataBuilder(OverviewStatsBuilder builder) {
Timber.d("loadDataBuilder");
Resources res = getResources();
findTextViewById(R.id.tv_today).setText(res.getString(R.string.stats_today));
final int minutes = (int) Math.round(builder.mTodayStats[THETIME_INDEX] / 60.0);
final String span = res.getQuantityString(R.plurals.time_span_minutes, minutes, minutes);
findTextViewById(R.id.tv_today_minute).setText(res.getQuantityString(R.plurals.stats_today_cards, builder.mTodayStats[CARDS_INDEX], builder.mTodayStats[CARDS_INDEX], span));
findTextViewById(R.id.tv_today_repeat).setText(res.getString(R.string.stats_today_again_count, builder.mTodayStats[FAILED_INDEX]));
if (builder.mTodayStats[CARDS_INDEX] > 0) {
findTextViewById(R.id.tv_today_correct_rate).setVisibility(VISIBLE);
findTextViewById(R.id.tv_today_correct_rate).setText(res.getString(R.string.stats_today_correct_count, builder.mTodayStats[CARDS_INDEX] - builder.mTodayStats[FAILED_INDEX], builder.mTodayStats[CARDS_INDEX], (((1 - builder.mTodayStats[FAILED_INDEX] / (float) (builder.mTodayStats[CARDS_INDEX])) * 100.0))));
} else {
findTextViewById(R.id.tv_today_correct_rate).setVisibility(GONE);
}
findTextViewById(R.id.tv_today_study).setText(res.getString(R.string.stats_today_type_breakdown, builder.mTodayStats[LRN_INDEX], builder.mTodayStats[REV_INDEX], builder.mTodayStats[RELRN_INDEX], builder.mTodayStats[FILT_INDEX]));
if (builder.mTodayStats[MCNT_INDEX] != 0) {
findTextViewById(R.id.tv_today_hint).setText(res.getString(R.string.stats_today_mature_cards, builder.mTodayStats[MSUM_INDEX], builder.mTodayStats[MCNT_INDEX], (builder.mTodayStats[MSUM_INDEX] / (float) (builder.mTodayStats[MCNT_INDEX]) * 100.0)));
} else {
findTextViewById(R.id.tv_today_hint).setText(res.getString(R.string.stats_today_no_mature_cards));
}
findTextViewById(R.id.description).setText(res.getString(builder.mType.descriptionId));
OverviewStatsBuilder.OverviewStats oStats = builder.mOverViewStats;
// FORECAST
findTextViewById(R.id.tv_predict).setText(res.getString(R.string.stats_forecast).toUpperCase());
findTextViewById(R.id.tv_predict_all_content).setText(res.getString(R.string.stats_overview_forecast_total, oStats.forecastTotalReviews));
findTextViewById(R.id.tv_predict_avg_content).setText(res.getString(R.string.stats_overview_forecast_average, oStats.forecastAverageReviews));
findTextViewById(R.id.tv_predict_deadline_content).setText(res.getString(R.string.stats_overview_forecast_due_tomorrow, oStats.forecastDueTomorrow));
// REVIEW COUNT
findTextViewById(R.id.tv_review).setText(res.getString(R.string.stats_review_count).toUpperCase());
findTextViewById(R.id.tv_review_day_content).setText(oStats.daysStudied + "/" + oStats.allDays);
findTextViewById(R.id.tv_review_day_percent).setText("(" + (int) ((float) oStats.daysStudied / (float) oStats.allDays * 100) + "%)");
findTextViewById(R.id.tv_review_all_content).setText(res.getString(R.string.stats_overview_total_reviews, oStats.totalReviews));
findTextViewById(R.id.tv_review_avg_content).setText(res.getString(R.string.stats_overview_reviews_per_day_studydays, oStats.reviewsPerDayOnStudyDays));
boolean allDaysStudied = oStats.daysStudied == oStats.allDays;
if (!allDaysStudied) {
findTextViewById(R.id.tv_review_hint).setText(res.getString(R.string.stats_overview_reviews_per_day_all, oStats.reviewsPerDayOnAll));
findTextViewById(R.id.tv_review_hint).setVisibility(VISIBLE);
} else {
findTextViewById(R.id.tv_review_hint).setVisibility(GONE);
}
// REVIEW TIME
findTextViewById(R.id.tv_review_time).setText(res.getString(R.string.stats_review_time).toUpperCase());
findTextViewById(R.id.tv_review_time_count_content).setText(oStats.daysStudied + "/" + oStats.allDays);
findTextViewById(R.id.tv_review_time_count_percent).setText("(" + (int) ((float) oStats.daysStudied / (float) oStats.allDays * 100) + "%)");
findTextViewById(R.id.tv_review_time_all_content).setText(res.getString(R.string.stats_overview_total_time_in_period, Math.round(oStats.totalTime)));
findTextViewById(R.id.tv_review_time_avg_content).setText(res.getString(R.string.stats_overview_time_per_day_studydays, oStats.timePerDayOnStudyDays));
double cardsPerMinute = oStats.totalTime == 0 ? 0 : ((double) oStats.totalReviews) / oStats.totalTime;
double averageAnswerTime = oStats.totalReviews == 0 ? 0 : (oStats.totalTime * 60) / ((double) oStats.totalReviews);
if (!allDaysStudied) {
findTextViewById(R.id.tv_review_time_hint).setText(res.getString(R.string.stats_overview_time_per_day_all, oStats.timePerDayOnAll) + "," + res.getString(R.string.stats_overview_average_answer_time, averageAnswerTime, cardsPerMinute));
} else {
findTextViewById(R.id.tv_review_time_hint).setText(res.getString(R.string.stats_overview_average_answer_time, averageAnswerTime, cardsPerMinute));
}
// ADDED
findTextViewById(R.id.tv_add).setText(res.getString(R.string.stats_added).toUpperCase());
findTextViewById(R.id.tv_add_all_content).setText(res.getString(R.string.stats_overview_total_new_cards, oStats.totalNewCards));
findTextViewById(R.id.tv_add_avg_content).setText(res.getString(R.string.stats_overview_new_cards_per_day, oStats.newCardsPerDay));
// INTERVALS
findTextViewById(R.id.tv_distance).setText(res.getString(R.string.stats_review_intervals).toUpperCase());
findTextViewById(R.id.tv_distance_avg).setText(res.getString(R.string.stats_overview_average_interval));
findTextViewById(R.id.tv_distance_avg_content).setText(Utils.roundedTimeSpan(getContext(), (int) Math.round(oStats.averageInterval * Stats.SECONDS_PER_DAY)));
findTextViewById(R.id.tv_distance_max).setText(res.getString(R.string.stats_overview_longest_interval));
findTextViewById(R.id.tv_distance_all_content).setText(Utils.roundedTimeSpan(getContext(), (int) Math.round(oStats.longestInterval * Stats.SECONDS_PER_DAY)));
// ANSWER BUTTONS
findTextViewById(R.id.tv_answer_button).setText(res.getString(R.string.stats_answer_buttons).toUpperCase());
findTextViewById(R.id.tv_answer_study_content).setText(res.getString(R.string.stats_overview_answer_buttons_learn, oStats.newCardsOverview.getPercentage()));
findTextViewById(R.id.tv_answer_study_percent).setText("(" + oStats.newCardsOverview.correct + "/" + oStats.newCardsOverview.total + ")");
findTextViewById(R.id.tv_answer_not_familiar_content).setText(res.getString(R.string.stats_overview_answer_buttons_young, oStats.youngCardsOverview.getPercentage()));
findTextViewById(R.id.tv_answer_not_familiar_percent).setText("(" + oStats.youngCardsOverview.correct + "/" + oStats.youngCardsOverview.total + ")");
findTextViewById(R.id.tv_answer_familiar_content).setText(res.getString(R.string.stats_overview_answer_buttons_mature, oStats.matureCardsOverview.getPercentage()));
findTextViewById(R.id.tv_answer_familiar_percent).setText("(" + oStats.matureCardsOverview.correct + "/" + oStats.matureCardsOverview.total + ")");
// CARD TYPES
findTextViewById(R.id.tv_note_type).setText(res.getString(R.string.stats_cards_types).toUpperCase());
findTextViewById(R.id.tv_note_type_all_card).setText(R.string.stats_overview_card_types_total_cards);
findTextViewById(R.id.tv_note_type_all_card_content).setText("" + oStats.totalCards);
findTextViewById(R.id.tv_note_type_all).setText(R.string.stats_overview_card_types_total_notes);
findTextViewById(R.id.tv_note_type_all_content).setText("" + oStats.totalNotes);
findTextViewById(R.id.tv_note_low_level).setText(R.string.stats_overview_card_types_lowest_ease);
findTextViewById(R.id.tv_note_low_level_content).setText(oStats.lowestEase + "%");
findTextViewById(R.id.tv_note_avg_level).setText(R.string.stats_overview_card_types_average_ease);
findTextViewById(R.id.tv_note_avg_level_content).setText(oStats.averageEase + "%");
findTextViewById(R.id.tv_note_high_level).setText(R.string.stats_overview_card_types_highest_ease);
findTextViewById(R.id.tv_note_high_level_content).setText(oStats.highestEase + "%");
}
use of com.ichi2.libanki.utils.Time in project AnkiChinaAndroid by ankichinateam.
the class Connection method doInBackgroundSync.
private Payload doInBackgroundSync(Payload data) {
sIsCancellable = true;
Timber.d("doInBackgroundSync()");
// Block execution until any previous background task finishes, or timeout after 5s
boolean ok = CollectionTask.waitToFinish(5);
String hkey = (String) data.data[0];
boolean media = (Boolean) data.data[1];
String conflictResolution = (String) data.data[2];
HostNum hostNum = (HostNum) data.data[3];
long restServerSpace = (long) data.data[4];
// Use safe version that catches exceptions so that full sync is still possible
Collection col = CollectionHelper.getInstance().getColSafe(AnkiDroidApp.getInstance());
boolean colCorruptFullSync = false;
if (!CollectionHelper.getInstance().colIsOpen() || !ok) {
if (conflictResolution != null && "download".equals(conflictResolution)) {
colCorruptFullSync = true;
} else {
data.success = false;
data.result = new Object[] { "genericError" };
return data;
}
}
try {
CollectionHelper.getInstance().lockCollection();
HttpSyncer server = new RemoteServer(this, hkey, hostNum);
Syncer client = new Syncer(col, server, hostNum);
// run sync and check state
boolean noChanges = false;
if (conflictResolution == null) {
Timber.i("Sync - starting sync");
publishProgress(R.string.sync_prepare_syncing);
Object[] ret = client.sync(this, restServerSpace);
data.message = client.getSyncMsg();
if (ret == null) {
data.success = false;
data.result = new Object[] { "genericError" };
return data;
}
String retCode = (String) ret[0];
if (!"noChanges".equals(retCode) && !"success".equals(retCode)) {
data.success = false;
data.result = ret;
// Check if there was a sanity check error
if ("sanityCheckError".equals(retCode)) {
// Force full sync next time
col.modSchemaNoCheck();
col.save();
}
return data;
}
// save and note success state
if ("noChanges".equals(retCode)) {
// publishProgress(R.string.sync_no_changes_message);
noChanges = true;
}
restServerSpace = client.getRestSpace();
} else {
try {
// Disable sync cancellation for full-sync
sIsCancellable = false;
server = new FullSyncer(col, hkey, this, hostNum);
if ("upload".equals(conflictResolution)) {
Timber.i("Sync - fullsync - upload collection");
publishProgress(R.string.sync_preparing_full_sync_message);
Object[] ret = server.upload(restServerSpace);
col.reopen();
if (ret == null) {
data.success = false;
data.result = new Object[] { "genericError" };
return data;
}
if (!ret[0].equals(HttpSyncer.ANKIWEB_STATUS_OK)) {
data.success = false;
data.result = ret;
return data;
}
} else if ("download".equals(conflictResolution)) {
Timber.i("Sync - fullsync - download collection");
publishProgress(R.string.sync_downloading_message);
Object[] ret = server.download();
if (ret == null) {
Timber.w("Sync - fullsync - unknown error");
data.success = false;
data.result = new Object[] { "genericError" };
return data;
}
if ("success".equals(ret[0])) {
data.success = true;
col.reopen();
}
if (!"success".equals(ret[0])) {
Timber.w("Sync - fullsync - download failed");
data.success = false;
data.result = ret;
if (!colCorruptFullSync) {
col.reopen();
}
return data;
}
}
} catch (OutOfMemoryError e) {
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundSync-fullSync");
data.success = false;
data.result = new Object[] { "OutOfMemoryError" };
return data;
} catch (RuntimeException e) {
if (timeoutOccurred(e)) {
data.result = new Object[] { "connectionError", e };
} else if ("UserAbortedSync".equals(e.getMessage())) {
data.result = new Object[] { "UserAbortedSync", e };
} else {
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundSync-fullSync");
data.result = new Object[] { "IOException", e };
}
data.success = false;
return data;
}
}
// clear undo to avoid non syncing orphans (because undo resets usn too
if (!noChanges) {
col.clearUndo();
}
// then move on to media sync
sIsCancellable = true;
boolean noMediaChanges = false;
boolean enoughServerSpace = true;
String mediaError = null;
if (media) {
server = new RemoteMediaServer(col, hkey, this, hostNum);
MediaSyncer mediaClient = new MediaSyncer(col, (RemoteMediaServer) server, this);
String ret;
try {
// ������ܻ���Ϊ�ϴ��ļ������ռ��С���׳��쳣���ڴ�֮ǰ��Ҫ����ʣ��ռ��С
ret = mediaClient.sync(restServerSpace);
Timber.e("sync media ret is null");
if (ret == null) {
mediaError = AnkiDroidApp.getAppResources().getString(R.string.sync_media_error);
} else {
if ("corruptMediaDB".equals(ret)) {
mediaError = AnkiDroidApp.getAppResources().getString(R.string.sync_media_db_error);
noMediaChanges = true;
}
if ("noChanges".equals(ret)) {
publishProgress(R.string.sync_media_no_changes);
noMediaChanges = true;
}
if ("sanityFailed".equals(ret)) {
mediaError = AnkiDroidApp.getAppResources().getString(R.string.sync_media_sanity_failed);
} else {
publishProgress(R.string.sync_media_success);
}
}
} catch (RuntimeException e) {
if (timeoutOccurred(e)) {
data.result = new Object[] { "connectionError", e };
} else if ("UserAbortedSync".equals(e.getMessage())) {
data.result = new Object[] { "UserAbortedSync", e };
}
mediaError = AnkiDroidApp.getAppResources().getString(R.string.sync_media_error) + "\n\n" + e.getLocalizedMessage();
}
}
if (noChanges && (!media || noMediaChanges)) {
data.success = false;
data.result = new Object[] { "noChanges" };
return data;
} else {
data.success = true;
data.data = new Object[] { conflictResolution, col, mediaError };
return data;
}
} catch (MediaSyncException e) {
Timber.e("Media sync rejected by server");
data.success = false;
data.result = new Object[] { "mediaSyncServerError", e };
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundSync");
return data;
} catch (UnknownHttpResponseException e) {
Timber.e(e, "doInBackgroundSync -- unknown response code error");
data.success = false;
int code = e.getResponseCode();
String msg = e.getLocalizedMessage();
data.result = new Object[] { "error", code, msg };
return data;
} catch (NoEnoughServerSpaceException e) {
Timber.e("NoEnoughServerSpaceException ");
e.printStackTrace();
data.success = false;
data.result = new Object[] { "noServerSpace", e.rest, e.need };
return data;
} catch (Exception e) {
// Global error catcher.
// Try to give a human readable error, otherwise print the raw error message
Timber.e(e, "doInBackgroundSync error");
data.success = false;
if (timeoutOccurred(e)) {
data.result = new Object[] { "connectionError", e };
} else if ("UserAbortedSync".equals(e.getMessage())) {
data.result = new Object[] { "UserAbortedSync", e };
} else {
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundSync");
data.result = new Object[] { e.getLocalizedMessage(), e };
}
return data;
} finally {
Timber.i("Sync Finished - Closing Collection");
// don't bump mod time unless we explicitly save
if (col != null) {
col.close(false);
}
CollectionHelper.getInstance().unlockCollection();
}
}
Aggregations