Java tutorial
/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import java.io.File; import java.util.Arrays; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.NavUtils; import android.util.DisplayMetrics; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.webkit.WebSettings.LayoutAlgorithm; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; public class OpenActivity extends BaseActivity { // see jnicalls.cpp for these native routines: private native String nativeGetRecentPatterns(); private native String nativeGetSavedPatterns(String paths); private native String nativeGetDownloadedPatterns(String paths); private native String nativeGetSuppliedPatterns(String paths); private native void nativeToggleDir(String path); private enum PATTERNS { SUPPLIED, RECENT, SAVED, DOWNLOADED; } private static PATTERNS currpatterns = PATTERNS.SUPPLIED; // remember scroll positions for each type of patterns private static int supplied_pos = 0; private static int recent_pos = 0; private static int saved_pos = 0; private static int downloaded_pos = 0; private WebView gwebview; // for displaying html data // ----------------------------------------------------------------------------- // this class lets us intercept link taps and restore the scroll position private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView webview, String url) { if (url.startsWith("open:")) { openFile(url.substring(5)); return true; } if (url.startsWith("toggledir:")) { nativeToggleDir(url.substring(10)); saveScrollPosition(); showSuppliedPatterns(); return true; } if (url.startsWith("delete:")) { removeFile(url.substring(7)); return true; } if (url.startsWith("edit:")) { editFile(url.substring(5)); return true; } return false; } @Override public void onPageFinished(WebView webview, String url) { super.onPageFinished(webview, url); // webview.scrollTo doesn't always work here; // we need to delay until webview.getContentHeight() > 0 final int scrollpos = restoreScrollPosition(); if (scrollpos > 0) { final Handler handler = new Handler(); Runnable runnable = new Runnable() { public void run() { if (gwebview.getContentHeight() > 0) { gwebview.scrollTo(0, scrollpos); } else { // try again a bit later handler.postDelayed(this, 100); } } }; handler.postDelayed(runnable, 100); } /* following also works if we setJavaScriptEnabled(true), but is not quite as nice when a folder is closed because the scroll position can change to force the last line to appear at the bottom of the webview int scrollpos = restoreScrollPosition(); if (scrollpos > 0) { final StringBuilder sb = new StringBuilder("javascript:window.scrollTo(0, "); sb.append(scrollpos); sb.append("/ window.devicePixelRatio);"); webview.loadUrl(sb.toString()); } super.onPageFinished(webview, url); */ } } // ----------------------------------------------------------------------------- private void saveScrollPosition() { switch (currpatterns) { case SUPPLIED: supplied_pos = gwebview.getScrollY(); break; case RECENT: recent_pos = gwebview.getScrollY(); break; case SAVED: saved_pos = gwebview.getScrollY(); break; case DOWNLOADED: downloaded_pos = gwebview.getScrollY(); break; } } // ----------------------------------------------------------------------------- private int restoreScrollPosition() { switch (currpatterns) { case SUPPLIED: return supplied_pos; case RECENT: return recent_pos; case SAVED: return saved_pos; case DOWNLOADED: return downloaded_pos; } return 0; // should never get here } // ----------------------------------------------------------------------------- private void openFile(String filepath) { // switch to main screen and open given file Intent intent = new Intent(this, MainActivity.class); intent.putExtra(MainActivity.OPENFILE_MESSAGE, filepath); startActivity(intent); } // ----------------------------------------------------------------------------- private void removeFile(String filepath) { final String fullpath = baseapp.userdir.getAbsolutePath() + "/" + filepath; final File file = new File(fullpath); // ask user if it's okay to delete given file AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle("Delete file?"); alert.setMessage("Do you really want to delete " + file.getName() + "?"); alert.setPositiveButton("DELETE", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (file.delete()) { // file has been deleted so refresh gwebview saveScrollPosition(); switch (currpatterns) { case SUPPLIED: break; // should never happen case RECENT: break; // should never happen case SAVED: showSavedPatterns(); break; case DOWNLOADED: showDownloadedPatterns(); break; } } else { // should never happen Log.e("removeFile", "Failed to delete file: " + fullpath); } } }); alert.setNegativeButton("CANCEL", null); alert.show(); } // ----------------------------------------------------------------------------- private void editFile(String filepath) { // check if filepath is compressed if (filepath.endsWith(".gz") || filepath.endsWith(".zip")) { if (currpatterns == PATTERNS.SUPPLIED) { Toast.makeText(this, "Reading a compressed file is not supported.", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Editing a compressed file is not supported.", Toast.LENGTH_SHORT).show(); } return; } // let user read/edit given file if (currpatterns == PATTERNS.SUPPLIED) { // read contents of supplied file into a string String fullpath = baseapp.supplieddir.getAbsolutePath() + "/" + filepath; // display filecontents Intent intent = new Intent(this, InfoActivity.class); intent.putExtra(InfoActivity.INFO_MESSAGE, fullpath); startActivity(intent); } else { // let user read or edit a saved or downloaded file String fullpath = baseapp.userdir.getAbsolutePath() + "/" + filepath; Intent intent = new Intent(this, EditActivity.class); intent.putExtra(EditActivity.EDITFILE_MESSAGE, fullpath); startActivity(intent); } } // ----------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.open_layout); gwebview = (WebView) findViewById(R.id.webview); gwebview.setWebViewClient(new MyWebViewClient()); // avoid wrapping long lines -- this doesn't work: // gwebview.getSettings().setUseWideViewPort(true); // this is better: gwebview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); DisplayMetrics metrics = getResources().getDisplayMetrics(); if (metrics.densityDpi > 300) { // use bigger font size for high density screens (default size is 16) gwebview.getSettings().setDefaultFontSize(32); } // no need for JavaScript??? // gwebview.getSettings().setJavaScriptEnabled(true); // allow zooming??? // gwebview.getSettings().setBuiltInZoomControls(true); // show the Up button in the action bar getActionBar().setDisplayHomeAsUpEnabled(true); // note that onResume will do the initial display } // ----------------------------------------------------------------------------- @Override protected void onPause() { super.onPause(); saveScrollPosition(); } // ----------------------------------------------------------------------------- @Override protected void onResume() { super.onResume(); // update gwebview restoreScrollPosition(); switch (currpatterns) { case SUPPLIED: showSuppliedPatterns(); break; case RECENT: showRecentPatterns(); break; case SAVED: showSavedPatterns(); break; case DOWNLOADED: showDownloadedPatterns(); break; } } // ----------------------------------------------------------------------------- @Override public boolean onCreateOptionsMenu(Menu menu) { // add main.xml items to the action bar getMenuInflater().inflate(R.menu.main, menu); // disable the item for this activity MenuItem item = menu.findItem(R.id.open); item.setEnabled(false); return true; } // ----------------------------------------------------------------------------- @Override public boolean onOptionsItemSelected(MenuItem item) { // action bar item has been tapped Intent intent; switch (item.getItemId()) { case android.R.id.home: // the Home or Up button will go back to MainActivity NavUtils.navigateUpFromSameTask(this); return true; case R.id.open: // do nothing break; case R.id.settings: finish(); intent = new Intent(this, SettingsActivity.class); startActivity(intent); return true; case R.id.help: finish(); intent = new Intent(this, HelpActivity.class); startActivity(intent); return true; } return super.onOptionsItemSelected(item); } // ----------------------------------------------------------------------------- // called when the Supplied button is tapped public void doSupplied(View view) { if (currpatterns != PATTERNS.SUPPLIED) { saveScrollPosition(); currpatterns = PATTERNS.SUPPLIED; showSuppliedPatterns(); } } // ----------------------------------------------------------------------------- // called when the Recent button is tapped public void doRecent(View view) { if (currpatterns != PATTERNS.RECENT) { saveScrollPosition(); currpatterns = PATTERNS.RECENT; showRecentPatterns(); } } // ----------------------------------------------------------------------------- // called when the Saved button is tapped public void doSaved(View view) { if (currpatterns != PATTERNS.SAVED) { saveScrollPosition(); currpatterns = PATTERNS.SAVED; showSavedPatterns(); } } // ----------------------------------------------------------------------------- // called when the Downloaded button is tapped public void doDownloaded(View view) { if (currpatterns != PATTERNS.DOWNLOADED) { saveScrollPosition(); currpatterns = PATTERNS.DOWNLOADED; showDownloadedPatterns(); } } // ----------------------------------------------------------------------------- private String enumerateDirectory(File dir, String prefix) { // return the files and/or sub-directories in the given directory // as a string of paths where: // - paths are relative to to the initial directory // - directory paths end with '/' // - each path is terminated by \n String result = ""; File[] files = dir.listFiles(); if (files != null) { Arrays.sort(files); // sort into alphabetical order for (File file : files) { if (file.isDirectory()) { String dirname = prefix + file.getName() + "/"; result += dirname + "\n"; result += enumerateDirectory(file, dirname); } else { result += prefix + file.getName() + "\n"; } } } return result; } // ----------------------------------------------------------------------------- private void showSuppliedPatterns() { String paths = enumerateDirectory(new File(baseapp.supplieddir, "Patterns"), ""); String htmldata = nativeGetSuppliedPatterns(paths); // use a special base URL so that <img src="foo.png"/> will extract foo.png from the assets folder gwebview.loadDataWithBaseURL("file:///android_asset/", htmldata, "text/html", "utf-8", null); } // ----------------------------------------------------------------------------- private void showRecentPatterns() { String htmldata = nativeGetRecentPatterns(); gwebview.loadDataWithBaseURL(null, htmldata, "text/html", "utf-8", null); } // ----------------------------------------------------------------------------- private void showSavedPatterns() { String paths = enumerateDirectory(new File(baseapp.userdir, "Saved"), ""); String htmldata = nativeGetSavedPatterns(paths); gwebview.loadDataWithBaseURL(null, htmldata, "text/html", "utf-8", null); } // ----------------------------------------------------------------------------- private void showDownloadedPatterns() { String paths = enumerateDirectory(new File(baseapp.userdir, "Downloads"), ""); String htmldata = nativeGetDownloadedPatterns(paths); gwebview.loadDataWithBaseURL(null, htmldata, "text/html", "utf-8", null); } } // OpenActivity class