Search in sources :

Example 1 with TTS

use of com.ichi2.anki.cardviewer.TTS in project AnkiChinaAndroid by ankichinateam.

the class ImportDialog 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);
    switch(mType) {
        case DIALOG_IMPORT_HINT:
            {
                // Instruct the user that they need to put their APKG files into the AnkiDroid directory
                return builder.title(res.getString(R.string.import_title)).content(res.getString(R.string.import_hint, CollectionHelper.getCurrentAnkiDroidDirectory(getActivity()))).positiveText(res.getString(R.string.dialog_ok)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((dialog, which) -> mImportDialogListener.showImportDialog(DIALOG_IMPORT_SELECT)).onNegative((dialog, which) -> dismissAllDialogFragments()).show();
            }
        case DIALOG_IMPORT_SELECT:
            {
                // Allow user to choose from the list of available APKG files
                List<File> fileList = Utils.getImportableDecks(getActivity());
                if (fileList.size() == 0) {
                    UIUtils.showThemedToast(getActivity(), getResources().getString(R.string.upgrade_import_no_file_found, "'.apkg'"), false);
                    return builder.showListener(dialog -> dialog.cancel()).show();
                } else {
                    String[] tts = new String[fileList.size()];
                    final String[] importValues = new String[fileList.size()];
                    for (int i = 0; i < tts.length; i++) {
                        tts[i] = fileList.get(i).getName();
                        importValues[i] = fileList.get(i).getAbsolutePath();
                    }
                    return builder.title(res.getString(R.string.import_select_title)).items(tts).itemsCallback((materialDialog, view, i, charSequence) -> {
                        String importPath = importValues[i];
                        // If collection package, we assume the collection will be replaced
                        if (ImportUtils.isCollectionPackage(filenameFromPath(importPath))) {
                            mImportDialogListener.showImportDialog(DIALOG_IMPORT_REPLACE_CONFIRM, importPath);
                        // Otherwise we add the file since exported decks / shared decks can't be imported via replace anyway
                        } else {
                            mImportDialogListener.showImportDialog(DIALOG_IMPORT_ADD_CONFIRM, importPath);
                        }
                    }).show();
                }
            }
        case DIALOG_IMPORT_ADD_CONFIRM:
            {
                String displayFileName = convertToDisplayName(getArguments().getString("dialogMessage"));
                return builder.title(res.getString(R.string.import_title)).content(res.getString(R.string.import_message_add_confirm, filenameFromPath(displayFileName))).positiveText(res.getString(R.string.import_message_add)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((dialog, which) -> {
                    mImportDialogListener.importAdd(getArguments().getString("dialogMessage"));
                    dismissAllDialogFragments();
                }).show();
            }
        case DIALOG_IMPORT_REPLACE_CONFIRM:
            {
                String displayFileName = convertToDisplayName(getArguments().getString("dialogMessage"));
                return builder.title(res.getString(R.string.import_title)).content(res.getString(R.string.import_message_replace_confirm, displayFileName)).positiveText(res.getString(R.string.dialog_positive_replace)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((dialog, which) -> {
                    mImportDialogListener.importReplace(getArguments().getString("dialogMessage"));
                    dismissAllDialogFragments();
                }).show();
            }
        default:
            return null;
    }
}
Also used : Bundle(android.os.Bundle) URLDecoder(java.net.URLDecoder) AnalyticsDialogFragment(com.ichi2.anki.analytics.AnalyticsDialogFragment) R(com.ichi2.anki.R) CollectionHelper(com.ichi2.anki.CollectionHelper) File(java.io.File) Timber(timber.log.Timber) List(java.util.List) UIUtils(com.ichi2.anki.UIUtils) ImportUtils(com.ichi2.utils.ImportUtils) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) Utils(com.ichi2.libanki.Utils) Resources(android.content.res.Resources) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) List(java.util.List) Resources(android.content.res.Resources)

Example 2 with TTS

use of com.ichi2.anki.cardviewer.TTS in project Anki-Android by ankidroid.

the class AbstractFlashcardViewer method displayCardQuestion.

protected void displayCardQuestion(boolean reload) {
    Timber.d("displayCardQuestion()");
    sDisplayAnswer = false;
    mBackButtonPressedToReturn = false;
    setInterface();
    mTypeAnswer.setInput("");
    mTypeAnswer.updateInfo(mCurrentCard, getResources());
    if (!mCurrentCard.isEmpty() && mTypeAnswer.validForEditText()) {
        // Show text entry based on if the user wants to write the answer
        mAnswerField.setVisibility(View.VISIBLE);
        LanguageHintService.applyLanguageHint(mAnswerField, mTypeAnswer.getLanguageHint());
    } else {
        mAnswerField.setVisibility(View.GONE);
    }
    CardHtml content = mHtmlGenerator.generateHtml(mCurrentCard, reload, Side.FRONT);
    updateCard(content);
    hideEaseButtons();
    mAutomaticAnswer.onDisplayQuestion();
    // If Card-based TTS is enabled, we "automatic display" after the TTS has finished as we don't know the duration
    if (!mTTS.isEnabled()) {
        mAutomaticAnswer.scheduleAutomaticDisplayAnswer(mUseTimerDynamicMS);
    }
    Timber.i("AbstractFlashcardViewer:: Question successfully shown for card id %d", mCurrentCard.getId());
}
Also used : CardHtml(com.ichi2.anki.cardviewer.CardHtml)

