diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml
index adfda3d0ce..0d83b3a37d 100644
--- a/Source/Android/app/src/main/AndroidManifest.xml
+++ b/Source/Android/app/src/main/AndroidManifest.xml
@@ -27,7 +27,7 @@
         android:banner="@drawable/banner_tv">
 
         <activity
-            android:name=".activities.MainActivity"
+            android:name=".ui.main.MainActivity"
             android:theme="@style/DolphinGamecube">
 
             <!-- This intentfilter marks this Activity as the one that gets launched from Home screen. -->
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java
index f9308fc80e..09e833d1ad 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java
@@ -1,5 +1,6 @@
 package org.dolphinemu.dolphinemu.activities;
 
+import android.app.Activity;
 import android.content.AsyncQueryHandler;
 import android.content.ContentValues;
 import android.content.Intent;
@@ -19,6 +20,7 @@ import org.dolphinemu.dolphinemu.R;
 import org.dolphinemu.dolphinemu.adapters.FileAdapter;
 import org.dolphinemu.dolphinemu.model.GameDatabase;
 import org.dolphinemu.dolphinemu.model.GameProvider;
+import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
 
 /**
  * An Activity that shows a list of files and folders, allowing the user to tell the app which folder(s)
@@ -131,4 +133,10 @@ public class AddDirectoryActivity extends AppCompatActivity implements FileAdapt
 	{
 		mToolbar.setSubtitle(path);
 	}
+
+	public static void launch(Activity activity)
+	{
+		Intent fileChooser = new Intent(activity, AddDirectoryActivity.class);
+		activity.startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY);
+	}
 }
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java
deleted file mode 100644
index 5dc3bbd983..0000000000
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.dolphinemu.dolphinemu.activities;
-
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.annotation.Nullable;
-import android.support.design.widget.FloatingActionButton;
-import android.support.design.widget.TabLayout;
-import android.support.v4.view.ViewPager;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-
-import org.dolphinemu.dolphinemu.NativeLibrary;
-import org.dolphinemu.dolphinemu.R;
-import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
-import org.dolphinemu.dolphinemu.fragments.PlatformGamesFragment;
-import org.dolphinemu.dolphinemu.model.Game;
-import org.dolphinemu.dolphinemu.model.GameDatabase;
-import org.dolphinemu.dolphinemu.model.GameProvider;
-import org.dolphinemu.dolphinemu.services.AssetCopyService;
-import org.dolphinemu.dolphinemu.utils.StartupHandler;
-
-/**
- * The main Activity of the Lollipop style UI. Manages several PlatformGamesFragments, which
- * individually display a grid of available games for each Fragment, in a tabbed layout.
- */
-public final class MainActivity extends AppCompatActivity
-{
-	public static final int REQUEST_ADD_DIRECTORY = 1;
-	public static final int REQUEST_EMULATE_GAME = 2;
-
-	private ViewPager mViewPager;
-	private PlatformPagerAdapter mPlatformPagerAdapter;
-
-	@Override
-	protected void onCreate(Bundle savedInstanceState)
-	{
-		super.onCreate(savedInstanceState);
-		setContentView(R.layout.activity_main);
-
-		// Set up the Toolbar.
-		Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_main);
-		setSupportActionBar(toolbar);
-
-		// TODO Rather than calling into native code, this should use the commented line below.
-		// String versionName = BuildConfig.VERSION_NAME;
-		String versionName = NativeLibrary.GetVersionString();
-		toolbar.setSubtitle(versionName);
-
-		// Set up the Tab bar.
-		mViewPager = (ViewPager) findViewById(R.id.pager_platforms);
-
-		mPlatformPagerAdapter = new PlatformPagerAdapter(getFragmentManager(), this);
-		mViewPager.setAdapter(mPlatformPagerAdapter);
-
-		TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs_platforms);
-		tabLayout.setupWithViewPager(mViewPager);
-
-		// Set up the FAB.
-		FloatingActionButton buttonAddDirectory = (FloatingActionButton) findViewById(R.id.button_add_directory);
-		buttonAddDirectory.setOnClickListener(new View.OnClickListener()
-		{
-			@Override
-			public void onClick(View view)
-			{
-				Intent fileChooser = new Intent(MainActivity.this, AddDirectoryActivity.class);
-
-				// The second argument to this method is read below in onActivityResult().
-				startActivityForResult(fileChooser, REQUEST_ADD_DIRECTORY);
-			}
-		});
-
-		// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
-		if (savedInstanceState == null)
-			StartupHandler.HandleInit(this);
-	}
-
-	/**
-	 * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity.
-	 *
-	 * @param requestCode An int describing whether the Activity that is returning did so successfully.
-	 * @param resultCode  An int describing what Activity is giving us this callback.
-	 * @param result      The information the returning Activity is providing us.
-	 */
-	@Override
-	protected void onActivityResult(int requestCode, int resultCode, Intent result)
-	{
-		switch (requestCode)
-		{
-			case REQUEST_ADD_DIRECTORY:
-				// If the user picked a file, as opposed to just backing out.
-				if (resultCode == RESULT_OK)
-				{
-					// Sanity check to make sure the Activity that just returned was the AddDirectoryActivity;
-					// other activities might use this callback in the future (don't forget to change Javadoc!)
-					if (requestCode == REQUEST_ADD_DIRECTORY)
-					{
-						refreshFragment();
-					}
-				}
-				break;
-
-			case REQUEST_EMULATE_GAME:
-				// Invalidate Picasso image so that the new screenshot is animated in.
-				PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem());
-
-				if (fragment != null)
-				{
-					fragment.refreshScreenshotAtPosition(resultCode);
-				}
-				break;
-		}
-	}
-
-	@Override
-	public boolean onCreateOptionsMenu(Menu menu)
-	{
-		MenuInflater inflater = getMenuInflater();
-		inflater.inflate(R.menu.menu_game_grid, menu);
-		return true;
-	}
-
-	/**
-	 * Called by the framework whenever any actionbar/toolbar icon is clicked.
-	 *
-	 * @param item The icon that was clicked on.
-	 * @return True if the event was handled, false to bubble it up to the OS.
-	 */
-	@Override
-	public boolean onOptionsItemSelected(MenuItem item)
-	{
-		switch (item.getItemId())
-		{
-			case R.id.menu_settings:
-				// Launch the Settings Actvity.
-				Intent settings = new Intent(this, SettingsActivity.class);
-				startActivity(settings);
-				return true;
-
-			case R.id.menu_refresh:
-				getContentResolver().insert(GameProvider.URI_REFRESH, null);
-				refreshFragment();
-
-				return true;
-		}
-
-		return false;
-	}
-
-	public void refreshFragment()
-	{
-		PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem());
-		if (fragment != null)
-		{
-			fragment.refresh();
-		}
-	}
-
-	@Nullable
-	public PlatformGamesFragment getPlatformFragment(int platform)
-	{
-		String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform;
-
-		return (PlatformGamesFragment) getFragmentManager().findFragmentByTag(fragmentTag);
-	}
-}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java
index a595cdeb0f..c6ce27acfe 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java
@@ -1,6 +1,7 @@
 package org.dolphinemu.dolphinemu.activities;
 
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.v7.app.AppCompatActivity;
@@ -38,4 +39,10 @@ public final class SettingsActivity extends AppCompatActivity
 		Intent settingsSaver = new Intent(this, SettingsSaveService.class);
 		startService(settingsSaver);
 	}
