From f6314cdd2b16b32fc18d77dac03baaf15b2152fa Mon Sep 17 00:00:00 2001 From: littleguy77 Date: Wed, 31 Dec 2014 11:35:04 -0500 Subject: [PATCH 1/5] front: Consolidate FindRomsTask and CacheRomInfoTask into one class. --- .../mupen64plusae/GalleryActivity.java | 12 +-- .../mupen64plusae/task/CacheRomInfoTask.java | 35 ++++++-- .../mupen64plusae/task/FindRomsTask.java | 81 ------------------- 3 files changed, 31 insertions(+), 97 deletions(-) delete mode 100644 src/paulscode/android/mupen64plusae/task/FindRomsTask.java diff --git a/src/paulscode/android/mupen64plusae/GalleryActivity.java b/src/paulscode/android/mupen64plusae/GalleryActivity.java index 7030343626..3e3bbc6f27 100644 --- a/src/paulscode/android/mupen64plusae/GalleryActivity.java +++ b/src/paulscode/android/mupen64plusae/GalleryActivity.java @@ -39,8 +39,6 @@ import paulscode.android.mupen64plusae.task.CacheRomInfoTask.CacheRomInfoListener; import paulscode.android.mupen64plusae.task.ComputeMd5Task; import paulscode.android.mupen64plusae.task.ComputeMd5Task.ComputeMd5Listener; -import paulscode.android.mupen64plusae.task.FindRomsTask; -import paulscode.android.mupen64plusae.task.FindRomsTask.FindRomsListener; import paulscode.android.mupen64plusae.util.ChangeLog; import paulscode.android.mupen64plusae.util.DeviceUtil; import paulscode.android.mupen64plusae.util.Notifier; @@ -63,7 +61,7 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.GridView; -public class GalleryActivity extends Activity implements OnItemClickListener, ComputeMd5Listener, FindRomsListener, CacheRomInfoListener +public class GalleryActivity extends Activity implements OnItemClickListener, ComputeMd5Listener, CacheRomInfoListener { // App data and user preferences private AppData mAppData = null; @@ -261,13 +259,7 @@ private void refreshRoms( final File startDir ) { // Asynchronously search for ROMs Notifier.showToast( this, "Searching for ROMs in " + startDir.getName() ); - new FindRomsTask( startDir, this ).execute(); - } - - @Override - public void onFindRomsFinished( List result ) - { - new CacheRomInfoTask( result, mAppData.mupen64plus_ini, mUserPrefs.romInfoCache_cfg, mUserPrefs.galleryDataDir, this ).execute(); + new CacheRomInfoTask( startDir, mAppData.mupen64plus_ini, mUserPrefs.romInfoCache_cfg, mUserPrefs.galleryDataDir, this ).execute(); } @Override diff --git a/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java b/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java index 9d1e8a9227..f37481a5e9 100644 --- a/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java +++ b/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java @@ -21,7 +21,9 @@ package paulscode.android.mupen64plusae.task; import java.io.File; +import java.util.ArrayList; import java.util.List; +import java.util.Locale; import paulscode.android.mupen64plusae.persistent.ConfigFile; import paulscode.android.mupen64plusae.persistent.ConfigFile.ConfigSection; @@ -36,13 +38,16 @@ public class CacheRomInfoTask extends AsyncTask public interface CacheRomInfoListener { public void onCacheRomInfoProgress( ConfigSection section ); + public void onCacheRomInfoFinished( ConfigFile file ); } - public CacheRomInfoTask( List files, String databasePath, String configPath, String artDir, CacheRomInfoListener listener ) + public CacheRomInfoTask( File searchPath, String databasePath, String configPath, String artDir, CacheRomInfoListener listener ) { - if( files == null ) - throw new IllegalArgumentException( "File list cannot be null" ); + if( searchPath == null ) + throw new IllegalArgumentException( "Root path cannot be null" ); + if( !searchPath.exists() ) + throw new IllegalArgumentException( "Root path does not exist: " + searchPath.getAbsolutePath() ); if( TextUtils.isEmpty( databasePath ) ) throw new IllegalArgumentException( "ROM database path cannot be null or empty" ); if( TextUtils.isEmpty( configPath ) ) @@ -52,14 +57,14 @@ public CacheRomInfoTask( List files, String databasePath, String configPat if( listener == null ) throw new IllegalArgumentException( "Listener cannot be null" ); - mFiles = files; + mSearchPath = searchPath; mDatabasePath = databasePath; mConfigPath = configPath; mArtDir = artDir; mListener = listener; } - private final List mFiles; + private final File mSearchPath; private final String mDatabasePath; private final String mConfigPath; private final String mArtDir; @@ -68,11 +73,12 @@ public CacheRomInfoTask( List files, String databasePath, String configPat @Override protected ConfigFile doInBackground( Void... params ) { + final List files = getRomFiles( mSearchPath ); final RomDatabase database = new RomDatabase( mDatabasePath ); final ConfigFile config = new ConfigFile( mConfigPath ); config.clear(); - for( final File file : mFiles ) + for( final File file : files ) { String md5 = ComputeMd5Task.computeMd5( file ); RomDetail detail = database.lookupByMd5WithFallback( md5, file ); @@ -99,4 +105,21 @@ protected void onPostExecute( ConfigFile result ) { mListener.onCacheRomInfoFinished( result ); } + + private List getRomFiles( File searchPath ) + { + List result = new ArrayList(); + if( searchPath.isDirectory() ) + { + for( File file : searchPath.listFiles() ) + result.addAll( getRomFiles( file ) ); + } + else + { + String name = searchPath.getName().toLowerCase( Locale.US ); + if( name.matches( ".*\\.(n64|v64|z64|zip)$" ) ) + result.add( searchPath ); + } + return result; + } } \ No newline at end of file diff --git a/src/paulscode/android/mupen64plusae/task/FindRomsTask.java b/src/paulscode/android/mupen64plusae/task/FindRomsTask.java deleted file mode 100644 index 371cb418c5..0000000000 --- a/src/paulscode/android/mupen64plusae/task/FindRomsTask.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Mupen64PlusAE, an N64 emulator for the Android platform - * - * Copyright (C) 2013 Paul Lamb - * - * This file is part of Mupen64PlusAE. - * - * Mupen64PlusAE 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. - * - * Mupen64PlusAE 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 Mupen64PlusAE. If - * not, see . - * - * Authors: littleguy77 - */ -package paulscode.android.mupen64plusae.task; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import android.os.AsyncTask; - -public class FindRomsTask extends AsyncTask> -{ - public interface FindRomsListener - { - public void onFindRomsFinished( List result ); - } - - public FindRomsTask( File rootPath, FindRomsListener listener ) - { - if( rootPath == null ) - throw new IllegalArgumentException( "Root path cannot be null" ); - if( !rootPath.exists() ) - throw new IllegalArgumentException( "Root path does not exist: " + rootPath.getAbsolutePath() ); - if( listener == null ) - throw new IllegalArgumentException( "Listener cannot be null" ); - - mRootPath = rootPath; - mListener = listener; - } - - private final File mRootPath; - private final FindRomsListener mListener; - - @Override - protected List doInBackground( Void... params ) - { - return getRomFiles( mRootPath ); - } - - private List getRomFiles( File rootPath ) - { - List result = new ArrayList(); - if( rootPath.isDirectory() ) - { - for( File file : rootPath.listFiles() ) - result.addAll( getRomFiles( file ) ); - } - else - { - String name = rootPath.getName().toLowerCase( Locale.US ); - if( name.matches( ".*\\.(n64|v64|z64|zip)$" ) ) - result.add( rootPath ); - } - return result; - } - - @Override - protected void onPostExecute( List result ) - { - mListener.onFindRomsFinished( result ); - } -} \ No newline at end of file From 7da16aa6d8a55414b41d362b3d7588e63bf1a5d8 Mon Sep 17 00:00:00 2001 From: littleguy77 Date: Wed, 31 Dec 2014 11:35:28 -0500 Subject: [PATCH 2/5] front: Consolidate DownloadFileTask and CacheRomInfoTask into one class. If we ever need a dedicated download task, we can just resurrect the DownloadFileTask implementation from the repository. --- .../mupen64plusae/task/CacheRomInfoTask.java | 65 ++++++++- .../mupen64plusae/task/DownloadFileTask.java | 128 ------------------ .../android/mupen64plusae/util/FileUtil.java | 73 ---------- 3 files changed, 63 insertions(+), 203 deletions(-) delete mode 100644 src/paulscode/android/mupen64plusae/task/DownloadFileTask.java diff --git a/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java b/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java index f37481a5e9..80b9e69f7c 100644 --- a/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java +++ b/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java @@ -20,14 +20,18 @@ */ package paulscode.android.mupen64plusae.task; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Locale; import paulscode.android.mupen64plusae.persistent.ConfigFile; import paulscode.android.mupen64plusae.persistent.ConfigFile.ConfigSection; -import paulscode.android.mupen64plusae.util.FileUtil; import paulscode.android.mupen64plusae.util.RomDatabase; import paulscode.android.mupen64plusae.util.RomDatabase.RomDetail; import android.os.AsyncTask; @@ -86,7 +90,7 @@ protected ConfigFile doInBackground( Void... params ) config.put( md5, "goodName", detail.goodName ); config.put( md5, "romPath", file.getAbsolutePath() ); config.put( md5, "artPath", artPath ); - FileUtil.downloadFile( detail.artUrl, artPath ); + downloadFile( detail.artUrl, artPath ); this.publishProgress( config.get( md5 ) ); } @@ -122,4 +126,61 @@ private List getRomFiles( File searchPath ) } return result; } + + private Throwable downloadFile( String sourceUrl, String destPath ) + { + // Be sure destination directory exists + new File( destPath ).getParentFile().mkdirs(); + + // Download file + URL url = null; + DataInputStream input = null; + FileOutputStream fos = null; + DataOutputStream output = null; + try + { + url = new URL( sourceUrl ); + input = new DataInputStream( url.openStream() ); + fos = new FileOutputStream( destPath ); + output = new DataOutputStream( fos ); + + int contentLength = url.openConnection().getContentLength(); + byte[] buffer = new byte[contentLength]; + input.readFully( buffer ); + output.write( buffer ); + output.flush(); + } + catch( Throwable error ) + { + return error; + } + finally + { + if( output != null ) + try + { + output.close(); + } + catch( IOException ignored ) + { + } + if( fos != null ) + try + { + fos.close(); + } + catch( IOException ignored ) + { + } + if( input != null ) + try + { + input.close(); + } + catch( IOException ignored ) + { + } + } + return null; + } } \ No newline at end of file diff --git a/src/paulscode/android/mupen64plusae/task/DownloadFileTask.java b/src/paulscode/android/mupen64plusae/task/DownloadFileTask.java deleted file mode 100644 index 2ba0132b8d..0000000000 --- a/src/paulscode/android/mupen64plusae/task/DownloadFileTask.java +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Mupen64PlusAE, an N64 emulator for the Android platform - * - * Copyright (C) 2013 Paul Lamb - * - * This file is part of Mupen64PlusAE. - * - * Mupen64PlusAE 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. - * - * Mupen64PlusAE 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 Mupen64PlusAE. If - * not, see . - * - * Authors: littleguy77 - */ -package paulscode.android.mupen64plusae.task; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; - -import android.os.AsyncTask; -import android.text.TextUtils; - -/** - * Asynchronously copies a file from a network source to a local destination. - */ -public class DownloadFileTask extends AsyncTask -{ - public interface DownloadFileListener - { - public void onDownloadFinished( String sourceUrl, String destPath, Throwable error ); - } - - /** - * @param sourceUrl URL of the source file - * @param destPath Full path of the destination file - */ - public DownloadFileTask( String sourceUrl, String destPath, DownloadFileListener listener ) - { - if( TextUtils.isEmpty( sourceUrl ) ) - throw new IllegalArgumentException( "Source URL cannot be null or empty" ); - if( TextUtils.isEmpty( destPath ) ) - throw new IllegalArgumentException( "Destination path cannot be null or empty" ); - if( listener == null ) - throw new IllegalArgumentException( "Listener cannot be null" ); - - mSourceUrl = sourceUrl; - mDestPath = destPath; - mListener = listener; - } - - private final String mSourceUrl; - private final String mDestPath; - private final DownloadFileListener mListener; - - @Override - protected Throwable doInBackground( Void... params ) - { - // Be sure destination directory exists - new File( mDestPath ).getParentFile().mkdirs(); - - // Download file - URL url = null; - DataInputStream input = null; - FileOutputStream fos = null; - DataOutputStream output = null; - try - { - url = new URL( mSourceUrl ); - input = new DataInputStream( url.openStream() ); - fos = new FileOutputStream( mDestPath ); - output = new DataOutputStream( fos ); - - int contentLength = url.openConnection().getContentLength(); - byte[] buffer = new byte[contentLength]; - input.readFully( buffer ); - output.write( buffer ); - output.flush(); - } - catch( Throwable error ) - { - return error; - } - finally - { - if( output != null ) - try - { - output.close(); - } - catch( IOException ignored ) - { - } - if( fos != null ) - try - { - fos.close(); - } - catch( IOException ignored ) - { - } - if( input != null ) - try - { - input.close(); - } - catch( IOException ignored ) - { - } - } - return null; - } - - @Override - protected void onPostExecute( Throwable result ) - { - mListener.onDownloadFinished( mSourceUrl, mDestPath, result ); - } -} \ No newline at end of file diff --git a/src/paulscode/android/mupen64plusae/util/FileUtil.java b/src/paulscode/android/mupen64plusae/util/FileUtil.java index f6c8e49cf1..ad89fdc531 100644 --- a/src/paulscode/android/mupen64plusae/util/FileUtil.java +++ b/src/paulscode/android/mupen64plusae/util/FileUtil.java @@ -20,8 +20,6 @@ */ package paulscode.android.mupen64plusae.util; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; @@ -31,7 +29,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.URL; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; @@ -41,7 +38,6 @@ import java.util.List; import android.text.Html; -import android.text.TextUtils; import android.util.Log; /** @@ -332,73 +328,4 @@ public static String readStringFromFile( File file ) throws IOException stream.close(); } } - - /** - * Copies a file from a network source to a local destination. - * - * @param sourceUrl URL of the source file - * @param destPath Full path of the destination file - * - * @return True if the download succeeded, false otherwise. - */ - public static boolean downloadFile( String sourceUrl, String destPath ) - { - // Quit if source or destination is empty - if( TextUtils.isEmpty( sourceUrl ) || TextUtils.isEmpty( destPath ) ) - return false; - - // Be sure destination directory exists - new File( destPath ).getParentFile().mkdirs(); - - // Download file - URL url = null; - DataInputStream input = null; - FileOutputStream fos = null; - DataOutputStream output = null; - try - { - url = new URL( sourceUrl ); - input = new DataInputStream( url.openStream() ); - fos = new FileOutputStream( destPath ); - output = new DataOutputStream( fos ); - - int contentLength = url.openConnection().getContentLength(); - byte[] buffer = new byte[contentLength]; - input.readFully( buffer ); - output.write( buffer ); - output.flush(); - } - catch( Exception ignored ) - { - return false; - } - finally - { - if( output != null ) - try - { - output.close(); - } - catch( IOException ignored ) - { - } - if( fos != null ) - try - { - fos.close(); - } - catch( IOException ignored ) - { - } - if( input != null ) - try - { - input.close(); - } - catch( IOException ignored ) - { - } - } - return true; - } } From b004e2b7322934b50326088522d46ae0f88b0bd0 Mon Sep 17 00:00:00 2001 From: littleguy77 Date: Wed, 31 Dec 2014 11:35:45 -0500 Subject: [PATCH 3/5] front: Allow CacheRomInfoTask to be quickly canceled. --- .../android/mupen64plusae/task/CacheRomInfoTask.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java b/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java index 80b9e69f7c..1faa1a825d 100644 --- a/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java +++ b/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java @@ -84,14 +84,20 @@ protected ConfigFile doInBackground( Void... params ) for( final File file : files ) { + if( isCancelled() ) break; String md5 = ComputeMd5Task.computeMd5( file ); + + if( isCancelled() ) break; RomDetail detail = database.lookupByMd5WithFallback( md5, file ); + + if( isCancelled() ) break; String artPath = mArtDir + "/" + detail.artName; config.put( md5, "goodName", detail.goodName ); config.put( md5, "romPath", file.getAbsolutePath() ); config.put( md5, "artPath", artPath ); downloadFile( detail.artUrl, artPath ); + if( isCancelled() ) break; this.publishProgress( config.get( md5 ) ); } config.save(); @@ -116,7 +122,10 @@ private List getRomFiles( File searchPath ) if( searchPath.isDirectory() ) { for( File file : searchPath.listFiles() ) + { + if( isCancelled() ) break; result.addAll( getRomFiles( file ) ); + } } else { From ca66c2b758fea1a05b97c4c105e0f28d0b56cf53 Mon Sep 17 00:00:00 2001 From: littleguy77 Date: Wed, 31 Dec 2014 11:35:55 -0500 Subject: [PATCH 4/5] front: Cancel CacheRomInfoTask when GalleryActivity stops. --- .../mupen64plusae/GalleryActivity.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/paulscode/android/mupen64plusae/GalleryActivity.java b/src/paulscode/android/mupen64plusae/GalleryActivity.java index 3e3bbc6f27..01797d0353 100644 --- a/src/paulscode/android/mupen64plusae/GalleryActivity.java +++ b/src/paulscode/android/mupen64plusae/GalleryActivity.java @@ -70,6 +70,9 @@ public class GalleryActivity extends Activity implements OnItemClickListener, Co // Widgets private GridView mGridView; + // Background tasks + private CacheRomInfoTask mCacheRomInfoTask = null; + @Override protected void onNewIntent( Intent intent ) { @@ -133,6 +136,18 @@ protected void onCreate( Bundle savedInstanceState ) } } + protected void onStop() + { + super.onStop(); + + // Cancel long-running background tasks + if( mCacheRomInfoTask != null ) + { + mCacheRomInfoTask.cancel( false ); + mCacheRomInfoTask = null; + } + } + @Override public boolean onCreateOptionsMenu( Menu menu ) { @@ -259,7 +274,8 @@ private void refreshRoms( final File startDir ) { // Asynchronously search for ROMs Notifier.showToast( this, "Searching for ROMs in " + startDir.getName() ); - new CacheRomInfoTask( startDir, mAppData.mupen64plus_ini, mUserPrefs.romInfoCache_cfg, mUserPrefs.galleryDataDir, this ).execute(); + mCacheRomInfoTask = new CacheRomInfoTask( startDir, mAppData.mupen64plus_ini, mUserPrefs.romInfoCache_cfg, mUserPrefs.galleryDataDir, this ); + mCacheRomInfoTask.execute(); } @Override @@ -271,6 +287,7 @@ public void onCacheRomInfoProgress( ConfigSection section ) @Override public void onCacheRomInfoFinished( ConfigFile config ) { + mCacheRomInfoTask = null; Notifier.showToast( this, "Finished" ); refreshGrid( config ); } From a03ad22fdc93cfd38e4b6ab871fd51d57506b6a4 Mon Sep 17 00:00:00 2001 From: littleguy77 Date: Wed, 31 Dec 2014 11:43:35 -0500 Subject: [PATCH 5/5] front: Refresh GalleryActivity even if CacheRomInfoTask is canceled. --- .../android/mupen64plusae/GalleryActivity.java | 4 ++-- .../android/mupen64plusae/task/CacheRomInfoTask.java | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/paulscode/android/mupen64plusae/GalleryActivity.java b/src/paulscode/android/mupen64plusae/GalleryActivity.java index 01797d0353..fe98f89cfd 100644 --- a/src/paulscode/android/mupen64plusae/GalleryActivity.java +++ b/src/paulscode/android/mupen64plusae/GalleryActivity.java @@ -285,10 +285,10 @@ public void onCacheRomInfoProgress( ConfigSection section ) } @Override - public void onCacheRomInfoFinished( ConfigFile config ) + public void onCacheRomInfoFinished( ConfigFile config, boolean canceled ) { mCacheRomInfoTask = null; - Notifier.showToast( this, "Finished" ); + Notifier.showToast( this, canceled ? "Canceled" : "Finished" ); refreshGrid( config ); } diff --git a/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java b/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java index 1faa1a825d..232fc2b211 100644 --- a/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java +++ b/src/paulscode/android/mupen64plusae/task/CacheRomInfoTask.java @@ -43,7 +43,7 @@ public interface CacheRomInfoListener { public void onCacheRomInfoProgress( ConfigSection section ); - public void onCacheRomInfoFinished( ConfigFile file ); + public void onCacheRomInfoFinished( ConfigFile file, boolean canceled ); } public CacheRomInfoTask( File searchPath, String databasePath, String configPath, String artDir, CacheRomInfoListener listener ) @@ -113,7 +113,13 @@ protected void onProgressUpdate( ConfigSection... values ) @Override protected void onPostExecute( ConfigFile result ) { - mListener.onCacheRomInfoFinished( result ); + mListener.onCacheRomInfoFinished( result, false ); + } + + @Override + protected void onCancelled( ConfigFile result ) + { + mListener.onCacheRomInfoFinished( result, true ); } private List getRomFiles( File searchPath )