Example 3 with TTS

use of com.ichi2.anki.cardviewer.TTS in project Anki-Android by ankidroid.

the class Sound method playSoundInternal.

/**
 * Plays a sound without ensuring that the playAllListener will release the audio
 */
@SuppressWarnings({ "PMD.EmptyIfStmt", "PMD.CollapsibleIfStatements" })
private void playSoundInternal(String soundPath, @NonNull OnCompletionListener playAllListener, VideoView videoView, OnErrorListener errorListener) {
    Timber.d("Playing %s has listener? %b", soundPath, playAllListener != null);
    Uri soundUri = Uri.parse(soundPath);
    mCurrentAudioUri = soundUri;
    final OnErrorListener errorHandler = errorListener == null ? (mp, what, extra, path) -> {
        Timber.w("Media Error: (%d, %d). Calling OnCompletionListener", what, extra);
        return false;
    } : errorListener;
    if ("tts".equals(soundPath.substring(0, 3))) {
    // TODO: give information about did
    // ReadText.textToSpeech(soundPath.substring(4, soundPath.length()),
    // Integer.parseInt(soundPath.substring(3, 4)));
    } else {
        // Check if the file extension is that of a known video format
        final String extension = soundPath.substring(soundPath.lastIndexOf(".") + 1).toLowerCase(Locale.getDefault());
        boolean isVideo = Arrays.asList(VIDEO_WHITELIST).contains(extension);
        if (!isVideo) {
            final String guessedType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
            isVideo = (guessedType != null) && guessedType.startsWith("video/");
        }
        // Also check that there is a video thumbnail, as some formats like mp4 can be audio only
        isVideo = isVideo && hasVideoThumbnail(soundUri);
        // holder
        if (isVideo && videoView == null && mCallingActivity != null && mCallingActivity.get() != null) {
            Timber.d("Requesting AbstractFlashcardViewer play video - no SurfaceHolder");
            mPlayAllListener = playAllListener;
            ((AbstractFlashcardViewer) mCallingActivity.get()).playVideo(soundPath);
            return;
        }
        // Play media
        try {
            // Create media player
            if (mMediaPlayer == null) {
                Timber.d("Creating media player for playback");
                mMediaPlayer = new MediaPlayer();
            } else {
                Timber.d("Resetting media for playback");
                mMediaPlayer.reset();
            }
            if (mAudioManager == null) {
                mAudioManager = (AudioManager) AnkiDroidApp.getInstance().getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
            }
            // Provide a VideoView to the MediaPlayer if valid video file
            if (isVideo && videoView != null) {
                mMediaPlayer.setDisplay(videoView.getHolder());
                mMediaPlayer.setOnVideoSizeChangedListener((mp, width, height) -> configureVideo(videoView, width, height));
            }
            mMediaPlayer.setOnErrorListener((mp, which, extra) -> errorHandler.onError(mp, which, extra, soundPath));
            // Setup the MediaPlayer
            mMediaPlayer.setDataSource(AnkiDroidApp.getInstance().getApplicationContext(), soundUri);
            mMediaPlayer.setAudioAttributes(new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build());
            mMediaPlayer.setOnPreparedListener(mp -> {
                Timber.d("Starting media player");
                mMediaPlayer.start();
            });
            mMediaPlayer.setOnCompletionListener(playAllListener);
            mMediaPlayer.prepareAsync();
            Timber.d("Requesting audio focus");
            // Set mAudioFocusRequest for API 26 and above.
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                mAudioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK).setOnAudioFocusChangeListener(afChangeListener).build();
            }
            CompatHelper.getCompat().requestAudioFocus(mAudioManager, afChangeListener, mAudioFocusRequest);
        } catch (Exception e) {
            Timber.e(e, "playSounds - Error reproducing sound %s", soundPath);
            if (!errorHandler.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNSUPPORTED, 0, soundPath)) {
                Timber.d("Force playing next sound.");
                playAllListener.onCompletion(mMediaPlayer);
            }
        }
    }
}
Also used : AbstractFlashcardViewer(com.ichi2.anki.AbstractFlashcardViewer) AudioAttributes(android.media.AudioAttributes) AudioFocusRequest(android.media.AudioFocusRequest) Uri(android.net.Uri) MediaPlayer(android.media.MediaPlayer)