+
+	public static void launch(Context context)
+	{
+		Intent settings = new Intent(context, SettingsActivity.class);
+		context.startActivity(settings);
+	}
 }
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java
index a01e080549..6d580eaafb 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java
@@ -4,10 +4,8 @@ import android.app.Activity;
 import android.app.ActivityOptions;
 import android.app.FragmentManager;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.os.Bundle;
-import android.preference.PreferenceManager;
 import android.support.v17.leanback.app.BrowseFragment;
 import android.support.v17.leanback.database.CursorMapper;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
@@ -19,23 +17,22 @@ import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
-import android.widget.Toast;
 
-import org.dolphinemu.dolphinemu.NativeLibrary;
 import org.dolphinemu.dolphinemu.R;
 import org.dolphinemu.dolphinemu.adapters.GameRowPresenter;
 import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter;
 import org.dolphinemu.dolphinemu.model.Game;
-import org.dolphinemu.dolphinemu.model.GameDatabase;
-import org.dolphinemu.dolphinemu.model.GameProvider;
 import org.dolphinemu.dolphinemu.model.TvSettingsItem;
-import org.dolphinemu.dolphinemu.services.AssetCopyService;
+import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
+import org.dolphinemu.dolphinemu.ui.main.MainView;
 import org.dolphinemu.dolphinemu.utils.StartupHandler;
 import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder;
 
