Search in sources :

Example 16 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project Anki-Android by ankidroid.

the class AnkiDroidApp method onCreate.

/**
 * On application creation.
 */
@Override
public void onCreate() {
    super.onCreate();
    if (sInstance != null) {
        Timber.i("onCreate() called multiple times");
        // 5887 - fix crash.
        if (sInstance.getResources() == null) {
            Timber.w("Skipping re-initialisation - no resources. Maybe uninstalling app?");
            return;
        }
    }
    sInstance = this;
    // Get preferences
    SharedPreferences preferences = getSharedPrefs(this);
    // Setup logging and crash reporting
    mAcraCoreConfigBuilder = new CoreConfigurationBuilder(this);
    if (BuildConfig.DEBUG) {
        // Enable verbose error logging and do method tracing to put the Class name as log tag
        Timber.plant(new DebugTree());
        setDebugACRAConfig(preferences);
        List<ReferenceMatcher> referenceMatchers = new ArrayList<>();
        // Add known memory leaks to 'referenceMatchers'
        matchKnownMemoryLeaks(referenceMatchers);
        // AppWatcher manual install if not already installed
        if (!AppWatcher.INSTANCE.isInstalled()) {
            AppWatcher.INSTANCE.manualInstall(this);
        }
        // Show 'Leaks' app launcher. It has been removed by default via constants.xml.
        LeakCanary.INSTANCE.showLeakDisplayActivityLauncherIcon(true);
    } else {
        Timber.plant(new ProductionCrashReportingTree());
        setProductionACRAConfig(preferences);
        disableLeakCanary();
    }
    Timber.tag(TAG);
    Timber.d("Startup - Application Start");
    // Analytics falls back to a sensible default if this is not set.
    if (ACRA.isACRASenderServiceProcess() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        try {
            WebViewDebugging.setDataDirectorySuffix("acra");
        } catch (Exception e) {
            Timber.w(e, "Failed to set WebView data directory");
        }
    }
    // analytics after ACRA, they both install UncaughtExceptionHandlers but Analytics chains while ACRA does not
    UsageAnalytics.initialize(this);
    if (BuildConfig.DEBUG) {
        UsageAnalytics.setDryRun(true);
    }
    // Stop after analytics and logging are initialised.
    if (ACRA.isACRASenderServiceProcess()) {
        Timber.d("Skipping AnkiDroidApp.onCreate from ACRA sender process");
        return;
    }
    if (AdaptionUtil.isUserATestClient()) {
        UIUtils.showThemedToast(this.getApplicationContext(), getString(R.string.user_is_a_robot), false);
    }
    // make default HTML / JS debugging true for debug build and disable for unit/android tests
    if (BuildConfig.DEBUG && !AdaptionUtil.isRunningAsUnitTest()) {
        preferences.edit().putBoolean("html_javascript_debugging", true).apply();
    }
    CardBrowserContextMenu.ensureConsistentStateWithSharedPreferences(this);
    AnkiCardContextMenu.ensureConsistentStateWithSharedPreferences(this);
    NotificationChannels.setup(getApplicationContext());
    // Configure WebView to allow file scheme pages to access cookies.
    if (!acceptFileSchemeCookies()) {
        return;
    }
    // Forget the last deck that was used in the CardBrowser
    CardBrowser.clearLastDeckId();
    // Create the AnkiDroid directory if missing. Send exception report if inaccessible.
    if (Permissions.hasStorageAccessPermission(this)) {
        try {
            String dir = CollectionHelper.getCurrentAnkiDroidDirectory(this);
            CollectionHelper.initializeAnkiDroidDirectory(dir);
        } catch (StorageAccessException e) {
            Timber.e(e, "Could not initialize AnkiDroid directory");
            String defaultDir = CollectionHelper.getDefaultAnkiDroidDirectory(this);
            if (isSdCardMounted() && CollectionHelper.getCurrentAnkiDroidDirectory(this).equals(defaultDir)) {
                // Don't send report if the user is using a custom directory as SD cards trip up here a lot
                sendExceptionReport(e, "AnkiDroidApp.onCreate");
            }
        }
    }
    Timber.i("AnkiDroidApp: Starting Services");
    new BootService().onReceive(this, new Intent(this, BootService.class));
    // Register BroadcastReceiver NotificationService
    NotificationService ns = new NotificationService();
    LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
    lbm.registerReceiver(ns, new IntentFilter(NotificationService.INTENT_ACTION));
}
Also used : IntentFilter(android.content.IntentFilter) ReferenceMatcher(shark.ReferenceMatcher) SharedPreferences(android.content.SharedPreferences) ArrayList(java.util.ArrayList) StorageAccessException(com.ichi2.anki.exception.StorageAccessException) Intent(android.content.Intent) NotificationService(com.ichi2.anki.services.NotificationService) LocalBroadcastManager(androidx.localbroadcastmanager.content.LocalBroadcastManager) ManuallyReportedException(com.ichi2.anki.exception.ManuallyReportedException) StorageAccessException(com.ichi2.anki.exception.StorageAccessException) CoreConfigurationBuilder(org.acra.config.CoreConfigurationBuilder) DebugTree(timber.log.Timber.DebugTree) BootService(com.ichi2.anki.services.BootService)