Example 4 with TTS

use of com.ichi2.anki.cardviewer.TTS in project Anki-Android by Ramblurr.

the class DeckPicker method onPrepareDialog.

@Override
protected void onPrepareDialog(int id, Dialog dialog) {
    Resources res = getResources();
    StyledDialog ad = (StyledDialog) dialog;
    switch(id) {
        case DIALOG_DELETE_DECK:
            if (!AnkiDroidApp.colIsOpen() || mDeckList == null || mDeckList.size() == 0) {
                return;
            }
            boolean isDyn = AnkiDroidApp.getCol().getDecks().isDyn(mCurrentDid);
            if (isDyn) {
                ad.setMessage(String.format(res.getString(R.string.delete_cram_deck_message), "\'" + AnkiDroidApp.getCol().getDecks().name(mCurrentDid) + "\'"));
            } else {
                ad.setMessage(String.format(res.getString(R.string.delete_deck_message), "\'" + AnkiDroidApp.getCol().getDecks().name(mCurrentDid) + "\'"));
            }
            break;
        case DIALOG_CONTEXT_MENU:
            if (!AnkiDroidApp.colIsOpen() || mDeckList == null || mDeckList.size() == 0) {
                return;
            }
            mCurrentDid = Long.parseLong(mDeckList.get(mContextMenuPosition).get("did"));
            try {
                ad.changeListItem(CONTEXT_MENU_COLLAPSE_DECK, getResources().getString(AnkiDroidApp.getCol().getDecks().get(mCurrentDid).getBoolean("collapsed") ? R.string.contextmenu_deckpicker_inflate_deck : R.string.contextmenu_deckpicker_collapse_deck));
            } catch (NotFoundException e) {
            // do nothing
            } catch (JSONException e) {
            // do nothing
            }
            ad.setTitle(AnkiDroidApp.getCol().getDecks().name(mCurrentDid));
            break;
        case DIALOG_IMPORT_LOG:
        case DIALOG_SYNC_LOG:
        case DIALOG_SYNC_SANITY_ERROR:
            // If both have text, separate them by a new line.
            if (!TextUtils.isEmpty(mDialogMessage) && !TextUtils.isEmpty(mSyncMessage)) {
                ad.setMessage(mDialogMessage + "\n\n" + mSyncMessage);
            } else if (!TextUtils.isEmpty(mDialogMessage)) {
                ad.setMessage(mDialogMessage);
            } else {
                ad.setMessage(mSyncMessage);
            }
            break;
        case DIALOG_DB_ERROR:
            mLoadFailed = false;
            ad.getButton(Dialog.BUTTON3).setEnabled(hasErrorFiles());
            break;
        case DIALOG_LOAD_FAILED:
            mLoadFailed = true;
            if (mOpenCollectionDialog != null && mOpenCollectionDialog.isShowing()) {
                mOpenCollectionDialog.setMessage(res.getString(R.string.col_load_failed));
            }
            break;
        case DIALOG_ERROR_HANDLING:
            ArrayList<String> options = new ArrayList<String>();
            ArrayList<Integer> values = new ArrayList<Integer>();
            if (AnkiDroidApp.getCol() == null) {
                // 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
            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);
            }
            ad.setItems(titles, new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    switch(mRepairValues[which]) {
                        case 0:
                            loadCollection();
                            return;
                        case 1:
                            integrityCheck();
                            return;
                        case 2:
                            showDialog(DIALOG_REPAIR_COLLECTION);
                            return;
                        case 3:
                            showDialog(DIALOG_RESTORE_BACKUP);
                            return;
                        case 4:
                            showDialog(DIALOG_FULL_SYNC_FROM_SERVER);
                            return;
                        case 5:
                            showDialog(DIALOG_NEW_COLLECTION);
                            return;
                    }
                }
            });
            break;
        case DIALOG_IMPORT_SELECT:
            List<File> fileList = Utils.getImportableDecks();
            if (fileList.size() == 0) {
                Themes.showThemedToast(DeckPicker.this, getResources().getString(R.string.upgrade_import_no_file_found), false);
            }
            ad.setEnabled(fileList.size() != 0);
            String[] tts = new String[fileList.size()];
            mImportValues = new String[fileList.size()];
            for (int i = 0; i < tts.length; i++) {
                tts[i] = fileList.get(i).getName().replace(".apkg", "");
                mImportValues[i] = fileList.get(i).getAbsolutePath();
            }
            ad.setItems(tts, new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    mImportPath = mImportValues[which];
                    switch(mImportMethod) {
                        case IMPORT_METHOD_ADD:
                            DeckTask.launchDeckTask(DeckTask.TASK_TYPE_IMPORT, mImportAddListener, new TaskData(AnkiDroidApp.getCol(), mImportPath, false));
                            mImportPath = null;
                            break;
                        case IMPORT_METHOD_REPLACE:
                            DeckTask.launchDeckTask(DeckTask.TASK_TYPE_IMPORT_REPLACE, mImportReplaceListener, new TaskData(AnkiDroidApp.getCol(), mImportPath));
                            mImportPath = null;
                            break;
                        case IMPORT_METHOD_ASK:
                        default:
                            showDialog(DIALOG_IMPORT);
                    }
                    mImportMethod = IMPORT_METHOD_ASK;
                }
            });
            break;
    }
}
Also used : DialogInterface(android.content.DialogInterface) StyledDialog(com.ichi2.themes.StyledDialog) ArrayList(java.util.ArrayList) NotFoundException(android.content.res.Resources.NotFoundException) JSONException(org.json.JSONException) TaskData(com.ichi2.async.DeckTask.TaskData) Resources(android.content.res.Resources) File(java.io.File)

