diff options
| author | Eder Bastos <bastos.eder@gmail.com> | 2015-05-06 20:12:58 -0400 |
|---|---|---|
| committer | Eder Bastos <bastos.eder@gmail.com> | 2015-05-07 22:27:42 -0400 |
| commit | b47835fc07371964816938c982c5aea3a9f564bb (patch) | |
| tree | 7a66d02b900e00a4541d4292877c9d06bdc2c2c0 /Source/Android/app/src/main/java | |
| parent | 80fe5e0a55260eec17d905cd224919c3734c5876 (diff) | |
Implement first few screens of Android 5.0-based UI.
Diffstat (limited to 'Source/Android/app/src/main/java')
8 files changed, 601 insertions, 0 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index ab9f25b306..e7d2e2b328 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -130,6 +130,12 @@ public final class NativeLibrary */ public static native String GetTitle(String filename); + public static native String GetDescription(String filename); + public static native String GetGameId(String filename); + public static native String GetDate(String filename); + public static native long GetFilesize(String filename); + public static native boolean IsWiiTitle(String filename); + /** * Gets the Dolphin version string. * diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java new file mode 100644 index 0000000000..be0fbbed1a --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java @@ -0,0 +1,131 @@ +package org.dolphinemu.dolphinemu.activities; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Environment; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.widget.Toolbar; + +import org.dolphinemu.dolphinemu.AssetCopyService; +import org.dolphinemu.dolphinemu.NativeLibrary; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.adapters.GameAdapter; +import org.dolphinemu.dolphinemu.model.Game; +import org.dolphinemu.dolphinemu.model.GcGame; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class GameGridActivity extends Activity +{ + private RecyclerView mRecyclerView; + private RecyclerView.Adapter mAdapter; + private RecyclerView.LayoutManager mLayoutManager; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_game_grid); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_game_list); + setActionBar(toolbar); + + mRecyclerView = (RecyclerView) findViewById(R.id.grid_games); + + // use this setting to improve performance if you know that changes + // in content do not change the layout size of the RecyclerView + //mRecyclerView.setHasFixedSize(true); + + // Specifying the LayoutManager determines how the RecyclerView arranges views. + mLayoutManager = new GridLayoutManager(this, 4); + mRecyclerView.setLayoutManager(mLayoutManager); + + mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8)); + + // Create an adapter that will relate the dataset to the views on-screen. + mAdapter = new GameAdapter(getGameList()); + mRecyclerView.setAdapter(mAdapter); + + // Stuff in this block only happens when this activity is newly created (i.e. not a rotation) + if (savedInstanceState == null) + { + // Copy assets into appropriate locations. + Intent copyAssets = new Intent(this, AssetCopyService.class); + startService(copyAssets); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) + { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.gamelist_menu, menu); + return true; + + } + + // TODO Replace all of this with a SQLite database + private ArrayList<Game> getGameList() + { + ArrayList<Game> gameList = new ArrayList<Game>(); + + final String DefaultDir = Environment.getExternalStorageDirectory() + File.separator + "dolphin-emu"; + + NativeLibrary.SetUserDirectory(DefaultDir); + + String Directories = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPaths", "0"); + Log.v("DolphinEmu", "Directories: " + Directories); + int intDirectories = Integer.parseInt(Directories); + + // Extensions to filter by. + Set<String> exts = new HashSet<String>(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs")); + + for (int a = 0; a < intDirectories; ++a) + { + String BrowseDir = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPath" + a, ""); + Log.v("DolphinEmu", "Directory " + a + ": " + BrowseDir); + + File currentDir = new File(BrowseDir); + File[] dirs = currentDir.listFiles(); + try + { + for (File entry : dirs) + { + if (!entry.isHidden() && !entry.isDirectory()) + { + String entryName = entry.getName(); + + // Check that the file has an appropriate extension before trying to read out of it. + if (exts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.')))) + { + GcGame game = new GcGame(NativeLibrary.GetTitle(entry.getAbsolutePath()), + NativeLibrary.GetDescription(entry.getAbsolutePath()).replace("\n", " "), + // TODO Some games might actually not be from this region, believe it or not. + "United States", + entry.getAbsolutePath(), + NativeLibrary.GetGameId(entry.getAbsolutePath()), + NativeLibrary.GetDate(entry.getAbsolutePath())); + + gameList.add(game); + } + + } + + } + } catch (Exception ignored) + { + } + } + + return gameList; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java new file mode 100644 index 0000000000..30bc9daad6 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java @@ -0,0 +1,113 @@ +package org.dolphinemu.dolphinemu.adapters; + +import android.graphics.Rect; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.squareup.picasso.Picasso; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.Game; +import org.dolphinemu.dolphinemu.viewholders.GameViewHolder; + +import java.util.ArrayList; + +public class GameAdapter extends RecyclerView.Adapter<GameViewHolder> +{ + private ArrayList<Game> mGameList; + + /** + * Mostly just initializes the dataset to be displayed. + * + * @param gameList + */ + public GameAdapter(ArrayList<Game> gameList) + { + mGameList = gameList; + } + + /** + * Called by the LayoutManager when it is necessary to create a new view. + * + * @param parent The RecyclerView (I think?) the created view will be thrown into. + * @param viewType Not used here, but useful when more than one type of child will be used in the RecyclerView. + * @return The created ViewHolder with references to all the child view's members. + */ + @Override + public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType) + { + // Create a new view. + View gameCard = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.card_game, parent, false); + + // Use that view to create a ViewHolder. + GameViewHolder holder = new GameViewHolder(gameCard); + return holder; + } + + /** + * Called by the LayoutManager when a new view is not necessary because we can recycle + * an existing one (for example, if a view just scrolled onto the screen from the bottom, we + * can use the view that just scrolled off the top instead of inflating a new one.) + * + * @param holder A ViewHolder representing the view we're recycling. + * @param position The position of the 'new' view in the dataset. + */ + @Override + public void onBindViewHolder(GameViewHolder holder, int position) + { + // Get a reference to the item from the dataset; we'll use this to fill in the view contents. + final Game game = mGameList.get(position); + + // Fill in the view contents. + Picasso.with(holder.imageScreenshot.getContext()) + .load(game.getScreenPath()) + .error(R.drawable.no_banner) + .into(holder.imageScreenshot); + + holder.textGameTitle.setText(game.getTitle()); + if (game.getDescription() != null) + { + holder.textDescription.setText(game.getDescription()); + } + holder.buttonDetails.setTag(game.getGameId()); + + holder.path = game.getPath(); + holder.screenshotPath = game.getScreenPath(); + holder.game = game; + + } + + /** + * Called by the LayoutManager to find out how much data we have. + * + * @return Size of the dataset. + */ + @Override + public int getItemCount() + { + return mGameList.size(); + } + + public static class SpacesItemDecoration extends RecyclerView.ItemDecoration + { + private int space; + + public SpacesItemDecoration(int space) + { + this.space = space; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) + { + outRect.left = space; + outRect.right = space; + outRect.bottom = space; + outRect.top = space; + + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java new file mode 100644 index 0000000000..19c6621345 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java @@ -0,0 +1,96 @@ +package org.dolphinemu.dolphinemu.dialogs; + + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import com.squareup.picasso.Picasso; + +import org.dolphinemu.dolphinemu.BuildConfig; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.emulation.EmulationActivity; +import org.dolphinemu.dolphinemu.model.Game; + +import de.hdodenhof.circleimageview.CircleImageView; + +public class GameDetailsDialog extends DialogFragment +{ + public static final String ARGUMENT_GAME_TITLE = BuildConfig.APPLICATION_ID + ".game_title"; + public static final String ARGUMENT_GAME_DESCRIPTION = BuildConfig.APPLICATION_ID + ".game_description"; + public static final String ARGUMENT_GAME_COUNTRY = BuildConfig.APPLICATION_ID + ".game_country"; + public static final String ARGUMENT_GAME_DATE = BuildConfig.APPLICATION_ID + ".game_date"; + public static final String ARGUMENT_GAME_PATH = BuildConfig.APPLICATION_ID + ".game_path"; + public static final String ARGUMENT_GAME_SCREENSHOT_PATH = BuildConfig.APPLICATION_ID + ".game_screenshot_path"; + + + public static GameDetailsDialog newInstance(Game game) + { + GameDetailsDialog fragment = new GameDetailsDialog(); + + Bundle arguments = new Bundle(); + arguments.putString(ARGUMENT_GAME_TITLE, game.getTitle()); + arguments.putString(ARGUMENT_GAME_DESCRIPTION, game.getDescription()); + arguments.putString(ARGUMENT_GAME_COUNTRY, game.getCountry()); + arguments.putString(ARGUMENT_GAME_DATE, game.getDate()); + arguments.putString(ARGUMENT_GAME_PATH, game.getPath()); + arguments.putString(ARGUMENT_GAME_SCREENSHOT_PATH, game.getScreenPath()); + fragment.setArguments(arguments); + + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) + { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + ViewGroup contents = (ViewGroup) getActivity().getLayoutInflater().inflate(R.layout.dialog_game_details, null); + + final ImageView imageGameScreen = (ImageView) contents.findViewById(R.id.image_game_screen); + CircleImageView circleBanner = (CircleImageView) contents.findViewById(R.id.circle_banner); + + TextView textTitle = (TextView) contents.findViewById(R.id.text_game_title); + TextView textDescription = (TextView) contents.findViewById(R.id.text_game_description); + + TextView textCountry = (TextView) contents.findViewById(R.id.text_country); + TextView textDate = (TextView) contents.findViewById(R.id.text_date); + + ImageButton buttonLaunch = (ImageButton) contents.findViewById(R.id.button_launch); + + textTitle.setText(getArguments().getString(ARGUMENT_GAME_TITLE)); + textDescription.setText(getArguments().getString(ARGUMENT_GAME_DESCRIPTION)); + textCountry.setText(getArguments().getString(ARGUMENT_GAME_COUNTRY)); + textDate.setText(getArguments().getString(ARGUMENT_GAME_DATE)); + buttonLaunch.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View view) + { + // Start the emulation activity and send the path of the clicked ROM to it. + Intent intent = new Intent(view.getContext(), EmulationActivity.class); + + intent.putExtra("SelectedGame", getArguments().getString(ARGUMENT_GAME_PATH)); + startActivity(intent); + } + }); + + // Fill in the view contents. + Picasso.with(imageGameScreen.getContext()) + .load(getArguments().getString(ARGUMENT_GAME_SCREENSHOT_PATH)) + .noFade() + .noPlaceholder() + .into(imageGameScreen); + + circleBanner.setImageResource(R.drawable.no_banner); + + builder.setView(contents); + return builder.create(); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/Game.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/Game.java new file mode 100644 index 0000000000..9d3e736841 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/Game.java @@ -0,0 +1,23 @@ +package org.dolphinemu.dolphinemu.model; + +public interface Game +{ + public static final int PLATFORM_GC = 0; + public static final int PLATFORM_WII = 1; + + public int getPlatform(); + + public String getDate(); + + public String getTitle(); + + public String getDescription(); + + public String getCountry(); + + public String getPath(); + + public String getGameId(); + + public String getScreenPath(); +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GcGame.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GcGame.java new file mode 100644 index 0000000000..d682bee0b6 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GcGame.java @@ -0,0 +1,96 @@ +package org.dolphinemu.dolphinemu.model; + + +import java.io.File; + +public final class GcGame implements Game +{ + private String mTitle; + private String mDescription; + private String mCountry; + private String mPath; + private String mGameId; + + private String mScreenshotFolderPath; + + private String mDate; + private int mPlatform = PLATFORM_GC; + + private static final String PATH_SCREENSHOT_FOLDER = "file:///sdcard/dolphin-emu/ScreenShots/"; + + public GcGame(String title, String description, String country, String path, String gameId, String date) + { + mTitle = title; + mDescription = description; + mCountry = country; + mPath = path; + mGameId = gameId; + mDate = date; + mScreenshotFolderPath = PATH_SCREENSHOT_FOLDER + getGameId() + "/"; + } + + @Override + public int getPlatform() + { + return mPlatform; + } + + @Override + public String getTitle() + { + return mTitle; + } + + @Override + public String getDescription() + { + return mDescription; + } + + @Override + public String getDate() + { + return mDate; + } + + @Override + public String getCountry() + { + return mCountry; + } + + @Override + public String getPath() + { + return mPath; + } + + public String getGameId() + { + return mGameId; + } + + public String getScreenshotFolderPath() + { + return mScreenshotFolderPath; + } + + @Override + public String getScreenPath() + { + // Count how many screenshots are available, so we can use the most recent one. + File screenshotFolder = new File(mScreenshotFolderPath.substring(mScreenshotFolderPath.indexOf('s') - 1)); + int screenCount = 0; + + if (screenshotFolder.isDirectory()) + { + screenCount = screenshotFolder.list().length; + } + + String screenPath = mScreenshotFolderPath + + getGameId() + "-" + + screenCount + ".png"; + + return screenPath; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/WiiGame.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/WiiGame.java new file mode 100644 index 0000000000..c64de8d582 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/WiiGame.java @@ -0,0 +1,53 @@ +package org.dolphinemu.dolphinemu.model; + + +public final class WiiGame implements Game +{ + @Override + public int getPlatform() + { + return 0; + } + + @Override + public String getDate() + { + return null; + } + + @Override + public String getTitle() + { + return null; + } + + @Override + public String getDescription() + { + return null; + } + + @Override + public String getCountry() + { + return null; + } + + @Override + public String getPath() + { + return null; + } + + @Override + public String getGameId() + { + return null; + } + + @Override + public String getScreenPath() + { + return null; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java new file mode 100644 index 0000000000..47acf588de --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java @@ -0,0 +1,83 @@ +package org.dolphinemu.dolphinemu.viewholders; + +import android.app.Activity; +import android.content.Intent; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.dialogs.GameDetailsDialog; +import org.dolphinemu.dolphinemu.emulation.EmulationActivity; +import org.dolphinemu.dolphinemu.model.Game; + + +public class GameViewHolder extends RecyclerView.ViewHolder +{ + public ImageView imageScreenshot; + public TextView textGameTitle; + public TextView textDescription; + public ImageButton buttonDetails; + + // Used to handle onClick(). Set this in onBindViewHolder(). + public String path; + public String screenshotPath; + public Game game; + + public GameViewHolder(View itemView) + { + super(itemView); + + itemView.setOnClickListener(mCardClickListener); + + imageScreenshot = (ImageView) itemView.findViewById(R.id.image_game_screen); + textGameTitle = (TextView) itemView.findViewById(R.id.text_game_title); + textDescription = (TextView) itemView.findViewById(R.id.text_game_description); + buttonDetails = (ImageButton) itemView.findViewById(R.id.button_details); + + buttonDetails.setOnClickListener(mDetailsButtonListener); + } + + private View.OnClickListener mCardClickListener = new View.OnClickListener() + { + /** + * Launches the game that was clicked on. + * + * @param view The card representing the game the user wants to play. + */ + @Override + public void onClick(View view) + { + // Start the emulation activity and send the path of the clicked ROM to it. + Intent intent = new Intent(view.getContext(), EmulationActivity.class); + + intent.putExtra("SelectedGame", path); + + view.getContext().startActivity(intent); + } + }; + + private View.OnClickListener mDetailsButtonListener = new View.OnClickListener() + { + + /** + * Launches the details activity for this Game, using an ID stored in the + * details button's Tag. + * + * @param view The Details button that was clicked on. + */ + @Override + public void onClick(View view) + { + // Get the ID of the game we want to look at. + // TODO This should be all we need to pass in, eventually. + // String gameId = (String) view.getTag(); + + Activity activity = (Activity) view.getContext(); + GameDetailsDialog.newInstance(game).show(activity.getFragmentManager(), "game_details"); + } + }; + +} |