Example 17 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project Anki-Android by ankidroid.

the class DeckPicker method onOptionsItemSelected.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    Resources res = getResources();
    if (getDrawerToggle().onOptionsItemSelected(item)) {
        return true;
    }
    int itemId = item.getItemId();
    if (itemId == R.id.action_undo) {
        Timber.i("DeckPicker:: Undo button pressed");
        undo();
        return true;
    } else if (itemId == R.id.action_sync) {
        Timber.i("DeckPicker:: Sync button pressed");
        sync();
        return true;
    } else if (itemId == R.id.action_import) {
        Timber.i("DeckPicker:: Import button pressed");
        showDialogFragment(ImportFileSelectionFragment.createInstance(this));
        return true;
    } else if (itemId == R.id.action_new_filtered_deck) {
        CreateDeckDialog createFilteredDeckDialog = new CreateDeckDialog(DeckPicker.this, R.string.new_deck, CreateDeckDialog.DeckDialogType.FILTERED_DECK, null);
        createFilteredDeckDialog.setOnNewDeckCreated((id) -> {
            // a filtered deck was created
            openStudyOptions(true);
        });
        createFilteredDeckDialog.showFilteredDeckDialog();
        return true;
    } else if (itemId == R.id.action_check_database) {
        Timber.i("DeckPicker:: Check database button pressed");
        showDatabaseErrorDialog(DatabaseErrorDialog.DIALOG_CONFIRM_DATABASE_CHECK);
        return true;
    } else if (itemId == R.id.action_check_media) {
        Timber.i("DeckPicker:: Check media button pressed");
        showMediaCheckDialog(MediaCheckDialog.DIALOG_CONFIRM_MEDIA_CHECK);
        return true;
    } else if (itemId == R.id.action_empty_cards) {
        Timber.i("DeckPicker:: Empty cards button pressed");
        handleEmptyCards();
        return true;
    } else if (itemId == R.id.action_model_browser_open) {
        Timber.i("DeckPicker:: Model browser button pressed");
        Intent noteTypeBrowser = new Intent(this, ModelBrowser.class);
        startActivityForResultWithAnimation(noteTypeBrowser, 0, START);
        return true;
    } else if (itemId == R.id.action_restore_backup) {
        Timber.i("DeckPicker:: Restore from backup button pressed");
        showDatabaseErrorDialog(DatabaseErrorDialog.DIALOG_CONFIRM_RESTORE_BACKUP);
        return true;
    } else if (itemId == R.id.action_export) {
        Timber.i("DeckPicker:: Export collection button pressed");
        String msg = getResources().getString(R.string.confirm_apkg_export);
        mExportingDelegate.showExportDialog(msg);
        return true;
    }
    return super.onOptionsItemSelected(item);
}
Also used : DividerItemDecoration(androidx.recyclerview.widget.DividerItemDecoration) StartupFailure(com.ichi2.anki.InitialActivity.StartupFailure) Bundle(android.os.Bundle) NonNull(androidx.annotation.NonNull) Uri(android.net.Uri) DialogHandler(com.ichi2.anki.dialogs.DialogHandler) Drawable(android.graphics.drawable.Drawable) ShortcutManagerCompat(androidx.core.content.pm.ShortcutManagerCompat) Manifest(android.Manifest) Decks(com.ichi2.libanki.Decks) Fragment(androidx.fragment.app.Fragment) JSONException(com.ichi2.utils.JSONException) ContextCompat(androidx.core.content.ContextCompat) DeckPickerBackupNoSpaceLeftDialog(com.ichi2.anki.dialogs.DeckPickerBackupNoSpaceLeftDialog) IntentFilter(android.content.IntentFilter) Triple(com.ichi2.utils.Triple) SearchView(androidx.appcompat.widget.SearchView) DeckPickerContextMenu(com.ichi2.anki.dialogs.DeckPickerContextMenu) Cancellable(com.ichi2.async.Cancellable) DeckRenameException(com.ichi2.libanki.backend.exception.DeckRenameException) StringRes(androidx.annotation.StringRes) Unit(kotlin.Unit) Nullable(androidx.annotation.Nullable) Message(android.os.Message) HostNumFactory(com.ichi2.anki.web.HostNumFactory) CompatHelper(com.ichi2.compat.CompatHelper) DeckAdapter(com.ichi2.anki.widgets.DeckAdapter) LinearLayoutManager(androidx.recyclerview.widget.LinearLayoutManager) DeckPickerNoSpaceToDowngradeDialog(com.ichi2.anki.dialogs.DeckPickerNoSpaceToDowngradeDialog) DeckPickerConfirmDeleteDeckDialog(com.ichi2.anki.dialogs.DeckPickerConfirmDeleteDeckDialog) Direction(com.ichi2.anim.ActivityTransitionAnimation.Direction) FULL_DOWNLOAD(com.ichi2.async.Connection.ConflictResolution.FULL_DOWNLOAD) SdCardReceiver(com.ichi2.anki.receiver.SdCardReceiver) Editor(android.content.SharedPreferences.Editor) CustomSyncServerUrlException(com.ichi2.libanki.sync.CustomSyncServerUrlException) FileSizeFormatter(com.ichi2.anki.dialogs.DeckPickerNoSpaceToDowngradeDialog.FileSizeFormatter) DeckPickerNoSpaceLeftDialog(com.ichi2.anki.dialogs.DeckPickerNoSpaceLeftDialog) StudyOptionsListener(com.ichi2.anki.StudyOptionsFragment.StudyOptionsListener) BadgeDrawableBuilder(com.ichi2.ui.BadgeDrawableBuilder) Menu(android.view.Menu) DeckService(com.ichi2.anki.servicelayer.DeckService) Connection(com.ichi2.async.Connection) Settings(android.provider.Settings) AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) SwipeRefreshLayout(androidx.swiperefreshlayout.widget.SwipeRefreshLayout) CollectionIntegrityStorageCheck(com.ichi2.anki.CollectionHelper.CollectionIntegrityStorageCheck) ActivityExportingDelegate(com.ichi2.anki.export.ActivityExportingDelegate) TextUtils(android.text.TextUtils) File(java.io.File) SharedPreferences(android.content.SharedPreferences) TypedValue(android.util.TypedValue) IconCompat(androidx.core.graphics.drawable.IconCompat) ImportUtils(com.ichi2.utils.ImportUtils) EditText(android.widget.EditText) SchedulerService(com.ichi2.anki.servicelayer.SchedulerService) LinearLayout(android.widget.LinearLayout) AsyncDialogFragment(com.ichi2.anki.dialogs.AsyncDialogFragment) PackageManager(android.content.pm.PackageManager) TaskManager(com.ichi2.async.TaskManager) WindowManager(android.view.WindowManager) UsageAnalytics(com.ichi2.anki.analytics.UsageAnalytics) ModelManager(com.ichi2.libanki.ModelManager) ConfirmationDialog(com.ichi2.anki.dialogs.ConfirmationDialog) AnkiStatsTaskHandler(com.ichi2.anki.stats.AnkiStatsTaskHandler) Permissions(com.ichi2.utils.Permissions) View(android.view.View) RecyclerView(androidx.recyclerview.widget.RecyclerView) SyncStatus(com.ichi2.utils.SyncStatus) FragmentTransaction(androidx.fragment.app.FragmentTransaction) BroadcastReceiver(android.content.BroadcastReceiver) DatabaseErrorDialog(com.ichi2.anki.dialogs.DatabaseErrorDialog) CustomStudyDialogFactory(com.ichi2.anki.dialogs.customstudy.CustomStudyDialogFactory) Timber(timber.log.Timber) UndoService(com.ichi2.anki.servicelayer.UndoService) List(java.util.List) TextView(android.widget.TextView) ImportFileSelectionFragment(com.ichi2.anki.dialogs.ImportFileSelectionFragment) RelativeLayout(android.widget.RelativeLayout) Filterable(android.widget.Filterable) TaskListenerWithContext(com.ichi2.async.TaskListenerWithContext) ViewPropertyAnimator(android.view.ViewPropertyAnimator) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) Snackbar(com.google.android.material.snackbar.Snackbar) Window(android.view.Window) VersionUtils(com.ichi2.utils.VersionUtils) Context(android.content.Context) TaskListener(com.ichi2.async.TaskListener) KeyEvent(android.view.KeyEvent) GravityEnum(com.afollestad.materialdialogs.GravityEnum) Pair(android.util.Pair) DeckPickerAnalyticsOptInDialog(com.ichi2.anki.dialogs.DeckPickerAnalyticsOptInDialog) ImportDialog(com.ichi2.anki.dialogs.ImportDialog) Intent(android.content.Intent) Collection(com.ichi2.libanki.Collection) StyledProgressDialog(com.ichi2.themes.StyledProgressDialog) PixelFormat(android.graphics.PixelFormat) TypedArray(android.content.res.TypedArray) MenuItem(android.view.MenuItem) WidgetStatus(com.ichi2.widget.WidgetStatus) SyncErrorDialog(com.ichi2.anki.dialogs.SyncErrorDialog) Payload(com.ichi2.async.Connection.Payload) Model(com.ichi2.libanki.Model) Build(android.os.Build) ShortcutInfoCompat(androidx.core.content.pm.ShortcutInfoCompat) Utils(com.ichi2.libanki.Utils) DialogInterface(android.content.DialogInterface) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) Computation(com.ichi2.utils.Computation) AbstractDeckTreeNode(com.ichi2.libanki.sched.AbstractDeckTreeNode) ActivityCompat(androidx.core.app.ActivityCompat) CreateDeckDialog(com.ichi2.anki.dialogs.CreateDeckDialog) CollectionTask(com.ichi2.async.CollectionTask) SQLException(android.database.SQLException) CustomStudyDialog(com.ichi2.anki.dialogs.customstudy.CustomStudyDialog) Syncer(com.ichi2.libanki.sync.Syncer) MediaCheckDialog(com.ichi2.anki.dialogs.MediaCheckDialog) AdaptionUtil(com.ichi2.utils.AdaptionUtil) VisibleForTesting(androidx.annotation.VisibleForTesting) Resources(android.content.res.Resources) OnClickListener(android.view.View.OnClickListener) Intent(android.content.Intent) Resources(android.content.res.Resources) CreateDeckDialog(com.ichi2.anki.dialogs.CreateDeckDialog)