Example 5 with TTS

use of com.ichi2.anki.cardviewer.TTS in project Anki-Android by Ramblurr.

the class ReadText method textToSpeech.

public static void textToSpeech(String text, long did, int ord, int qa) {
    mTextToSpeak = text;
    mQuestionAnswer = qa;
    mDid = did;
    mOrd = ord;
    String language = getLanguage(mDid, mOrd, mQuestionAnswer);
    if (availableTtsLocales.isEmpty()) {
        Locale[] systemLocales = Locale.getAvailableLocales();
        for (Locale loc : systemLocales) {
            if (mTts.isLanguageAvailable(loc) == TextToSpeech.LANG_COUNTRY_AVAILABLE) {
                availableTtsLocales.add(new String[] { loc.getISO3Language(), loc.getDisplayName() });
            }
        }
    }
    // Check, if stored language is available
    for (int i = 0; i < availableTtsLocales.size(); i++) {
        if (language.equals(NO_TTS)) {
            return;
        } else if (language.equals(availableTtsLocales.get(i)[0])) {
            speak(mTextToSpeak, language);
            return;
        }
    }
    // Otherwise ask
    Resources res = mReviewer.getResources();
    StyledDialog.Builder builder = new StyledDialog.Builder(mReviewer);
    if (availableTtsLocales.size() == 0) {
        builder.setTitle(res.getString(R.string.no_tts_available_title));
        builder.setMessage(res.getString(R.string.no_tts_available_message));
        builder.setIcon(R.drawable.ic_dialog_alert);
        builder.setPositiveButton(res.getString(R.string.ok), null);
    } else {
        ArrayList<CharSequence> dialogItems = new ArrayList<CharSequence>();
        final ArrayList<String> dialogIds = new ArrayList<String>();
        builder.setTitle(R.string.select_locale_title);
        // Add option: "no tts"
        dialogItems.add(res.getString(R.string.tts_no_tts));
        dialogIds.add(NO_TTS);
        for (int i = 0; i < availableTtsLocales.size(); i++) {
            dialogItems.add(availableTtsLocales.get(i)[1]);
            dialogIds.add(availableTtsLocales.get(i)[0]);
        }
        String[] items = new String[dialogItems.size()];
        dialogItems.toArray(items);
        builder.setItems(items, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                MetaDB.storeLanguage(mReviewer, mDid, mOrd, mQuestionAnswer, dialogIds.get(which));
                speak(mTextToSpeak, dialogIds.get(which));
            }
        });
    }
    builder.create().show();
}
Also used : Locale(java.util.Locale) DialogInterface(android.content.DialogInterface) StyledDialog(com.ichi2.themes.StyledDialog) ArrayList(java.util.ArrayList) Resources(android.content.res.Resources)

Aggregations

Resources (android.content.res.Resources)5 Uri (android.net.Uri)4 ArrayList (java.util.ArrayList)4 MaterialDialog (com.afollestad.materialdialogs.MaterialDialog)3 Locale (java.util.Locale)3 Timber (timber.log.Timber)3 Context (android.content.Context)2 DialogInterface (android.content.DialogInterface)2 MediaPlayer (android.media.MediaPlayer)2 Handler (android.os.Handler)2 TextToSpeech (android.speech.tts.TextToSpeech)2 UtteranceProgressListener (android.speech.tts.UtteranceProgressListener)2 View (android.view.View)2 WindowManager (android.view.WindowManager)2 Toast (android.widget.Toast)2 NonNull (androidx.annotation.NonNull)2 Nullable (androidx.annotation.Nullable)2 VisibleForTesting (androidx.annotation.VisibleForTesting)2 Snackbar (com.google.android.material.snackbar.Snackbar)2 AbstractFlashcardViewer (com.ichi2.anki.AbstractFlashcardViewer)2