Java tutorial
/* OpenOffice Document Reader is Android's first native ODF Viewer! Copyright (C) 2010 Thomas Taschauer - tomtasche@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/> */ package at.tomtasche.reader.ui.activity; import java.io.FileNotFoundException; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.zip.ZipException; import org.geometerplus.android.fbreader.IConstants; import android.annotation.SuppressLint; import android.app.ActionBar; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.preference.PreferenceManager; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import android.text.InputType; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.Toast; import at.stefl.opendocument.java.odf.IllegalMimeTypeException; import at.stefl.opendocument.java.odf.UnsupportedMimeTypeException; import at.stefl.opendocument.java.odf.ZipEntryNotFoundException; import at.tomtasche.reader.background.AndroidFileCache; import at.tomtasche.reader.background.Document; import at.tomtasche.reader.background.DocumentLoader; import at.tomtasche.reader.background.DocumentLoader.EncryptedDocumentException; import at.tomtasche.reader.background.FileLoader; import at.tomtasche.reader.background.LoadingListener; import at.tomtasche.reader.background.UpLoader; import at.tomtasche.reader.ui.widget.PageFragment; import at.tomtasche.reader.ui.widget.ProgressDialogFragment; import com.devspark.appmsg.AppMsg; import com.fullreader.R; import com.webprestige.fr.bookmarks.DatabaseHandler; import com.webprestige.fr.otherdocs.FrDocument; @SuppressLint("NewApi") public abstract class DocumentActivity extends FragmentActivity implements LoaderCallbacks<Document>, DocumentLoadingActivity { private static final String EXTRA_URI = "uri"; private static final String EXTRA_LIMIT = "limit"; private static final String EXTRA_PASSWORD = "password"; private static final String EXTRA_TRANSLATABLE = "translatable"; private ProgressDialogFragment progressDialog; private PageFragment pageFragment; private List<LoadingListener> loadingListeners; private Document document; private Handler handler; public FrDocument mFrDocument; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ? if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) { String msg = ""; if (loadCurrentLanguage().equals("en")) { msg = "An ability to open odt files is available only for devices with a version of Android 3.0 and above"; } else if (loadCurrentLanguage().equals("de")) { msg = "Die Fhigkeit, odt-Datei zu ffnen, ist nur fr Gerte mit Android-Version 3.0 und hher verfgbar"; } else if (loadCurrentLanguage().equals("fr")) { msg = "Possibilit d'ouvrir odt n'est disponible que pour les appareils avec une version d'Android 3.0 et au-dessus"; } else if (loadCurrentLanguage().equals("uk")) { msg = "? ? odt ? ? ? ? Android 3.0 "; } else if (loadCurrentLanguage().equals("ru")) { msg = "? ? odt ? ? ?? ? ? Android 3.0 "; } else { if (Locale.getDefault().getDisplayLanguage().equals("??")) { msg = "? ? odt ? ? ?? ? ? Android 3.0 "; } else if (Locale.getDefault().getDisplayLanguage().equals("?")) { msg = "? ? odt ? ? ? ? Android 3.0 "; } else { msg = "An ability to open odt files is available only for devices with a version of Android 3.0 and above"; } } Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); finish(); } else { setTitle(""); setContentView(R.layout.open_document_main); handler = new Handler(); loadingListeners = new LinkedList<LoadingListener>(); getSupportLoaderManager().initLoader(0, null, this); getSupportLoaderManager().initLoader(1, null, this); pageFragment = (PageFragment) getSupportFragmentManager().findFragmentByTag(PageFragment.FRAGMENT_TAG); if (pageFragment == null) { pageFragment = new PageFragment(); getSupportFragmentManager().beginTransaction() .add(R.id.document_container, pageFragment, PageFragment.FRAGMENT_TAG).commit(); Uri uri = getIntent().getData(); if (Intent.ACTION_VIEW.equals(getIntent().getAction()) && uri != null) { loadUri(uri); } } // int theme = PreferenceManager.getDefaultSharedPreferences(this).getInt(IConstants.THEME_PREF, IConstants.THEME_REDTREE); ActionBar bar = getActionBar(); switch (theme) { case IConstants.THEME_MYBLACK: bar.setBackgroundDrawable( getResources().getDrawable(com.fullreader.R.drawable.theme_black_action_bar)); break; case IConstants.THEME_LAMINAT: bar.setBackgroundDrawable( getResources().getDrawable(com.fullreader.R.drawable.theme_laminat_action_bar)); break; case IConstants.THEME_REDTREE: bar.setBackgroundDrawable( getResources().getDrawable(com.fullreader.R.drawable.theme_redtree_action_bar)); break; } } } @Override public DocumentLoader loadUri(Uri uri) { return loadUri(uri, null, true, false); } public DocumentLoader loadUri(Uri uri, String password) { return loadUri(uri, password, true, false); } public DocumentLoader loadUri(Uri uri, boolean limit) { return loadUri(uri, null, limit, false); } public DocumentLoader loadUri(Uri uri, String password, boolean limit, boolean translatable) { Bundle bundle = new Bundle(); bundle.putString(EXTRA_PASSWORD, password); bundle.putParcelable(EXTRA_URI, uri); bundle.putBoolean(EXTRA_LIMIT, limit); bundle.putBoolean(EXTRA_TRANSLATABLE, translatable); int lastIndex = uri.toString().lastIndexOf("/"); String name = uri.toString().substring(lastIndex + 1); mFrDocument = new FrDocument(-1, name, uri.toString(), FrDocument.DOCTYPE_ODT, FrDocument.getDate()); mFrDocument.updateDate(FrDocument.getDate()); DatabaseHandler handler = new DatabaseHandler(this); long id = handler.hasFrDocument(mFrDocument); if (id == -1) { handler.addFrDocument(mFrDocument); } else { mFrDocument.updateId((int) id); handler.updateFrDocumentLastDate(mFrDocument); } return (DocumentLoader) getSupportLoaderManager().restartLoader(0, bundle, this); } public UpLoader uploadUri(Uri uri) { Bundle bundle = new Bundle(); bundle.putParcelable(EXTRA_URI, uri); return (UpLoader) getSupportLoaderManager().restartLoader(1, bundle, this); } @Override public Loader<Document> onCreateLoader(int id, Bundle bundle) { boolean limit = true; boolean translatable = false; String password = null; Uri uri = DocumentLoader.URI_INTRO; if (bundle != null) { uri = bundle.getParcelable(EXTRA_URI); limit = bundle.getBoolean(EXTRA_LIMIT); translatable = bundle.getBoolean(EXTRA_TRANSLATABLE); password = bundle.getString(EXTRA_PASSWORD); } switch (id) { case 0: DocumentLoader documentLoader = new DocumentLoader(this, uri); documentLoader.setPassword(password); documentLoader.setLimit(limit); documentLoader.setTranslatable(translatable); showProgress(documentLoader, false); return documentLoader; case 1: default: UpLoader upLoader = new UpLoader(this, uri); showProgress(upLoader, true); return upLoader; } } @Override public void onLoadFinished(final Loader<Document> loader, Document document) { dismissProgress(); FileLoader fileLoader = (FileLoader) loader; Throwable error = fileLoader.getLastError(); final Uri uri = fileLoader.getLastUri(); if (error != null) { handleError(error, uri); } else if (document != null) { this.document = document; // TODO: we should load the first page here already // DocumentActivity should - basically - work out-of-the-box // (without any further logic)! if (document.isLimited()) { showCrouton(R.string.toast_info_limited, new Runnable() { @Override public void run() { loadUri(uri, ((DocumentLoader) loader).getPassword(), false, false); } }, AppMsg.STYLE_INFO); } for (LoadingListener listener : loadingListeners) { listener.onSuccess(document, uri); } } } @Override public void onLoaderReset(Loader<Document> loader) { } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if (intent == null) return; Uri uri = intent.getData(); if (requestCode == 42 && resultCode == RESULT_OK && uri != null) loadUri(uri); } private void showProgress(final Loader<Document> loader, final boolean upload) { if (progressDialog != null) return; try { progressDialog = new ProgressDialogFragment(upload); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); progressDialog.show(transaction, ProgressDialogFragment.FRAGMENT_TAG); if (!upload) { final FileLoader fileLoader = (FileLoader) loader; handler.postDelayed(new Runnable() { @Override public void run() { if (progressDialog == null) return; progressDialog.setProgress(fileLoader.getProgress()); if (loader.isStarted()) handler.postDelayed(this, 1000); } }, 1000); } } catch (IllegalStateException e) { e.printStackTrace(); progressDialog = null; } } private void dismissProgress() { // dirty hack because committing isn't allowed right after // onLoadFinished: // "java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished" if (progressDialog == null) progressDialog = (ProgressDialogFragment) getSupportFragmentManager() .findFragmentByTag(ProgressDialogFragment.FRAGMENT_TAG); if (progressDialog != null && progressDialog.getShowsDialog() && progressDialog.isNotNull()) { try { progressDialog.dismissAllowingStateLoss(); } catch (NullPointerException e) { e.printStackTrace(); } progressDialog = null; } } public void handleError(Throwable error, final Uri uri) { Log.e("OpenDocument Reader", "Error opening file at " + uri.toString(), error); final Uri cacheUri = AndroidFileCache.getCacheFileUri(); for (LoadingListener listener : loadingListeners) { listener.onError(error, uri); // TODO: return here, but only if the listener was registered by a // JUnit test } int errorDescription; if (error == null) { return; } else if (error instanceof EncryptedDocumentException) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.toast_error_password_protected); final EditText input = new EditText(this); input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); builder.setView(input); builder.setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { loadUri(cacheUri, input.getText().toString()); dialog.dismiss(); } }); builder.setNegativeButton(getString(android.R.string.cancel), null); builder.show(); return; } else if (error instanceof IllegalMimeTypeException || error instanceof ZipException || error instanceof ZipEntryNotFoundException || error instanceof UnsupportedMimeTypeException) { /*AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.toast_error_illegal_file); builder.setMessage(R.string.dialog_upload_file); builder.setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { uploadUri(cacheUri); dialog.dismiss(); } }); builder.setNegativeButton(getString(android.R.string.cancel), null); builder.show();*/ return; } else if (error instanceof FileNotFoundException) { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY) || Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { errorDescription = R.string.toast_error_find_file; } else { errorDescription = R.string.toast_error_storage; } } else if (error instanceof IllegalArgumentException) { errorDescription = R.string.toast_error_illegal_file; } else if (error instanceof OutOfMemoryError) { errorDescription = R.string.toast_error_out_of_memory; } else { errorDescription = R.string.toast_error_generic; } showCrouton(errorDescription, null, AppMsg.STYLE_ALERT); } public void addLoadingListener(LoadingListener loadingListener) { loadingListeners.add(loadingListener); } public Document getDocument() { return document; } public PageFragment getPageFragment() { return pageFragment; } public void showToast(int resId) { showToast(getString(resId)); } public void showToast(String message) { Toast.makeText(this, message, Toast.LENGTH_LONG).show(); } public void showCrouton(int resId, final Runnable callback, AppMsg.Style style) { showCrouton(getString(resId), callback, style); } public void showCrouton(final String message, final Runnable callback, final AppMsg.Style style) { runOnUiThread(new Runnable() { @Override public void run() { AppMsg crouton = AppMsg.makeText(DocumentActivity.this, message, style); crouton.setDuration(AppMsg.LENGTH_LONG); crouton.getView().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (callback != null) callback.run(); } }); crouton.show(); } }); } String loadCurrentLanguage() { SharedPreferences sPref = getSharedPreferences("languagePrefs", MODE_PRIVATE); return sPref.getString("curLanguage", ""); } /*@Override public void onDestroy(){ super.onDestroy(); if (mFrDocument != null){ mFrDocument.updateDate(FrDocument.getDate()); DatabaseHandler handler = new DatabaseHandler(this); long id = handler.hasFrDocument(mFrDocument); if (id == -1){ handler.addFrDocument(mFrDocument); } else{ mFrDocument.updateId((int)id); handler.updateFrDocumentLastDate(mFrDocument); } } }*/ }