Example 18 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project Anki-Android by ankidroid.

the class CardTemplatePreviewerTest method testPreviewUnsavedTemplate_Basic.

@Test
public void testPreviewUnsavedTemplate_Basic() {
    String modelName = "Basic";
    Model collectionBasicModelOriginal = getCurrentDatabaseModelCopy(modelName);
    List<String> fields = collectionBasicModelOriginal.getFieldsNames();
    JSONObject template = collectionBasicModelOriginal.getJSONArray("tmpls").getJSONObject(0);
    template.put("qfmt", template.getString("qfmt") + "PREVIEWER_TEST");
    String tempModelPath = TemporaryModel.saveTempModel(getTargetContext(), collectionBasicModelOriginal);
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.putExtra(TemporaryModel.INTENT_MODEL_FILENAME, tempModelPath);
    intent.putExtra("index", 0);
    ActivityController<TestCardTemplatePreviewer> previewerController = Robolectric.buildActivity(TestCardTemplatePreviewer.class, intent).create().start().resume().visible();
    saveControllerForCleanup((previewerController));
    TestCardTemplatePreviewer testCardTemplatePreviewer = previewerController.get();
    String[] arr = testCardTemplatePreviewer.getDummyCard(collectionBasicModelOriginal, 0).note().getFields();
    assertThat(arr[0], is("(" + fields.get(0) + ")"));
    assertThat(arr[1], is("(" + fields.get(1) + ")"));
}
Also used : JSONObject(com.ichi2.utils.JSONObject) Model(com.ichi2.libanki.Model) Intent(android.content.Intent) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) Test(org.junit.Test)

