mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 06:15:38 +00:00
Android: Add "Choose Cover Image" to game list menu
This commit is contained in:
parent
f68836206b
commit
4ab283a2ae
|
@ -168,16 +168,17 @@ public class AndroidHostInterface {
|
|||
}
|
||||
|
||||
static private AndroidHostInterface mInstance;
|
||||
static private String mUserDirectory;
|
||||
|
||||
static public boolean createInstance(Context context) {
|
||||
// Set user path.
|
||||
String externalStorageDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
if (externalStorageDirectory.isEmpty())
|
||||
externalStorageDirectory = "/sdcard";
|
||||
mUserDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
if (mUserDirectory.isEmpty())
|
||||
mUserDirectory = "/sdcard";
|
||||
|
||||
externalStorageDirectory += "/duckstation";
|
||||
Log.i("AndroidHostInterface", "User directory: " + externalStorageDirectory);
|
||||
mInstance = create(context, externalStorageDirectory);
|
||||
mUserDirectory += "/duckstation";
|
||||
Log.i("AndroidHostInterface", "User directory: " + mUserDirectory);
|
||||
mInstance = create(context, mUserDirectory);
|
||||
return mInstance != null;
|
||||
}
|
||||
|
||||
|
@ -189,6 +190,8 @@ public class AndroidHostInterface {
|
|||
return mInstance;
|
||||
}
|
||||
|
||||
static public String getUserDirectory() { return mUserDirectory; }
|
||||
|
||||
static public boolean hasInstanceAndEmulationThreadIsRunning() {
|
||||
return hasInstance() && getInstance().isEmulationThreadRunning();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ import android.annotation.SuppressLint;
|
|||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.ImageDecoder;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.storage.StorageManager;
|
||||
|
@ -272,4 +275,19 @@ public final class FileUtil {
|
|||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap loadBitmapFromUri(final Context context, final Uri uri) {
|
||||
InputStream stream = null;
|
||||
try {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
|
||||
final ImageDecoder.Source source =ImageDecoder.createSource(context.getContentResolver(), uri);
|
||||
return ImageDecoder.decodeBitmap(source);
|
||||
} else {
|
||||
return MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,6 +32,10 @@ public class GameList {
|
|||
public void removeRefreshListener(OnRefreshListener listener) {
|
||||
mRefreshListeners.remove(listener);
|
||||
}
|
||||
public void fireRefreshListeners() {
|
||||
for (OnRefreshListener listener : mRefreshListeners)
|
||||
listener.onGameListRefresh();
|
||||
}
|
||||
|
||||
private class GameListEntryComparator implements Comparator<GameListEntry> {
|
||||
@Override
|
||||
|
@ -56,8 +60,7 @@ public class GameList {
|
|||
e.printStackTrace();
|
||||
}
|
||||
mEntries = newEntries;
|
||||
for (OnRefreshListener listener : mRefreshListeners)
|
||||
listener.onGameListRefresh();
|
||||
fireRefreshListeners();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -69,4 +72,13 @@ public class GameList {
|
|||
public GameListEntry getEntry(int index) {
|
||||
return mEntries[index];
|
||||
}
|
||||
|
||||
public GameListEntry getEntryForPath(String path) {
|
||||
for (final GameListEntry entry : mEntries) {
|
||||
if (entry.getPath().equals(path))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,6 +100,8 @@ public class GameListEntry {
|
|||
|
||||
public String getCoverPath() { return mCoverPath; }
|
||||
|
||||
public void setCoverPath(String coverPath) { mCoverPath = coverPath; }
|
||||
|
||||
public static String getFileNameForPath(String path) {
|
||||
int lastSlash = path.lastIndexOf('/');
|
||||
if (lastSlash > 0 && lastSlash < path.length() - 1)
|
||||
|
|
|
@ -8,6 +8,8 @@ import android.content.SharedPreferences;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
@ -29,9 +31,12 @@ import androidx.core.content.ContextCompat;
|
|||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
@ -41,6 +46,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
private static final int REQUEST_START_FILE = 4;
|
||||
private static final int REQUEST_SETTINGS = 5;
|
||||
private static final int REQUEST_EDIT_GAME_DIRECTORIES = 6;
|
||||
private static final int REQUEST_CHOOSE_COVER_IMAGE = 7;
|
||||
|
||||
private GameList mGameList;
|
||||
private ListView mGameListView;
|
||||
|
@ -48,6 +54,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
private GameGridFragment mGameGridFragment;
|
||||
private boolean mHasExternalStoragePermissions = false;
|
||||
private boolean mIsShowingGameGrid = false;
|
||||
private String mPathForChosenCoverImage = null;
|
||||
|
||||
public GameList getGameList() {
|
||||
return mGameList;
|
||||
|
@ -297,6 +304,16 @@ public class MainActivity extends AppCompatActivity {
|
|||
mGameList.refresh(false, false, this);
|
||||
}
|
||||
break;
|
||||
|
||||
case REQUEST_CHOOSE_COVER_IMAGE: {
|
||||
final String gamePath = mPathForChosenCoverImage;
|
||||
mPathForChosenCoverImage = null;
|
||||
if (resultCode != RESULT_OK)
|
||||
return;
|
||||
|
||||
finishChooseCoverImage(gamePath, data.getData());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,6 +372,9 @@ public class MainActivity extends AppCompatActivity {
|
|||
} else if (id == R.id.game_list_entry_menu_properties) {
|
||||
openGameProperties(entry.getPath());
|
||||
return true;
|
||||
} else if (id == R.id.game_list_entry_menu_choose_cover_image) {
|
||||
startChooseCoverImage(entry.getPath());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -387,6 +407,48 @@ public class MainActivity extends AppCompatActivity {
|
|||
startActivityForResult(Intent.createChooser(intent, getString(R.string.main_activity_choose_disc_image)), REQUEST_START_FILE);
|
||||
}
|
||||
|
||||
private void startChooseCoverImage(String gamePath) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("image/*");
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
mPathForChosenCoverImage = gamePath;
|
||||
startActivityForResult(Intent.createChooser(intent, getString(R.string.menu_game_list_entry_choose_cover_image)),
|
||||
REQUEST_CHOOSE_COVER_IMAGE);
|
||||
}
|
||||
|
||||
private void finishChooseCoverImage(String gamePath, Uri uri) {
|
||||
final GameListEntry gameListEntry = mGameList.getEntryForPath(gamePath);
|
||||
if (gameListEntry == null)
|
||||
return;
|
||||
|
||||
final Bitmap bitmap = FileUtil.loadBitmapFromUri(this, uri);
|
||||
if (bitmap == null) {
|
||||
Toast.makeText(this, "Failed to open/decode image.", Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
final String coverFileName = String.format("%s/covers/%s.png",
|
||||
AndroidHostInterface.getUserDirectory(), gameListEntry.getTitle());
|
||||
try {
|
||||
final File file = new File(coverFileName);
|
||||
final OutputStream outputStream = new FileOutputStream(file);
|
||||
final boolean result = bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
|
||||
outputStream.close();;
|
||||
if (!result) {
|
||||
file.delete();
|
||||
throw new Exception("Failed to compress bitmap.");
|
||||
}
|
||||
|
||||
gameListEntry.setCoverPath(coverFileName);
|
||||
mGameList.fireRefreshListeners();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "Failed to save image.", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
bitmap.recycle();
|
||||
}
|
||||
|
||||
private boolean doBIOSCheck() {
|
||||
if (AndroidHostInterface.getInstance().hasAnyBIOSImages())
|
||||
return true;
|
||||
|
|
|
@ -10,4 +10,7 @@
|
|||
<item
|
||||
android:id="@+id/game_list_entry_menu_properties"
|
||||
android:title="@string/menu_game_list_entry_game_properties" />
|
||||
<item
|
||||
android:id="@+id/game_list_entry_menu_choose_cover_image"
|
||||
android:title="@string/menu_game_list_entry_choose_cover_image" />
|
||||
</menu>
|
|
@ -311,4 +311,5 @@
|
|||
<string name="memory_card_editor_import_card_read_failed">Failed to read \'%s\'.</string>
|
||||
<string name="memory_card_editor_import_card_failed">Failed to import card \'%s\'. It may not be a supported format.</string>
|
||||
<string name="memory_card_editor_import_card_success">Imported card \'%s\'.</string>
|
||||
<string name="menu_game_list_entry_choose_cover_image">Choose Cover Image</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue