Java tutorial
/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.wakhub.monodict.activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.database.Cursor; import android.database.CursorIndexOutOfBoundsException; import android.graphics.Typeface; import android.media.AudioManager; import android.media.ToneGenerator; import android.os.Bundle; import android.os.PowerManager; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBarActivity; import android.text.TextUtils; import android.util.Log; import android.view.MenuItem; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; import com.astuetz.PagerSlidingTabStrip; import com.github.wakhub.monodict.MonodictApp; import com.github.wakhub.monodict.R; import com.github.wakhub.monodict.activity.bean.ActivityHelper; import com.github.wakhub.monodict.activity.bean.CommonActivityTrait; import com.github.wakhub.monodict.activity.bean.DatabaseHelper; import com.github.wakhub.monodict.activity.bean.SpeechHelper; import com.github.wakhub.monodict.db.Card; import com.github.wakhub.monodict.db.Model; import com.github.wakhub.monodict.preferences.FlashcardActivityState; import com.github.wakhub.monodict.preferences.Preferences_; import com.github.wakhub.monodict.ui.CardContextActionListener; import com.github.wakhub.monodict.ui.CardContextMenu; import com.github.wakhub.monodict.ui.CardDialog; import com.github.wakhub.monodict.ui.CardEditDialog; import com.github.wakhub.monodict.utils.DateTimeUtils; import com.github.wakhub.monodict.utils.ViewUtils; import com.google.common.base.Optional; import com.google.common.eventbus.Subscribe; import com.google.common.io.ByteStreams; import com.google.common.io.CharStreams; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonIOException; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.melnykov.fab.FloatingActionButton; import com.nispok.snackbar.Snackbar; import com.nispok.snackbar.SnackbarManager; import com.nispok.snackbar.listeners.EventListener; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.Background; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.OnActivityResult; import org.androidannotations.annotations.OptionsItem; import org.androidannotations.annotations.OptionsMenu; import org.androidannotations.annotations.SystemService; import org.androidannotations.annotations.UiThread; import org.androidannotations.annotations.ViewById; import org.androidannotations.annotations.sharedpreferences.Pref; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.lang.ref.WeakReference; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * EventBus * - FlashcardActivityPagerFragment * * @see com.github.wakhub.monodict.activity.FlashcardActivity_ */ @EActivity(R.layout.activity_flashcard) @OptionsMenu({ R.menu.flashcard }) public class FlashcardActivity extends ActionBarActivity implements CardDialog.OnCardDialogListener, CardContextActionListener, SpeechHelper.OnUtteranceListener, ViewPager.OnPageChangeListener, FlashcardActivityPagerFragment.Listener { private static final String TAG = FlashcardActivity.class.getSimpleName(); private static final int REQUEST_CODE_SELECT_DIRECTORY_TO_EXPORT = 10010; private static final int REQUEST_CODE_SELECT_FILE_TO_IMPORT = 10011; private static final String JSON_KEY_CARDS = "cards"; @ViewById PagerSlidingTabStrip tabs; @ViewById ViewPager pager; @ViewById FloatingActionButton alphabeticalOrderButton; @ViewById FloatingActionButton shuffleButton; @SystemService PowerManager powerManager; @Pref Preferences_ preferences; @Bean CommonActivityTrait commonActivityTrait; @Bean ActivityHelper activityHelper; @Bean SpeechHelper speechHelper; @Bean DatabaseHelper databaseHelper; @Bean FlashcardActivityState state; private Optional<CardDialog> cardDialog = Optional.absent(); private Optional<CardEditDialog> cardEditDialog = Optional.absent(); private AlertDialog autoPlayDialog = null; private TextView autoPlayTranslateText = null; private TextView autoPlayDisplayText = null; private ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_SYSTEM, 80); private Optional<Cursor> optCursor = Optional.absent(); private Optional<CardDialog> optCardDialog = Optional.absent(); private static enum AutoPlayProgress { START, WAIT_FOR_TRANSLATE, TRANSLATE, WAIT_FOR_DISPLAY, DISPLAY, WAIT_FOR_NEXT, WAIT_FOR_STOP, STOP } private AutoPlayProgress autoPlayProgress = AutoPlayProgress.STOP; private boolean isReloadRequired = false; @Override public void onInitPage(FlashcardActivityPagerFragment fragment, int box) { reloadCursor(box, state.getOrder()); } private Snackbar createSnackbar() { return Snackbar.with(getApplicationContext()).swipeToDismiss(true).eventListener(new EventListener() { @Override public void onShow(Snackbar snackbar) { int snackbarHeight = snackbar.getHeight(); ViewUtils.addMarginBottom(alphabeticalOrderButton, snackbarHeight); ViewUtils.addMarginBottom(shuffleButton, snackbarHeight); } @Override public void onShown(Snackbar snackbar) { snackbar.animation(false); } @Override public void onDismiss(Snackbar snackbar) { int snackbarHeight = snackbar.getHeight(); ViewUtils.addMarginBottom(alphabeticalOrderButton, -snackbarHeight); ViewUtils.addMarginBottom(shuffleButton, -snackbarHeight); } @Override public void onDismissed(Snackbar snackbar) { } }); } @AfterViews void afterViews() { Log.d(TAG, "state: " + state.toString()); commonActivityTrait.initActivity(preferences); pager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), this, getTabLabels())); pager.setCurrentItem(state.getBox() - 1); tabs.setViewPager(pager); tabs.setIndicatorColorResource(R.color.dark_gray); tabs.setOnPageChangeListener(this); } private FlashcardActivityPagerFragment getCurrentFragment() { return getPagerFragment(pager.getCurrentItem()); } private FlashcardActivityPagerFragment getPagerFragment(int position) { return ((ViewPagerAdapter) pager.getAdapter()).getFragment(position); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { Log.d(TAG, "onPageSelected: " + position); stopAutoPlay(); int box = position + 1; state.setBox(box); reloadCursor(box, state.getOrder()); } @Override public void onPageScrollStateChanged(int state) { } void refreshPager() { ViewPagerAdapter pagerAdapter = (ViewPagerAdapter) pager.getAdapter(); pagerAdapter.titles = getTabLabels(); tabs.notifyDataSetChanged(); reloadCursor(); } private void reloadCursor() { int box = state.getBox(); int order = state.getOrder(); reloadCursor(box, order); } private void reloadCursor(int box, int order) { Log.d(TAG, String.format("reloadCursor %d %d", box, order)); try { if (order == FlashcardActivityState.ORDER_SHUFFLE) { optCursor = Optional.of(databaseHelper.findCardInBoxRandomly(box, state.getRandomSeed())); } else { optCursor = Optional.of(databaseHelper.findCardInBoxAlphabetically(box)); } } catch (SQLException e) { optCursor = Optional.absent(); activityHelper.showError(e); } List<Card> cardList = new ArrayList<>(); if (optCursor.isPresent()) { Cursor cursor = optCursor.get(); for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { cardList.add(new Card(cursor)); } } onReloadCursor(box, cardList); } @UiThread void onReloadCursor(int box, List<Card> cardList) { FlashcardActivityPagerFragment fragment = ((ViewPagerAdapter) pager.getAdapter()).getFragment(box - 1); fragment.setDataSet(cardList); fragment.notifyDataSetChanged(); } private String[] getTabLabels() { Map<Integer, Integer> countsForBoxes; try { countsForBoxes = databaseHelper.getCountsForBoxes(); } catch (SQLException e) { activityHelper.showError(e); return new String[] {}; } String[] titles = new String[Card.BOX_MAX]; for (int i = 0; i < Card.BOX_MAX; i++) { int box = i + 1; String label = String.format("BOX%d", box); if (i == 0) { label = "INBOX"; } if (countsForBoxes.keySet().contains(box)) { label += String.format("(%d)", countsForBoxes.get(box)); } titles[i] = label; } return titles; } @Override protected void onResume() { super.onResume(); MonodictApp.getEventBus().register(this); if (isReloadRequired) { refreshPager(); } } @Override protected void onPause() { super.onPause(); MonodictApp.getEventBus().unregister(this); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); getCurrentFragment().notifyDataSetChanged(); } @OnActivityResult(SpeechHelper.REQUEST_CODE_TTS) void onActivityResultSpeechHelper(int resultCode, Intent data) { speechHelper.onActivityResult(SpeechHelper.REQUEST_CODE_TTS, resultCode, data); } @OnActivityResult(REQUEST_CODE_SELECT_DIRECTORY_TO_EXPORT) void onActivityResultSelectDirectoryToExport(int resultCode, Intent data) { if (resultCode != RESULT_OK) { return; } String path = data.getExtras().getString(DirectorySelectorActivity.RESULT_INTENT_PATH); String defaultPath = String.format("%s/%s-%s.json", path, getResources().getString(R.string.app_name), DateTimeUtils.getInstance().getCurrentDateTimeString()); activityHelper.buildInputDialog(defaultPath, new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog materialDialog) { TextView textView = (TextView) materialDialog.findViewById(android.R.id.text1); String outputPath = textView.getText().toString(); exportCardsTo(outputPath); } }).title(R.string.action_export).show(); } @OnActivityResult(REQUEST_CODE_SELECT_FILE_TO_IMPORT) void onActivityResultSelectFileToImport(int resultCode, Intent data) { if (resultCode != RESULT_OK) { return; } Bundle extras = data.getExtras(); String path = extras.getString(FileSelectorActivity.RESULT_INTENT_PATH); String filename = extras.getString(FileSelectorActivity.RESULT_INTENT_FILENAME); importCardsFrom(path + "/" + filename); } @Click(R.id.shuffle_button) void onActionShuffle() { Log.d(TAG, "onActionShuffle"); state.refreshRandomSeed(); int order = FlashcardActivityState.ORDER_SHUFFLE; state.setOrder(order); reloadCursor(state.getBox(), order); getCurrentFragment().notifyDataSetChanged(); } @Click(R.id.alphabetical_order_button) void onActionOrderAlphabetically() { Log.d(TAG, "onActionOrderAlphabetically"); int order = FlashcardActivityState.ORDER_ALPHABETICALLY; state.setOrder(order); reloadCursor(state.getBox(), order); getCurrentFragment().notifyDataSetChanged(); } @UiThread void showAutoPlayAlertDialog() { if (autoPlayDialog != null) { return; } LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); layout.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); autoPlayDisplayText = new TextView(this); autoPlayDisplayText.setTypeface(Typeface.DEFAULT_BOLD); layout.addView(autoPlayDisplayText); autoPlayTranslateText = new TextView(this); autoPlayTranslateText.setText(R.string.message_in_processing); layout.addView(autoPlayTranslateText); autoPlayDialog = new MaterialDialog.Builder(this).title(R.string.action_auto_play) .iconRes(R.drawable.ic_play_arrow_black_24dp).customView(layout, true) .negativeText(android.R.string.cancel).cancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { dialog.cancel(); } }).dismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { autoPlayDisplayText = null; autoPlayTranslateText = null; stopAutoPlay(); } }).show(); } @UiThread void setAutoPlayCard(Card card) { if (autoPlayDialog == null || autoPlayDisplayText == null || autoPlayTranslateText == null) { return; } if (!optCursor.isPresent()) { return; } Cursor cursor = optCursor.get(); String autoPlayText = getResources().getString(R.string.action_auto_play); autoPlayDialog .setTitle(String.format("%s: %d/%d", autoPlayText, cursor.getPosition() + 1, cursor.getCount())); autoPlayDisplayText.setText(card.getDisplay()); autoPlayTranslateText.setText(card.getTranslate()); } private boolean autoPlayLoop() { if (!optCursor.isPresent()) { return false; } Cursor cursor = optCursor.get(); Card card; switch (autoPlayProgress) { case START: speechHelper.init(); showAutoPlayAlertDialog(); speechHelper.setOnUtteranceListener(this); cursor.moveToFirst(); autoPlayProgress = AutoPlayProgress.WAIT_FOR_DISPLAY; try { card = new Card(cursor); } catch (CursorIndexOutOfBoundsException e) { activityHelper.showError(e); return false; } setAutoPlayCard(card); toneGenerator.startTone(ToneGenerator.TONE_PROP_ACK); activityHelper.sleep(2000); break; case WAIT_FOR_DISPLAY: autoPlayProgress = AutoPlayProgress.DISPLAY; activityHelper.sleep(500); speechHelper.speech(new Card(cursor).getDisplay()); break; case WAIT_FOR_TRANSLATE: autoPlayProgress = AutoPlayProgress.TRANSLATE; activityHelper.sleep(500); try { card = new Card(cursor); } catch (CursorIndexOutOfBoundsException e) { activityHelper.showError(e); return false; } speechHelper.speech(card.getTranslate().substring(0, Math.min(card.getTranslate().length(), 100)), null); break; case WAIT_FOR_NEXT: cursor.moveToNext(); setAutoPlayCard(new Card(cursor)); autoPlayProgress = AutoPlayProgress.WAIT_FOR_DISPLAY; activityHelper.sleep(500); toneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP); activityHelper.sleep(1000); break; case WAIT_FOR_STOP: stopAutoPlay(); return false; } return true; } @Background void startAutoPlay() { PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); wakeLock.acquire(); autoPlayProgress = AutoPlayProgress.START; reloadCursor(); while (autoPlayLoop()) { activityHelper.sleep(500); } wakeLock.release(); } private void stopAutoPlay() { if (autoPlayProgress == AutoPlayProgress.STOP) { return; } Log.d(TAG, "stopAutoPlay"); autoPlayProgress = AutoPlayProgress.STOP; speechHelper.finish(); speechHelper.setOnUtteranceListener(null); toneGenerator.startTone(ToneGenerator.TONE_PROP_ACK); if (autoPlayDialog != null) { autoPlayDialog.dismiss(); autoPlayDialog = null; } } @OptionsItem(R.id.action_add) void onActionAdd() { new CardEditDialog(this, null).show(); } @OptionsItem(R.id.action_auto_play) void onActionAutoPlay() { startAutoPlay(); } @OptionsItem(R.id.action_delete_all) void onActionDeleteAll() { activityHelper.buildConfirmDialog(new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog materialDialog) { deleteAllCards(); } }).iconRes(R.drawable.ic_delete_black_36dp).title(R.string.action_delete_all) .content(R.string.message_confirm_delete).show(); } @OptionsItem(R.id.action_import) void onActionImport() { FileSelectorActivity_.intent(this).extraTitle(getResources().getString(R.string.action_import)) .extraExtensions(new String[] { ".json" }).startForResult(REQUEST_CODE_SELECT_FILE_TO_IMPORT); } @OptionsItem(R.id.action_export) void onActionExport() { DirectorySelectorActivity_.intent(this).startForResult(REQUEST_CODE_SELECT_DIRECTORY_TO_EXPORT); } @Background void deleteAllCards() { try { databaseHelper.deleteAllCards(); } catch (SQLException e) { activityHelper.showError(e); return; } onDeleteAllCards(); } @UiThread void onDeleteAllCards() { reloadCursor(1, state.getOrder()); refreshPager(); } @Background void importCardsFrom(String jsonPath) { String json; try { FileInputStream inputStream = new FileInputStream(jsonPath); json = TextUtils.join("", CharStreams.readLines(new InputStreamReader(inputStream))); } catch (IOException e) { activityHelper.showError(e); return; } JsonArray cards; try { JsonElement jsonElement = new JsonParser().parse(json); JsonObject object = jsonElement.getAsJsonObject(); cards = object.getAsJsonArray(JSON_KEY_CARDS); } catch (JsonIOException e) { activityHelper.showError(e); return; } for (JsonElement element : cards) { JsonObject cardData = element.getAsJsonObject(); Card card = new Card(cardData); try { databaseHelper.createCard(card); } catch (SQLException e) { activityHelper.showError(e); return; } } onImportCards(); } @UiThread void onImportCards() { SnackbarManager.show(createSnackbar().text(R.string.message_success), this); reloadCursor(1, state.getOrder()); refreshPager(); } @Background void exportCardsTo(String path) { JSONObject jsonObject = new JSONObject(); JSONArray jsonArray = new JSONArray(); try { Cursor cursor = databaseHelper.findAllCards(); for (int i = 0; i < cursor.getCount(); i++) { Card card = new Card(cursor); JSONObject cardData = new JSONObject(); try { cardData.put(Card.Column.DISPLAY, card.getDisplay()); cardData.put(Card.Column.TRANSLATE, card.getTranslate()); cardData.put(Card.Column.BOX, card.getBox()); cardData.put(Card.Column.DICTIONARY, card.getDictionary()); jsonArray.put(cardData); } catch (JSONException e) { activityHelper.showError(e); return; } cursor.moveToNext(); } } catch (SQLException e) { activityHelper.showError(e); return; } try { jsonObject.put(JSON_KEY_CARDS, jsonArray); } catch (JSONException e) { activityHelper.showError(e); return; } try { // TODO: Make sure it works ByteStreams.copy(new ByteArrayInputStream(jsonObject.toString().getBytes()), new FileOutputStream(path)); } catch (IOException e) { activityHelper.showError(e); return; } onExportCards(); } @UiThread void onExportCards() { SnackbarManager.show(createSnackbar().text(R.string.message_success), this); } @Override protected void onDestroy() { stopAutoPlay(); speechHelper.finish(); super.onDestroy(); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (commonActivityTrait.onOptionsItemSelected(item)) { return true; } return super.onOptionsItemSelected(item); } @Override public boolean onCardContextActionSpeech(Card card) { Log.d(TAG, "onCardContextActionSpeech: " + card); speechHelper.speech(card.getDisplay().trim()); return true; } @Override public boolean onCardContextActionEdit(Card card) { Log.d(TAG, "onCardContextActionEdit: " + card); new CardEditDialog(this, card).show(); return true; } @Override public boolean onCardContextActionDelete(Card card) { Log.d(TAG, "onCardContextActionDelete: " + card); final Card finalCard = card; activityHelper.buildConfirmDialog(new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog materialDialog) { try { databaseHelper.deleteCard(finalCard); } catch (SQLException e) { activityHelper.showError(e); return; } if (optCardDialog.isPresent()) { optCardDialog.get().dismiss(); } SnackbarManager.show( createSnackbar().text( getResources().getString(R.string.message_item_removed, finalCard.getDisplay())), FlashcardActivity.this); reloadCursor(); refreshPager(); } }).iconRes(R.drawable.ic_delete_black_36dp).title(R.string.action_delete) .content(R.string.message_confirm_delete).show(); return true; } @Override public boolean onCardContextActionMoveIntoInbox(Card card) { Log.d(TAG, "onCardContextActionMoveIntoInbox: " + card); if (card.getBox() == 1) { return false; } try { card.setBox(1); databaseHelper.updateCard(card); } catch (SQLException e) { activityHelper.showError(e); } reloadCursor(); refreshPager(); return true; } @Override public boolean onCardContextActionSearch(Card card) { Log.d(TAG, "onCardContextActionSearch: " + card); isReloadRequired = true; activityHelper.searchOnMainActivity(card.getDisplay()); return true; } @Override public boolean onCardDialogClickBackButton(Card card) { int box = card.getBox(); if (box < 2) { return true; } try { card.setBox(box - 1); databaseHelper.updateCard(card); } catch (SQLException e) { activityHelper.showError(e); return false; } reloadCursor(); refreshPager(); return true; } @Override public boolean onCardDialogClickForwardButton(Card card) { int box = card.getBox(); try { card.setBox(box + 1); databaseHelper.updateCard(card); } catch (SQLException e) { activityHelper.showError(e); return false; } reloadCursor(); refreshPager(); return true; } @Subscribe public void onEvent(FlashcardActivityPagerFragment.FlashcardItemClickEvent event) { Log.d(TAG, "onEvent: " + event); if (optCardDialog.isPresent()) { optCardDialog.get().dismiss(); } CardDialog dialog = new CardDialog(this, event.getCard()); dialog.setListener(this); dialog.setContextActionContext(this); dialog.setContextActionListener(this); optCardDialog = Optional.of(dialog); dialog.show(); } @Subscribe public void onEvent(FlashcardActivityPagerFragment.FlashcardItemSpeechEvent event) { Log.d(TAG, "onEvent: " + event); speechHelper.speech(event.getCard().getDisplay()); } @Subscribe public void onEvent(FlashcardActivityPagerFragment.FlashcardItemMoreEvent event) { Log.d(TAG, "onEvent: " + event); CardContextMenu contextMenu = new CardContextMenu(this, event.getView(), event.getCard(), new int[] { R.string.action_speech }); contextMenu.setContextActionListener(this); contextMenu.show(); } @Subscribe public void onEvent(Model.ModelChangeRequestEvent event) { Log.d(TAG, "onEvent: " + event); Card card = (Card) event.getModel(); if (event.getType().equals(Model.ModelChangeRequestEvent.TYPE_UPDATE)) { try { databaseHelper.updateCard(card); } catch (SQLException e) { activityHelper.showError(e); return; } SnackbarManager.show(createSnackbar() .text(getResources().getString(R.string.message_item_modified, card.getDisplay())), this); } if (event.getType().equals(Model.ModelChangeRequestEvent.TYPE_INSERT)) { try { Card duplicate = databaseHelper.getCardByDisplay(card.getDisplay()); if (duplicate != null) { activityHelper.onDuplicatedCardFound(duplicate, card.getDisplay(), card.getDictionary()); return; } databaseHelper.createCard(card); } catch (SQLException e) { activityHelper.showError(e); return; } SnackbarManager.show( createSnackbar().text( getResources().getString(R.string.message_item_added_to, card.getDisplay(), "INBOX")), this); } reloadCursor(); refreshPager(); } // { OnUtteranceListener @Override public void onUtteranceDone(String utteranceId) { switch (autoPlayProgress) { case DISPLAY: autoPlayProgress = AutoPlayProgress.WAIT_FOR_TRANSLATE; return; case TRANSLATE: if (!optCursor.isPresent()) { return; } Cursor cursor = optCursor.get(); if (cursor.getPosition() >= cursor.getCount() - 1) { autoPlayProgress = AutoPlayProgress.WAIT_FOR_STOP; } else { autoPlayProgress = AutoPlayProgress.WAIT_FOR_NEXT; } } } @Override public void onUtteranceError(String utteranceId) { activityHelper.showToast("Canceled"); onUtteranceDone(utteranceId); } // OnUtteranceListener } private static final class ViewPagerAdapter extends FragmentPagerAdapter { private final WeakReference<FlashcardActivity> activityRef; private String[] titles; private final List<FlashcardActivityPagerFragment> fragments; private ViewPagerAdapter(FragmentManager fm, FlashcardActivity activity, String[] titles) { super(fm); this.activityRef = new WeakReference<>(activity); this.titles = titles; fragments = new ArrayList<>(); for (int i = 0; i < Card.BOX_MAX; i++) { fragments.add(FlashcardActivityPagerFragment.create(i + 1)); } } @Override public Fragment getItem(int position) { if (position < fragments.size()) { return fragments.get(position); } return null; } private FlashcardActivityPagerFragment getFragment(int position) { return (FlashcardActivityPagerFragment) getItem(position); } @Override public CharSequence getPageTitle(int position) { FlashcardActivity activity = activityRef.get(); if (activity == null) { return ""; } return titles[position]; } @Override public int getCount() { return titles.length; } } }