use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project Anki-Android by ankidroid.
the class ZipFile method exportInto.
/**
* Export source database into new destination database Note: The following python syntax isn't supported in
* Android: for row in mSrc.db.execute("select * from cards where id in "+ids2str(cids)): therefore we use a
* different method for copying tables
*
* @param path String path to destination database
* @throws JSONException
* @throws IOException
*/
public void exportInto(@NonNull String path, Context context) throws JSONException, IOException, ImportExportException {
// create a new collection at the target
new File(path).delete();
Collection dst = Storage.Collection(context, path);
mSrc = mCol;
// find cards
Long[] cids = cardIds();
// attach dst to src so we can copy data between them. This isn't done in original libanki as Python more
// flexible
dst.close();
Timber.d("Attach DB");
mSrc.getDb().getDatabase().execSQL("ATTACH '" + path + "' AS DST_DB");
// copy cards, noting used nids (as unique set)
Timber.d("Copy cards");
mSrc.getDb().getDatabase().execSQL("INSERT INTO DST_DB.cards select * from cards where id in " + Utils.ids2str(cids));
List<Long> uniqueNids = mSrc.getDb().queryLongList("select distinct nid from cards where id in " + Utils.ids2str(cids));
// notes
Timber.d("Copy notes");
String strnids = Utils.ids2str(uniqueNids);
mSrc.getDb().getDatabase().execSQL("INSERT INTO DST_DB.notes select * from notes where id in " + strnids);
// remove system tags if not exporting scheduling info
if (!mIncludeSched) {
Timber.d("Stripping system tags from list");
ArrayList<String> srcTags = mSrc.getDb().queryStringList("select tags from notes where id in " + strnids);
ArrayList<Object[]> args = new ArrayList<>(srcTags.size());
Object[] arg = new Object[2];
for (int row = 0; row < srcTags.size(); row++) {
arg[0] = removeSystemTags(srcTags.get(row));
arg[1] = uniqueNids.get(row);
args.add(row, arg);
}
mSrc.getDb().executeMany("UPDATE DST_DB.notes set tags=? where id=?", args);
}
// models used by the notes
Timber.d("Finding models used by notes");
ArrayList<Long> mids = mSrc.getDb().queryLongList("select distinct mid from DST_DB.notes where id in " + strnids);
// card history and revlog
if (mIncludeSched) {
Timber.d("Copy history and revlog");
mSrc.getDb().getDatabase().execSQL("insert into DST_DB.revlog select * from revlog where cid in " + Utils.ids2str(cids));
// reopen collection to destination database (different from original python code)
mSrc.getDb().getDatabase().execSQL("DETACH DST_DB");
dst.reopen();
} else {
Timber.d("Detaching destination db and reopening");
// first reopen collection to destination database (different from original python code)
mSrc.getDb().getDatabase().execSQL("DETACH DST_DB");
dst.reopen();
// then need to reset card state
Timber.d("Resetting cards");
dst.getSched().resetCards(cids);
}
// models - start with zero
Timber.d("Copy models");
for (Model m : mSrc.getModels().all()) {
if (mids.contains(m.getLong("id"))) {
dst.getModels().update(m);
}
}
// decks
Timber.d("Copy decks");
java.util.Collection<Long> dids = null;
if (mDid != null) {
dids = new HashSet<>(mSrc.getDecks().children(mDid).values());
dids.add(mDid);
}
JSONObject dconfs = new JSONObject();
for (Deck d : mSrc.getDecks().all()) {
if ("1".equals(d.getString("id"))) {
continue;
}
if (dids != null && !dids.contains(d.getLong("id"))) {
continue;
}
if (d.isStd() && d.getLong("conf") != 1L) {
if (mIncludeSched) {
dconfs.put(Long.toString(d.getLong("conf")), true);
}
}
Deck destinationDeck = d.deepClone();
if (!mIncludeSched) {
// scheduling not included, so reset deck settings to default
destinationDeck.put("conf", 1);
}
dst.getDecks().update(destinationDeck);
}
// copy used deck confs
Timber.d("Copy deck options");
for (DeckConfig dc : mSrc.getDecks().allConf()) {
if (dconfs.has(dc.getString("id"))) {
dst.getDecks().updateConf(dc);
}
}
// find used media
Timber.d("Find used media");
JSONObject media = new JSONObject();
mMediaDir = mSrc.getMedia().dir();
if (mIncludeMedia) {
ArrayList<Long> mid = mSrc.getDb().queryLongList("select mid from notes where id in " + strnids);
ArrayList<String> flds = mSrc.getDb().queryStringList("select flds from notes where id in " + strnids);
for (int idx = 0; idx < mid.size(); idx++) {
for (String file : mSrc.getMedia().filesInStr(mid.get(idx), flds.get(idx))) {
// skip files in subdirs
if (file.contains(File.separator)) {
continue;
}
media.put(file, true);
}
}
if (mMediaDir != null) {
for (File f : new File(mMediaDir).listFiles()) {
if (f.isDirectory()) {
continue;
}
String fname = f.getName();
if (fname.startsWith("_")) {
// Loop through every model that will be exported, and check if it contains a reference to f
for (JSONObject model : mSrc.getModels().all()) {
if (_modelHasMedia(model, fname)) {
media.put(fname, true);
break;
}
}
}
}
}
}
JSONArray keys = media.names();
if (keys != null) {
mMediaFiles.ensureCapacity(keys.length());
addAll(mMediaFiles, keys.stringIterable());
}
Timber.d("Cleanup");
dst.setCrt(mSrc.getCrt());
// todo: tags?
mCount = dst.cardCount();
dst.setMod();
postExport();
dst.close();
}
use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project Anki-Android by ankidroid.
the class DeckPicker method showStartupScreensAndDialogs.
private void showStartupScreensAndDialogs(SharedPreferences preferences, int skip) {
// For Android 8/8.1 we want to use software rendering by default or the Reviewer UI is broken #7369
if (CompatHelper.getSdkVersion() == Build.VERSION_CODES.O || CompatHelper.getSdkVersion() == Build.VERSION_CODES.O_MR1) {
if (!preferences.contains("softwareRender")) {
Timber.i("Android 8/8.1 detected with no render preference. Turning on software render.");
preferences.edit().putBoolean("softwareRender", true).apply();
} else {
Timber.i("Android 8/8.1 detected, software render preference already exists.");
}
}
if (!BackupManager.enoughDiscSpace(CollectionHelper.getCurrentAnkiDroidDirectory(this))) {
Timber.i("Not enough space to do backup");
showDialogFragment(DeckPickerNoSpaceLeftDialog.newInstance());
} else if (preferences.getBoolean("noSpaceLeft", false)) {
Timber.i("No space left");
showDialogFragment(DeckPickerBackupNoSpaceLeftDialog.newInstance());
preferences.edit().remove("noSpaceLeft").apply();
} else if (InitialActivity.performSetupFromFreshInstallOrClearedPreferences(preferences)) {
onFinishedStartup();
} else if (skip < 2 && !InitialActivity.isLatestVersion(preferences)) {
Timber.i("AnkiDroid is being updated and a collection already exists.");
// The user might appreciate us now, see if they will help us get better?
if (!preferences.contains(UsageAnalytics.ANALYTICS_OPTIN_KEY)) {
displayAnalyticsOptInDialog();
}
// For upgrades, we check if we are upgrading
// to a version that contains additions to the database integrity check routine that we would
// like to run on all collections. A missing version number is assumed to be a fresh
// installation of AnkiDroid and we don't run the check.
long current = VersionUtils.getPkgVersionCode();
Timber.i("Current AnkiDroid version: %s", current);
long previous;
if (preferences.contains(UPGRADE_VERSION_KEY)) {
// Upgrading currently installed app
previous = getPreviousVersion(preferences, current);
} else {
// Fresh install
previous = current;
}
preferences.edit().putLong(UPGRADE_VERSION_KEY, current).apply();
// It is rebuilt on the next sync or media check
if (previous < 20300200) {
Timber.i("Deleting media database");
File mediaDb = new File(CollectionHelper.getCurrentAnkiDroidDirectory(this), "collection.media.ad.db2");
if (mediaDb.exists()) {
mediaDb.delete();
}
}
// Recommend the user to do a full-sync if they're upgrading from before 2.3.1beta8
if (previous < 20301208) {
Timber.i("Recommend the user to do a full-sync");
mRecommendFullSync = true;
}
// Fix "font-family" definition in templates created by AnkiDroid before 2.6alhpa23
if (previous < 20600123) {
Timber.i("Fixing font-family definition in templates");
try {
ModelManager models = getCol().getModels();
for (Model m : models.all()) {
String css = m.getString("css");
if (css.contains("font-familiy")) {
m.put("css", css.replace("font-familiy", "font-family"));
models.save(m);
}
}
models.flush();
} catch (JSONException e) {
Timber.e(e, "Failed to upgrade css definitions.");
}
}
// Check if preference upgrade or database check required, otherwise go to new feature screen
int upgradeDbVersion = AnkiDroidApp.CHECK_DB_AT_VERSION;
// Specifying a checkpoint in the future is not supported, please don't do it!
if (current < upgradeDbVersion) {
Timber.e("Invalid value for CHECK_DB_AT_VERSION");
UIUtils.showSimpleSnackbar(this, "Invalid value for CHECK_DB_AT_VERSION", false);
onFinishedStartup();
return;
}
// Skip full DB check if the basic check is OK
// TODO: remove this variable if we really want to do the full db check on every user
boolean skipDbCheck = false;
// if (previous < upgradeDbVersion && getCol().basicCheck()) {
// skipDbCheck = true;
// }
boolean upgradedPreferences = InitialActivity.upgradePreferences(this, previous);
// noinspection ConstantConditions
if (!skipDbCheck && previous < upgradeDbVersion) {
Timber.i("showStartupScreensAndDialogs() running integrityCheck()");
// #5852 - since we may have a warning about disk space, we don't want to force a check database
// and show a warning before the user knows what is happening.
new MaterialDialog.Builder(this).title(R.string.integrity_check_startup_title).content(R.string.integrity_check_startup_content).positiveText(R.string.check_db).negativeText(R.string.close).onPositive((materialDialog, dialogAction) -> integrityCheck()).onNeutral((materialDialog, dialogAction) -> restartActivity()).onNegative((materialDialog, dialogAction) -> restartActivity()).canceledOnTouchOutside(false).cancelable(false).build().show();
return;
}
if (upgradedPreferences) {
Timber.i("Updated preferences with no integrity check - restarting activity");
// If integrityCheck() doesn't occur, but we did update preferences we should restart DeckPicker to
// proceed
restartActivity();
return;
}
// There the "lastVersion" is set, so that this code is not reached again
if (VersionUtils.isReleaseVersion()) {
Timber.i("Displaying new features");
Intent infoIntent = new Intent(this, Info.class);
infoIntent.putExtra(Info.TYPE_EXTRA, Info.TYPE_NEW_VERSION);
if (skip != 0) {
startActivityForResultWithAnimation(infoIntent, SHOW_INFO_NEW_VERSION, START);
} else {
startActivityForResultWithoutAnimation(infoIntent, SHOW_INFO_NEW_VERSION);
}
} else {
Timber.i("Dev Build - not showing 'new features'");
// Don't show new features dialog for development builds
InitialActivity.setUpgradedToLatestVersion(preferences);
String ver = getResources().getString(R.string.updated_version, VersionUtils.getPkgVersionName());
UIUtils.showSnackbar(this, ver, true, -1, null, findViewById(R.id.root_layout), null);
showStartupScreensAndDialogs(preferences, 2);
}
} else {
// This is the main call when there is nothing special required
Timber.i("No startup screens required");
onFinishedStartup();
}
}
use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project Anki-Android by ankidroid.
the class TemporaryModelTest method testTempModelStorage.
@Test
public void testTempModelStorage() throws Exception {
// Start off with clean state in the cache dir
TemporaryModel.clearTempModelFiles();
// Make sure save / retrieve works
String tempModelPath = TemporaryModel.saveTempModel(getTargetContext(), new JSONObject("{\"foo\": \"bar\"}"));
Assert.assertNotNull("Saving temp model unsuccessful", tempModelPath);
JSONObject tempModel = TemporaryModel.getTempModel(tempModelPath);
Assert.assertNotNull("Temp model not read successfully", tempModel);
Assert.assertEquals(new JSONObject("{\"foo\": \"bar\"}").toString(), tempModel.toString());
// Make sure clearing works
Assert.assertEquals(1, TemporaryModel.clearTempModelFiles());
Timber.i("The following logged NoSuchFileException is an expected part of verifying a file delete.");
try {
TemporaryModel.getTempModel(tempModelPath);
Assert.fail("Should have caught an exception here because the file is missing");
} catch (IOException e) {
// this is expected
}
}
Aggregations