Example 19 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project Anki-Android by ankidroid.

the class NoteEditor method setMMButtonListener.

private void setMMButtonListener(ImageButton mediaButton, final int index) {
    mediaButton.setOnClickListener(v -> {
        Timber.i("NoteEditor:: Multimedia button pressed for field %d", index);
        if (mEditorNote.items()[index][1].length() > 0) {
            final Collection col = CollectionHelper.getInstance().getCol(NoteEditor.this);
            // If the field already exists then we start the field editor, which figures out the type
            // automatically
            IMultimediaEditableNote note = getCurrentMultimediaEditableNote(col);
            startMultimediaFieldEditor(index, note);
        } else {
            // Otherwise we make a popup menu allowing the user to choose between audio/image/text field
            // TODO: Update the icons for dark material theme, then can set 3rd argument to true
            PopupMenuWithIcons popup = new PopupMenuWithIcons(NoteEditor.this, v, true);
            MenuInflater inflater = popup.getMenuInflater();
            inflater.inflate(R.menu.popupmenu_multimedia_options, popup.getMenu());
            popup.setOnMenuItemClickListener(item -> {
                int itemId = item.getItemId();
                if (itemId == R.id.menu_multimedia_audio) {
                    Timber.i("NoteEditor:: Record audio button pressed");
                    startMultimediaFieldEditorForField(index, new AudioRecordingField());
                    return true;
                } else if (itemId == R.id.menu_multimedia_audio_clip || itemId == R.id.menu_multimedia_video_clip) {
                    Timber.i("NoteEditor:: Add audio clip button pressed");
                    startMultimediaFieldEditorForField(index, new MediaClipField());
                    return true;
                } else if (itemId == R.id.menu_multimedia_photo) {
                    Timber.i("NoteEditor:: Add image button pressed");
                    startMultimediaFieldEditorForField(index, new ImageField());
                    return true;
                } else if (itemId == R.id.menu_multimedia_text) {
                    Timber.i("NoteEditor:: Advanced editor button pressed");
                    startAdvancedTextEditor(index);
                    return true;
                } else if (itemId == R.id.menu_multimedia_clear_field) {
                    Timber.i("NoteEditor:: Clear field button pressed");
                    clearField(index);
                }
                return false;
            });
            if (AdaptionUtil.isRestrictedLearningDevice()) {
                popup.getMenu().findItem(R.id.menu_multimedia_photo).setVisible(false);
                popup.getMenu().findItem(R.id.menu_multimedia_text).setVisible(false);
            }
            popup.show();
        }
    });
}
Also used : ImageField(com.ichi2.anki.multimediacard.fields.ImageField) MenuInflater(android.view.MenuInflater) PopupMenuWithIcons(com.ichi2.anki.widgets.PopupMenuWithIcons) Collection(com.ichi2.libanki.Collection) MediaClipField(com.ichi2.anki.multimediacard.fields.MediaClipField) IMultimediaEditableNote(com.ichi2.anki.multimediacard.IMultimediaEditableNote) SuppressLint(android.annotation.SuppressLint) AudioRecordingField(com.ichi2.anki.multimediacard.fields.AudioRecordingField)