-public final class TvMainActivity extends Activity
+public final class TvMainActivity extends Activity implements MainView
 {
-	protected BrowseFragment mBrowseFragment;
+	private MainPresenter mPresenter = new MainPresenter(this);
+
+	private BrowseFragment mBrowseFragment;
 
 	private ArrayObjectAdapter mRowsAdapter;
 
@@ -58,6 +55,8 @@ public final class TvMainActivity extends Activity
 
 		buildRowsAdapter();
 
+		mPresenter.onCreate();
+
 		mBrowseFragment.setOnItemViewClickedListener(
 				new OnItemViewClickedListener()
 				{
@@ -68,34 +67,7 @@ public final class TvMainActivity extends Activity
 						if (item instanceof TvSettingsItem)
 						{
 							TvSettingsItem settingsItem = (TvSettingsItem) item;
-
-							switch (settingsItem.getItemId())
-							{
-								case R.id.menu_refresh:
-									getContentResolver().insert(GameProvider.URI_REFRESH, null);
-
-									// TODO Let the Activity know the data is refreshed in some other, better way.
-									recreate();
-									break;
-
-								case R.id.menu_settings:
-									// Launch the Settings Actvity.
-									Intent settings = new Intent(TvMainActivity.this, SettingsActivity.class);
-									startActivity(settings);
-									break;
-
-								case R.id.button_add_directory:
-									Intent fileChooser = new Intent(TvMainActivity.this, AddDirectoryActivity.class);
-
-									// The second argument to this method is read below in onActivityResult().
-									startActivityForResult(fileChooser, MainActivity.REQUEST_ADD_DIRECTORY);
-
-									break;
-
-								default:
-									Toast.makeText(TvMainActivity.this, "Unimplemented menu option.", Toast.LENGTH_SHORT).show();
-									break;
-							}
+							mPresenter.handleOptionSelection(settingsItem.getItemId());
 						}
 						else
 						{
@@ -122,6 +94,52 @@ public final class TvMainActivity extends Activity
 			StartupHandler.HandleInit(this);
 	}
 
+	/**
+	 * MainView
+	 */
+
+	@Override
+	public void setVersionString(String version)
+	{
+		// No-op
+	}
+
+	@Override
+	public void refresh()
+	{
+		recreate();
+	}
+
+	@Override
+	public void refreshFragmentScreenshot(int fragmentPosition)
+	{
+		// No-op (For now)
+	}
+
+	@Override
+	public void launchSettingsActivity()
+	{
+		SettingsActivity.launch(this);
+	}
+
+	@Override
+	public void launchFileListActivity()
+	{
+		AddDirectoryActivity.launch(this);
+	}
+
+	@Override
+	public void showGames(int platformIndex, Cursor games)
+	{
+		ListRow row = buildGamesRow(platformIndex, games);
+
+		// Add row to the adapter only if it is not empty.
+		if (row != null)
+		{
+			mRowsAdapter.add(row);
+		}
+	}
+
 	/**
 	 * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity.
 	 *
@@ -132,22 +150,7 @@ public final class TvMainActivity extends Activity
 	@Override
 	protected void onActivityResult(int requestCode, int resultCode, Intent result)
 	{
-		switch (requestCode)
-		{
-			case MainActivity.REQUEST_ADD_DIRECTORY:
-				// If the user picked a file, as opposed to just backing out.
-				if (resultCode == RESULT_OK)
-				{
-					// Sanity check to make sure the Activity that just returned was the AddDirectoryActivity;
-					// other activities might use this callback in the future (don't forget to change Javadoc!)
-					if (requestCode == MainActivity.REQUEST_ADD_DIRECTORY)
-					{
-						// TODO Let the Activity know the data is refreshed in some other, better way.
-						recreate();
-					}
-				}
-				break;
-		}
+		mPresenter.handleActivityResult(requestCode, resultCode);
 	}
 
 	private void buildRowsAdapter()
@@ -157,50 +160,19 @@ public final class TvMainActivity extends Activity
 		// For each platform
 		for (int platformIndex = 0; platformIndex <= Game.PLATFORM_ALL; ++platformIndex)
 		{
-			ListRow row = buildGamesRow(platformIndex);
-
-			// Add row to the adapter only if it is not empty.
-			if (row != null)
-			{
-				mRowsAdapter.add(row);
-			}
+			mPresenter.loadGames(platformIndex);
 		}
 
-		ListRow settingsRow = buildSettingsRow();
-		mRowsAdapter.add(settingsRow);
+		mRowsAdapter.add(buildSettingsRow());
 
 		mBrowseFragment.setAdapter(mRowsAdapter);
 	}
 
-	private ListRow buildGamesRow(int platform)
+	private ListRow buildGamesRow(int platform, Cursor games)
 	{
 		// Create an adapter for this row.
 		CursorObjectAdapter row = new CursorObjectAdapter(new GameRowPresenter());
 
-		Cursor games;
-		if (platform == Game.PLATFORM_ALL)
-		{
-			// Get all games.
-			games = getContentResolver().query(
-					GameProvider.URI_GAME,                        // URI of table to query
-					null,                                        // Return all columns
-					null,                                        // Return all games
-					null,                                        // Return all games
-					GameDatabase.KEY_GAME_TITLE + " asc"        // Sort by game name, ascending order
-			);
-		}
-		else
-		{
-			// Get games for this particular platform.
-			games = getContentResolver().query(
-					GameProvider.URI_GAME,                        // URI of table to query
-					null,                                        // Return all columns
-					GameDatabase.KEY_GAME_PLATFORM + " = ?",    // Select by platform
-					new String[]{Integer.toString(platform)},    // Platform id
-					GameDatabase.KEY_GAME_TITLE + " asc"        // Sort by game name, ascending order
-			);
-		}
-
 		// If cursor is empty, don't return a Row.
 		if (!games.moveToFirst())
 		{
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
index e74bd6f96d..205447e054 100644
--- 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
@@ -17,9 +17,9 @@ import com.squareup.picasso.Picasso;
 
 import org.dolphinemu.dolphinemu.R;
 import org.dolphinemu.dolphinemu.activities.EmulationActivity;
-import org.dolphinemu.dolphinemu.activities.MainActivity;
 import org.dolphinemu.dolphinemu.dialogs.GameDetailsDialog;
 import org.dolphinemu.dolphinemu.model.GameDatabase;
+import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
 import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
 
 /**
@@ -231,7 +231,7 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
 				"image_game_screenshot");
 
 		((Activity) view.getContext()).startActivityForResult(intent,
-				MainActivity.REQUEST_EMULATE_GAME,
+				MainPresenter.REQUEST_EMULATE_GAME,
 				options.toBundle());
 	}
 
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java
new file mode 100644
index 0000000000..372edd3249
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java
@@ -0,0 +1,176 @@
+package org.dolphinemu.dolphinemu.ui.main;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.design.widget.FloatingActionButton;
+import android.support.design.widget.TabLayout;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import org.dolphinemu.dolphinemu.R;
+import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity;
+import org.dolphinemu.dolphinemu.activities.SettingsActivity;
+import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
+import org.dolphinemu.dolphinemu.fragments.PlatformGamesFragment;
+import org.dolphinemu.dolphinemu.model.GameProvider;
+import org.dolphinemu.dolphinemu.utils.StartupHandler;
+
+/**
+ * The main Activity of the Lollipop style UI. Manages several PlatformGamesFragments, which
+ * individually display a grid of available games for each Fragment, in a tabbed layout.
+ */
+public final class MainActivity extends AppCompatActivity implements MainView
+{
+	private ViewPager mViewPager;
+	private Toolbar mToolbar;
+	private TabLayout mTabLayout;
+	private FloatingActionButton mFab;
+
+	private MainPresenter mPresenter = new MainPresenter(this);
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState)
+	{
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_main);
+
+		findViews();
+
+		setSupportActionBar(mToolbar);
+
+		PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(getFragmentManager(), this);
+
+		mViewPager.setAdapter(platformPagerAdapter);
+		mTabLayout.setupWithViewPager(mViewPager);
+
+		// Set up the FAB.
+		mFab.setOnClickListener(new View.OnClickListener()
+		{
+			@Override
+			public void onClick(View view)
+			{
+				mPresenter.onFabClick();
+			}
+		});
+
+		mPresenter.onCreate();
+
+		// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
+		// TODO Split some of this stuff into Application.onCreate()
+		if (savedInstanceState == null)
+			StartupHandler.HandleInit(this);
+	}
+
+	// TODO: Replace with a ButterKnife injection.
+	private void findViews()
+	{
+		mToolbar = (Toolbar) findViewById(R.id.toolbar_main);
+		mViewPager = (ViewPager) findViewById(R.id.pager_platforms);
+		mTabLayout = (TabLayout) findViewById(R.id.tabs_platforms);
+		mFab = (FloatingActionButton) findViewById(R.id.button_add_directory);
+	}
+
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu)
+	{
+		MenuInflater inflater = getMenuInflater();
+		inflater.inflate(R.menu.menu_game_grid, menu);
+		return true;
+	}
+
+	/**
+	 * MainView
+	 */
+
+	@Override
+	public void setVersionString(String version)
+	{
+		mToolbar.setSubtitle(version);
+	}
+
+	@Override
+	public void refresh()
+	{
+		getContentResolver().insert(GameProvider.URI_REFRESH, null);
+		refreshFragment();
+	}
+
+	@Override
+	public void refreshFragmentScreenshot(int fragmentPosition)
+	{
+		// Invalidate Picasso image so that the new screenshot is animated in.
+		PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem());
+
+		if (fragment != null)
+		{
+			fragment.refreshScreenshotAtPosition(fragmentPosition);
+		}
+	}
+
+	@Override
+	public void launchSettingsActivity()
+	{
+		SettingsActivity.launch(this);
+	}
+
+	@Override
+	public void launchFileListActivity()
+	{
+		AddDirectoryActivity.launch(this);
+	}
+
+	@Override
+	public void showGames(int platformIndex, Cursor games)
+	{
+		// no-op. Handled by PlatformGamesFragment.
+	}
+
+	/**
+	 * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity.
+	 *
+	 * @param requestCode An int describing whether the Activity that is returning did so successfully.
+	 * @param resultCode  An int describing what Activity is giving us this callback.
+	 * @param result      The information the returning Activity is providing us.
+	 */
+	@Override
+	protected void onActivityResult(int requestCode, int resultCode, Intent result)
+	{
+		mPresenter.handleActivityResult(requestCode, resultCode);
+	}
+
+	/**
+	 * Called by the framework whenever any actionbar/toolbar icon is clicked.
+	 *
+	 * @param item The icon that was clicked on.
+	 * @return True if the event was handled, false to bubble it up to the OS.
+	 */
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item)
+	{
+		return mPresenter.handleOptionSelection(item.getItemId());
+	}
+
+	private void refreshFragment()
+	{
+		PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem());
+		if (fragment != null)
+		{
+			fragment.refresh();
+		}
+	}
+
+	@Nullable
+	private PlatformGamesFragment getPlatformFragment(int platform)
+	{
+		String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform;
+
+		return (PlatformGamesFragment) getFragmentManager().findFragmentByTag(fragmentTag);
+	}
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java
new file mode 100644
index 0000000000..97b7a39f25
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java
@@ -0,0 +1,95 @@
+package org.dolphinemu.dolphinemu.ui.main;
+
+
+import android.database.Cursor;
+
+import org.dolphinemu.dolphinemu.DolphinApplication;
+import org.dolphinemu.dolphinemu.NativeLibrary;
+import org.dolphinemu.dolphinemu.R;
+import org.dolphinemu.dolphinemu.model.GameDatabase;
+
+import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Action1;
+import rx.schedulers.Schedulers;
+
+public final class MainPresenter
+{
+	public static final int REQUEST_ADD_DIRECTORY = 1;
+	public static final int REQUEST_EMULATE_GAME = 2;
+
+	private final MainView mView;
+
+	public MainPresenter(MainView view)
+	{
+		mView = view;
+	}
+
+	public void onCreate()
+	{
+		// TODO Rather than calling into native code, this should use the commented line below.
+		// String versionName = BuildConfig.VERSION_NAME;
+		String versionName = NativeLibrary.GetVersionString();
+		mView.setVersionString(versionName);
+	}
+
+	public void onFabClick()
+	{
+		mView.launchFileListActivity();
+	}
+
+	public boolean handleOptionSelection(int itemId)
+	{
+		switch (itemId)
+		{
+			case R.id.menu_settings:
+				mView.launchSettingsActivity();
+				return true;
+
+			case R.id.menu_refresh:
+				mView.refresh();
+				return true;
+
+			case R.id.button_add_directory:
+				mView.launchFileListActivity();
+				return true;
+		}
+
+		return false;
+	}
+
+	public void handleActivityResult(int requestCode, int resultCode)
+	{
+		switch (requestCode)
+		{
+			case REQUEST_ADD_DIRECTORY:
+				// If the user picked a file, as opposed to just backing out.
+				if (resultCode == MainActivity.RESULT_OK)
+				{
+					mView.refresh();
+				}
+				break;
+
+			case REQUEST_EMULATE_GAME:
+				mView.refreshFragmentScreenshot(resultCode);
+				break;
+		}
+	}
+
+	public void loadGames(final int platformIndex)
+	{
+		GameDatabase databaseHelper = DolphinApplication.databaseHelper;
+
+		databaseHelper.getGamesForPlatform(platformIndex)
+				.subscribeOn(Schedulers.io())
+				.observeOn(AndroidSchedulers.mainThread())
+				.subscribe(new Action1<Cursor>()
+						   {
+							   @Override
+							   public void call(Cursor games)
+							   {
+								   mView.showGames(platformIndex, games);
+							   }
+						   }
+				);
+	}
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java
new file mode 100644
index 0000000000..1d286bebf3
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java
@@ -0,0 +1,47 @@
+package org.dolphinemu.dolphinemu.ui.main;
+
+
+import android.database.Cursor;
+
+/**
+ * Abstraction for the screen that shows on application launch.
+ * Implementations will differ primarily to target touch-screen
+ * or non-touch screen devices.
+ */
+public interface MainView
+{
+	/**
+	 * Pass the view the native library's version string. Displaying
+	 * it is optional.
+	 *
+	 * @param version A string pulled from native code.
+	 */
+	void setVersionString(String version);
+
+	/**
+	 * Tell the view to refresh its contents.
+	 */
+	void refresh();
+
+	/**
+	 * Tell the view to tell the currently displayed {@link android.support.v4.app.Fragment}
+	 * to refresh the screenshot at the given position in its list of games.
+	 *
+	 * @param fragmentPosition An index corresponding to the list or grid of games.
+	 */
+	void refreshFragmentScreenshot(int fragmentPosition);
+
+
+	void launchSettingsActivity();
+
+	void launchFileListActivity();
+
+	/**
+	 * To be called when an asynchronous database read completes. Passes the
+	 * result, in this case a {@link Cursor} to the view.
+	 *
+	 * @param platformIndex Which platform contains these games.
+	 * @param games A Cursor containing the games read from the database.
+	 */
+	void showGames(int platformIndex, Cursor games);
+}