Example 20 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project Anki-Android by ankidroid.

the class Media method mediaChangesZip.

/*
     * Media syncing: zips
     * ***********************************************************
     */
/**
 * Unlike python, our temp zip file will be on disk instead of in memory. This avoids storing
 * potentially large files in memory which is not feasible with Android's limited heap space.
 * <p>
 * Notes:
 * <p>
 * - The maximum size of the changes zip is decided by the constant SYNC_ZIP_SIZE. If a media file exceeds this
 * limit, only that file (in full) will be zipped to be sent to the server.
 * <p>
 * - This method will be repeatedly called from MediaSyncer until there are no more files (marked "dirty" in the DB)
 * to send.
 * <p>
 * - Since AnkiDroid avoids scanning the media directory on every sync, it is possible for a file to be marked as a
 * new addition but actually have been deleted (e.g., with a file manager). In this case we skip over the file
 * and mark it as removed in the database. (This behaviour differs from the desktop client).
 * <p>
 */
public Pair<File, List<String>> mediaChangesZip() {
    File f = new File(mCol.getPath().replaceFirst("collection\\.anki2$", "tmpSyncToServer.zip"));
    List<String> fnames = new ArrayList<>();
    try (ZipOutputStream z = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
        Cursor cur = mDb.query("select fname, csum from media where dirty=1 limit " + Consts.SYNC_MAX_FILES)) {
        z.setMethod(ZipOutputStream.DEFLATED);
        // meta is a list of (fname, zipname), where zipname of null is a deleted file
        // NOTE: In python, meta is a list of tuples that then gets serialized into json and added
        // to the zip as a string. In our version, we use JSON objects from the start to avoid the
        // serialization step. Instead of a list of tuples, we use JSONArrays of JSONArrays.
        JSONArray meta = new JSONArray();
        int sz = 0;
        byte[] buffer = new byte[2048];
        for (int c = 0; cur.moveToNext(); c++) {
            String fname = cur.getString(0);
            String csum = cur.getString(1);
            fnames.add(fname);
            String normname = Utils.nfcNormalized(fname);
            if (!TextUtils.isEmpty(csum)) {
                try {
                    mCol.log("+media zip " + fname);
                    File file = new File(dir(), fname);
                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file), 2048);
                    z.putNextEntry(new ZipEntry(Integer.toString(c)));
                    int count = 0;
                    while ((count = bis.read(buffer, 0, 2048)) != -1) {
                        z.write(buffer, 0, count);
                    }
                    z.closeEntry();
                    bis.close();
                    meta.put(new JSONArray().put(normname).put(Integer.toString(c)));
                    sz += file.length();
                } catch (FileNotFoundException e) {
                    Timber.w(e);
                    // A file has been marked as added but no longer exists in the media directory.
                    // Skip over it and mark it as removed in the db.
                    removeFile(fname);
                }
            } else {
                mCol.log("-media zip " + fname);
                meta.put(new JSONArray().put(normname).put(""));
            }
            if (sz >= Consts.SYNC_MAX_BYTES) {
                break;
            }
        }
        z.putNextEntry(new ZipEntry("_meta"));
        z.write(Utils.jsonToString(meta).getBytes());
        z.closeEntry();
        // Don't leave lingering temp files if the VM terminates.
        f.deleteOnExit();
        return new Pair<>(f, fnames);
    } catch (IOException e) {
        Timber.e(e, "Failed to create media changes zip: ");
        throw new RuntimeException(e);
    }
}
Also used : ZipEntry(java.util.zip.ZipEntry) ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray) FileNotFoundException(java.io.FileNotFoundException) IOException(java.io.IOException) Cursor(android.database.Cursor) FileInputStream(java.io.FileInputStream) BufferedInputStream(java.io.BufferedInputStream) ZipOutputStream(java.util.zip.ZipOutputStream) FileOutputStream(java.io.FileOutputStream) ZipFile(java.util.zip.ZipFile) File(java.io.File) BufferedOutputStream(java.io.BufferedOutputStream) Pair(android.util.Pair)

Aggregations

Test (org.junit.Test)23 Intent (android.content.Intent)21 JSONObject (com.ichi2.utils.JSONObject)17 Model (com.ichi2.libanki.Model)14 View (android.view.View)13 ArrayList (java.util.ArrayList)13 Bundle (android.os.Bundle)12 Collection (com.ichi2.libanki.Collection)11 Note (com.ichi2.libanki.Note)9 File (java.io.File)9 JSONArray (com.ichi2.utils.JSONArray)8 SharedPreferences (android.content.SharedPreferences)7 TextView (android.widget.TextView)7 EditText (android.widget.EditText)6 Deck (com.ichi2.libanki.Deck)6 Dialog (android.app.Dialog)5 NonNull (androidx.annotation.NonNull)5 MaterialDialog (com.afollestad.materialdialogs.MaterialDialog)5 RobolectricTest (com.ichi2.anki.RobolectricTest)5 TaskData (com.ichi2.async.TaskData)5