android: frontend: auto-reformat all code for consistent style.

This commit is contained in:
bunnei 2019-07-18 22:39:02 -04:00
parent e2818bf7be
commit 8f89bd53ff
81 changed files with 6629 additions and 7752 deletions

View File

@ -6,13 +6,11 @@ import org.citra.citra_android.model.GameDatabase;
import org.citra.citra_android.services.DirectoryInitializationService; import org.citra.citra_android.services.DirectoryInitializationService;
import org.citra.citra_android.utils.PermissionsHandler; import org.citra.citra_android.utils.PermissionsHandler;
public class DolphinApplication extends Application public class DolphinApplication extends Application {
{
public static GameDatabase databaseHelper; public static GameDatabase databaseHelper;
@Override @Override
public void onCreate() public void onCreate() {
{
super.onCreate(); super.onCreate();
if (PermissionsHandler.hasWriteAccess(getApplicationContext())) if (PermissionsHandler.hasWriteAccess(getApplicationContext()))

View File

@ -18,60 +18,27 @@ import java.lang.ref.WeakReference;
* Class which contains methods that interact * Class which contains methods that interact
* with the native side of the Dolphin code. * with the native side of the Dolphin code.
*/ */
public final class NativeLibrary public final class NativeLibrary {
{
public static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
/**
* Button type for use in onTouchEvent
*/
public static final class ButtonType
{
public static final int BUTTON_A = 700;
public static final int BUTTON_B = 701;
public static final int BUTTON_X = 702;
public static final int BUTTON_Y = 703;
public static final int BUTTON_START = 704;
public static final int BUTTON_SELECT = 705;
public static final int BUTTON_HOME = 706;
public static final int BUTTON_ZL = 707;
public static final int BUTTON_ZR = 708;
public static final int DPAD_UP = 709;
public static final int DPAD_DOWN = 710;
public static final int DPAD_LEFT = 711;
public static final int DPAD_RIGHT = 712;
public static final int STICK_LEFT = 713;
public static final int STICK_LEFT_UP = 714;
public static final int STICK_LEFT_DOWN = 715;
public static final int STICK_LEFT_LEFT = 716;
public static final int STICK_LEFT_RIGHT = 717;
public static final int STICK_C = 718;
public static final int STICK_C_UP = 719;
public static final int STICK_C_DOWN = 720;
public static final int STICK_C_LEFT = 771;
public static final int STICK_C_RIGHT = 772;
public static final int TRIGGER_L = 773;
public static final int TRIGGER_R = 774;
}
/**
* Button states
*/
public static final class ButtonState
{
public static final int RELEASED = 0;
public static final int PRESSED = 1;
}
private NativeLibrary()
{
// Disallows instantiation.
}
/** /**
* Default touchscreen device * Default touchscreen device
*/ */
public static final String TouchScreenDevice = "Touchscreen"; public static final String TouchScreenDevice = "Touchscreen";
public static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
private static boolean alertResult = false;
static {
try {
System.loadLibrary("main");
} catch (UnsatisfiedLinkError ex) {
Log.error("[NativeLibrary] " + ex.toString());
}
CacheClassesAndMethods();
}
private NativeLibrary() {
// Disallows instantiation.
}
/** /**
* Handles button press events for a gamepad. * Handles button press events for a gamepad.
@ -318,34 +285,14 @@ public final class NativeLibrary
*/ */
public static native void SwapScreens(); public static native void SwapScreens();
static
{
try
{
System.loadLibrary("main");
}
catch (UnsatisfiedLinkError ex)
{
Log.error("[NativeLibrary] " + ex.toString());
}
CacheClassesAndMethods();
}
private static boolean alertResult = false;
public static boolean displayAlertMsg(final String caption, final String text, public static boolean displayAlertMsg(final String caption, final String text,
final boolean yesNo) final boolean yesNo) {
{
Log.error("[NativeLibrary] Alert: " + text); Log.error("[NativeLibrary] Alert: " + text);
final EmulationActivity emulationActivity = sEmulationActivity.get(); final EmulationActivity emulationActivity = sEmulationActivity.get();
boolean result = false; boolean result = false;
if (emulationActivity == null) if (emulationActivity == null) {
{
Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic alert."); Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic alert.");
} } else {
else
{
// Create object used for waiting. // Create object used for waiting.
final Object lock = new Object(); final Object lock = new Object();
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity) AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity)
@ -354,21 +301,17 @@ public final class NativeLibrary
// If not yes/no dialog just have one button that dismisses modal, // If not yes/no dialog just have one button that dismisses modal,
// otherwise have a yes and no button that sets alertResult accordingly. // otherwise have a yes and no button that sets alertResult accordingly.
if (!yesNo) if (!yesNo) {
{
builder builder
.setCancelable(false) .setCancelable(false)
.setPositiveButton("OK", (dialog, whichButton) -> .setPositiveButton("OK", (dialog, whichButton) ->
{ {
dialog.dismiss(); dialog.dismiss();
synchronized (lock) synchronized (lock) {
{
lock.notify(); lock.notify();
} }
}); });
} } else {
else
{
alertResult = false; alertResult = false;
builder builder
@ -376,8 +319,7 @@ public final class NativeLibrary
{ {
alertResult = true; alertResult = true;
dialog.dismiss(); dialog.dismiss();
synchronized (lock) synchronized (lock) {
{
lock.notify(); lock.notify();
} }
}) })
@ -385,8 +327,7 @@ public final class NativeLibrary
{ {
alertResult = false; alertResult = false;
dialog.dismiss(); dialog.dismiss();
synchronized (lock) synchronized (lock) {
{
lock.notify(); lock.notify();
} }
}); });
@ -396,14 +337,10 @@ public final class NativeLibrary
emulationActivity.runOnUiThread(() -> builder.show()); emulationActivity.runOnUiThread(() -> builder.show());
// Wait for the lock to notify that it is complete. // Wait for the lock to notify that it is complete.
synchronized (lock) synchronized (lock) {
{ try {
try
{
lock.wait(); lock.wait();
} } catch (Exception e) {
catch (Exception e)
{
} }
} }
@ -413,16 +350,53 @@ public final class NativeLibrary
return result; return result;
} }
public static void setEmulationActivity(EmulationActivity emulationActivity) public static void setEmulationActivity(EmulationActivity emulationActivity) {
{
Log.verbose("[NativeLibrary] Registering EmulationActivity."); Log.verbose("[NativeLibrary] Registering EmulationActivity.");
sEmulationActivity = new WeakReference<>(emulationActivity); sEmulationActivity = new WeakReference<>(emulationActivity);
} }
public static void clearEmulationActivity() public static void clearEmulationActivity() {
{
Log.verbose("[NativeLibrary] Unregistering EmulationActivity."); Log.verbose("[NativeLibrary] Unregistering EmulationActivity.");
sEmulationActivity.clear(); sEmulationActivity.clear();
} }
/**
* Button type for use in onTouchEvent
*/
public static final class ButtonType {
public static final int BUTTON_A = 700;
public static final int BUTTON_B = 701;
public static final int BUTTON_X = 702;
public static final int BUTTON_Y = 703;
public static final int BUTTON_START = 704;
public static final int BUTTON_SELECT = 705;
public static final int BUTTON_HOME = 706;
public static final int BUTTON_ZL = 707;
public static final int BUTTON_ZR = 708;
public static final int DPAD_UP = 709;
public static final int DPAD_DOWN = 710;
public static final int DPAD_LEFT = 711;
public static final int DPAD_RIGHT = 712;
public static final int STICK_LEFT = 713;
public static final int STICK_LEFT_UP = 714;
public static final int STICK_LEFT_DOWN = 715;
public static final int STICK_LEFT_LEFT = 716;
public static final int STICK_LEFT_RIGHT = 717;
public static final int STICK_C = 718;
public static final int STICK_C_UP = 719;
public static final int STICK_C_DOWN = 720;
public static final int STICK_C_LEFT = 771;
public static final int STICK_C_RIGHT = 772;
public static final int TRIGGER_L = 773;
public static final int TRIGGER_R = 774;
}
/**
* Button states
*/
public static final class ButtonState {
public static final int RELEASED = 0;
public static final int PRESSED = 1;
}
} }

View File

@ -10,15 +10,12 @@ import org.citra.citra_android.fragments.CustomFilePickerFragment;
import java.io.File; import java.io.File;
public class CustomFilePickerActivity extends FilePickerActivity public class CustomFilePickerActivity extends FilePickerActivity {
{
@Override @Override
protected AbstractFilePickerFragment<File> getFragment( protected AbstractFilePickerFragment<File> getFragment(
@Nullable final String startPath, final int mode, final boolean allowMultiple, @Nullable final String startPath, final int mode, final boolean allowMultiple,
final boolean allowCreateDir, final boolean allowExistingFile, final boolean allowCreateDir, final boolean allowExistingFile,
final boolean singleClick) final boolean singleClick) {
{
AbstractFilePickerFragment<File> fragment = new CustomFilePickerFragment(); AbstractFilePickerFragment<File> fragment = new CustomFilePickerFragment();
// startPath is allowed to be null. In that case, default folder should be SD-card and not "/" // startPath is allowed to be null. In that case, default folder should be SD-card and not "/"
fragment.setArgs( fragment.setArgs(

View File

@ -12,7 +12,6 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -46,44 +45,12 @@ import static android.view.MotionEvent.AXIS_Y;
import static android.view.MotionEvent.AXIS_Z; import static android.view.MotionEvent.AXIS_Z;
import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.lang.annotation.RetentionPolicy.SOURCE;
public final class EmulationActivity extends AppCompatActivity public final class EmulationActivity extends AppCompatActivity {
{
private static final String BACKSTACK_NAME_MENU = "menu";
private static final String BACKSTACK_NAME_SUBMENU = "submenu";
public static final int REQUEST_CHANGE_DISC = 1; public static final int REQUEST_CHANGE_DISC = 1;
private View mDecorView;
private ImageView mImageView;
private EmulationFragment mEmulationFragment;
private SharedPreferences mPreferences;
private ControllerMappingHelper mControllerMappingHelper;
// So that MainActivity knows which view to invalidate before the return animation.
private int mPosition;
private boolean mDeviceHasTouchScreen;
private boolean mMenuVisible;
private boolean mBackPressedOnce;
private boolean activityRecreated;
private String mScreenPath;
private String mSelectedTitle;
private String mPath;
public static final String EXTRA_SELECTED_GAME = "SelectedGame"; public static final String EXTRA_SELECTED_GAME = "SelectedGame";
public static final String EXTRA_SELECTED_TITLE = "SelectedTitle"; public static final String EXTRA_SELECTED_TITLE = "SelectedTitle";
public static final String EXTRA_SCREEN_PATH = "ScreenPath"; public static final String EXTRA_SCREEN_PATH = "ScreenPath";
public static final String EXTRA_GRID_POSITION = "GridPosition"; public static final String EXTRA_GRID_POSITION = "GridPosition";
@Retention(SOURCE)
@IntDef({MENU_ACTION_EDIT_CONTROLS_PLACEMENT, MENU_ACTION_TOGGLE_CONTROLS, MENU_ACTION_ADJUST_SCALE,
MENU_ACTION_EXIT, MENU_ACTION_TOGGLE_PREF_STATS, MENU_ACTION_SWITCH_SCREEN_LAYOUT,
MENU_ACTION_SWAP_SCREENS, MENU_ACTION_RESET_OVERLAY})
public @interface MenuAction
{
}
public static final int MENU_ACTION_EDIT_CONTROLS_PLACEMENT = 0; public static final int MENU_ACTION_EDIT_CONTROLS_PLACEMENT = 0;
public static final int MENU_ACTION_TOGGLE_CONTROLS = 1; public static final int MENU_ACTION_TOGGLE_CONTROLS = 1;
public static final int MENU_ACTION_ADJUST_SCALE = 2; public static final int MENU_ACTION_ADJUST_SCALE = 2;
@ -92,11 +59,11 @@ public final class EmulationActivity extends AppCompatActivity
public static final int MENU_ACTION_SWITCH_SCREEN_LAYOUT = 5; public static final int MENU_ACTION_SWITCH_SCREEN_LAYOUT = 5;
public static final int MENU_ACTION_SWAP_SCREENS = 6; public static final int MENU_ACTION_SWAP_SCREENS = 6;
public static final int MENU_ACTION_RESET_OVERLAY = 7; public static final int MENU_ACTION_RESET_OVERLAY = 7;
private static final String BACKSTACK_NAME_MENU = "menu";
private static final String BACKSTACK_NAME_SUBMENU = "submenu";
private static SparseIntArray buttonsActionsMap = new SparseIntArray(); private static SparseIntArray buttonsActionsMap = new SparseIntArray();
static static {
{
buttonsActionsMap.append(R.id.menu_emulation_edit_layout, buttonsActionsMap.append(R.id.menu_emulation_edit_layout,
EmulationActivity.MENU_ACTION_EDIT_CONTROLS_PLACEMENT); EmulationActivity.MENU_ACTION_EDIT_CONTROLS_PLACEMENT);
buttonsActionsMap.append(R.id.menu_emulation_toggle_controls, buttonsActionsMap.append(R.id.menu_emulation_toggle_controls,
@ -114,9 +81,30 @@ public final class EmulationActivity extends AppCompatActivity
.append(R.id.menu_emulation_reset_overlay, EmulationActivity.MENU_ACTION_RESET_OVERLAY); .append(R.id.menu_emulation_reset_overlay, EmulationActivity.MENU_ACTION_RESET_OVERLAY);
} }
private View mDecorView;
private ImageView mImageView;
private EmulationFragment mEmulationFragment;
private SharedPreferences mPreferences;
private ControllerMappingHelper mControllerMappingHelper;
// So that MainActivity knows which view to invalidate before the return animation.
private int mPosition;
private boolean mDeviceHasTouchScreen;
private boolean mMenuVisible;
private boolean mBackPressedOnce;
private boolean activityRecreated;
private String mScreenPath;
private String mSelectedTitle;
private String mPath;
private Runnable afterShowingScreenshot = new Runnable() {
@Override
public void run() {
setResult(mPosition);
supportFinishAfterTransition();
}
};
public static void launch(FragmentActivity activity, String path, String title, public static void launch(FragmentActivity activity, String path, String title,
String screenshotPath, int position, View sharedView) String screenshotPath, int position, View sharedView) {
{
Intent launcher = new Intent(activity, EmulationActivity.class); Intent launcher = new Intent(activity, EmulationActivity.class);
launcher.putExtra(EXTRA_SELECTED_GAME, path); launcher.putExtra(EXTRA_SELECTED_GAME, path);
@ -136,12 +124,10 @@ public final class EmulationActivity extends AppCompatActivity
} }
@Override @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState) {
{
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (savedInstanceState == null) if (savedInstanceState == null) {
{
// Get params we were passed // Get params we were passed
Intent gameToEmulate = getIntent(); Intent gameToEmulate = getIntent();
mPath = gameToEmulate.getStringExtra(EXTRA_SELECTED_GAME); mPath = gameToEmulate.getStringExtra(EXTRA_SELECTED_GAME);
@ -149,9 +135,7 @@ public final class EmulationActivity extends AppCompatActivity
mScreenPath = gameToEmulate.getStringExtra(EXTRA_SCREEN_PATH); mScreenPath = gameToEmulate.getStringExtra(EXTRA_SCREEN_PATH);
mPosition = gameToEmulate.getIntExtra(EXTRA_GRID_POSITION, -1); mPosition = gameToEmulate.getIntExtra(EXTRA_GRID_POSITION, -1);
activityRecreated = false; activityRecreated = false;
} } else {
else
{
activityRecreated = true; activityRecreated = true;
restoreState(savedInstanceState); restoreState(savedInstanceState);
} }
@ -160,16 +144,14 @@ public final class EmulationActivity extends AppCompatActivity
mControllerMappingHelper = new ControllerMappingHelper(); mControllerMappingHelper = new ControllerMappingHelper();
int themeId; int themeId;
if (mDeviceHasTouchScreen) if (mDeviceHasTouchScreen) {
{
themeId = R.style.CitraEmulation; themeId = R.style.CitraEmulation;
// Get a handle to the Window containing the UI. // Get a handle to the Window containing the UI.
mDecorView = getWindow().getDecorView(); mDecorView = getWindow().getDecorView();
mDecorView.setOnSystemUiVisibilityChangeListener(visibility -> mDecorView.setOnSystemUiVisibilityChangeListener(visibility ->
{ {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
{
// Go back to immersive fullscreen mode in 3s // Go back to immersive fullscreen mode in 3s
Handler handler = new Handler(getMainLooper()); Handler handler = new Handler(getMainLooper());
handler.postDelayed(this::enableFullscreenImmersive, 3000 /* 3s */); handler.postDelayed(this::enableFullscreenImmersive, 3000 /* 3s */);
@ -177,9 +159,7 @@ public final class EmulationActivity extends AppCompatActivity
}); });
// Set these options now so that the SurfaceView the game renders into is the right size. // Set these options now so that the SurfaceView the game renders into is the right size.
enableFullscreenImmersive(); enableFullscreenImmersive();
} } else {
else
{
themeId = R.style.CitraEmulationTv; themeId = R.style.CitraEmulationTv;
} }
@ -192,16 +172,14 @@ public final class EmulationActivity extends AppCompatActivity
// Find or create the EmulationFragment // Find or create the EmulationFragment
mEmulationFragment = (EmulationFragment) getSupportFragmentManager() mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
.findFragmentById(R.id.frame_emulation_fragment); .findFragmentById(R.id.frame_emulation_fragment);
if (mEmulationFragment == null) if (mEmulationFragment == null) {
{
mEmulationFragment = EmulationFragment.newInstance(mPath); mEmulationFragment = EmulationFragment.newInstance(mPath);
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.add(R.id.frame_emulation_fragment, mEmulationFragment) .add(R.id.frame_emulation_fragment, mEmulationFragment)
.commit(); .commit();
} }
if (savedInstanceState == null) if (savedInstanceState == null) {
{
// Picasso will take a while to load these big-ass screenshots. So don't run // Picasso will take a while to load these big-ass screenshots. So don't run
// the animation until we say so. // the animation until we say so.
postponeEnterTransition(); postponeEnterTransition();
@ -210,17 +188,14 @@ public final class EmulationActivity extends AppCompatActivity
.load(mScreenPath) .load(mScreenPath)
.noFade() .noFade()
.noPlaceholder() .noPlaceholder()
.into(mImageView, new Callback() .into(mImageView, new Callback() {
{
@Override @Override
public void onSuccess() public void onSuccess() {
{
supportStartPostponedEnterTransition(); supportStartPostponedEnterTransition();
} }
@Override @Override
public void onError() public void onError() {
{
// Still have to do this, or else the app will crash. // Still have to do this, or else the app will crash.
supportStartPostponedEnterTransition(); supportStartPostponedEnterTransition();
} }
@ -229,14 +204,11 @@ public final class EmulationActivity extends AppCompatActivity
Animations.fadeViewOut(mImageView) Animations.fadeViewOut(mImageView)
.setStartDelay(2000) .setStartDelay(2000)
.withEndAction(() -> mImageView.setVisibility(View.GONE)); .withEndAction(() -> mImageView.setVisibility(View.GONE));
} } else {
else
{
mImageView.setVisibility(View.GONE); mImageView.setVisibility(View.GONE);
} }
if (mDeviceHasTouchScreen) if (mDeviceHasTouchScreen) {
{
setTitle(mSelectedTitle); setTitle(mSelectedTitle);
} }
@ -245,8 +217,7 @@ public final class EmulationActivity extends AppCompatActivity
} }
@Override @Override
protected void onSaveInstanceState(Bundle outState) protected void onSaveInstanceState(Bundle outState) {
{
outState.putString(EXTRA_SELECTED_GAME, mPath); outState.putString(EXTRA_SELECTED_GAME, mPath);
outState.putString(EXTRA_SELECTED_TITLE, mSelectedTitle); outState.putString(EXTRA_SELECTED_TITLE, mSelectedTitle);
outState.putString(EXTRA_SCREEN_PATH, mScreenPath); outState.putString(EXTRA_SCREEN_PATH, mScreenPath);
@ -254,8 +225,7 @@ public final class EmulationActivity extends AppCompatActivity
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
} }
protected void restoreState(Bundle savedInstanceState) protected void restoreState(Bundle savedInstanceState) {
{
mPath = savedInstanceState.getString(EXTRA_SELECTED_GAME); mPath = savedInstanceState.getString(EXTRA_SELECTED_GAME);
mSelectedTitle = savedInstanceState.getString(EXTRA_SELECTED_TITLE); mSelectedTitle = savedInstanceState.getString(EXTRA_SELECTED_TITLE);
mScreenPath = savedInstanceState.getString(EXTRA_SCREEN_PATH); mScreenPath = savedInstanceState.getString(EXTRA_SCREEN_PATH);
@ -263,34 +233,26 @@ public final class EmulationActivity extends AppCompatActivity
} }
@Override @Override
public void onBackPressed() public void onBackPressed() {
{ if (!mDeviceHasTouchScreen) {
if (!mDeviceHasTouchScreen)
{
boolean popResult = getSupportFragmentManager().popBackStackImmediate( boolean popResult = getSupportFragmentManager().popBackStackImmediate(
BACKSTACK_NAME_SUBMENU, FragmentManager.POP_BACK_STACK_INCLUSIVE); BACKSTACK_NAME_SUBMENU, FragmentManager.POP_BACK_STACK_INCLUSIVE);
if (!popResult) if (!popResult) {
{
toggleMenu(); toggleMenu();
} }
} } else {
else
{
if (mBackPressedOnce) { if (mBackPressedOnce) {
mEmulationFragment.stopEmulation(); mEmulationFragment.stopEmulation();
exitWithAnimation(); exitWithAnimation();
} } else {
else
{
mBackPressedOnce = true; mBackPressedOnce = true;
Toast.makeText(this, "Press back again to exit", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "Press back again to exit", Toast.LENGTH_SHORT).show();
} }
Handler mHandler = new Handler(); Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() mHandler.postDelayed(new Runnable() {
{ @Override
@Override public void run() public void run() {
{
mBackPressedOnce = false; mBackPressedOnce = false;
mHandler.removeCallbacks(this); mHandler.removeCallbacks(this);
} }
@ -299,12 +261,10 @@ public final class EmulationActivity extends AppCompatActivity
} }
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) protected void onActivityResult(int requestCode, int resultCode, Intent result) {
{
} }
private void enableFullscreenImmersive() private void enableFullscreenImmersive() {
{
// It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar. // It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar.
mDecorView.setSystemUiVisibility( mDecorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
@ -315,14 +275,12 @@ public final class EmulationActivity extends AppCompatActivity
View.SYSTEM_UI_FLAG_IMMERSIVE); View.SYSTEM_UI_FLAG_IMMERSIVE);
} }
private void toggleMenu() private void toggleMenu() {
{
boolean result = getSupportFragmentManager().popBackStackImmediate( boolean result = getSupportFragmentManager().popBackStackImmediate(
BACKSTACK_NAME_MENU, FragmentManager.POP_BACK_STACK_INCLUSIVE); BACKSTACK_NAME_MENU, FragmentManager.POP_BACK_STACK_INCLUSIVE);
mMenuVisible = false; mMenuVisible = false;
if (!result) if (!result) {
{
// Removing the menu failed, so that means it wasn't visible. Add it. // Removing the menu failed, so that means it wasn't visible. Add it.
Fragment fragment = MenuFragment.newInstance(mSelectedTitle); Fragment fragment = MenuFragment.newInstance(mSelectedTitle);
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
@ -338,8 +296,7 @@ public final class EmulationActivity extends AppCompatActivity
} }
} }
public void exitWithAnimation() public void exitWithAnimation() {
{
runOnUiThread(() -> runOnUiThread(() ->
{ {
Picasso.with(EmulationActivity.this) Picasso.with(EmulationActivity.this)
@ -349,42 +306,27 @@ public final class EmulationActivity extends AppCompatActivity
.load(mScreenPath) .load(mScreenPath)
.noFade() .noFade()
.noPlaceholder() .noPlaceholder()
.into(mImageView, new Callback() .into(mImageView, new Callback() {
{
@Override @Override
public void onSuccess() public void onSuccess() {
{
showScreenshot(); showScreenshot();
} }
@Override @Override
public void onError() public void onError() {
{
finish(); finish();
} }
}); });
}); });
} }
private void showScreenshot() private void showScreenshot() {
{
Animations.fadeViewIn(mImageView) Animations.fadeViewIn(mImageView)
.withEndAction(afterShowingScreenshot); .withEndAction(afterShowingScreenshot);
} }
private Runnable afterShowingScreenshot = new Runnable()
{
@Override @Override
public void run() public boolean onCreateOptionsMenu(Menu menu) {
{
setResult(mPosition);
supportFinishAfterTransition();
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present. // Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_emulation, menu); getMenuInflater().inflate(R.menu.menu_emulation, menu);
return true; return true;
@ -392,20 +334,16 @@ public final class EmulationActivity extends AppCompatActivity
@SuppressWarnings("WrongConstant") @SuppressWarnings("WrongConstant")
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) public boolean onOptionsItemSelected(MenuItem item) {
{
int action = buttonsActionsMap.get(item.getItemId(), -1); int action = buttonsActionsMap.get(item.getItemId(), -1);
if (action >= 0) if (action >= 0) {
{
handleMenuAction(action); handleMenuAction(action);
} }
return true; return true;
} }
public void handleMenuAction(@MenuAction int menuAction) public void handleMenuAction(@MenuAction int menuAction) {
{ switch (menuAction) {
switch (menuAction)
{
// Edit the placement of the controls // Edit the placement of the controls
case MENU_ACTION_EDIT_CONTROLS_PLACEMENT: case MENU_ACTION_EDIT_CONTROLS_PLACEMENT:
editControlsPlacement(); editControlsPlacement();
@ -449,36 +387,27 @@ public final class EmulationActivity extends AppCompatActivity
} }
} }
private void editControlsPlacement() {
private void editControlsPlacement() if (mEmulationFragment.isConfiguringControls()) {
{
if (mEmulationFragment.isConfiguringControls())
{
mEmulationFragment.stopConfiguringControls(); mEmulationFragment.stopConfiguringControls();
} } else {
else
{
mEmulationFragment.startConfiguringControls(); mEmulationFragment.startConfiguringControls();
} }
} }
// Gets button presses // Gets button presses
@Override @Override
public boolean dispatchKeyEvent(KeyEvent event) public boolean dispatchKeyEvent(KeyEvent event) {
{ if (mMenuVisible) {
if (mMenuVisible)
{
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
} }
int action; int action;
switch (event.getAction()) switch (event.getAction()) {
{
case KeyEvent.ACTION_DOWN: case KeyEvent.ACTION_DOWN:
// Handling the case where the back button is pressed. // Handling the case where the back button is pressed.
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
{
onBackPressed(); onBackPressed();
return true; return true;
} }
@ -496,15 +425,13 @@ public final class EmulationActivity extends AppCompatActivity
return NativeLibrary.onGamePadEvent(input.getDescriptor(), event.getKeyCode(), action); return NativeLibrary.onGamePadEvent(input.getDescriptor(), event.getKeyCode(), action);
} }
private void toggleControls() private void toggleControls() {
{
final SharedPreferences.Editor editor = mPreferences.edit(); final SharedPreferences.Editor editor = mPreferences.edit();
boolean[] enabledButtons = new boolean[14]; boolean[] enabledButtons = new boolean[14];
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.emulation_toggle_controls); builder.setTitle(R.string.emulation_toggle_controls);
for (int i = 0; i < enabledButtons.length; i++) for (int i = 0; i < enabledButtons.length; i++) {
{
enabledButtons[i] = mPreferences.getBoolean("buttonToggle" + i, true); enabledButtons[i] = mPreferences.getBoolean("buttonToggle" + i, true);
} }
builder.setMultiChoiceItems(R.array.n3dsButtons, enabledButtons, builder.setMultiChoiceItems(R.array.n3dsButtons, enabledButtons,
@ -525,8 +452,7 @@ public final class EmulationActivity extends AppCompatActivity
alertDialog.show(); alertDialog.show();
} }
private void adjustScale() private void adjustScale() {
{
LayoutInflater inflater = LayoutInflater.from(this); LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.dialog_seekbar, null); View view = inflater.inflate(R.layout.dialog_seekbar, null);
@ -536,20 +462,16 @@ public final class EmulationActivity extends AppCompatActivity
seekbar.setMax(150); seekbar.setMax(150);
seekbar.setProgress(mPreferences.getInt("controlScale", 50)); seekbar.setProgress(mPreferences.getInt("controlScale", 50));
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
{ public void onStartTrackingTouch(SeekBar seekBar) {
public void onStartTrackingTouch(SeekBar seekBar)
{
// Do nothing // Do nothing
} }
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
{
value.setText(String.valueOf(progress + 50)); value.setText(String.valueOf(progress + 50));
} }
public void onStopTrackingTouch(SeekBar seekBar) public void onStopTrackingTouch(SeekBar seekBar) {
{
// Do nothing // Do nothing
} }
}); });
@ -573,8 +495,7 @@ public final class EmulationActivity extends AppCompatActivity
alertDialog.show(); alertDialog.show();
} }
private void resetOverlay() private void resetOverlay() {
{
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setTitle(getString(R.string.emulation_touch_overlay_reset)) .setTitle(getString(R.string.emulation_touch_overlay_reset))
.setPositiveButton(R.string.yes, (dialogInterface, i) -> .setPositiveButton(R.string.yes, (dialogInterface, i) ->
@ -589,15 +510,12 @@ public final class EmulationActivity extends AppCompatActivity
} }
@Override @Override
public boolean dispatchGenericMotionEvent(MotionEvent event) public boolean dispatchGenericMotionEvent(MotionEvent event) {
{ if (mMenuVisible) {
if (mMenuVisible)
{
return false; return false;
} }
if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)) if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)) {
{
return super.dispatchGenericMotionEvent(event); return super.dispatchGenericMotionEvent(event);
} }
@ -609,30 +527,23 @@ public final class EmulationActivity extends AppCompatActivity
List<InputDevice.MotionRange> motions = input.getMotionRanges(); List<InputDevice.MotionRange> motions = input.getMotionRanges();
float[] axisValues = {0.0f, 0.0f}; float[] axisValues = {0.0f, 0.0f};
for (InputDevice.MotionRange range : motions) for (InputDevice.MotionRange range : motions) {
{
boolean consumed = false; boolean consumed = false;
int axis = range.getAxis(); int axis = range.getAxis();
float origValue = event.getAxisValue(axis); float origValue = event.getAxisValue(axis);
float value = mControllerMappingHelper.scaleAxis(input, axis, origValue); float value = mControllerMappingHelper.scaleAxis(input, axis, origValue);
if (axis == AXIS_X || axis == AXIS_Z) if (axis == AXIS_X || axis == AXIS_Z) {
{
axisValues[0] = value; axisValues[0] = value;
} } else if (axis == AXIS_Y || axis == AXIS_RZ) {
else if (axis == AXIS_Y || axis == AXIS_RZ)
{
axisValues[1] = value; axisValues[1] = value;
} }
// If the input is still in the "flat" area, that means it's really zero. // If the input is still in the "flat" area, that means it's really zero.
// This is used to compensate for imprecision in joysticks. // This is used to compensate for imprecision in joysticks.
if (Math.abs(axisValues[0]) > range.getFlat() || Math.abs(axisValues[1]) > range.getFlat()) if (Math.abs(axisValues[0]) > range.getFlat() || Math.abs(axisValues[1]) > range.getFlat()) {
{
consumed = NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), axis, axisValues[0], axisValues[1]); consumed = NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), axis, axisValues[0], axisValues[1]);
} } else {
else
{
consumed = NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), axis, 0.0f, 0.0f); consumed = NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), axis, 0.0f, 0.0f);
} }
@ -642,8 +553,14 @@ public final class EmulationActivity extends AppCompatActivity
return false; return false;
} }
public boolean isActivityRecreated() public boolean isActivityRecreated() {
{
return activityRecreated; return activityRecreated;
} }
@Retention(SOURCE)
@IntDef({MENU_ACTION_EDIT_CONTROLS_PLACEMENT, MENU_ACTION_TOGGLE_CONTROLS, MENU_ACTION_ADJUST_SCALE,
MENU_ACTION_EXIT, MENU_ACTION_TOGGLE_PREF_STATS, MENU_ACTION_SWITCH_SCREEN_LAYOUT,
MENU_ACTION_SWAP_SCREENS, MENU_ACTION_RESET_OVERLAY})
public @interface MenuAction {
}
} }

View File

@ -22,8 +22,7 @@ import org.citra.citra_android.viewholders.GameViewHolder;
* large dataset. * large dataset.
*/ */
public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> implements public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> implements
View.OnClickListener View.OnClickListener {
{
private Cursor mCursor; private Cursor mCursor;
private GameDataSetObserver mObserver; private GameDataSetObserver mObserver;
@ -33,8 +32,7 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
* Initializes the adapter's observer, which watches for changes to the dataset. The adapter will * Initializes the adapter's observer, which watches for changes to the dataset. The adapter will
* display no data until a Cursor is supplied by a CursorLoader. * display no data until a Cursor is supplied by a CursorLoader.
*/ */
public GameAdapter() public GameAdapter() {
{
mDatasetValid = false; mDatasetValid = false;
mObserver = new GameDataSetObserver(); mObserver = new GameDataSetObserver();
} }
@ -47,8 +45,7 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
* @return The created ViewHolder with references to all the child view's members. * @return The created ViewHolder with references to all the child view's members.
*/ */
@Override @Override
public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType) public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
{
// Create a new view. // Create a new view.
View gameCard = LayoutInflater.from(parent.getContext()) View gameCard = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_game, parent, false); .inflate(R.layout.card_game, parent, false);
@ -68,12 +65,9 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
* @param position The position of the 'new' view in the dataset. * @param position The position of the 'new' view in the dataset.
*/ */
@Override @Override
public void onBindViewHolder(GameViewHolder holder, int position) public void onBindViewHolder(GameViewHolder holder, int position) {
{ if (mDatasetValid) {
if (mDatasetValid) if (mCursor.moveToPosition(position)) {
{
if (mCursor.moveToPosition(position))
{
String screenPath = mCursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH); String screenPath = mCursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH);
PicassoUtils.loadGameBanner(holder.imageScreenshot, screenPath, PicassoUtils.loadGameBanner(holder.imageScreenshot, screenPath,
mCursor.getString(GameDatabase.GAME_COLUMN_PATH)); mCursor.getString(GameDatabase.GAME_COLUMN_PATH));
@ -89,14 +83,10 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
holder.country = mCursor.getInt(GameDatabase.GAME_COLUMN_COUNTRY); holder.country = mCursor.getInt(GameDatabase.GAME_COLUMN_COUNTRY);
holder.company = mCursor.getString(GameDatabase.GAME_COLUMN_COMPANY); holder.company = mCursor.getString(GameDatabase.GAME_COLUMN_COMPANY);
holder.screenshotPath = mCursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH); holder.screenshotPath = mCursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH);
} } else {
else
{
Log.error("[GameAdapter] Can't bind view; Cursor is not valid."); Log.error("[GameAdapter] Can't bind view; Cursor is not valid.");
} }
} } else {
else
{
Log.error("[GameAdapter] Can't bind view; dataset is not valid."); Log.error("[GameAdapter] Can't bind view; dataset is not valid.");
} }
} }
@ -107,10 +97,8 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
* @return Size of the dataset. * @return Size of the dataset.
*/ */
@Override @Override
public int getItemCount() public int getItemCount() {
{ if (mDatasetValid && mCursor != null) {
if (mDatasetValid && mCursor != null)
{
return mCursor.getCount(); return mCursor.getCount();
} }
Log.error("[GameAdapter] Dataset is not valid."); Log.error("[GameAdapter] Dataset is not valid.");
@ -124,12 +112,9 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
* @return A valid ID from the database, or 0 if not available. * @return A valid ID from the database, or 0 if not available.
*/ */
@Override @Override
public long getItemId(int position) public long getItemId(int position) {
{ if (mDatasetValid && mCursor != null) {
if (mDatasetValid && mCursor != null) if (mCursor.moveToPosition(position)) {
{
if (mCursor.moveToPosition(position))
{
return mCursor.getLong(GameDatabase.COLUMN_DB_ID); return mCursor.getLong(GameDatabase.COLUMN_DB_ID);
} }
} }
@ -145,8 +130,7 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
* @param hasStableIds ignored. * @param hasStableIds ignored.
*/ */
@Override @Override
public void setHasStableIds(boolean hasStableIds) public void setHasStableIds(boolean hasStableIds) {
{
super.setHasStableIds(true); super.setHasStableIds(true);
} }
@ -156,34 +140,27 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
* *
* @param cursor The newly-loaded Cursor. * @param cursor The newly-loaded Cursor.
*/ */
public void swapCursor(Cursor cursor) public void swapCursor(Cursor cursor) {
{
// Sanity check. // Sanity check.
if (cursor == mCursor) if (cursor == mCursor) {
{
return; return;
} }
// Before getting rid of the old cursor, disassociate it from the Observer. // Before getting rid of the old cursor, disassociate it from the Observer.
final Cursor oldCursor = mCursor; final Cursor oldCursor = mCursor;
if (oldCursor != null && mObserver != null) if (oldCursor != null && mObserver != null) {
{
oldCursor.unregisterDataSetObserver(mObserver); oldCursor.unregisterDataSetObserver(mObserver);
} }
mCursor = cursor; mCursor = cursor;
if (mCursor != null) if (mCursor != null) {
{
// Attempt to associate the new Cursor with the Observer. // Attempt to associate the new Cursor with the Observer.
if (mObserver != null) if (mObserver != null) {
{
mCursor.registerDataSetObserver(mObserver); mCursor.registerDataSetObserver(mObserver);
} }
mDatasetValid = true; mDatasetValid = true;
} } else {
else
{
mDatasetValid = false; mDatasetValid = false;
} }
@ -196,8 +173,7 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
* @param view The card representing the game the user wants to play. * @param view The card representing the game the user wants to play.
*/ */
@Override @Override
public void onClick(View view) public void onClick(View view) {
{
GameViewHolder holder = (GameViewHolder) view.getTag(); GameViewHolder holder = (GameViewHolder) view.getTag();
EmulationActivity.launch((FragmentActivity) view.getContext(), EmulationActivity.launch((FragmentActivity) view.getContext(),
@ -208,19 +184,16 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
holder.imageScreenshot); holder.imageScreenshot);
} }
public static class SpacesItemDecoration extends RecyclerView.ItemDecoration public static class SpacesItemDecoration extends RecyclerView.ItemDecoration {
{
private int space; private int space;
public SpacesItemDecoration(int space) public SpacesItemDecoration(int space) {
{
this.space = space; this.space = space;
} }
@Override @Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) RecyclerView.State state) {
{
outRect.left = space; outRect.left = space;
outRect.right = space; outRect.right = space;
outRect.bottom = space; outRect.bottom = space;
@ -228,11 +201,9 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
} }
} }
private final class GameDataSetObserver extends DataSetObserver private final class GameDataSetObserver extends DataSetObserver {
{
@Override @Override
public void onChanged() public void onChanged() {
{
super.onChanged(); super.onChanged();
mDatasetValid = true; mDatasetValid = true;
@ -240,8 +211,7 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
} }
@Override @Override
public void onInvalidated() public void onInvalidated() {
{
super.onInvalidated(); super.onInvalidated();
mDatasetValid = false; mDatasetValid = false;

View File

@ -17,11 +17,9 @@ import org.citra.citra_android.viewholders.TvGameViewHolder;
* The Leanback library / docs call this a Presenter, but it works very * The Leanback library / docs call this a Presenter, but it works very
* similarly to a RecyclerView.Adapter. * similarly to a RecyclerView.Adapter.
*/ */
public final class GameRowPresenter extends Presenter public final class GameRowPresenter extends Presenter {
{
@Override @Override
public ViewHolder onCreateViewHolder(ViewGroup parent) public ViewHolder onCreateViewHolder(ViewGroup parent) {
{
// Create a new view. // Create a new view.
ImageCardView gameCard = new ImageCardView(parent.getContext()); ImageCardView gameCard = new ImageCardView(parent.getContext());
@ -37,8 +35,7 @@ public final class GameRowPresenter extends Presenter
} }
@Override @Override
public void onBindViewHolder(ViewHolder viewHolder, Object item) public void onBindViewHolder(ViewHolder viewHolder, Object item) {
{
TvGameViewHolder holder = (TvGameViewHolder) viewHolder; TvGameViewHolder holder = (TvGameViewHolder) viewHolder;
Game game = (Game) item; Game game = (Game) item;
@ -66,8 +63,7 @@ public final class GameRowPresenter extends Presenter
} }
@Override @Override
public void onUnbindViewHolder(ViewHolder viewHolder) public void onUnbindViewHolder(ViewHolder viewHolder) {
{
// no op // no op
} }
} }

View File

@ -8,10 +8,8 @@ import android.view.ViewGroup;
import org.citra.citra_android.model.TvSettingsItem; import org.citra.citra_android.model.TvSettingsItem;
import org.citra.citra_android.viewholders.TvSettingsViewHolder; import org.citra.citra_android.viewholders.TvSettingsViewHolder;
public final class SettingsRowPresenter extends Presenter public final class SettingsRowPresenter extends Presenter {
{ public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent)
{
// Create a new view. // Create a new view.
ImageCardView settingsCard = new ImageCardView(parent.getContext()); ImageCardView settingsCard = new ImageCardView(parent.getContext());
@ -26,8 +24,7 @@ public final class SettingsRowPresenter extends Presenter
return new TvSettingsViewHolder(settingsCard); return new TvSettingsViewHolder(settingsCard);
} }
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
{
TvSettingsViewHolder holder = (TvSettingsViewHolder) viewHolder; TvSettingsViewHolder holder = (TvSettingsViewHolder) viewHolder;
TvSettingsItem settingsItem = (TvSettingsItem) item; TvSettingsItem settingsItem = (TvSettingsItem) item;
@ -39,8 +36,7 @@ public final class SettingsRowPresenter extends Presenter
holder.cardParent.setMainImage(resources.getDrawable(settingsItem.getIconId(), null)); holder.cardParent.setMainImage(resources.getDrawable(settingsItem.getIconId(), null));
} }
public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
{
// no op // no op
} }
} }

View File

@ -16,8 +16,7 @@ import org.citra.citra_android.activities.EmulationActivity;
import de.hdodenhof.circleimageview.CircleImageView; import de.hdodenhof.circleimageview.CircleImageView;
public final class GameDetailsDialog extends DialogFragment public final class GameDetailsDialog extends DialogFragment {
{
private static final String ARG_GAME_TITLE = "game_title"; private static final String ARG_GAME_TITLE = "game_title";
private static final String ARG_GAME_DESCRIPTION = "game_description"; private static final String ARG_GAME_DESCRIPTION = "game_description";
private static final String ARG_GAME_COUNTRY = "game_country"; private static final String ARG_GAME_COUNTRY = "game_country";
@ -27,8 +26,7 @@ public final class GameDetailsDialog extends DialogFragment
// TODO Add all of this to the Loader in GameActivity.java // TODO Add all of this to the Loader in GameActivity.java
public static GameDetailsDialog newInstance(String title, String description, int country, public static GameDetailsDialog newInstance(String title, String description, int country,
String company, String path, String screenshotPath) String company, String path, String screenshotPath) {
{
GameDetailsDialog fragment = new GameDetailsDialog(); GameDetailsDialog fragment = new GameDetailsDialog();
Bundle arguments = new Bundle(); Bundle arguments = new Bundle();
@ -44,8 +42,7 @@ public final class GameDetailsDialog extends DialogFragment
} }
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) public Dialog onCreateDialog(Bundle savedInstanceState) {
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
ViewGroup contents = (ViewGroup) getActivity().getLayoutInflater() ViewGroup contents = (ViewGroup) getActivity().getLayoutInflater()
.inflate(R.layout.dialog_game_details, null); .inflate(R.layout.dialog_game_details, null);

View File

@ -18,8 +18,7 @@ import java.util.List;
* {@link AlertDialog} derivative that listens for * {@link AlertDialog} derivative that listens for
* motion events from controllers and joysticks. * motion events from controllers and joysticks.
*/ */
public final class MotionAlertDialog extends AlertDialog public final class MotionAlertDialog extends AlertDialog {
{
// The selected input preference // The selected input preference
private final InputBindingSetting setting; private final InputBindingSetting setting;
private final ControllerMappingHelper mControllerMappingHelper; private final ControllerMappingHelper mControllerMappingHelper;
@ -31,22 +30,18 @@ public final class MotionAlertDialog extends AlertDialog
* @param context The current {@link Context}. * @param context The current {@link Context}.
* @param setting The Preference to show this dialog for. * @param setting The Preference to show this dialog for.
*/ */
public MotionAlertDialog(Context context, InputBindingSetting setting) public MotionAlertDialog(Context context, InputBindingSetting setting) {
{
super(context); super(context);
this.setting = setting; this.setting = setting;
this.mControllerMappingHelper = new ControllerMappingHelper(); this.mControllerMappingHelper = new ControllerMappingHelper();
} }
public boolean onKeyEvent(int keyCode, KeyEvent event) public boolean onKeyEvent(int keyCode, KeyEvent event) {
{
Log.debug("[MotionAlertDialog] Received key event: " + event.getAction()); Log.debug("[MotionAlertDialog] Received key event: " + event.getAction());
switch (event.getAction()) switch (event.getAction()) {
{
case KeyEvent.ACTION_DOWN: case KeyEvent.ACTION_DOWN:
if (!mControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode)) if (!mControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode)) {
{
saveKeyInput(event); saveKeyInput(event);
} }
// Even if we ignore the key, we still consume it. Thus return true regardless. // Even if we ignore the key, we still consume it. Thus return true regardless.
@ -58,21 +53,18 @@ public final class MotionAlertDialog extends AlertDialog
} }
@Override @Override
public boolean dispatchKeyEvent(KeyEvent event) public boolean dispatchKeyEvent(KeyEvent event) {
{
// Handle this key if we care about it, otherwise pass it down the framework // Handle this key if we care about it, otherwise pass it down the framework
return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event); return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event);
} }
@Override @Override
public boolean dispatchGenericMotionEvent(MotionEvent event) public boolean dispatchGenericMotionEvent(MotionEvent event) {
{
// Handle this event if we care about it, otherwise pass it down the framework // Handle this event if we care about it, otherwise pass it down the framework
return onMotionEvent(event) || super.dispatchGenericMotionEvent(event); return onMotionEvent(event) || super.dispatchGenericMotionEvent(event);
} }
private boolean onMotionEvent(MotionEvent event) private boolean onMotionEvent(MotionEvent event) {
{
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
return false; return false;
if (event.getAction() != MotionEvent.ACTION_MOVE) if (event.getAction() != MotionEvent.ACTION_MOVE)
@ -86,24 +78,20 @@ public final class MotionAlertDialog extends AlertDialog
float axisMoveValue = 0.0f; float axisMoveValue = 0.0f;
InputDevice.MotionRange lastMovedRange = null; InputDevice.MotionRange lastMovedRange = null;
char lastMovedDir = '?'; char lastMovedDir = '?';
if (mWaitingForEvent) if (mWaitingForEvent) {
{
// Get only the axis that seem to have moved (more than .5) // Get only the axis that seem to have moved (more than .5)
for (InputDevice.MotionRange range : motionRanges) for (InputDevice.MotionRange range : motionRanges) {
{
int axis = range.getAxis(); int axis = range.getAxis();
float origValue = event.getAxisValue(axis); float origValue = event.getAxisValue(axis);
float value = mControllerMappingHelper.scaleAxis(input, axis, origValue); float value = mControllerMappingHelper.scaleAxis(input, axis, origValue);
if (Math.abs(value) > 0.5f) if (Math.abs(value) > 0.5f) {
{
// It is common to have multiple axis with the same physical input. For example, // It is common to have multiple axis with the same physical input. For example,
// shoulder butters are provided as both AXIS_LTRIGGER and AXIS_BRAKE. // shoulder butters are provided as both AXIS_LTRIGGER and AXIS_BRAKE.
// To handle this, we ignore an axis motion that's the exact same as a motion // To handle this, we ignore an axis motion that's the exact same as a motion
// we already saw. This way, we ignore axis with two names, but catch the case // we already saw. This way, we ignore axis with two names, but catch the case
// where a joystick is moved in two directions. // where a joystick is moved in two directions.
// ref: bottom of https://developer.android.com/training/game-controllers/controller-input.html // ref: bottom of https://developer.android.com/training/game-controllers/controller-input.html
if (value != axisMoveValue) if (value != axisMoveValue) {
{
axisMoveValue = value; axisMoveValue = value;
numMovedAxis++; numMovedAxis++;
lastMovedRange = range; lastMovedRange = range;
@ -113,8 +101,7 @@ public final class MotionAlertDialog extends AlertDialog
} }
// If only one axis moved, that's the winner. // If only one axis moved, that's the winner.
if (numMovedAxis == 1) if (numMovedAxis == 1) {
{
mWaitingForEvent = false; mWaitingForEvent = false;
saveMotionInput(input, lastMovedRange, lastMovedDir); saveMotionInput(input, lastMovedRange, lastMovedDir);
} }
@ -129,8 +116,7 @@ public final class MotionAlertDialog extends AlertDialog
* *
* @param keyEvent KeyEvent of this key press. * @param keyEvent KeyEvent of this key press.
*/ */
private void saveKeyInput(KeyEvent keyEvent) private void saveKeyInput(KeyEvent keyEvent) {
{
InputDevice device = keyEvent.getDevice(); InputDevice device = keyEvent.getDevice();
String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode(); String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode();
String uiString = device.getName() + ": Button " + keyEvent.getKeyCode(); String uiString = device.getName() + ": Button " + keyEvent.getKeyCode();
@ -147,8 +133,7 @@ public final class MotionAlertDialog extends AlertDialog
* @param axisDir Either '-' or '+' * @param axisDir Either '-' or '+'
*/ */
private void saveMotionInput(InputDevice device, InputDevice.MotionRange motionRange, private void saveMotionInput(InputDevice device, InputDevice.MotionRange motionRange,
char axisDir) char axisDir) {
{
String bindStr = String bindStr =
"Device '" + device.getDescriptor() + "'-Axis " + motionRange.getAxis() + axisDir; "Device '" + device.getDescriptor() + "'-Axis " + motionRange.getAxis() + axisDir;
String uiString = device.getName() + ": Axis " + motionRange.getAxis() + axisDir; String uiString = device.getName() + ": Axis " + motionRange.getAxis() + axisDir;
@ -159,8 +144,7 @@ public final class MotionAlertDialog extends AlertDialog
/** /**
* Save the input string to settings and SharedPreferences, then dismiss this Dialog. * Save the input string to settings and SharedPreferences, then dismiss this Dialog.
*/ */
private void saveInput(String bind, String ui) private void saveInput(String bind, String ui) {
{
setting.setValue(bind); setting.setValue(bind);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());

View File

@ -8,12 +8,10 @@ import com.nononsenseapps.filepicker.FilePickerFragment;
import java.io.File; import java.io.File;
public class CustomFilePickerFragment extends FilePickerFragment public class CustomFilePickerFragment extends FilePickerFragment {
{
@NonNull @NonNull
@Override @Override
public Uri toUri(@NonNull final File file) public Uri toUri(@NonNull final File file) {
{
return FileProvider return FileProvider
.getUriForFile(getContext(), .getUriForFile(getContext(),
getContext().getApplicationContext().getPackageName() + ".filesprovider", getContext().getApplicationContext().getPackageName() + ".filesprovider",

View File

@ -27,8 +27,7 @@ import org.citra.citra_android.services.DirectoryInitializationService.Directory
import org.citra.citra_android.utils.DirectoryStateReceiver; import org.citra.citra_android.utils.DirectoryStateReceiver;
import org.citra.citra_android.utils.Log; import org.citra.citra_android.utils.Log;
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback {
{
private static final String KEY_GAMEPATH = "gamepath"; private static final String KEY_GAMEPATH = "gamepath";
private static final Handler perfStatsUpdateHandler = new Handler(); private static final Handler perfStatsUpdateHandler = new Handler();
@ -47,8 +46,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
private Runnable perfStatsUpdater; private Runnable perfStatsUpdater;
public static EmulationFragment newInstance(String gamePath) public static EmulationFragment newInstance(String gamePath) {
{
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(KEY_GAMEPATH, gamePath); args.putString(KEY_GAMEPATH, gamePath);
@ -59,17 +57,13 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
} }
@Override @Override
public void onAttach(Context context) public void onAttach(Context context) {
{
super.onAttach(context); super.onAttach(context);
if (context instanceof EmulationActivity) if (context instanceof EmulationActivity) {
{
activity = (EmulationActivity) context; activity = (EmulationActivity) context;
NativeLibrary.setEmulationActivity((EmulationActivity) context); NativeLibrary.setEmulationActivity((EmulationActivity) context);
} } else {
else
{
throw new IllegalStateException("EmulationFragment must have EmulationActivity parent"); throw new IllegalStateException("EmulationFragment must have EmulationActivity parent");
} }
} }
@ -78,8 +72,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
* Initialize anything that doesn't depend on the layout / views in here. * Initialize anything that doesn't depend on the layout / views in here.
*/ */
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState) {
{
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// So this fragment doesn't restart on configuration changes; i.e. rotation. // So this fragment doesn't restart on configuration changes; i.e. rotation.
@ -95,39 +88,31 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
* Initialize the UI and start emulation in here. * Initialize the UI and start emulation in here.
*/ */
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
{
View contents = inflater.inflate(R.layout.fragment_emulation, container, false); View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation); SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation);
surfaceView.getHolder().addCallback(this); surfaceView.getHolder().addCallback(this);
mInputOverlay = contents.findViewById(R.id.surface_input_overlay); mInputOverlay = contents.findViewById(R.id.surface_input_overlay);
if (mInputOverlay != null) if (mInputOverlay != null) {
{
// If the input overlay was previously disabled, then don't show it. // If the input overlay was previously disabled, then don't show it.
if (!mPreferences.getBoolean("showInputOverlay", true)) if (!mPreferences.getBoolean("showInputOverlay", true)) {
{
mInputOverlay.setVisibility(View.GONE); mInputOverlay.setVisibility(View.GONE);
} }
} }
Button doneButton = contents.findViewById(R.id.done_control_config); Button doneButton = contents.findViewById(R.id.done_control_config);
if (doneButton != null) if (doneButton != null) {
{
doneButton.setOnClickListener(v -> stopConfiguringControls()); doneButton.setOnClickListener(v -> stopConfiguringControls());
} }
mPerfStats = contents.findViewById(R.id.perf_stats_text); mPerfStats = contents.findViewById(R.id.perf_stats_text);
if (mPerfStats != null) if (mPerfStats != null) {
{
// If the overlay was previously disabled, then don't show it. // If the overlay was previously disabled, then don't show it.
if (!mPreferences.getBoolean("showPerfStats", true)) if (!mPreferences.getBoolean("showPerfStats", true)) {
{
mPerfStats.setVisibility(View.GONE); mPerfStats.setVisibility(View.GONE);
} } else {
else
{
updatePerfStats(); updatePerfStats();
} }
} }
@ -138,24 +123,18 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
} }
@Override @Override
public void onResume() public void onResume() {
{
super.onResume(); super.onResume();
if (DirectoryInitializationService.areDolphinDirectoriesReady()) if (DirectoryInitializationService.areDolphinDirectoriesReady()) {
{
mEmulationState.run(activity.isActivityRecreated()); mEmulationState.run(activity.isActivityRecreated());
} } else {
else
{
setupDolphinDirectoriesThenStartEmulation(); setupDolphinDirectoriesThenStartEmulation();
} }
} }
@Override @Override
public void onPause() public void onPause() {
{ if (directoryStateReceiver != null) {
if (directoryStateReceiver != null)
{
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver); LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver);
directoryStateReceiver = null; directoryStateReceiver = null;
} }
@ -165,14 +144,12 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
} }
@Override @Override
public void onDetach() public void onDetach() {
{
NativeLibrary.clearEmulationActivity(); NativeLibrary.clearEmulationActivity();
super.onDetach(); super.onDetach();
} }
private void setupDolphinDirectoriesThenStartEmulation() private void setupDolphinDirectoriesThenStartEmulation() {
{
IntentFilter statusIntentFilter = new IntentFilter( IntentFilter statusIntentFilter = new IntentFilter(
DirectoryInitializationService.BROADCAST_ACTION); DirectoryInitializationService.BROADCAST_ACTION);
@ -180,19 +157,14 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
new DirectoryStateReceiver(directoryInitializationState -> new DirectoryStateReceiver(directoryInitializationState ->
{ {
if (directoryInitializationState == if (directoryInitializationState ==
DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) {
{
mEmulationState.run(activity.isActivityRecreated()); mEmulationState.run(activity.isActivityRecreated());
} } else if (directoryInitializationState ==
else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) {
DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
{
Toast.makeText(getContext(), R.string.write_permission_needed, Toast.LENGTH_SHORT) Toast.makeText(getContext(), R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show(); .show();
} } else if (directoryInitializationState ==
else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE) {
DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
{
Toast.makeText(getContext(), R.string.external_storage_not_mounted, Toast.makeText(getContext(), R.string.external_storage_not_mounted,
Toast.LENGTH_SHORT) Toast.LENGTH_SHORT)
.show(); .show();
@ -206,19 +178,15 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
DirectoryInitializationService.startService(getActivity()); DirectoryInitializationService.startService(getActivity());
} }
public void toggleInputOverlayVisibility() public void toggleInputOverlayVisibility() {
{
SharedPreferences.Editor editor = mPreferences.edit(); SharedPreferences.Editor editor = mPreferences.edit();
// If the overlay is currently set to INVISIBLE // If the overlay is currently set to INVISIBLE
if (!mPreferences.getBoolean("showInputOverlay", false)) if (!mPreferences.getBoolean("showInputOverlay", false)) {
{
// Set it to VISIBLE // Set it to VISIBLE
mInputOverlay.setVisibility(View.VISIBLE); mInputOverlay.setVisibility(View.VISIBLE);
editor.putBoolean("showInputOverlay", true); editor.putBoolean("showInputOverlay", true);
} } else {
else
{
// Set it to INVISIBLE // Set it to INVISIBLE
mInputOverlay.setVisibility(View.GONE); mInputOverlay.setVisibility(View.GONE);
editor.putBoolean("showInputOverlay", false); editor.putBoolean("showInputOverlay", false);
@ -227,30 +195,24 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
editor.apply(); editor.apply();
} }
public void refreshInputOverlay() public void refreshInputOverlay() {
{
mInputOverlay.refreshControls(); mInputOverlay.refreshControls();
} }
public void resetInputOverlay() public void resetInputOverlay() {
{
mInputOverlay.resetButtonPlacement(); mInputOverlay.resetButtonPlacement();
} }
public void togglePerfStatsVisibility() public void togglePerfStatsVisibility() {
{
SharedPreferences.Editor editor = mPreferences.edit(); SharedPreferences.Editor editor = mPreferences.edit();
// If the overlay is currently set to INVISIBLE // If the overlay is currently set to INVISIBLE
if (!mPreferences.getBoolean("showPerfStats", false)) if (!mPreferences.getBoolean("showPerfStats", false)) {
{
updatePerfStats(); updatePerfStats();
// Set it to VISIBLE // Set it to VISIBLE
mPerfStats.setVisibility(View.VISIBLE); mPerfStats.setVisibility(View.VISIBLE);
editor.putBoolean("showPerfStats", true); editor.putBoolean("showPerfStats", true);
} } else {
else
{
stopPerfStatsUpdates(); stopPerfStatsUpdates();
// Set it to INVISIBLE // Set it to INVISIBLE
mPerfStats.setVisibility(View.GONE); mPerfStats.setVisibility(View.GONE);
@ -260,8 +222,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
editor.apply(); editor.apply();
} }
private void updatePerfStats() private void updatePerfStats() {
{
final int SYSTEM_FPS = 0; final int SYSTEM_FPS = 0;
final int FPS = 1; final int FPS = 1;
final int FRAMETIME = 2; final int FRAMETIME = 2;
@ -269,7 +230,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
perfStatsUpdater = () -> perfStatsUpdater = () ->
{ {
double perfStats[] = NativeLibrary.GetPerfStats(); double[] perfStats = NativeLibrary.GetPerfStats();
mPerfStats mPerfStats
.setText(String.format("FPS: %.5s\nFrametime: %.7sms\nSpeed: %.4s%%", perfStats[FPS], .setText(String.format("FPS: %.5s\nFrametime: %.7sms\nSpeed: %.4s%%", perfStats[FPS],
perfStats[FRAMETIME] * 1000.0, perfStats[SPEED] * 100.0)); perfStats[FRAMETIME] * 1000.0, perfStats[SPEED] * 100.0));
@ -279,193 +240,145 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
perfStatsUpdateHandler.post(perfStatsUpdater); perfStatsUpdateHandler.post(perfStatsUpdater);
} }
private void stopPerfStatsUpdates() private void stopPerfStatsUpdates() {
{ if (perfStatsUpdater != null) {
if (perfStatsUpdater != null)
{
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater); perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater);
} }
} }
@Override @Override
public void surfaceCreated(SurfaceHolder holder) public void surfaceCreated(SurfaceHolder holder) {
{
// We purposely don't do anything here. // We purposely don't do anything here.
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation. // All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
} }
@Override @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
{
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height); Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height);
mEmulationState.newSurface(holder.getSurface()); mEmulationState.newSurface(holder.getSurface());
} }
@Override @Override
public void surfaceDestroyed(SurfaceHolder holder) public void surfaceDestroyed(SurfaceHolder holder) {
{
mEmulationState.clearSurface(); mEmulationState.clearSurface();
} }
public void stopEmulation() public void stopEmulation() {
{
mEmulationState.stop(); mEmulationState.stop();
} }
public void startConfiguringControls() public void startConfiguringControls() {
{
getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE); getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
mInputOverlay.setIsInEditMode(true); mInputOverlay.setIsInEditMode(true);
} }
public void stopConfiguringControls() public void stopConfiguringControls() {
{
getView().findViewById(R.id.done_control_config).setVisibility(View.GONE); getView().findViewById(R.id.done_control_config).setVisibility(View.GONE);
mInputOverlay.setIsInEditMode(false); mInputOverlay.setIsInEditMode(false);
} }
public boolean isConfiguringControls() public boolean isConfiguringControls() {
{
return mInputOverlay.isInEditMode(); return mInputOverlay.isInEditMode();
} }
private static class EmulationState private static class EmulationState {
{
private enum State
{
STOPPED, RUNNING, PAUSED
}
private final String mGamePath; private final String mGamePath;
private Thread mEmulationThread; private Thread mEmulationThread;
private State state; private State state;
private Surface mSurface; private Surface mSurface;
private boolean mRunWhenSurfaceIsValid; private boolean mRunWhenSurfaceIsValid;
EmulationState(String gamePath) EmulationState(String gamePath) {
{
mGamePath = gamePath; mGamePath = gamePath;
// Starting state is stopped. // Starting state is stopped.
state = State.STOPPED; state = State.STOPPED;
} }
// Getters for the current state public synchronized boolean isStopped() {
public synchronized boolean isStopped()
{
return state == State.STOPPED; return state == State.STOPPED;
} }
public synchronized boolean isPaused() // Getters for the current state
{
public synchronized boolean isPaused() {
return state == State.PAUSED; return state == State.PAUSED;
} }
public synchronized boolean isRunning() public synchronized boolean isRunning() {
{
return state == State.RUNNING; return state == State.RUNNING;
} }
// State changing methods public synchronized void stop() {
if (state != State.STOPPED) {
public synchronized void stop()
{
if (state != State.STOPPED)
{
Log.debug("[EmulationFragment] Stopping emulation."); Log.debug("[EmulationFragment] Stopping emulation.");
state = State.STOPPED; state = State.STOPPED;
NativeLibrary.StopEmulation(); NativeLibrary.StopEmulation();
} } else {
else
{
Log.warning("[EmulationFragment] Stop called while already stopped."); Log.warning("[EmulationFragment] Stop called while already stopped.");
} }
} }
public synchronized void pause() // State changing methods
{
if (state != State.PAUSED) public synchronized void pause() {
{ if (state != State.PAUSED) {
state = State.PAUSED; state = State.PAUSED;
Log.debug("[EmulationFragment] Pausing emulation."); Log.debug("[EmulationFragment] Pausing emulation.");
// Release the surface before pausing, since emulation has to be running for that. // Release the surface before pausing, since emulation has to be running for that.
NativeLibrary.SurfaceDestroyed(); NativeLibrary.SurfaceDestroyed();
NativeLibrary.PauseEmulation(); NativeLibrary.PauseEmulation();
} } else {
else
{
Log.warning("[EmulationFragment] Pause called while already paused."); Log.warning("[EmulationFragment] Pause called while already paused.");
} }
} }
public synchronized void run(boolean isActivityRecreated) public synchronized void run(boolean isActivityRecreated) {
{ if (isActivityRecreated) {
if (isActivityRecreated) if (NativeLibrary.IsRunning()) {
{
if (NativeLibrary.IsRunning())
{
state = State.PAUSED; state = State.PAUSED;
} }
} } else {
else
{
Log.debug("[EmulationFragment] activity resumed or fresh start"); Log.debug("[EmulationFragment] activity resumed or fresh start");
} }
// If the surface is set, run now. Otherwise, wait for it to get set. // If the surface is set, run now. Otherwise, wait for it to get set.
if (mSurface != null) if (mSurface != null) {
{
runWithValidSurface(); runWithValidSurface();
} } else {
else
{
mRunWhenSurfaceIsValid = true; mRunWhenSurfaceIsValid = true;
} }
} }
// Surface callbacks // Surface callbacks
public synchronized void newSurface(Surface surface) public synchronized void newSurface(Surface surface) {
{
mSurface = surface; mSurface = surface;
if (mRunWhenSurfaceIsValid) if (mRunWhenSurfaceIsValid) {
{
runWithValidSurface(); runWithValidSurface();
} }
} }
public synchronized void clearSurface() public synchronized void clearSurface() {
{ if (mSurface == null) {
if (mSurface == null)
{
Log.warning("[EmulationFragment] clearSurface called, but surface already null."); Log.warning("[EmulationFragment] clearSurface called, but surface already null.");
} } else {
else
{
mSurface = null; mSurface = null;
Log.debug("[EmulationFragment] Surface destroyed."); Log.debug("[EmulationFragment] Surface destroyed.");
if (state == State.RUNNING) if (state == State.RUNNING) {
{
NativeLibrary.SurfaceDestroyed(); NativeLibrary.SurfaceDestroyed();
state = State.PAUSED; state = State.PAUSED;
} } else if (state == State.PAUSED) {
else if (state == State.PAUSED)
{
Log.warning("[EmulationFragment] Surface cleared while emulation paused."); Log.warning("[EmulationFragment] Surface cleared while emulation paused.");
} } else {
else
{
Log.warning("[EmulationFragment] Surface cleared while emulation stopped."); Log.warning("[EmulationFragment] Surface cleared while emulation stopped.");
} }
} }
} }
private void runWithValidSurface() private void runWithValidSurface() {
{
mRunWhenSurfaceIsValid = false; mRunWhenSurfaceIsValid = false;
if (state == State.STOPPED) if (state == State.STOPPED) {
{
mEmulationThread = new Thread(() -> mEmulationThread = new Thread(() ->
{ {
NativeLibrary.SurfaceChanged(mSurface); NativeLibrary.SurfaceChanged(mSurface);
@ -474,18 +387,18 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
}, "NativeEmulation"); }, "NativeEmulation");
mEmulationThread.start(); mEmulationThread.start();
} } else if (state == State.PAUSED) {
else if (state == State.PAUSED)
{
Log.debug("[EmulationFragment] Resuming emulation."); Log.debug("[EmulationFragment] Resuming emulation.");
NativeLibrary.SurfaceChanged(mSurface); NativeLibrary.SurfaceChanged(mSurface);
NativeLibrary.UnPauseEmulation(); NativeLibrary.UnPauseEmulation();
} } else {
else
{
Log.debug("[EmulationFragment] Bug, run called while already running."); Log.debug("[EmulationFragment] Bug, run called while already running.");
} }
state = State.RUNNING; state = State.RUNNING;
} }
private enum State {
STOPPED, RUNNING, PAUSED
}
} }
} }

View File

@ -14,13 +14,11 @@ import android.widget.TextView;
import org.citra.citra_android.R; import org.citra.citra_android.R;
import org.citra.citra_android.activities.EmulationActivity; import org.citra.citra_android.activities.EmulationActivity;
public final class MenuFragment extends Fragment implements View.OnClickListener public final class MenuFragment extends Fragment implements View.OnClickListener {
{
private static final String KEY_TITLE = "title"; private static final String KEY_TITLE = "title";
private static SparseIntArray buttonsActionsMap = new SparseIntArray(); private static SparseIntArray buttonsActionsMap = new SparseIntArray();
static static {
{
buttonsActionsMap.append(R.id.menu_emulation_toggle_perf_stats, buttonsActionsMap.append(R.id.menu_emulation_toggle_perf_stats,
EmulationActivity.MENU_ACTION_TOGGLE_PREF_STATS); EmulationActivity.MENU_ACTION_TOGGLE_PREF_STATS);
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT); buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
@ -30,8 +28,7 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
EmulationActivity.MENU_ACTION_SWAP_SCREENS); EmulationActivity.MENU_ACTION_SWAP_SCREENS);
} }
public static MenuFragment newInstance(String title) public static MenuFragment newInstance(String title) {
{
MenuFragment fragment = new MenuFragment(); MenuFragment fragment = new MenuFragment();
Bundle arguments = new Bundle(); Bundle arguments = new Bundle();
@ -43,13 +40,11 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
{
View rootView = inflater.inflate(R.layout.fragment_ingame_menu, container, false); View rootView = inflater.inflate(R.layout.fragment_ingame_menu, container, false);
LinearLayout options = rootView.findViewById(R.id.layout_options); LinearLayout options = rootView.findViewById(R.id.layout_options);
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++) for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++) {
{
Button button = (Button) options.getChildAt(childIndex); Button button = (Button) options.getChildAt(childIndex);
button.setOnClickListener(this); button.setOnClickListener(this);
@ -57,8 +52,7 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
TextView titleText = rootView.findViewById(R.id.text_game_title); TextView titleText = rootView.findViewById(R.id.text_game_title);
String title = getArguments().getString(KEY_TITLE); String title = getArguments().getString(KEY_TITLE);
if (title != null) if (title != null) {
{
titleText.setText(title); titleText.setText(title);
} }
@ -67,11 +61,9 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
@SuppressWarnings("WrongConstant") @SuppressWarnings("WrongConstant")
@Override @Override
public void onClick(View button) public void onClick(View button) {
{
int action = buttonsActionsMap.get(button.getId()); int action = buttonsActionsMap.get(button.getId());
if (action >= 0) if (action >= 0) {
{
((EmulationActivity) getActivity()).handleMenuAction(action); ((EmulationActivity) getActivity()).handleMenuAction(action);
} }
} }

View File

@ -4,8 +4,7 @@ import android.content.ContentValues;
import android.database.Cursor; import android.database.Cursor;
import android.os.Environment; import android.os.Environment;
public final class Game public final class Game {
{
private static final String PATH_SCREENSHOT_FOLDER = private static final String PATH_SCREENSHOT_FOLDER =
"file://" + Environment.getExternalStorageDirectory().getPath() + "/citra-emu/ScreenShots/"; "file://" + Environment.getExternalStorageDirectory().getPath() + "/citra-emu/ScreenShots/";
@ -19,8 +18,7 @@ public final class Game
private int mCountry; private int mCountry;
public Game(String title, String description, int country, String path, public Game(String title, String description, int country, String path,
String gameId, String company, String screenshotPath) String gameId, String company, String screenshotPath) {
{
mTitle = title; mTitle = title;
mDescription = description; mDescription = description;
mCountry = country; mCountry = country;
@ -30,44 +28,8 @@ public final class Game
mScreenshotPath = screenshotPath; mScreenshotPath = screenshotPath;
} }
public String getTitle()
{
return mTitle;
}
public String getDescription()
{
return mDescription;
}
public String getCompany()
{
return mCompany;
}
public int getCountry()
{
return mCountry;
}
public String getPath()
{
return mPath;
}
public String getGameId()
{
return mGameId;
}
public String getScreenshotPath()
{
return mScreenshotPath;
}
public static ContentValues asContentValues(String title, String description, public static ContentValues asContentValues(String title, String description,
int country, String path, String gameId, String company) int country, String path, String gameId, String company) {
{
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
String screenPath = PATH_SCREENSHOT_FOLDER + gameId + "/" + gameId + "-1.png"; String screenPath = PATH_SCREENSHOT_FOLDER + gameId + "/" + gameId + "-1.png";
@ -83,8 +45,7 @@ public final class Game
return values; return values;
} }
public static Game fromCursor(Cursor cursor) public static Game fromCursor(Cursor cursor) {
{
return new Game(cursor.getString(GameDatabase.GAME_COLUMN_TITLE), return new Game(cursor.getString(GameDatabase.GAME_COLUMN_TITLE),
cursor.getString(GameDatabase.GAME_COLUMN_DESCRIPTION), cursor.getString(GameDatabase.GAME_COLUMN_DESCRIPTION),
cursor.getInt(GameDatabase.GAME_COLUMN_COUNTRY), cursor.getInt(GameDatabase.GAME_COLUMN_COUNTRY),
@ -93,4 +54,32 @@ public final class Game
cursor.getString(GameDatabase.GAME_COLUMN_COMPANY), cursor.getString(GameDatabase.GAME_COLUMN_COMPANY),
cursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH)); cursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH));
} }
public String getTitle() {
return mTitle;
}
public String getDescription() {
return mDescription;
}
public String getCompany() {
return mCompany;
}
public int getCountry() {
return mCountry;
}
public String getPath() {
return mPath;
}
public String getGameId() {
return mGameId;
}
public String getScreenshotPath() {
return mScreenshotPath;
}
} }

View File

@ -20,12 +20,8 @@ import rx.Observable;
* A helper class that provides several utilities simplifying interaction with * A helper class that provides several utilities simplifying interaction with
* the SQLite database. * the SQLite database.
*/ */
public final class GameDatabase extends SQLiteOpenHelper public final class GameDatabase extends SQLiteOpenHelper {
{
private static final int DB_VERSION = 1;
public static final int COLUMN_DB_ID = 0; public static final int COLUMN_DB_ID = 0;
public static final int GAME_COLUMN_PATH = 1; public static final int GAME_COLUMN_PATH = 1;
public static final int GAME_COLUMN_TITLE = 2; public static final int GAME_COLUMN_TITLE = 2;
public static final int GAME_COLUMN_DESCRIPTION = 3; public static final int GAME_COLUMN_DESCRIPTION = 3;
@ -33,11 +29,8 @@ public final class GameDatabase extends SQLiteOpenHelper
public static final int GAME_COLUMN_GAME_ID = 5; public static final int GAME_COLUMN_GAME_ID = 5;
public static final int GAME_COLUMN_COMPANY = 6; public static final int GAME_COLUMN_COMPANY = 6;
public static final int GAME_COLUMN_SCREENSHOT_PATH = 7; public static final int GAME_COLUMN_SCREENSHOT_PATH = 7;
public static final int FOLDER_COLUMN_PATH = 1; public static final int FOLDER_COLUMN_PATH = 1;
public static final String KEY_DB_ID = "_id"; public static final String KEY_DB_ID = "_id";
public static final String KEY_GAME_PATH = "path"; public static final String KEY_GAME_PATH = "path";
public static final String KEY_GAME_TITLE = "title"; public static final String KEY_GAME_TITLE = "title";
public static final String KEY_GAME_DESCRIPTION = "description"; public static final String KEY_GAME_DESCRIPTION = "description";
@ -45,12 +38,10 @@ public final class GameDatabase extends SQLiteOpenHelper
public static final String KEY_GAME_ID = "game_id"; public static final String KEY_GAME_ID = "game_id";
public static final String KEY_GAME_COMPANY = "company"; public static final String KEY_GAME_COMPANY = "company";
public static final String KEY_GAME_SCREENSHOT_PATH = "screenshot_path"; public static final String KEY_GAME_SCREENSHOT_PATH = "screenshot_path";
public static final String KEY_FOLDER_PATH = "path"; public static final String KEY_FOLDER_PATH = "path";
public static final String TABLE_NAME_FOLDERS = "folders"; public static final String TABLE_NAME_FOLDERS = "folders";
public static final String TABLE_NAME_GAMES = "games"; public static final String TABLE_NAME_GAMES = "games";
private static final int DB_VERSION = 1;
private static final String TYPE_PRIMARY = " INTEGER PRIMARY KEY"; private static final String TYPE_PRIMARY = " INTEGER PRIMARY KEY";
private static final String TYPE_INTEGER = " INTEGER"; private static final String TYPE_INTEGER = " INTEGER";
private static final String TYPE_STRING = " TEXT"; private static final String TYPE_STRING = " TEXT";
@ -76,15 +67,13 @@ public final class GameDatabase extends SQLiteOpenHelper
private static final String SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS " + TABLE_NAME_FOLDERS; private static final String SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS " + TABLE_NAME_FOLDERS;
private static final String SQL_DELETE_GAMES = "DROP TABLE IF EXISTS " + TABLE_NAME_GAMES; private static final String SQL_DELETE_GAMES = "DROP TABLE IF EXISTS " + TABLE_NAME_GAMES;
public GameDatabase(Context context) public GameDatabase(Context context) {
{
// Superclass constructor builds a database or uses an existing one. // Superclass constructor builds a database or uses an existing one.
super(context, "games.db", null, DB_VERSION); super(context, "games.db", null, DB_VERSION);
} }
@Override @Override
public void onCreate(SQLiteDatabase database) public void onCreate(SQLiteDatabase database) {
{
Log.debug("[GameDatabase] GameDatabase - Creating database..."); Log.debug("[GameDatabase] GameDatabase - Creating database...");
execSqlAndLog(database, SQL_CREATE_GAMES); execSqlAndLog(database, SQL_CREATE_GAMES);
@ -92,8 +81,7 @@ public final class GameDatabase extends SQLiteOpenHelper
} }
@Override @Override
public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) {
{
Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases.."); Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases..");
execSqlAndLog(database, SQL_DELETE_FOLDERS); execSqlAndLog(database, SQL_DELETE_FOLDERS);
execSqlAndLog(database, SQL_CREATE_FOLDERS); execSqlAndLog(database, SQL_CREATE_FOLDERS);
@ -103,8 +91,7 @@ public final class GameDatabase extends SQLiteOpenHelper
} }
@Override @Override
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
{
Log.info("[GameDatabase] Upgrading database from schema version " + oldVersion + " to " + Log.info("[GameDatabase] Upgrading database from schema version " + oldVersion + " to " +
newVersion); newVersion);
@ -116,8 +103,7 @@ public final class GameDatabase extends SQLiteOpenHelper
scanLibrary(database); scanLibrary(database);
} }
public void scanLibrary(SQLiteDatabase database) public void scanLibrary(SQLiteDatabase database) {
{
// Before scanning known folders, go through the game table and remove any entries for which the file itself is missing. // Before scanning known folders, go through the game table and remove any entries for which the file itself is missing.
Cursor fileCursor = database.query(TABLE_NAME_GAMES, Cursor fileCursor = database.query(TABLE_NAME_GAMES,
null, // Get all columns. null, // Get all columns.
@ -130,13 +116,11 @@ public final class GameDatabase extends SQLiteOpenHelper
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. // Possibly overly defensive, but ensures that moveToNext() does not skip a row.
fileCursor.moveToPosition(-1); fileCursor.moveToPosition(-1);
while (fileCursor.moveToNext()) while (fileCursor.moveToNext()) {
{
String gamePath = fileCursor.getString(GAME_COLUMN_PATH); String gamePath = fileCursor.getString(GAME_COLUMN_PATH);
File game = new File(gamePath); File game = new File(gamePath);
if (!game.exists()) if (!game.exists()) {
{
Log.error("[GameDatabase] Game file no longer exists. Removing from the library: " + Log.error("[GameDatabase] Game file no longer exists. Removing from the library: " +
gamePath); gamePath);
database.delete(TABLE_NAME_GAMES, database.delete(TABLE_NAME_GAMES,
@ -162,8 +146,7 @@ public final class GameDatabase extends SQLiteOpenHelper
folderCursor.moveToPosition(-1); folderCursor.moveToPosition(-1);
// Iterate through all results of the DB query (i.e. all folders in the library.) // Iterate through all results of the DB query (i.e. all folders in the library.)
while (folderCursor.moveToNext()) while (folderCursor.moveToNext()) {
{
String folderPath = folderCursor.getString(FOLDER_COLUMN_PATH); String folderPath = folderCursor.getString(FOLDER_COLUMN_PATH);
File folder = new File(folderPath); File folder = new File(folderPath);
@ -173,35 +156,28 @@ public final class GameDatabase extends SQLiteOpenHelper
// Iterate through every file in the folder. // Iterate through every file in the folder.
File[] children = folder.listFiles(); File[] children = folder.listFiles();
if (children != null) if (children != null) {
{ for (File file : children) {
for (File file : children) if (!file.isHidden() && !file.isDirectory()) {
{
if (!file.isHidden() && !file.isDirectory())
{
String filePath = file.getPath(); String filePath = file.getPath();
int extensionStart = filePath.lastIndexOf('.'); int extensionStart = filePath.lastIndexOf('.');
if (extensionStart > 0) if (extensionStart > 0) {
{
String fileExtension = filePath.substring(extensionStart); String fileExtension = filePath.substring(extensionStart);
// Check that the file has an extension we care about before trying to read out of it. // Check that the file has an extension we care about before trying to read out of it.
if (allowedExtensions.contains(fileExtension.toLowerCase())) if (allowedExtensions.contains(fileExtension.toLowerCase())) {
{
String name = NativeLibrary.GetTitle(filePath); String name = NativeLibrary.GetTitle(filePath);
// If the game's title field is empty, use the filename. // If the game's title field is empty, use the filename.
if (name.isEmpty()) if (name.isEmpty()) {
{
name = filePath.substring(filePath.lastIndexOf("/") + 1); name = filePath.substring(filePath.lastIndexOf("/") + 1);
} }
String gameId = NativeLibrary.GetGameId(filePath); String gameId = NativeLibrary.GetGameId(filePath);
// If the game's ID field is empty, use the filename without extension. // If the game's ID field is empty, use the filename without extension.
if (gameId.isEmpty()) if (gameId.isEmpty()) {
{
gameId = filePath.substring(filePath.lastIndexOf("/") + 1, gameId = filePath.substring(filePath.lastIndexOf("/") + 1,
filePath.lastIndexOf(".")); filePath.lastIndexOf("."));
} }
@ -225,13 +201,10 @@ public final class GameDatabase extends SQLiteOpenHelper
// could potentially be more than one argument. // could potentially be more than one argument.
// If update fails, insert a new game instead. // If update fails, insert a new game instead.
if (rowsMatched == 0) if (rowsMatched == 0) {
{
Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE)); Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE));
database.insert(TABLE_NAME_GAMES, null, game); database.insert(TABLE_NAME_GAMES, null, game);
} } else {
else
{
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE)); Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE));
} }
} }
@ -240,16 +213,13 @@ public final class GameDatabase extends SQLiteOpenHelper
} }
} }
// If the folder is empty because it no longer exists, remove it from the library. // If the folder is empty because it no longer exists, remove it from the library.
else if (!folder.exists()) else if (!folder.exists()) {
{
Log.error( Log.error(
"[GameDatabase] Folder no longer exists. Removing from the library: " + folderPath); "[GameDatabase] Folder no longer exists. Removing from the library: " + folderPath);
database.delete(TABLE_NAME_FOLDERS, database.delete(TABLE_NAME_FOLDERS,
KEY_DB_ID + " = ?", KEY_DB_ID + " = ?",
new String[]{Long.toString(folderCursor.getLong(COLUMN_DB_ID))}); new String[]{Long.toString(folderCursor.getLong(COLUMN_DB_ID))});
} } else {
else
{
Log.error("[GameDatabase] Folder contains no games: " + folderPath); Log.error("[GameDatabase] Folder contains no games: " + folderPath);
} }
} }
@ -259,8 +229,7 @@ public final class GameDatabase extends SQLiteOpenHelper
database.close(); database.close();
} }
public Observable<Cursor> getGames() public Observable<Cursor> getGames() {
{
return Observable.create(subscriber -> return Observable.create(subscriber ->
{ {
Log.info("[GameDatabase] Reading games list..."); Log.info("[GameDatabase] Reading games list...");
@ -284,8 +253,7 @@ public final class GameDatabase extends SQLiteOpenHelper
}); });
} }
private void execSqlAndLog(SQLiteDatabase database, String sql) private void execSqlAndLog(SQLiteDatabase database, String sql) {
{
Log.verbose("[GameDatabase] Executing SQL: " + sql); Log.verbose("[GameDatabase] Executing SQL: " + sql);
database.execSQL(sql); database.execSQL(sql);
} }

View File

@ -14,8 +14,7 @@ import org.citra.citra_android.utils.Log;
* Provides an interface allowing Activities to interact with the SQLite database. * Provides an interface allowing Activities to interact with the SQLite database.
* CRUD methods in this class can be called by Activities using getContentResolver(). * CRUD methods in this class can be called by Activities using getContentResolver().
*/ */
public final class GameProvider extends ContentProvider public final class GameProvider extends ContentProvider {
{
public static final String REFRESH_LIBRARY = "refresh"; public static final String REFRESH_LIBRARY = "refresh";
public static final String AUTHORITY = "content://" + BuildConfig.APPLICATION_ID + ".provider"; public static final String AUTHORITY = "content://" + BuildConfig.APPLICATION_ID + ".provider";
@ -32,8 +31,7 @@ public final class GameProvider extends ContentProvider
private GameDatabase mDbHelper; private GameDatabase mDbHelper;
@Override @Override
public boolean onCreate() public boolean onCreate() {
{
Log.info("[GameProvider] Creating Content Provider..."); Log.info("[GameProvider] Creating Content Provider...");
mDbHelper = new GameDatabase(getContext()); mDbHelper = new GameDatabase(getContext());
@ -43,16 +41,14 @@ public final class GameProvider extends ContentProvider
@Override @Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection, public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) String[] selectionArgs, String sortOrder) {
{
Log.info("[GameProvider] Querying URI: " + uri); Log.info("[GameProvider] Querying URI: " + uri);
SQLiteDatabase db = mDbHelper.getReadableDatabase(); SQLiteDatabase db = mDbHelper.getReadableDatabase();
String table = uri.getLastPathSegment(); String table = uri.getLastPathSegment();
if (table == null) if (table == null) {
{
Log.error("[GameProvider] Badly formatted URI: " + uri); Log.error("[GameProvider] Badly formatted URI: " + uri);
return null; return null;
} }
@ -64,23 +60,18 @@ public final class GameProvider extends ContentProvider
} }
@Override @Override
public String getType(@NonNull Uri uri) public String getType(@NonNull Uri uri) {
{
Log.verbose("[GameProvider] Getting MIME type for URI: " + uri); Log.verbose("[GameProvider] Getting MIME type for URI: " + uri);
String lastSegment = uri.getLastPathSegment(); String lastSegment = uri.getLastPathSegment();
if (lastSegment == null) if (lastSegment == null) {
{
Log.error("[GameProvider] Badly formatted URI: " + uri); Log.error("[GameProvider] Badly formatted URI: " + uri);
return null; return null;
} }
if (lastSegment.equals(GameDatabase.TABLE_NAME_FOLDERS)) if (lastSegment.equals(GameDatabase.TABLE_NAME_FOLDERS)) {
{
return MIME_TYPE_FOLDER; return MIME_TYPE_FOLDER;
} } else if (lastSegment.equals(GameDatabase.TABLE_NAME_GAMES)) {
else if (lastSegment.equals(GameDatabase.TABLE_NAME_GAMES))
{
return MIME_TYPE_GAME; return MIME_TYPE_GAME;
} }
@ -89,8 +80,7 @@ public final class GameProvider extends ContentProvider
} }
@Override @Override
public Uri insert(@NonNull Uri uri, ContentValues values) public Uri insert(@NonNull Uri uri, ContentValues values) {
{
Log.info("[GameProvider] Inserting row at URI: " + uri); Log.info("[GameProvider] Inserting row at URI: " + uri);
SQLiteDatabase database = mDbHelper.getWritableDatabase(); SQLiteDatabase database = mDbHelper.getWritableDatabase();
@ -98,10 +88,8 @@ public final class GameProvider extends ContentProvider
long id = -1; long id = -1;
if (table != null) if (table != null) {
{ if (table.equals(REFRESH_LIBRARY)) {
if (table.equals(REFRESH_LIBRARY))
{
Log.info( Log.info(
"[GameProvider] URI specified table REFRESH_LIBRARY. No insertion necessary; refreshing library contents..."); "[GameProvider] URI specified table REFRESH_LIBRARY. No insertion necessary; refreshing library contents...");
mDbHelper.scanLibrary(database); mDbHelper.scanLibrary(database);
@ -111,25 +99,19 @@ public final class GameProvider extends ContentProvider
id = database.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_IGNORE); id = database.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_IGNORE);
// If insertion was successful... // If insertion was successful...
if (id > 0) if (id > 0) {
{
// If we just added a folder, add its contents to the game list. // If we just added a folder, add its contents to the game list.
if (table.equals(GameDatabase.TABLE_NAME_FOLDERS)) if (table.equals(GameDatabase.TABLE_NAME_FOLDERS)) {
{
mDbHelper.scanLibrary(database); mDbHelper.scanLibrary(database);
} }
// Notify the UI that its contents should be refreshed. // Notify the UI that its contents should be refreshed.
getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, null);
uri = Uri.withAppendedPath(uri, Long.toString(id)); uri = Uri.withAppendedPath(uri, Long.toString(id));
} } else {
else
{
Log.error("[GameProvider] Row already exists: " + uri + " id: " + id); Log.error("[GameProvider] Row already exists: " + uri + " id: " + id);
} }
} } else {
else
{
Log.error("[GameProvider] Badly formatted URI: " + uri); Log.error("[GameProvider] Badly formatted URI: " + uri);
} }
@ -139,16 +121,14 @@ public final class GameProvider extends ContentProvider
} }
@Override @Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
{
Log.error("[GameProvider] Delete operations unsupported. URI: " + uri); Log.error("[GameProvider] Delete operations unsupported. URI: " + uri);
return 0; return 0;
} }
@Override @Override
public int update(@NonNull Uri uri, ContentValues values, String selection, public int update(@NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) String[] selectionArgs) {
{
Log.error("[GameProvider] Update operations unsupported. URI: " + uri); Log.error("[GameProvider] Update operations unsupported. URI: " + uri);
return 0; return 0;
} }

View File

@ -1,30 +1,25 @@
package org.citra.citra_android.model; package org.citra.citra_android.model;
public final class TvSettingsItem public final class TvSettingsItem {
{
private final int mItemId; private final int mItemId;
private final int mIconId; private final int mIconId;
private final int mLabelId; private final int mLabelId;
public TvSettingsItem(int itemId, int iconId, int labelId) public TvSettingsItem(int itemId, int iconId, int labelId) {
{
mItemId = itemId; mItemId = itemId;
mIconId = iconId; mIconId = iconId;
mLabelId = labelId; mLabelId = labelId;
} }
public int getItemId() public int getItemId() {
{
return mItemId; return mItemId;
} }
public int getIconId() public int getIconId() {
{
return mIconId; return mIconId;
} }
public int getLabelId() public int getLabelId() {
{
return mLabelId; return mLabelId;
} }
} }

View File

@ -0,0 +1,23 @@
package org.citra.citra_android.model.settings;
public final class BooleanSetting extends Setting {
private boolean mValue;
public BooleanSetting(String key, String section, int file, boolean value) {
super(key, section, file);
mValue = value;
}
public boolean getValue() {
return mValue;
}
public void setValue(boolean value) {
mValue = value;
}
@Override
public String getValueAsString() {
return mValue ? "True" : "False";
}
}

View File

@ -1,28 +1,23 @@
package org.citra.citra_android.model.settings; package org.citra.citra_android.model.settings;
public final class FloatSetting extends Setting public final class FloatSetting extends Setting {
{
private float mValue; private float mValue;
public FloatSetting(String key, String section, int file, float value) public FloatSetting(String key, String section, int file, float value) {
{
super(key, section, file); super(key, section, file);
mValue = value; mValue = value;
} }
public float getValue() public float getValue() {
{
return mValue; return mValue;
} }
public void setValue(float value) public void setValue(float value) {
{
mValue = value; mValue = value;
} }
@Override @Override
public String getValueAsString() public String getValueAsString() {
{
return Float.toString(mValue); return Float.toString(mValue);
} }
} }

View File

@ -1,28 +1,23 @@
package org.citra.citra_android.model.settings; package org.citra.citra_android.model.settings;
public final class IntSetting extends Setting public final class IntSetting extends Setting {
{
private int mValue; private int mValue;
public IntSetting(String key, String section, int file, int value) public IntSetting(String key, String section, int file, int value) {
{
super(key, section, file); super(key, section, file);
mValue = value; mValue = value;
} }
public int getValue() public int getValue() {
{
return mValue; return mValue;
} }
public void setValue(int value) public void setValue(int value) {
{
mValue = value; mValue = value;
} }
@Override @Override
public String getValueAsString() public String getValueAsString() {
{
return Integer.toString(mValue); return Integer.toString(mValue);
} }
} }

View File

@ -6,8 +6,7 @@ package org.citra.citra_android.model.settings;
* must be inferred at read-time. The type of value determines which child of this class is used * must be inferred at read-time. The type of value determines which child of this class is used
* to represent the Setting. * to represent the Setting.
*/ */
public abstract class Setting public abstract class Setting {
{
private String mKey; private String mKey;
private String mSection; private String mSection;
private int mFile; private int mFile;
@ -19,8 +18,7 @@ public abstract class Setting
* @param section The corresponding recent section header; e.g. [Core] or [Enhancements] without the brackets. * @param section The corresponding recent section header; e.g. [Core] or [Enhancements] without the brackets.
* @param file The ini file the Setting is stored in. * @param file The ini file the Setting is stored in.
*/ */
public Setting(String key, String section, int file) public Setting(String key, String section, int file) {
{
mKey = key; mKey = key;
mSection = section; mSection = section;
mFile = file; mFile = file;
@ -29,24 +27,21 @@ public abstract class Setting
/** /**
* @return The identifier used to write this setting to the ini file. * @return The identifier used to write this setting to the ini file.
*/ */
public String getKey() public String getKey() {
{
return mKey; return mKey;
} }
/** /**
* @return The name of the header under which this Setting should be written in the ini file. * @return The name of the header under which this Setting should be written in the ini file.
*/ */
public String getSection() public String getSection() {
{
return mSection; return mSection;
} }
/** /**
* @return The ini file the Setting is stored in. * @return The ini file the Setting is stored in.
*/ */
public int getFile() public int getFile() {
{
return mFile; return mFile;
} }

View File

@ -6,8 +6,7 @@ import java.util.HashMap;
* A semantically-related group of Settings objects. These Settings are * A semantically-related group of Settings objects. These Settings are
* internally stored as a HashMap. * internally stored as a HashMap.
*/ */
public final class SettingSection public final class SettingSection {
{
private String mName; private String mName;
private HashMap<String, Setting> mSettings = new HashMap<>(); private HashMap<String, Setting> mSettings = new HashMap<>();
@ -17,13 +16,11 @@ public final class SettingSection
* *
* @param name The header of this section; e.g. [Core] or [Enhancements] without the brackets. * @param name The header of this section; e.g. [Core] or [Enhancements] without the brackets.
*/ */
public SettingSection(String name) public SettingSection(String name) {
{
mName = name; mName = name;
} }
public String getName() public String getName() {
{
return mName; return mName;
} }
@ -32,8 +29,7 @@ public final class SettingSection
* *
* @param setting The Setting to be inserted. * @param setting The Setting to be inserted.
*/ */
public void putSetting(Setting setting) public void putSetting(Setting setting) {
{
mSettings.put(setting.getKey(), setting); mSettings.put(setting.getKey(), setting);
} }
@ -43,13 +39,11 @@ public final class SettingSection
* @param key Used to retrieve the Setting. * @param key Used to retrieve the Setting.
* @return A Setting object (you should probably cast this before using) * @return A Setting object (you should probably cast this before using)
*/ */
public Setting getSetting(String key) public Setting getSetting(String key) {
{
return mSettings.get(key); return mSettings.get(key);
} }
public HashMap<String, Setting> getSettings() public HashMap<String, Setting> getSettings() {
{
return mSettings; return mSettings;
} }
} }

View File

@ -1,28 +1,23 @@
package org.citra.citra_android.model.settings; package org.citra.citra_android.model.settings;
public final class StringSetting extends Setting public final class StringSetting extends Setting {
{
private String mValue; private String mValue;
public StringSetting(String key, String section, int file, String value) public StringSetting(String key, String section, int file, String value) {
{
super(key, section, file); super(key, section, file);
mValue = value; mValue = value;
} }
public String getValue() public String getValue() {
{
return mValue; return mValue;
} }
public void setValue(String value) public void setValue(String value) {
{
mValue = value; mValue = value;
} }
@Override @Override
public String getValueAsString() public String getValueAsString() {
{
return mValue; return mValue;
} }
} }

View File

@ -3,21 +3,17 @@ package org.citra.citra_android.model.settings.view;
import org.citra.citra_android.model.settings.IntSetting; import org.citra.citra_android.model.settings.IntSetting;
import org.citra.citra_android.model.settings.Setting; import org.citra.citra_android.model.settings.Setting;
public final class CheckBoxSetting extends SettingsItem public final class CheckBoxSetting extends SettingsItem {
{
private boolean mDefaultValue; private boolean mDefaultValue;
public CheckBoxSetting(String key, String section, int file, int titleId, int descriptionId, public CheckBoxSetting(String key, String section, int file, int titleId, int descriptionId,
boolean defaultValue, Setting setting) boolean defaultValue, Setting setting) {
{
super(key, section, file, setting, titleId, descriptionId); super(key, section, file, setting, titleId, descriptionId);
mDefaultValue = defaultValue; mDefaultValue = defaultValue;
} }
public boolean isChecked() public boolean isChecked() {
{ if (getSetting() == null) {
if (getSetting() == null)
{
return mDefaultValue; return mDefaultValue;
} }
@ -32,16 +28,12 @@ public final class CheckBoxSetting extends SettingsItem
* @param checked Pretty self explanatory. * @param checked Pretty self explanatory.
* @return null if overwritten successfully; otherwise, a newly created BooleanSetting. * @return null if overwritten successfully; otherwise, a newly created BooleanSetting.
*/ */
public IntSetting setChecked(boolean checked) public IntSetting setChecked(boolean checked) {
{ if (getSetting() == null) {
if (getSetting() == null)
{
IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), checked ? 1 : 0); IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), checked ? 1 : 0);
setSetting(setting); setSetting(setting);
return setting; return setting;
} } else {
else
{
IntSetting setting = (IntSetting) getSetting(); IntSetting setting = (IntSetting) getSetting();
setting.setValue(checked ? 1 : 0); setting.setValue(checked ? 1 : 0);
return null; return null;
@ -49,8 +41,7 @@ public final class CheckBoxSetting extends SettingsItem
} }
@Override @Override
public int getType() public int getType() {
{
return TYPE_CHECKBOX; return TYPE_CHECKBOX;
} }
} }

View File

@ -3,39 +3,32 @@ package org.citra.citra_android.model.settings.view;
import org.citra.citra_android.model.settings.Setting; import org.citra.citra_android.model.settings.Setting;
import org.citra.citra_android.model.settings.StringSetting; import org.citra.citra_android.model.settings.StringSetting;
public final class DateTimeSetting extends SettingsItem public final class DateTimeSetting extends SettingsItem {
{
private String mDefaultValue; private String mDefaultValue;
public DateTimeSetting(String key, String section, int file, int titleId, int descriptionId, public DateTimeSetting(String key, String section, int file, int titleId, int descriptionId,
String defaultValue, Setting setting) String defaultValue, Setting setting) {
{
super(key, section, file, setting, titleId, descriptionId); super(key, section, file, setting, titleId, descriptionId);
mDefaultValue = defaultValue; mDefaultValue = defaultValue;
} }
public String getValue() public String getValue() {
{ if (getSetting() != null) {
if (getSetting() != null)
{
StringSetting setting = (StringSetting) getSetting(); StringSetting setting = (StringSetting) getSetting();
return setting.getValue(); return setting.getValue();
} } else {
else
{
return mDefaultValue; return mDefaultValue;
} }
} }
public StringSetting setSelectedValue(String datetime)
{ public StringSetting setSelectedValue(String datetime) {
StringSetting setting = new StringSetting(getKey(), getSection(), getFile(), datetime); StringSetting setting = new StringSetting(getKey(), getSection(), getFile(), datetime);
setSetting(setting); setSetting(setting);
return setting; return setting;
} }
@Override @Override
public int getType() public int getType() {
{
return TYPE_DATETIME_SETTING; return TYPE_DATETIME_SETTING;
} }
} }

View File

@ -2,16 +2,13 @@ package org.citra.citra_android.model.settings.view;
import org.citra.citra_android.model.settings.Setting; import org.citra.citra_android.model.settings.Setting;
public final class HeaderSetting extends SettingsItem public final class HeaderSetting extends SettingsItem {
{ public HeaderSetting(String key, Setting setting, int titleId, int descriptionId) {
public HeaderSetting(String key, Setting setting, int titleId, int descriptionId)
{
super(key, null, 0, setting, titleId, descriptionId); super(key, null, 0, setting, titleId, descriptionId);
} }
@Override @Override
public int getType() public int getType() {
{
return SettingsItem.TYPE_HEADER; return SettingsItem.TYPE_HEADER;
} }
} }

View File

@ -3,17 +3,13 @@ package org.citra.citra_android.model.settings.view;
import org.citra.citra_android.model.settings.Setting; import org.citra.citra_android.model.settings.Setting;
import org.citra.citra_android.model.settings.StringSetting; import org.citra.citra_android.model.settings.StringSetting;
public final class InputBindingSetting extends SettingsItem public final class InputBindingSetting extends SettingsItem {
{ public InputBindingSetting(String key, String section, int file, int titleId, Setting setting) {
public InputBindingSetting(String key, String section, int file, int titleId, Setting setting)
{
super(key, section, file, setting, titleId, 0); super(key, section, file, setting, titleId, 0);
} }
public String getValue() public String getValue() {
{ if (getSetting() == null) {
if (getSetting() == null)
{
return ""; return "";
} }
@ -28,16 +24,12 @@ public final class InputBindingSetting extends SettingsItem
* @param bind The input that will be bound * @param bind The input that will be bound
* @return null if overwritten successfully; otherwise, a newly created StringSetting. * @return null if overwritten successfully; otherwise, a newly created StringSetting.
*/ */
public StringSetting setValue(String bind) public StringSetting setValue(String bind) {
{ if (getSetting() == null) {
if (getSetting() == null)
{
StringSetting setting = new StringSetting(getKey(), getSection(), getFile(), bind); StringSetting setting = new StringSetting(getKey(), getSection(), getFile(), bind);
setSetting(setting); setSetting(setting);
return setting; return setting;
} } else {
else
{
StringSetting setting = (StringSetting) getSetting(); StringSetting setting = (StringSetting) getSetting();
setting.setValue(bind); setting.setValue(bind);
return null; return null;
@ -45,8 +37,7 @@ public final class InputBindingSetting extends SettingsItem
} }
@Override @Override
public int getType() public int getType() {
{
return TYPE_INPUT_BINDING; return TYPE_INPUT_BINDING;
} }
} }

View File

@ -9,8 +9,7 @@ import org.citra.citra_android.model.settings.Setting;
* and a few with none (Headers, for example, do not correspond to anything in the ini * and a few with none (Headers, for example, do not correspond to anything in the ini
* file.) * file.)
*/ */
public abstract class SettingsItem public abstract class SettingsItem {
{
public static final int TYPE_HEADER = 0; public static final int TYPE_HEADER = 0;
public static final int TYPE_CHECKBOX = 1; public static final int TYPE_CHECKBOX = 1;
public static final int TYPE_SINGLE_CHOICE = 2; public static final int TYPE_SINGLE_CHOICE = 2;
@ -39,8 +38,7 @@ public abstract class SettingsItem
* @param descriptionId Resource ID for a text string to be displayed as this setting's description. * @param descriptionId Resource ID for a text string to be displayed as this setting's description.
*/ */
public SettingsItem(String key, String section, int file, Setting setting, int nameId, public SettingsItem(String key, String section, int file, Setting setting, int nameId,
int descriptionId) int descriptionId) {
{
mKey = key; mKey = key;
mSection = section; mSection = section;
mFile = file; mFile = file;
@ -52,32 +50,28 @@ public abstract class SettingsItem
/** /**
* @return The identifier for the backing Setting. * @return The identifier for the backing Setting.
*/ */
public String getKey() public String getKey() {
{
return mKey; return mKey;
} }
/** /**
* @return The header under which the backing Setting belongs. * @return The header under which the backing Setting belongs.
*/ */
public String getSection() public String getSection() {
{
return mSection; return mSection;
} }
/** /**
* @return The file the backing Setting is saved to. * @return The file the backing Setting is saved to.
*/ */
public int getFile() public int getFile() {
{
return mFile; return mFile;
} }
/** /**
* @return The backing Setting, possibly null. * @return The backing Setting, possibly null.
*/ */
public Setting getSetting() public Setting getSetting() {
{
return mSetting; return mSetting;
} }
@ -87,21 +81,18 @@ public abstract class SettingsItem
* *
* @param setting A non-null Setting. * @param setting A non-null Setting.
*/ */
public void setSetting(Setting setting) public void setSetting(Setting setting) {
{
mSetting = setting; mSetting = setting;
} }
/** /**
* @return A resource ID for a text string representing this Setting's name. * @return A resource ID for a text string representing this Setting's name.
*/ */
public int getNameId() public int getNameId() {
{
return mNameId; return mNameId;
} }
public int getDescriptionId() public int getDescriptionId() {
{
return mDescriptionId; return mDescriptionId;
} }

View File

@ -3,41 +3,33 @@ package org.citra.citra_android.model.settings.view;
import org.citra.citra_android.model.settings.IntSetting; import org.citra.citra_android.model.settings.IntSetting;
import org.citra.citra_android.model.settings.Setting; import org.citra.citra_android.model.settings.Setting;
public final class SingleChoiceSetting extends SettingsItem public final class SingleChoiceSetting extends SettingsItem {
{
private int mDefaultValue; private int mDefaultValue;
private int mChoicesId; private int mChoicesId;
private int mValuesId; private int mValuesId;
public SingleChoiceSetting(String key, String section, int file, int titleId, int descriptionId, public SingleChoiceSetting(String key, String section, int file, int titleId, int descriptionId,
int choicesId, int valuesId, int defaultValue, Setting setting) int choicesId, int valuesId, int defaultValue, Setting setting) {
{
super(key, section, file, setting, titleId, descriptionId); super(key, section, file, setting, titleId, descriptionId);
mValuesId = valuesId; mValuesId = valuesId;
mChoicesId = choicesId; mChoicesId = choicesId;
mDefaultValue = defaultValue; mDefaultValue = defaultValue;
} }
public int getChoicesId() public int getChoicesId() {
{
return mChoicesId; return mChoicesId;
} }
public int getValuesId() public int getValuesId() {
{
return mValuesId; return mValuesId;
} }
public int getSelectedValue() public int getSelectedValue() {
{ if (getSetting() != null) {
if (getSetting() != null)
{
IntSetting setting = (IntSetting) getSetting(); IntSetting setting = (IntSetting) getSetting();
return setting.getValue(); return setting.getValue();
} } else {
else
{
return mDefaultValue; return mDefaultValue;
} }
} }
@ -49,16 +41,12 @@ public final class SingleChoiceSetting extends SettingsItem
* @param selection New value of the int. * @param selection New value of the int.
* @return null if overwritten successfully otherwise; a newly created IntSetting. * @return null if overwritten successfully otherwise; a newly created IntSetting.
*/ */
public IntSetting setSelectedValue(int selection) public IntSetting setSelectedValue(int selection) {
{ if (getSetting() == null) {
if (getSetting() == null)
{
IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), selection); IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), selection);
setSetting(setting); setSetting(setting);
return setting; return setting;
} } else {
else
{
IntSetting setting = (IntSetting) getSetting(); IntSetting setting = (IntSetting) getSetting();
setting.setValue(selection); setting.setValue(selection);
return null; return null;
@ -66,8 +54,7 @@ public final class SingleChoiceSetting extends SettingsItem
} }
@Override @Override
public int getType() public int getType() {
{
return TYPE_SINGLE_CHOICE; return TYPE_SINGLE_CHOICE;
} }
} }

View File

@ -6,55 +6,42 @@ import org.citra.citra_android.model.settings.Setting;
import org.citra.citra_android.utils.Log; import org.citra.citra_android.utils.Log;
import org.citra.citra_android.utils.SettingsFile; import org.citra.citra_android.utils.SettingsFile;
public final class SliderSetting extends SettingsItem public final class SliderSetting extends SettingsItem {
{
private int mMax; private int mMax;
private int mDefaultValue; private int mDefaultValue;
private String mUnits; private String mUnits;
public SliderSetting(String key, String section, int file, int titleId, int descriptionId, public SliderSetting(String key, String section, int file, int titleId, int descriptionId,
int max, String units, int defaultValue, Setting setting) int max, String units, int defaultValue, Setting setting) {
{
super(key, section, file, setting, titleId, descriptionId); super(key, section, file, setting, titleId, descriptionId);
mMax = max; mMax = max;
mUnits = units; mUnits = units;
mDefaultValue = defaultValue; mDefaultValue = defaultValue;
} }
public int getMax() public int getMax() {
{
return mMax; return mMax;
} }
public int getSelectedValue() public int getSelectedValue() {
{
Setting setting = getSetting(); Setting setting = getSetting();
if (setting == null) if (setting == null) {
{
return mDefaultValue; return mDefaultValue;
} }
if (setting instanceof IntSetting) if (setting instanceof IntSetting) {
{
IntSetting intSetting = (IntSetting) setting; IntSetting intSetting = (IntSetting) setting;
return intSetting.getValue(); return intSetting.getValue();
} } else if (setting instanceof FloatSetting) {
else if (setting instanceof FloatSetting)
{
FloatSetting floatSetting = (FloatSetting) setting; FloatSetting floatSetting = (FloatSetting) setting;
if (floatSetting.getKey().equals(SettingsFile.KEY_FRAME_LIMIT)) if (floatSetting.getKey().equals(SettingsFile.KEY_FRAME_LIMIT)) {
{
return Math.round(floatSetting.getValue() * 100); return Math.round(floatSetting.getValue() * 100);
} } else {
else
{
return Math.round(floatSetting.getValue()); return Math.round(floatSetting.getValue());
} }
} } else {
else
{
Log.error("[SliderSetting] Error casting setting type."); Log.error("[SliderSetting] Error casting setting type.");
return -1; return -1;
} }
@ -67,16 +54,12 @@ public final class SliderSetting extends SettingsItem
* @param selection New value of the int. * @param selection New value of the int.
* @return null if overwritten successfully otherwise; a newly created IntSetting. * @return null if overwritten successfully otherwise; a newly created IntSetting.
*/ */
public IntSetting setSelectedValue(int selection) public IntSetting setSelectedValue(int selection) {
{ if (getSetting() == null) {
if (getSetting() == null)
{
IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), selection); IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), selection);
setSetting(setting); setSetting(setting);
return setting; return setting;
} } else {
else
{
IntSetting setting = (IntSetting) getSetting(); IntSetting setting = (IntSetting) getSetting();
setting.setValue(selection); setting.setValue(selection);
return null; return null;
@ -90,30 +73,24 @@ public final class SliderSetting extends SettingsItem
* @param selection New value of the float. * @param selection New value of the float.
* @return null if overwritten successfully otherwise; a newly created FloatSetting. * @return null if overwritten successfully otherwise; a newly created FloatSetting.
*/ */
public FloatSetting setSelectedValue(float selection) public FloatSetting setSelectedValue(float selection) {
{ if (getSetting() == null) {
if (getSetting() == null)
{
FloatSetting setting = new FloatSetting(getKey(), getSection(), getFile(), selection); FloatSetting setting = new FloatSetting(getKey(), getSection(), getFile(), selection);
setSetting(setting); setSetting(setting);
return setting; return setting;
} } else {
else
{
FloatSetting setting = (FloatSetting) getSetting(); FloatSetting setting = (FloatSetting) getSetting();
setting.setValue(selection); setting.setValue(selection);
return null; return null;
} }
} }
public String getUnits() public String getUnits() {
{
return mUnits; return mUnits;
} }
@Override @Override
public int getType() public int getType() {
{
return TYPE_SLIDER; return TYPE_SLIDER;
} }
} }

View File

@ -2,24 +2,20 @@ package org.citra.citra_android.model.settings.view;
import org.citra.citra_android.model.settings.Setting; import org.citra.citra_android.model.settings.Setting;
public final class SubmenuSetting extends SettingsItem public final class SubmenuSetting extends SettingsItem {
{
private String mMenuKey; private String mMenuKey;
public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId, String menuKey) public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId, String menuKey) {
{
super(key, null, 0, setting, titleId, descriptionId); super(key, null, 0, setting, titleId, descriptionId);
mMenuKey = menuKey; mMenuKey = menuKey;
} }
public String getMenuKey() public String getMenuKey() {
{
return mMenuKey; return mMenuKey;
} }
@Override @Override
public int getType() public int getType() {
{
return TYPE_SUBMENU; return TYPE_SUBMENU;
} }
} }

View File

@ -19,10 +19,10 @@ import android.graphics.drawable.Drawable;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.View; import android.view.View;
import android.view.Display;
import android.view.View.OnTouchListener; import android.view.View.OnTouchListener;
import org.citra.citra_android.NativeLibrary; import org.citra.citra_android.NativeLibrary;
@ -37,8 +37,7 @@ import java.util.Set;
* Draws the interactive input overlay on top of the * Draws the interactive input overlay on top of the
* {@link SurfaceView} that is rendering emulation. * {@link SurfaceView} that is rendering emulation.
*/ */
public final class InputOverlay extends SurfaceView implements OnTouchListener public final class InputOverlay extends SurfaceView implements OnTouchListener {
{
private final Set<InputOverlayDrawableButton> overlayButtons = new HashSet<>(); private final Set<InputOverlayDrawableButton> overlayButtons = new HashSet<>();
private final Set<InputOverlayDrawableDpad> overlayDpads = new HashSet<>(); private final Set<InputOverlayDrawableDpad> overlayDpads = new HashSet<>();
private final Set<InputOverlayDrawableJoystick> overlayJoysticks = new HashSet<>(); private final Set<InputOverlayDrawableJoystick> overlayJoysticks = new HashSet<>();
@ -50,35 +49,13 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
private SharedPreferences mPreferences; private SharedPreferences mPreferences;
/**
* Resizes a {@link Bitmap} by a given scale factor
*
* @param context The current {@link Context}
* @param bitmap The {@link Bitmap} to scale.
* @param scale The scale factor for the bitmap.
* @return The scaled {@link Bitmap}
*/
public static Bitmap resizeBitmap(Context context, Bitmap bitmap, float scale)
{
// Determine the button size based on the smaller screen dimension.
// This makes sure the buttons are the same size in both portrait and landscape.
DisplayMetrics dm = context.getResources().getDisplayMetrics();
int minDimension = Math.min(dm.widthPixels, dm.heightPixels);
return Bitmap.createScaledBitmap(bitmap,
(int) (minDimension * scale),
(int) (minDimension * scale),
true);
}
/** /**
* Constructor * Constructor
* *
* @param context The current {@link Context}. * @param context The current {@link Context}.
* @param attrs {@link AttributeSet} for parsing XML attributes. * @param attrs {@link AttributeSet} for parsing XML attributes.
*/ */
public InputOverlay(Context context, AttributeSet attrs) public InputOverlay(Context context, AttributeSet attrs) {
{
super(context, attrs); super(context, attrs);
mPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); mPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
@ -99,418 +76,24 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
requestFocus(); requestFocus();
} }
@Override /**
public void draw(Canvas canvas) * Resizes a {@link Bitmap} by a given scale factor
{ *
super.draw(canvas); * @param context The current {@link Context}
* @param bitmap The {@link Bitmap} to scale.
* @param scale The scale factor for the bitmap.
* @return The scaled {@link Bitmap}
*/
public static Bitmap resizeBitmap(Context context, Bitmap bitmap, float scale) {
// Determine the button size based on the smaller screen dimension.
// This makes sure the buttons are the same size in both portrait and landscape.
DisplayMetrics dm = context.getResources().getDisplayMetrics();
int minDimension = Math.min(dm.widthPixels, dm.heightPixels);
for (InputOverlayDrawableButton button : overlayButtons) return Bitmap.createScaledBitmap(bitmap,
{ (int) (minDimension * scale),
button.draw(canvas); (int) (minDimension * scale),
} true);
for (InputOverlayDrawableDpad dpad : overlayDpads)
{
dpad.draw(canvas);
}
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
{
joystick.draw(canvas);
}
}
@Override
public boolean onTouch(View v, MotionEvent event)
{
if (isInEditMode())
{
return onTouchWhileEditing(event);
}
int pointerIndex = event.getActionIndex();
if (mPreferences.getBoolean("isTouchEnabled", true))
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
NativeLibrary.onTouchEvent(event.getX(pointerIndex), event.getY(pointerIndex), true);
break;
case MotionEvent.ACTION_MOVE:
NativeLibrary.onTouchMoved(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// We dont really care where the touch has been released. We only care whether it has been
// released or not.
NativeLibrary.onTouchEvent(0, 0, false);
break;
}
}
for (InputOverlayDrawableButton button : overlayButtons)
{
// Determine the button state to apply based on the MotionEvent action flag.
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// If a pointer enters the bounds of a button, press that button.
if (button.getBounds()
.contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex)))
{
button.setPressedState(true);
button.setTrackId(event.getPointerId(pointerIndex));
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(),
ButtonState.PRESSED);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// If a pointer ends, release the button it was pressing.
if (button.getTrackId() == event.getPointerId(pointerIndex))
{
button.setPressedState(false);
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(),
ButtonState.RELEASED);
}
break;
}
}
for (InputOverlayDrawableDpad dpad : overlayDpads)
{
// Determine the button state to apply based on the MotionEvent action flag.
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// If a pointer enters the bounds of a button, press that button.
if (dpad.getBounds()
.contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex)))
{
boolean up = false;
boolean down = false;
boolean left = false;
boolean right = false;
if (dpad.getBounds().top + (dpad.getHeight() / 3) > (int) event.getY(pointerIndex))
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(0),
ButtonState.PRESSED);
up = true;
}
if (dpad.getBounds().bottom - (dpad.getHeight() / 3) < (int) event.getY(pointerIndex))
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(1),
ButtonState.PRESSED);
down = true;
}
if (dpad.getBounds().left + (dpad.getWidth() / 3) > (int) event.getX(pointerIndex))
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(2),
ButtonState.PRESSED);
left = true;
}
if (dpad.getBounds().right - (dpad.getWidth() / 3) < (int) event.getX(pointerIndex))
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(3),
ButtonState.PRESSED);
right = true;
}
setDpadState(dpad, up, down, left, right);
dpad.setTrackId(event.getPointerId(pointerIndex));
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// If a pointer ends, release the buttons.
if (dpad.getTrackId() == event.getPointerId(pointerIndex))
{
for (int i = 0; i < 4; i++)
{
dpad.setState(InputOverlayDrawableDpad.STATE_DEFAULT);
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i),
ButtonState.RELEASED);
}
}
break;
}
}
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
{
joystick.TrackEvent(event);
int axisID = joystick.getId();
float[] axises = joystick.getAxisValues();
NativeLibrary
.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, axisID, axises[0], axises[1]);
}
invalidate();
return true;
}
public boolean onTouchWhileEditing(MotionEvent event)
{
int pointerIndex = event.getActionIndex();
int fingerPositionX = (int) event.getX(pointerIndex);
int fingerPositionY = (int) event.getY(pointerIndex);
// Maybe combine Button and Joystick as subclasses of the same parent?
// Or maybe create an interface like IMoveableHUDControl?
for (InputOverlayDrawableButton button : overlayButtons)
{
// Determine the button state to apply based on the MotionEvent action flag.
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// If no button is being moved now, remember the currently touched button to move.
if (mButtonBeingConfigured == null &&
button.getBounds().contains(fingerPositionX, fingerPositionY))
{
mButtonBeingConfigured = button;
mButtonBeingConfigured.onConfigureTouch(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (mButtonBeingConfigured != null)
{
mButtonBeingConfigured.onConfigureTouch(event);
invalidate();
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (mButtonBeingConfigured == button)
{
// Persist button position by saving new place.
saveControlPosition(mButtonBeingConfigured.getId(),
mButtonBeingConfigured.getBounds().left,
mButtonBeingConfigured.getBounds().top);
mButtonBeingConfigured = null;
}
break;
}
}
for (InputOverlayDrawableDpad dpad : overlayDpads)
{
// Determine the button state to apply based on the MotionEvent action flag.
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// If no button is being moved now, remember the currently touched button to move.
if (mButtonBeingConfigured == null &&
dpad.getBounds().contains(fingerPositionX, fingerPositionY))
{
mDpadBeingConfigured = dpad;
mDpadBeingConfigured.onConfigureTouch(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (mDpadBeingConfigured != null)
{
mDpadBeingConfigured.onConfigureTouch(event);
invalidate();
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (mDpadBeingConfigured == dpad)
{
// Persist button position by saving new place.
saveControlPosition(mDpadBeingConfigured.getId(0),
mDpadBeingConfigured.getBounds().left, mDpadBeingConfigured.getBounds().top);
mDpadBeingConfigured = null;
}
break;
}
}
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
if (mJoystickBeingConfigured == null &&
joystick.getBounds().contains(fingerPositionX, fingerPositionY))
{
mJoystickBeingConfigured = joystick;
mJoystickBeingConfigured.onConfigureTouch(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (mJoystickBeingConfigured != null)
{
mJoystickBeingConfigured.onConfigureTouch(event);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (mJoystickBeingConfigured != null)
{
saveControlPosition(mJoystickBeingConfigured.getId(),
mJoystickBeingConfigured.getBounds().left,
mJoystickBeingConfigured.getBounds().top);
mJoystickBeingConfigured = null;
}
break;
}
}
return true;
}
private void setDpadState(InputOverlayDrawableDpad dpad, boolean up, boolean down, boolean left,
boolean right)
{
if (up)
{
if (left)
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP_LEFT);
else if (right)
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP_RIGHT);
else
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP);
}
else if (down)
{
if (left)
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN_LEFT);
else if (right)
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN_RIGHT);
else
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN);
}
else if (left)
{
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_LEFT);
}
else if (right)
{
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_RIGHT);
}
}
private void addOverlayControls(String orientation)
{
if (mPreferences.getBoolean("buttonToggle0", true))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_a,
R.drawable.button_a_pressed, ButtonType.BUTTON_A, orientation));
}
if (mPreferences.getBoolean("buttonToggle1", true))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_b,
R.drawable.button_b_pressed, ButtonType.BUTTON_B, orientation));
}
if (mPreferences.getBoolean("buttonToggle2", true))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_x,
R.drawable.button_x_pressed, ButtonType.BUTTON_X, orientation));
}
if (mPreferences.getBoolean("buttonToggle3", true))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_y,
R.drawable.button_y_pressed, ButtonType.BUTTON_Y, orientation));
}
if (mPreferences.getBoolean("buttonToggle4", true))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_l,
R.drawable.button_l_pressed, ButtonType.TRIGGER_L, orientation));
}
if (mPreferences.getBoolean("buttonToggle5", true))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_r,
R.drawable.button_r_pressed, ButtonType.TRIGGER_R, orientation));
}
if (mPreferences.getBoolean("buttonToggle6", false))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_zl,
R.drawable.button_zl_pressed, ButtonType.BUTTON_ZL, orientation));
}
if (mPreferences.getBoolean("buttonToggle7", false))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_zr,
R.drawable.button_zr_pressed, ButtonType.BUTTON_ZR, orientation));
}
if (mPreferences.getBoolean("buttonToggle8", true))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_start,
R.drawable.button_start_pressed, ButtonType.BUTTON_START, orientation));
}
if (mPreferences.getBoolean("buttonToggle9", true))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_select,
R.drawable.button_select_pressed, ButtonType.BUTTON_SELECT, orientation));
}
if (mPreferences.getBoolean("buttonToggle10", true))
{
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_home,
R.drawable.button_home_pressed, ButtonType.BUTTON_HOME, orientation));
}
if (mPreferences.getBoolean("buttonToggle11", false))
{
overlayDpads.add(initializeOverlayDpad(getContext(), R.drawable.dpad,
R.drawable.dpad_pressed_one_direction,
R.drawable.dpad_pressed_two_directions,
ButtonType.DPAD_UP, ButtonType.DPAD_DOWN,
ButtonType.DPAD_LEFT, ButtonType.DPAD_RIGHT, orientation));
}
if (mPreferences.getBoolean("buttonToggle12", true))
{
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.stick_main_range,
R.drawable.stick_main, R.drawable.stick_main_pressed,
ButtonType.STICK_LEFT, orientation));
}
if (mPreferences.getBoolean("buttonToggle13", false))
{
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.stick_main_range,
R.drawable.stick_c, R.drawable.stick_c_pressed, ButtonType.STICK_C, orientation));
}
}
public void refreshControls()
{
// Remove all the overlay buttons from the HashSet.
overlayButtons.removeAll(overlayButtons);
overlayDpads.removeAll(overlayDpads);
overlayJoysticks.removeAll(overlayJoysticks);
String orientation =
getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ?
"-Portrait" : "";
if (mPreferences.getBoolean("showInputOverlay", true))
{
// Add all the enabled overlay items back to the HashSet.
addOverlayControls(orientation);
}
invalidate();
}
private void saveControlPosition(int sharedPrefsId, int x, int y)
{
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor sPrefsEditor = sPrefs.edit();
sPrefsEditor.putFloat(sharedPrefsId + "-X", x);
sPrefsEditor.putFloat(sharedPrefsId + "-Y", y);
sPrefsEditor.apply();
} }
/** /**
@ -544,8 +127,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
* @return An {@link InputOverlayDrawableButton} with the correct drawing bounds set. * @return An {@link InputOverlayDrawableButton} with the correct drawing bounds set.
*/ */
private static InputOverlayDrawableButton initializeOverlayButton(Context context, private static InputOverlayDrawableButton initializeOverlayButton(Context context,
int defaultResId, int pressedResId, int buttonId, String orientation) int defaultResId, int pressedResId, int buttonId, String orientation) {
{
// Resources handle for fetching the initial Drawable resource. // Resources handle for fetching the initial Drawable resource.
final Resources res = context.getResources(); final Resources res = context.getResources();
@ -555,8 +137,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
// Decide scale based on button ID and user preference // Decide scale based on button ID and user preference
float scale; float scale;
switch (buttonId) switch (buttonId) {
{
case ButtonType.BUTTON_HOME: case ButtonType.BUTTON_HOME:
case ButtonType.BUTTON_START: case ButtonType.BUTTON_START:
case ButtonType.BUTTON_SELECT: case ButtonType.BUTTON_SELECT:
@ -629,8 +210,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
int buttonDown, int buttonDown,
int buttonLeft, int buttonLeft,
int buttonRight, int buttonRight,
String orientation) String orientation) {
{
// Resources handle for fetching the initial Drawable resource. // Resources handle for fetching the initial Drawable resource.
final Resources res = context.getResources(); final Resources res = context.getResources();
@ -640,8 +220,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
// Decide scale based on button ID and user preference // Decide scale based on button ID and user preference
float scale; float scale;
switch (buttonUp) switch (buttonUp) {
{
case ButtonType.DPAD_UP: case ButtonType.DPAD_UP:
scale = 0.275f; scale = 0.275f;
break; break;
@ -696,8 +275,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
* @return the initialized {@link InputOverlayDrawableJoystick}. * @return the initialized {@link InputOverlayDrawableJoystick}.
*/ */
private static InputOverlayDrawableJoystick initializeOverlayJoystick(Context context, private static InputOverlayDrawableJoystick initializeOverlayJoystick(Context context,
int resOuter, int defaultResInner, int pressedResInner, int joystick, String orientation) int resOuter, int defaultResInner, int pressedResInner, int joystick, String orientation) {
{
// Resources handle for fetching the initial Drawable resource. // Resources handle for fetching the initial Drawable resource.
final Resources res = context.getResources(); final Resources res = context.getResources();
@ -723,8 +301,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
// Decide inner scale based on joystick ID // Decide inner scale based on joystick ID
float innerScale; float innerScale;
switch (joystick) switch (joystick) {
{
case ButtonType.STICK_C: case ButtonType.STICK_C:
innerScale = 1.833f; innerScale = 1.833f;
break; break;
@ -751,24 +328,369 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
return overlayDrawable; return overlayDrawable;
} }
public void setIsInEditMode(boolean isInEditMode) @Override
{ public void draw(Canvas canvas) {
super.draw(canvas);
for (InputOverlayDrawableButton button : overlayButtons) {
button.draw(canvas);
}
for (InputOverlayDrawableDpad dpad : overlayDpads) {
dpad.draw(canvas);
}
for (InputOverlayDrawableJoystick joystick : overlayJoysticks) {
joystick.draw(canvas);
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (isInEditMode()) {
return onTouchWhileEditing(event);
}
int pointerIndex = event.getActionIndex();
if (mPreferences.getBoolean("isTouchEnabled", true)) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
NativeLibrary.onTouchEvent(event.getX(pointerIndex), event.getY(pointerIndex), true);
break;
case MotionEvent.ACTION_MOVE:
NativeLibrary.onTouchMoved(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// We dont really care where the touch has been released. We only care whether it has been
// released or not.
NativeLibrary.onTouchEvent(0, 0, false);
break;
}
}
for (InputOverlayDrawableButton button : overlayButtons) {
// Determine the button state to apply based on the MotionEvent action flag.
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// If a pointer enters the bounds of a button, press that button.
if (button.getBounds()
.contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) {
button.setPressedState(true);
button.setTrackId(event.getPointerId(pointerIndex));
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(),
ButtonState.PRESSED);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// If a pointer ends, release the button it was pressing.
if (button.getTrackId() == event.getPointerId(pointerIndex)) {
button.setPressedState(false);
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(),
ButtonState.RELEASED);
}
break;
}
}
for (InputOverlayDrawableDpad dpad : overlayDpads) {
// Determine the button state to apply based on the MotionEvent action flag.
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// If a pointer enters the bounds of a button, press that button.
if (dpad.getBounds()
.contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) {
boolean up = false;
boolean down = false;
boolean left = false;
boolean right = false;
if (dpad.getBounds().top + (dpad.getHeight() / 3) > (int) event.getY(pointerIndex)) {
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(0),
ButtonState.PRESSED);
up = true;
}
if (dpad.getBounds().bottom - (dpad.getHeight() / 3) < (int) event.getY(pointerIndex)) {
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(1),
ButtonState.PRESSED);
down = true;
}
if (dpad.getBounds().left + (dpad.getWidth() / 3) > (int) event.getX(pointerIndex)) {
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(2),
ButtonState.PRESSED);
left = true;
}
if (dpad.getBounds().right - (dpad.getWidth() / 3) < (int) event.getX(pointerIndex)) {
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(3),
ButtonState.PRESSED);
right = true;
}
setDpadState(dpad, up, down, left, right);
dpad.setTrackId(event.getPointerId(pointerIndex));
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// If a pointer ends, release the buttons.
if (dpad.getTrackId() == event.getPointerId(pointerIndex)) {
for (int i = 0; i < 4; i++) {
dpad.setState(InputOverlayDrawableDpad.STATE_DEFAULT);
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i),
ButtonState.RELEASED);
}
}
break;
}
}
for (InputOverlayDrawableJoystick joystick : overlayJoysticks) {
joystick.TrackEvent(event);
int axisID = joystick.getId();
float[] axises = joystick.getAxisValues();
NativeLibrary
.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, axisID, axises[0], axises[1]);
}
invalidate();
return true;
}
public boolean onTouchWhileEditing(MotionEvent event) {
int pointerIndex = event.getActionIndex();
int fingerPositionX = (int) event.getX(pointerIndex);
int fingerPositionY = (int) event.getY(pointerIndex);
// Maybe combine Button and Joystick as subclasses of the same parent?
// Or maybe create an interface like IMoveableHUDControl?
for (InputOverlayDrawableButton button : overlayButtons) {
// Determine the button state to apply based on the MotionEvent action flag.
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// If no button is being moved now, remember the currently touched button to move.
if (mButtonBeingConfigured == null &&
button.getBounds().contains(fingerPositionX, fingerPositionY)) {
mButtonBeingConfigured = button;
mButtonBeingConfigured.onConfigureTouch(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (mButtonBeingConfigured != null) {
mButtonBeingConfigured.onConfigureTouch(event);
invalidate();
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (mButtonBeingConfigured == button) {
// Persist button position by saving new place.
saveControlPosition(mButtonBeingConfigured.getId(),
mButtonBeingConfigured.getBounds().left,
mButtonBeingConfigured.getBounds().top);
mButtonBeingConfigured = null;
}
break;
}
}
for (InputOverlayDrawableDpad dpad : overlayDpads) {
// Determine the button state to apply based on the MotionEvent action flag.
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
// If no button is being moved now, remember the currently touched button to move.
if (mButtonBeingConfigured == null &&
dpad.getBounds().contains(fingerPositionX, fingerPositionY)) {
mDpadBeingConfigured = dpad;
mDpadBeingConfigured.onConfigureTouch(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (mDpadBeingConfigured != null) {
mDpadBeingConfigured.onConfigureTouch(event);
invalidate();
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (mDpadBeingConfigured == dpad) {
// Persist button position by saving new place.
saveControlPosition(mDpadBeingConfigured.getId(0),
mDpadBeingConfigured.getBounds().left, mDpadBeingConfigured.getBounds().top);
mDpadBeingConfigured = null;
}
break;
}
}
for (InputOverlayDrawableJoystick joystick : overlayJoysticks) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
if (mJoystickBeingConfigured == null &&
joystick.getBounds().contains(fingerPositionX, fingerPositionY)) {
mJoystickBeingConfigured = joystick;
mJoystickBeingConfigured.onConfigureTouch(event);
}
break;
case MotionEvent.ACTION_MOVE:
if (mJoystickBeingConfigured != null) {
mJoystickBeingConfigured.onConfigureTouch(event);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (mJoystickBeingConfigured != null) {
saveControlPosition(mJoystickBeingConfigured.getId(),
mJoystickBeingConfigured.getBounds().left,
mJoystickBeingConfigured.getBounds().top);
mJoystickBeingConfigured = null;
}
break;
}
}
return true;
}
private void setDpadState(InputOverlayDrawableDpad dpad, boolean up, boolean down, boolean left,
boolean right) {
if (up) {
if (left)
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP_LEFT);
else if (right)
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP_RIGHT);
else
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP);
} else if (down) {
if (left)
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN_LEFT);
else if (right)
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN_RIGHT);
else
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN);
} else if (left) {
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_LEFT);
} else if (right) {
dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_RIGHT);
}
}
private void addOverlayControls(String orientation) {
if (mPreferences.getBoolean("buttonToggle0", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_a,
R.drawable.button_a_pressed, ButtonType.BUTTON_A, orientation));
}
if (mPreferences.getBoolean("buttonToggle1", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_b,
R.drawable.button_b_pressed, ButtonType.BUTTON_B, orientation));
}
if (mPreferences.getBoolean("buttonToggle2", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_x,
R.drawable.button_x_pressed, ButtonType.BUTTON_X, orientation));
}
if (mPreferences.getBoolean("buttonToggle3", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_y,
R.drawable.button_y_pressed, ButtonType.BUTTON_Y, orientation));
}
if (mPreferences.getBoolean("buttonToggle4", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_l,
R.drawable.button_l_pressed, ButtonType.TRIGGER_L, orientation));
}
if (mPreferences.getBoolean("buttonToggle5", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_r,
R.drawable.button_r_pressed, ButtonType.TRIGGER_R, orientation));
}
if (mPreferences.getBoolean("buttonToggle6", false)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_zl,
R.drawable.button_zl_pressed, ButtonType.BUTTON_ZL, orientation));
}
if (mPreferences.getBoolean("buttonToggle7", false)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_zr,
R.drawable.button_zr_pressed, ButtonType.BUTTON_ZR, orientation));
}
if (mPreferences.getBoolean("buttonToggle8", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_start,
R.drawable.button_start_pressed, ButtonType.BUTTON_START, orientation));
}
if (mPreferences.getBoolean("buttonToggle9", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_select,
R.drawable.button_select_pressed, ButtonType.BUTTON_SELECT, orientation));
}
if (mPreferences.getBoolean("buttonToggle10", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_home,
R.drawable.button_home_pressed, ButtonType.BUTTON_HOME, orientation));
}
if (mPreferences.getBoolean("buttonToggle11", false)) {
overlayDpads.add(initializeOverlayDpad(getContext(), R.drawable.dpad,
R.drawable.dpad_pressed_one_direction,
R.drawable.dpad_pressed_two_directions,
ButtonType.DPAD_UP, ButtonType.DPAD_DOWN,
ButtonType.DPAD_LEFT, ButtonType.DPAD_RIGHT, orientation));
}
if (mPreferences.getBoolean("buttonToggle12", true)) {
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.stick_main_range,
R.drawable.stick_main, R.drawable.stick_main_pressed,
ButtonType.STICK_LEFT, orientation));
}
if (mPreferences.getBoolean("buttonToggle13", false)) {
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.stick_main_range,
R.drawable.stick_c, R.drawable.stick_c_pressed, ButtonType.STICK_C, orientation));
}
}
public void refreshControls() {
// Remove all the overlay buttons from the HashSet.
overlayButtons.removeAll(overlayButtons);
overlayDpads.removeAll(overlayDpads);
overlayJoysticks.removeAll(overlayJoysticks);
String orientation =
getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ?
"-Portrait" : "";
if (mPreferences.getBoolean("showInputOverlay", true)) {
// Add all the enabled overlay items back to the HashSet.
addOverlayControls(orientation);
}
invalidate();
}
private void saveControlPosition(int sharedPrefsId, int x, int y) {
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor sPrefsEditor = sPrefs.edit();
sPrefsEditor.putFloat(sharedPrefsId + "-X", x);
sPrefsEditor.putFloat(sharedPrefsId + "-Y", y);
sPrefsEditor.apply();
}
public void setIsInEditMode(boolean isInEditMode) {
mIsInEditMode = isInEditMode; mIsInEditMode = isInEditMode;
} }
private void defaultOverlay() private void defaultOverlay() {
{ if (!mPreferences.getBoolean("OverlayInit", false)) {
if (!mPreferences.getBoolean("OverlayInit", false))
{
// It's possible that a user has created their overlay before this was added // It's possible that a user has created their overlay before this was added
// Only change the overlay if the 'A' button is not in the upper corner. // Only change the overlay if the 'A' button is not in the upper corner.
// GameCube // GameCube
if (mPreferences.getFloat(ButtonType.BUTTON_A + "-X", 0f) == 0f) if (mPreferences.getFloat(ButtonType.BUTTON_A + "-X", 0f) == 0f) {
{
defaultOverlayLandscape(); defaultOverlayLandscape();
} }
if (mPreferences.getFloat(ButtonType.BUTTON_A + "-Portrait" + "-X", 0f) == 0f) if (mPreferences.getFloat(ButtonType.BUTTON_A + "-Portrait" + "-X", 0f) == 0f) {
{
defaultOverlayPortrait(); defaultOverlayPortrait();
} }
} }
@ -778,23 +700,20 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
sPrefsEditor.apply(); sPrefsEditor.apply();
} }
public void resetButtonPlacement() public void resetButtonPlacement() {
{
boolean isLandscape = boolean isLandscape =
getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
if (isLandscape) { if (isLandscape) {
defaultOverlayLandscape(); defaultOverlayLandscape();
} } else {
else {
defaultOverlayPortrait(); defaultOverlayPortrait();
} }
refreshControls(); refreshControls();
} }
private void defaultOverlayLandscape() private void defaultOverlayLandscape() {
{
SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); SharedPreferences.Editor sPrefsEditor = mPreferences.edit();
// Get screen size // Get screen size
Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay();
@ -803,8 +722,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
float maxX = outMetrics.heightPixels; float maxX = outMetrics.heightPixels;
float maxY = outMetrics.widthPixels; float maxY = outMetrics.widthPixels;
// Height and width changes depending on orientation. Use the larger value for height. // Height and width changes depending on orientation. Use the larger value for height.
if (maxY > maxX) if (maxY > maxX) {
{
float tmp = maxX; float tmp = maxX;
maxX = maxY; maxX = maxY;
maxY = tmp; maxY = tmp;
@ -846,8 +764,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
sPrefsEditor.commit(); sPrefsEditor.commit();
} }
private void defaultOverlayPortrait() private void defaultOverlayPortrait() {
{
SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); SharedPreferences.Editor sPrefsEditor = mPreferences.edit();
// Get screen size // Get screen size
Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay();
@ -856,8 +773,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
float maxX = outMetrics.heightPixels; float maxX = outMetrics.heightPixels;
float maxY = outMetrics.widthPixels; float maxY = outMetrics.widthPixels;
// Height and width changes depending on orientation. Use the larger value for height. // Height and width changes depending on orientation. Use the larger value for height.
if (maxY < maxX) if (maxY < maxX) {
{
float tmp = maxX; float tmp = maxX;
maxX = maxY; maxX = maxY;
maxY = tmp; maxY = tmp;
@ -900,8 +816,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
sPrefsEditor.commit(); sPrefsEditor.commit();
} }
public boolean isInEditMode() public boolean isInEditMode() {
{
return mIsInEditMode; return mIsInEditMode;
} }
} }

View File

@ -17,8 +17,7 @@ import android.view.MotionEvent;
* Custom {@link BitmapDrawable} that is capable * Custom {@link BitmapDrawable} that is capable
* of storing it's own ID. * of storing it's own ID.
*/ */
public final class InputOverlayDrawableButton public final class InputOverlayDrawableButton {
{
// The ID identifying what type of button this Drawable represents. // The ID identifying what type of button this Drawable represents.
private int mButtonType; private int mButtonType;
private int mTrackId; private int mTrackId;
@ -39,8 +38,7 @@ public final class InputOverlayDrawableButton
* @param buttonType Identifier for this type of button. * @param buttonType Identifier for this type of button.
*/ */
public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap, public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap,
Bitmap pressedStateBitmap, int buttonType) Bitmap pressedStateBitmap, int buttonType) {
{
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap); mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap); mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap);
mButtonType = buttonType; mButtonType = buttonType;
@ -54,28 +52,23 @@ public final class InputOverlayDrawableButton
* *
* @return this InputOverlayDrawableButton's button ID. * @return this InputOverlayDrawableButton's button ID.
*/ */
public int getId() public int getId() {
{
return mButtonType; return mButtonType;
} }
public void setTrackId(int trackId) public int getTrackId() {
{
mTrackId = trackId;
}
public int getTrackId()
{
return mTrackId; return mTrackId;
} }
public boolean onConfigureTouch(MotionEvent event) public void setTrackId(int trackId) {
{ mTrackId = trackId;
}
public boolean onConfigureTouch(MotionEvent event) {
int pointerIndex = event.getActionIndex(); int pointerIndex = event.getActionIndex();
int fingerPositionX = (int) event.getX(pointerIndex); int fingerPositionX = (int) event.getX(pointerIndex);
int fingerPositionY = (int) event.getY(pointerIndex); int fingerPositionY = (int) event.getY(pointerIndex);
switch (event.getAction()) switch (event.getAction()) {
{
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
mPreviousTouchX = fingerPositionX; mPreviousTouchX = fingerPositionX;
mPreviousTouchY = fingerPositionY; mPreviousTouchY = fingerPositionY;
@ -93,45 +86,37 @@ public final class InputOverlayDrawableButton
return true; return true;
} }
public void setPosition(int x, int y) public void setPosition(int x, int y) {
{
mControlPositionX = x; mControlPositionX = x;
mControlPositionY = y; mControlPositionY = y;
} }
public void draw(Canvas canvas) public void draw(Canvas canvas) {
{
getCurrentStateBitmapDrawable().draw(canvas); getCurrentStateBitmapDrawable().draw(canvas);
} }
private BitmapDrawable getCurrentStateBitmapDrawable() private BitmapDrawable getCurrentStateBitmapDrawable() {
{
return mPressedState ? mPressedStateBitmap : mDefaultStateBitmap; return mPressedState ? mPressedStateBitmap : mDefaultStateBitmap;
} }
public void setBounds(int left, int top, int right, int bottom) public void setBounds(int left, int top, int right, int bottom) {
{
mDefaultStateBitmap.setBounds(left, top, right, bottom); mDefaultStateBitmap.setBounds(left, top, right, bottom);
mPressedStateBitmap.setBounds(left, top, right, bottom); mPressedStateBitmap.setBounds(left, top, right, bottom);
} }
public Rect getBounds() public Rect getBounds() {
{
return mDefaultStateBitmap.getBounds(); return mDefaultStateBitmap.getBounds();
} }
public int getWidth() public int getWidth() {
{
return mWidth; return mWidth;
} }
public int getHeight() public int getHeight() {
{
return mHeight; return mHeight;
} }
public void setPressedState(boolean isPressed) public void setPressedState(boolean isPressed) {
{
mPressedState = isPressed; mPressedState = isPressed;
} }
} }

View File

@ -17,8 +17,16 @@ import android.view.MotionEvent;
* Custom {@link BitmapDrawable} that is capable * Custom {@link BitmapDrawable} that is capable
* of storing it's own ID. * of storing it's own ID.
*/ */
public final class InputOverlayDrawableDpad public final class InputOverlayDrawableDpad {
{ public static final int STATE_DEFAULT = 0;
public static final int STATE_PRESSED_UP = 1;
public static final int STATE_PRESSED_DOWN = 2;
public static final int STATE_PRESSED_LEFT = 3;
public static final int STATE_PRESSED_RIGHT = 4;
public static final int STATE_PRESSED_UP_LEFT = 5;
public static final int STATE_PRESSED_UP_RIGHT = 6;
public static final int STATE_PRESSED_DOWN_LEFT = 7;
public static final int STATE_PRESSED_DOWN_RIGHT = 8;
// The ID identifying what type of button this Drawable represents. // The ID identifying what type of button this Drawable represents.
private int[] mButtonType = new int[4]; private int[] mButtonType = new int[4];
private int mTrackId; private int mTrackId;
@ -31,16 +39,6 @@ public final class InputOverlayDrawableDpad
private BitmapDrawable mPressedTwoDirectionsStateBitmap; private BitmapDrawable mPressedTwoDirectionsStateBitmap;
private int mPressState = STATE_DEFAULT; private int mPressState = STATE_DEFAULT;
public static final int STATE_DEFAULT = 0;
public static final int STATE_PRESSED_UP = 1;
public static final int STATE_PRESSED_DOWN = 2;
public static final int STATE_PRESSED_LEFT = 3;
public static final int STATE_PRESSED_RIGHT = 4;
public static final int STATE_PRESSED_UP_LEFT = 5;
public static final int STATE_PRESSED_UP_RIGHT = 6;
public static final int STATE_PRESSED_DOWN_LEFT = 7;
public static final int STATE_PRESSED_DOWN_RIGHT = 8;
/** /**
* Constructor * Constructor
* *
@ -58,8 +56,7 @@ public final class InputOverlayDrawableDpad
Bitmap pressedOneDirectionStateBitmap, Bitmap pressedOneDirectionStateBitmap,
Bitmap pressedTwoDirectionsStateBitmap, Bitmap pressedTwoDirectionsStateBitmap,
int buttonUp, int buttonDown, int buttonUp, int buttonDown,
int buttonLeft, int buttonRight) int buttonLeft, int buttonRight) {
{
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap); mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
mPressedOneDirectionStateBitmap = new BitmapDrawable(res, pressedOneDirectionStateBitmap); mPressedOneDirectionStateBitmap = new BitmapDrawable(res, pressedOneDirectionStateBitmap);
mPressedTwoDirectionsStateBitmap = new BitmapDrawable(res, pressedTwoDirectionsStateBitmap); mPressedTwoDirectionsStateBitmap = new BitmapDrawable(res, pressedTwoDirectionsStateBitmap);
@ -73,12 +70,10 @@ public final class InputOverlayDrawableDpad
mButtonType[3] = buttonRight; mButtonType[3] = buttonRight;
} }
public void draw(Canvas canvas) public void draw(Canvas canvas) {
{
int px = mControlPositionX + (getWidth() / 2); int px = mControlPositionX + (getWidth() / 2);
int py = mControlPositionY + (getHeight() / 2); int py = mControlPositionY + (getHeight() / 2);
switch (mPressState) switch (mPressState) {
{
case STATE_DEFAULT: case STATE_DEFAULT:
mDefaultStateBitmap.draw(canvas); mDefaultStateBitmap.draw(canvas);
break; break;
@ -132,28 +127,23 @@ public final class InputOverlayDrawableDpad
* *
* @return the requested InputOverlayDrawableDpad's button ID. * @return the requested InputOverlayDrawableDpad's button ID.
*/ */
public int getId(int direction) public int getId(int direction) {
{
return mButtonType[direction]; return mButtonType[direction];
} }
public void setTrackId(int trackId) public int getTrackId() {
{
mTrackId = trackId;
}
public int getTrackId()
{
return mTrackId; return mTrackId;
} }
public boolean onConfigureTouch(MotionEvent event) public void setTrackId(int trackId) {
{ mTrackId = trackId;
}
public boolean onConfigureTouch(MotionEvent event) {
int pointerIndex = event.getActionIndex(); int pointerIndex = event.getActionIndex();
int fingerPositionX = (int) event.getX(pointerIndex); int fingerPositionX = (int) event.getX(pointerIndex);
int fingerPositionY = (int) event.getY(pointerIndex); int fingerPositionY = (int) event.getY(pointerIndex);
switch (event.getAction()) switch (event.getAction()) {
{
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
mPreviousTouchX = fingerPositionX; mPreviousTouchX = fingerPositionX;
mPreviousTouchY = fingerPositionY; mPreviousTouchY = fingerPositionY;
@ -171,36 +161,30 @@ public final class InputOverlayDrawableDpad
return true; return true;
} }
public void setPosition(int x, int y) public void setPosition(int x, int y) {
{
mControlPositionX = x; mControlPositionX = x;
mControlPositionY = y; mControlPositionY = y;
} }
public void setBounds(int left, int top, int right, int bottom) public void setBounds(int left, int top, int right, int bottom) {
{
mDefaultStateBitmap.setBounds(left, top, right, bottom); mDefaultStateBitmap.setBounds(left, top, right, bottom);
mPressedOneDirectionStateBitmap.setBounds(left, top, right, bottom); mPressedOneDirectionStateBitmap.setBounds(left, top, right, bottom);
mPressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom); mPressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom);
} }
public Rect getBounds() public Rect getBounds() {
{
return mDefaultStateBitmap.getBounds(); return mDefaultStateBitmap.getBounds();
} }
public int getWidth() public int getWidth() {
{
return mWidth; return mWidth;
} }
public int getHeight() public int getHeight() {
{
return mHeight; return mHeight;
} }
public void setState(int pressState) public void setState(int pressState) {
{
mPressState = pressState; mPressState = pressState;
} }
} }

View File

@ -17,8 +17,7 @@ import android.view.MotionEvent;
* Custom {@link BitmapDrawable} that is capable * Custom {@link BitmapDrawable} that is capable
* of storing it's own ID. * of storing it's own ID.
*/ */
public final class InputOverlayDrawableJoystick public final class InputOverlayDrawableJoystick {
{
private final int[] axisIDs = {0, 0, 0, 0}; private final int[] axisIDs = {0, 0, 0, 0};
private final float[] axises = {0f, 0f}; private final float[] axises = {0f, 0f};
private int trackId = -1; private int trackId = -1;
@ -48,8 +47,7 @@ public final class InputOverlayDrawableJoystick
*/ */
public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter, public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter,
Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed, Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed,
Rect rectOuter, Rect rectInner, int joystick) Rect rectOuter, Rect rectInner, int joystick) {
{
axisIDs[0] = joystick + 1; // Up axisIDs[0] = joystick + 1; // Up
axisIDs[1] = joystick + 2; // Down axisIDs[1] = joystick + 2; // Down
axisIDs[2] = joystick + 3; // Left axisIDs[2] = joystick + 3; // Left
@ -78,28 +76,23 @@ public final class InputOverlayDrawableJoystick
* *
* @return this InputOverlayDrawableJoystick's button ID. * @return this InputOverlayDrawableJoystick's button ID.
*/ */
public int getId() public int getId() {
{
return mJoystickType; return mJoystickType;
} }
public void draw(Canvas canvas) public void draw(Canvas canvas) {
{
mOuterBitmap.draw(canvas); mOuterBitmap.draw(canvas);
getCurrentStateBitmapDrawable().draw(canvas); getCurrentStateBitmapDrawable().draw(canvas);
mBoundsBoxBitmap.draw(canvas); mBoundsBoxBitmap.draw(canvas);
} }
public void TrackEvent(MotionEvent event) public void TrackEvent(MotionEvent event) {
{
int pointerIndex = event.getActionIndex(); int pointerIndex = event.getActionIndex();
switch (event.getAction() & MotionEvent.ACTION_MASK) switch (event.getAction() & MotionEvent.ACTION_MASK) {
{
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_POINTER_DOWN:
if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) {
{
mPressedState = true; mPressedState = true;
mOuterBitmap.setAlpha(0); mOuterBitmap.setAlpha(0);
mBoundsBoxBitmap.setAlpha(255); mBoundsBoxBitmap.setAlpha(255);
@ -111,8 +104,7 @@ public final class InputOverlayDrawableJoystick
break; break;
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_UP:
if (trackId == event.getPointerId(pointerIndex)) if (trackId == event.getPointerId(pointerIndex)) {
{
mPressedState = false; mPressedState = false;
axises[0] = axises[1] = 0.0f; axises[0] = axises[1] = 0.0f;
mOuterBitmap.setAlpha(255); mOuterBitmap.setAlpha(255);
@ -130,10 +122,8 @@ public final class InputOverlayDrawableJoystick
if (trackId == -1) if (trackId == -1)
return; return;
for (int i = 0; i < event.getPointerCount(); i++) for (int i = 0; i < event.getPointerCount(); i++) {
{ if (trackId == event.getPointerId(i)) {
if (trackId == event.getPointerId(i))
{
float touchX = event.getX(i); float touchX = event.getX(i);
float touchY = event.getY(i); float touchY = event.getY(i);
float maxY = getVirtBounds().bottom; float maxY = getVirtBounds().bottom;
@ -152,13 +142,11 @@ public final class InputOverlayDrawableJoystick
} }
} }
public boolean onConfigureTouch(MotionEvent event) public boolean onConfigureTouch(MotionEvent event) {
{
int pointerIndex = event.getActionIndex(); int pointerIndex = event.getActionIndex();
int fingerPositionX = (int) event.getX(pointerIndex); int fingerPositionX = (int) event.getX(pointerIndex);
int fingerPositionY = (int) event.getY(pointerIndex); int fingerPositionY = (int) event.getY(pointerIndex);
switch (event.getAction()) switch (event.getAction()) {
{
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
mPreviousTouchX = fingerPositionX; mPreviousTouchX = fingerPositionX;
mPreviousTouchY = fingerPositionY; mPreviousTouchY = fingerPositionY;
@ -186,18 +174,15 @@ public final class InputOverlayDrawableJoystick
} }
public float[] getAxisValues() public float[] getAxisValues() {
{
return axises; return axises;
} }
public int[] getAxisIDs() public int[] getAxisIDs() {
{
return axisIDs; return axisIDs;
} }
private void SetInnerBounds() private void SetInnerBounds() {
{
int X = getVirtBounds().centerX() + (int) ((axises[0]) * (getVirtBounds().width() / 2)); int X = getVirtBounds().centerX() + (int) ((axises[0]) * (getVirtBounds().width() / 2));
int Y = getVirtBounds().centerY() + (int) ((axises[1]) * (getVirtBounds().height() / 2)); int Y = getVirtBounds().centerY() + (int) ((axises[1]) * (getVirtBounds().height() / 2));
@ -216,49 +201,40 @@ public final class InputOverlayDrawableJoystick
mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds()); mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds());
} }
public void setPosition(int x, int y) public void setPosition(int x, int y) {
{
mControlPositionX = x; mControlPositionX = x;
mControlPositionY = y; mControlPositionY = y;
} }
private BitmapDrawable getCurrentStateBitmapDrawable() private BitmapDrawable getCurrentStateBitmapDrawable() {
{
return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap; return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap;
} }
public void setBounds(Rect bounds) public Rect getBounds() {
{
mOuterBitmap.setBounds(bounds);
}
public Rect getBounds()
{
return mOuterBitmap.getBounds(); return mOuterBitmap.getBounds();
} }
private void setVirtBounds(Rect bounds) public void setBounds(Rect bounds) {
{ mOuterBitmap.setBounds(bounds);
mVirtBounds = bounds;
} }
private void setOrigBounds(Rect bounds) private void setOrigBounds(Rect bounds) {
{
mOrigBounds = bounds; mOrigBounds = bounds;
} }
private Rect getVirtBounds() private Rect getVirtBounds() {
{
return mVirtBounds; return mVirtBounds;
} }
public int getWidth() private void setVirtBounds(Rect bounds) {
{ mVirtBounds = bounds;
}
public int getWidth() {
return mWidth; return mWidth;
} }
public int getHeight() public int getHeight() {
{
return mHeight; return mHeight;
} }
} }

View File

@ -30,8 +30,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* A service that spawns its own thread in order to copy several binary and shader files * A service that spawns its own thread in order to copy several binary and shader files
* from the Dolphin APK to the external file system. * from the Dolphin APK to the external file system.
*/ */
public final class DirectoryInitializationService extends IntentService public final class DirectoryInitializationService extends IntentService {
{
public static final String BROADCAST_ACTION = "org.citra.citra_android.BROADCAST"; public static final String BROADCAST_ACTION = "org.citra.citra_android.BROADCAST";
public static final String EXTRA_STATE = "directoryState"; public static final String EXTRA_STATE = "directoryState";
@ -39,48 +38,58 @@ public final class DirectoryInitializationService extends IntentService
private static String userPath; private static String userPath;
private static AtomicBoolean isDolphinDirectoryInitializationRunning = new AtomicBoolean(false); private static AtomicBoolean isDolphinDirectoryInitializationRunning = new AtomicBoolean(false);
public enum DirectoryInitializationState public DirectoryInitializationService() {
{
DOLPHIN_DIRECTORIES_INITIALIZED,
EXTERNAL_STORAGE_PERMISSION_NEEDED,
CANT_FIND_EXTERNAL_STORAGE
}
public DirectoryInitializationService()
{
// Superclass constructor is called to name the thread on which this service executes. // Superclass constructor is called to name the thread on which this service executes.
super("DirectoryInitializationService"); super("DirectoryInitializationService");
} }
public static void startService(Context context) public static void startService(Context context) {
{
Intent intent = new Intent(context, DirectoryInitializationService.class); Intent intent = new Intent(context, DirectoryInitializationService.class);
context.startService(intent); context.startService(intent);
} }
private static void deleteDirectoryRecursively(File file) {
if (file.isDirectory()) {
for (File child : file.listFiles())
deleteDirectoryRecursively(child);
}
file.delete();
}
public static boolean areDolphinDirectoriesReady() {
return directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
}
public static String getUserDirectory() {
if (directoryState == null) {
throw new IllegalStateException("DirectoryInitializationService has to run at least once!");
} else if (isDolphinDirectoryInitializationRunning.get()) {
throw new IllegalStateException(
"DirectoryInitializationService has to finish running first!");
}
return userPath;
}
private static native void CreateUserDirectories();
private static native void SetSysDirectory(String path);
@Override @Override
protected void onHandleIntent(Intent intent) protected void onHandleIntent(Intent intent) {
{
isDolphinDirectoryInitializationRunning.set(true); isDolphinDirectoryInitializationRunning.set(true);
if (directoryState != DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) if (directoryState != DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) {
{ if (PermissionsHandler.hasWriteAccess(this)) {
if (PermissionsHandler.hasWriteAccess(this)) if (setDolphinUserDirectory()) {
{
if (setDolphinUserDirectory())
{
initializeInternalStorage(); initializeInternalStorage();
CreateUserDirectories(); CreateUserDirectories();
NativeLibrary.CreateConfigFile(); NativeLibrary.CreateConfigFile();
directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED; directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
} } else {
else
{
directoryState = DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE; directoryState = DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE;
} }
} } else {
else
{
directoryState = DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED; directoryState = DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED;
} }
} }
@ -89,13 +98,10 @@ public final class DirectoryInitializationService extends IntentService
sendBroadcastState(directoryState); sendBroadcastState(directoryState);
} }
private boolean setDolphinUserDirectory() private boolean setDolphinUserDirectory() {
{ if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
File externalPath = Environment.getExternalStorageDirectory(); File externalPath = Environment.getExternalStorageDirectory();
if (externalPath != null) if (externalPath != null) {
{
userPath = externalPath.getAbsolutePath() + "/citra-emu"; userPath = externalPath.getAbsolutePath() + "/citra-emu";
Log.debug("[DirectoryInitializationService] User Dir: " + userPath); Log.debug("[DirectoryInitializationService] User Dir: " + userPath);
// NativeLibrary.SetUserDirectory(userPath); // NativeLibrary.SetUserDirectory(userPath);
@ -107,14 +113,12 @@ public final class DirectoryInitializationService extends IntentService
return false; return false;
} }
private void initializeInternalStorage() private void initializeInternalStorage() {
{
File sysDirectory = new File(getFilesDir(), "Sys"); File sysDirectory = new File(getFilesDir(), "Sys");
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
String revision = NativeLibrary.GetGitRevision(); String revision = NativeLibrary.GetGitRevision();
if (!preferences.getString("sysDirectoryVersion", "").equals(revision)) if (!preferences.getString("sysDirectoryVersion", "").equals(revision)) {
{
// There is no extracted Sys directory, or there is a Sys directory from another // There is no extracted Sys directory, or there is a Sys directory from another
// version of Dolphin that might contain outdated files. Let's (re-)extract Sys. // version of Dolphin that might contain outdated files. Let's (re-)extract Sys.
deleteDirectoryRecursively(sysDirectory); deleteDirectoryRecursively(sysDirectory);
@ -129,78 +133,38 @@ public final class DirectoryInitializationService extends IntentService
SetSysDirectory(sysDirectory.getPath()); SetSysDirectory(sysDirectory.getPath());
} }
private static void deleteDirectoryRecursively(File file) private void sendBroadcastState(DirectoryInitializationState state) {
{
if (file.isDirectory())
{
for (File child : file.listFiles())
deleteDirectoryRecursively(child);
}
file.delete();
}
public static boolean areDolphinDirectoriesReady()
{
return directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
}
public static String getUserDirectory()
{
if (directoryState == null)
{
throw new IllegalStateException("DirectoryInitializationService has to run at least once!");
}
else if (isDolphinDirectoryInitializationRunning.get())
{
throw new IllegalStateException(
"DirectoryInitializationService has to finish running first!");
}
return userPath;
}
private void sendBroadcastState(DirectoryInitializationState state)
{
Intent localIntent = Intent localIntent =
new Intent(BROADCAST_ACTION) new Intent(BROADCAST_ACTION)
.putExtra(EXTRA_STATE, state); .putExtra(EXTRA_STATE, state);
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
} }
private void copyAsset(String asset, File output, Boolean overwrite) private void copyAsset(String asset, File output, Boolean overwrite) {
{
Log.verbose("[DirectoryInitializationService] Copying File " + asset + " to " + output); Log.verbose("[DirectoryInitializationService] Copying File " + asset + " to " + output);
try try {
{ if (!output.exists() || overwrite) {
if (!output.exists() || overwrite)
{
InputStream in = getAssets().open(asset); InputStream in = getAssets().open(asset);
OutputStream out = new FileOutputStream(output); OutputStream out = new FileOutputStream(output);
copyFile(in, out); copyFile(in, out);
in.close(); in.close();
out.close(); out.close();
} }
} } catch (IOException e) {
catch (IOException e)
{
Log.error("[DirectoryInitializationService] Failed to copy asset file: " + asset + Log.error("[DirectoryInitializationService] Failed to copy asset file: " + asset +
e.getMessage()); e.getMessage());
} }
} }
private void copyAssetFolder(String assetFolder, File outputFolder, Boolean overwrite) private void copyAssetFolder(String assetFolder, File outputFolder, Boolean overwrite) {
{
Log.verbose("[DirectoryInitializationService] Copying Folder " + assetFolder + " to " + Log.verbose("[DirectoryInitializationService] Copying Folder " + assetFolder + " to " +
outputFolder); outputFolder);
try try {
{
boolean createdFolder = false; boolean createdFolder = false;
for (String file : getAssets().list(assetFolder)) for (String file : getAssets().list(assetFolder)) {
{ if (!createdFolder) {
if (!createdFolder)
{
outputFolder.mkdir(); outputFolder.mkdir();
createdFolder = true; createdFolder = true;
} }
@ -208,26 +172,24 @@ public final class DirectoryInitializationService extends IntentService
overwrite); overwrite);
copyAsset(assetFolder + File.separator + file, new File(outputFolder, file), overwrite); copyAsset(assetFolder + File.separator + file, new File(outputFolder, file), overwrite);
} }
} } catch (IOException e) {
catch (IOException e)
{
Log.error("[DirectoryInitializationService] Failed to copy asset folder: " + assetFolder + Log.error("[DirectoryInitializationService] Failed to copy asset folder: " + assetFolder +
e.getMessage()); e.getMessage());
} }
} }
private void copyFile(InputStream in, OutputStream out) throws IOException private void copyFile(InputStream in, OutputStream out) throws IOException {
{
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
int read; int read;
while ((read = in.read(buffer)) != -1) while ((read = in.read(buffer)) != -1) {
{
out.write(buffer, 0, read); out.write(buffer, 0, read);
} }
} }
private static native void CreateUserDirectories(); public enum DirectoryInitializationState {
DOLPHIN_DIRECTORIES_INITIALIZED,
private static native void SetSysDirectory(String path); EXTERNAL_STORAGE_PERMISSION_NEEDED,
CANT_FIND_EXTERNAL_STORAGE
}
} }

View File

@ -3,17 +3,14 @@ package org.citra.citra_android.services;
import android.app.IntentService; import android.app.IntentService;
import android.content.Intent; import android.content.Intent;
public final class USBPermService extends IntentService public final class USBPermService extends IntentService {
{ public USBPermService() {
public USBPermService()
{
super("USBPermService"); super("USBPermService");
} }
// Needed when extending IntentService. // Needed when extending IntentService.
// We don't care about the results of the intent handler for this. // We don't care about the results of the intent handler for this.
@Override @Override
protected void onHandleIntent(Intent intent) protected void onHandleIntent(Intent intent) {
{
} }
} }

View File

@ -14,16 +14,14 @@ import android.view.View;
* Implementation from: * Implementation from:
* https://gist.github.com/lapastillaroja/858caf1a82791b6c1a36 * https://gist.github.com/lapastillaroja/858caf1a82791b6c1a36
*/ */
public final class DividerItemDecoration extends RecyclerView.ItemDecoration public final class DividerItemDecoration extends RecyclerView.ItemDecoration {
{
private Drawable mDivider; private Drawable mDivider;
private boolean mShowFirstDivider = false; private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false; private boolean mShowLastDivider = false;
public DividerItemDecoration(Context context, AttributeSet attrs) public DividerItemDecoration(Context context, AttributeSet attrs) {
{
final TypedArray a = context final TypedArray a = context
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider}); .obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
mDivider = a.getDrawable(0); mDivider = a.getDrawable(0);
@ -31,21 +29,18 @@ public final class DividerItemDecoration extends RecyclerView.ItemDecoration
} }
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider, public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
boolean showLastDivider) boolean showLastDivider) {
{
this(context, attrs); this(context, attrs);
mShowFirstDivider = showFirstDivider; mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider; mShowLastDivider = showLastDivider;
} }
public DividerItemDecoration(Drawable divider) public DividerItemDecoration(Drawable divider) {
{
mDivider = divider; mDivider = divider;
} }
public DividerItemDecoration(Drawable divider, boolean showFirstDivider, public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
boolean showLastDivider) boolean showLastDivider) {
{
this(divider); this(divider);
mShowFirstDivider = showFirstDivider; mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider; mShowLastDivider = showLastDivider;
@ -53,33 +48,25 @@ public final class DividerItemDecoration extends RecyclerView.ItemDecoration
@Override @Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) RecyclerView.State state) {
{
super.getItemOffsets(outRect, view, parent, state); super.getItemOffsets(outRect, view, parent, state);
if (mDivider == null) if (mDivider == null) {
{
return; return;
} }
if (parent.getChildPosition(view) < 1) if (parent.getChildPosition(view) < 1) {
{
return; return;
} }
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
{
outRect.top = mDivider.getIntrinsicHeight(); outRect.top = mDivider.getIntrinsicHeight();
} } else {
else
{
outRect.left = mDivider.getIntrinsicWidth(); outRect.left = mDivider.getIntrinsicWidth();
} }
} }
@Override @Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
{ if (mDivider == null) {
if (mDivider == null)
{
super.onDrawOver(c, parent, state); super.onDrawOver(c, parent, state);
return; return;
} }
@ -89,31 +76,24 @@ public final class DividerItemDecoration extends RecyclerView.ItemDecoration
int orientation = getOrientation(parent); int orientation = getOrientation(parent);
int childCount = parent.getChildCount(); int childCount = parent.getChildCount();
if (orientation == LinearLayoutManager.VERTICAL) if (orientation == LinearLayoutManager.VERTICAL) {
{
size = mDivider.getIntrinsicHeight(); size = mDivider.getIntrinsicHeight();
left = parent.getPaddingLeft(); left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight(); right = parent.getWidth() - parent.getPaddingRight();
} } else { //horizontal
else
{ //horizontal
size = mDivider.getIntrinsicWidth(); size = mDivider.getIntrinsicWidth();
top = parent.getPaddingTop(); top = parent.getPaddingTop();
bottom = parent.getHeight() - parent.getPaddingBottom(); bottom = parent.getHeight() - parent.getPaddingBottom();
} }
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
{
View child = parent.getChildAt(i); View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) if (orientation == LinearLayoutManager.VERTICAL) {
{
top = child.getTop() - params.topMargin; top = child.getTop() - params.topMargin;
bottom = top + size; bottom = top + size;
} } else { //horizontal
else
{ //horizontal
left = child.getLeft() - params.leftMargin; left = child.getLeft() - params.leftMargin;
right = left + size; right = left + size;
} }
@ -122,17 +102,13 @@ public final class DividerItemDecoration extends RecyclerView.ItemDecoration
} }
// show last divider // show last divider
if (mShowLastDivider && childCount > 0) if (mShowLastDivider && childCount > 0) {
{
View child = parent.getChildAt(childCount - 1); View child = parent.getChildAt(childCount - 1);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) if (orientation == LinearLayoutManager.VERTICAL) {
{
top = child.getBottom() + params.bottomMargin; top = child.getBottom() + params.bottomMargin;
bottom = top + size; bottom = top + size;
} } else { // horizontal
else
{ // horizontal
left = child.getRight() + params.rightMargin; left = child.getRight() + params.rightMargin;
right = left + size; right = left + size;
} }
@ -141,15 +117,11 @@ public final class DividerItemDecoration extends RecyclerView.ItemDecoration
} }
} }
private int getOrientation(RecyclerView parent) private int getOrientation(RecyclerView parent) {
{ if (parent.getLayoutManager() instanceof LinearLayoutManager) {
if (parent.getLayoutManager() instanceof LinearLayoutManager)
{
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager(); LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation(); return layoutManager.getOrientation();
} } else {
else
{
throw new IllegalStateException( throw new IllegalStateException(
"DividerItemDecoration can only be used with a LinearLayoutManager."); "DividerItemDecoration can only be used with a LinearLayoutManager.");
} }

View File

@ -13,10 +13,8 @@ import android.view.View;
/** /**
* Work around a bug with the nVidia Shield. * Work around a bug with the nVidia Shield.
*/ */
public final class NVidiaShieldWorkaroundView extends View public final class NVidiaShieldWorkaroundView extends View {
{ public NVidiaShieldWorkaroundView(Context context, AttributeSet attrs) {
public NVidiaShieldWorkaroundView(Context context, AttributeSet attrs)
{
super(context, attrs); super(context, attrs);
// Setting this seems to workaround the bug // Setting this seems to workaround the bug

View File

@ -1,6 +1,5 @@
package org.citra.citra_android.ui.input.gamecube; package org.citra.citra_android.ui.input.gamecube;
public class ControllerFragment public class ControllerFragment {
{
} }

View File

@ -1,6 +1,5 @@
package org.citra.citra_android.ui.input.gamecube; package org.citra.citra_android.ui.input.gamecube;
public class ControllerFragmentPresenter public class ControllerFragmentPresenter {
{
} }

View File

@ -1,6 +1,5 @@
package org.citra.citra_android.ui.input.gamecube; package org.citra.citra_android.ui.input.gamecube;
public interface ControllerFragmentView public interface ControllerFragmentView {
{
} }

View File

@ -11,72 +11,59 @@ import android.widget.TextView;
import org.citra.citra_android.R; import org.citra.citra_android.R;
public class CustomTitleView extends LinearLayout implements TitleViewAdapter.Provider public class CustomTitleView extends LinearLayout implements TitleViewAdapter.Provider {
{
private final TextView mTitleView; private final TextView mTitleView;
private final View mBadgeView; private final View mBadgeView;
private final TitleViewAdapter mTitleViewAdapter = new TitleViewAdapter() private final TitleViewAdapter mTitleViewAdapter = new TitleViewAdapter() {
{
@Override @Override
public View getSearchAffordanceView() public View getSearchAffordanceView() {
{
return null; return null;
} }
@Override @Override
public void setTitle(CharSequence titleText) public void setTitle(CharSequence titleText) {
{
CustomTitleView.this.setTitle(titleText); CustomTitleView.this.setTitle(titleText);
} }
@Override @Override
public void setBadgeDrawable(Drawable drawable) public void setBadgeDrawable(Drawable drawable) {
{
CustomTitleView.this.setBadgeDrawable(drawable); CustomTitleView.this.setBadgeDrawable(drawable);
} }
}; };
public CustomTitleView(Context context) public CustomTitleView(Context context) {
{
this(context, null); this(context, null);
} }
public CustomTitleView(Context context, AttributeSet attrs) public CustomTitleView(Context context, AttributeSet attrs) {
{
this(context, attrs, 0); this(context, attrs, 0);
} }
public CustomTitleView(Context context, AttributeSet attrs, int defStyle) public CustomTitleView(Context context, AttributeSet attrs, int defStyle) {
{
super(context, attrs, defStyle); super(context, attrs, defStyle);
View root = LayoutInflater.from(context).inflate(R.layout.tv_title, this); View root = LayoutInflater.from(context).inflate(R.layout.tv_title, this);
mTitleView = root.findViewById(R.id.title); mTitleView = root.findViewById(R.id.title);
mBadgeView = root.findViewById(R.id.badge); mBadgeView = root.findViewById(R.id.badge);
} }
public void setTitle(CharSequence title) public void setTitle(CharSequence title) {
{ if (title != null) {
if (title != null)
{
mTitleView.setText(title); mTitleView.setText(title);
mTitleView.setVisibility(View.VISIBLE); mTitleView.setVisibility(View.VISIBLE);
mBadgeView.setVisibility(View.VISIBLE); mBadgeView.setVisibility(View.VISIBLE);
} }
} }
public void setBadgeDrawable(Drawable drawable) public void setBadgeDrawable(Drawable drawable) {
{ if (drawable != null) {
if (drawable != null)
{
mTitleView.setVisibility(View.GONE); mTitleView.setVisibility(View.GONE);
mBadgeView.setVisibility(View.VISIBLE); mBadgeView.setVisibility(View.VISIBLE);
} }
} }
@Override @Override
public TitleViewAdapter getTitleViewAdapter() public TitleViewAdapter getTitleViewAdapter() {
{
return mTitleViewAdapter; return mTitleViewAdapter;
} }
} }

View File

@ -28,8 +28,7 @@ import org.citra.citra_android.utils.StartupHandler;
* The main Activity of the Lollipop style UI. Manages several PlatformGamesFragments, which * 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. * individually display a grid of available games for each Fragment, in a tabbed layout.
*/ */
public final class MainActivity extends AppCompatActivity implements MainView public final class MainActivity extends AppCompatActivity implements MainView {
{
private Toolbar mToolbar; private Toolbar mToolbar;
private int mFrameLayoutId; private int mFrameLayoutId;
private PlatformGamesFragment mPlatformGamesFragment; private PlatformGamesFragment mPlatformGamesFragment;
@ -38,8 +37,7 @@ public final class MainActivity extends AppCompatActivity implements MainView
private MainPresenter mPresenter = new MainPresenter(this); private MainPresenter mPresenter = new MainPresenter(this);
@Override @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState) {
{
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
@ -58,8 +56,7 @@ public final class MainActivity extends AppCompatActivity implements MainView
if (savedInstanceState == null) if (savedInstanceState == null)
StartupHandler.HandleInit(this); StartupHandler.HandleInit(this);
if (PermissionsHandler.hasWriteAccess(this)) if (PermissionsHandler.hasWriteAccess(this)) {
{
mPlatformGamesFragment = new PlatformGamesFragment(); mPlatformGamesFragment = new PlatformGamesFragment();
getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment) getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment)
.commit(); .commit();
@ -67,22 +64,19 @@ public final class MainActivity extends AppCompatActivity implements MainView
} }
@Override @Override
protected void onResume() protected void onResume() {
{
super.onResume(); super.onResume();
mPresenter.addDirIfNeeded(new AddDirectoryHelper(this)); mPresenter.addDirIfNeeded(new AddDirectoryHelper(this));
} }
// TODO: Replace with a ButterKnife injection. // TODO: Replace with a ButterKnife injection.
private void findViews() private void findViews() {
{
mToolbar = findViewById(R.id.toolbar_main); mToolbar = findViewById(R.id.toolbar_main);
mFab = findViewById(R.id.button_add_directory); mFab = findViewById(R.id.button_add_directory);
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) public boolean onCreateOptionsMenu(Menu menu) {
{
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_game_grid, menu); inflater.inflate(R.menu.menu_game_grid, menu);
return true; return true;
@ -93,45 +87,38 @@ public final class MainActivity extends AppCompatActivity implements MainView
*/ */
@Override @Override
public void setVersionString(String version) public void setVersionString(String version) {
{
mToolbar.setSubtitle(version); mToolbar.setSubtitle(version);
} }
@Override @Override
public void refresh() public void refresh() {
{
getContentResolver().insert(GameProvider.URI_REFRESH, null); getContentResolver().insert(GameProvider.URI_REFRESH, null);
refreshFragment(); refreshFragment();
} }
@Override @Override
public void refreshFragmentScreenshot(int fragmentPosition) public void refreshFragmentScreenshot(int fragmentPosition) {
{
// Invalidate Picasso image so that the new screenshot is animated in. // Invalidate Picasso image so that the new screenshot is animated in.
PlatformGamesView fragment = getPlatformGamesView(); PlatformGamesView fragment = getPlatformGamesView();
if (fragment != null) if (fragment != null) {
{
fragment.refreshScreenshotAtPosition(fragmentPosition); fragment.refreshScreenshotAtPosition(fragmentPosition);
} }
} }
@Override @Override
public void launchSettingsActivity(String menuTag) public void launchSettingsActivity(String menuTag) {
{
SettingsActivity.launch(this, menuTag, ""); SettingsActivity.launch(this, menuTag, "");
} }
@Override @Override
public void launchFileListActivity() public void launchFileListActivity() {
{
FileBrowserHelper.openDirectoryPicker(this); FileBrowserHelper.openDirectoryPicker(this);
} }
@Override @Override
public void showGames(Cursor games) public void showGames(Cursor games) {
{
// no-op. Handled by PlatformGamesFragment. // no-op. Handled by PlatformGamesFragment.
} }
@ -141,14 +128,11 @@ public final class MainActivity extends AppCompatActivity implements MainView
* @param result The information the returning Activity is providing us. * @param result The information the returning Activity is providing us.
*/ */
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) protected void onActivityResult(int requestCode, int resultCode, Intent result) {
{ switch (requestCode) {
switch (requestCode)
{
case MainPresenter.REQUEST_ADD_DIRECTORY: case MainPresenter.REQUEST_ADD_DIRECTORY:
// If the user picked a file, as opposed to just backing out. // If the user picked a file, as opposed to just backing out.
if (resultCode == MainActivity.RESULT_OK) if (resultCode == MainActivity.RESULT_OK) {
{
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result)); mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
} }
break; break;
@ -160,21 +144,16 @@ public final class MainActivity extends AppCompatActivity implements MainView
} }
@Override @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
{ switch (requestCode) {
switch (requestCode)
{
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION: case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
{
DirectoryInitializationService.startService(this); DirectoryInitializationService.startService(this);
mPlatformGamesFragment = new PlatformGamesFragment(); mPlatformGamesFragment = new PlatformGamesFragment();
getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment) getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment)
.commit(); .commit();
} } else {
else
{
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT) Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show(); .show();
} }
@ -192,22 +171,18 @@ public final class MainActivity extends AppCompatActivity implements MainView
* @return True if the event was handled, false to bubble it up to the OS. * @return True if the event was handled, false to bubble it up to the OS.
*/ */
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) public boolean onOptionsItemSelected(MenuItem item) {
{
return mPresenter.handleOptionSelection(item.getItemId()); return mPresenter.handleOptionSelection(item.getItemId());
} }
private void refreshFragment() private void refreshFragment() {
{ if (mPlatformGamesFragment != null) {
if (mPlatformGamesFragment != null)
{
mPlatformGamesFragment.refresh(); mPlatformGamesFragment.refresh();
} }
} }
@Nullable @Nullable
private PlatformGamesView getPlatformGamesView() private PlatformGamesView getPlatformGamesView() {
{
return (PlatformGamesView) getSupportFragmentManager().findFragmentById(mFrameLayoutId); return (PlatformGamesView) getSupportFragmentManager().findFragmentById(mFrameLayoutId);
} }
} }

View File

@ -11,34 +11,28 @@ import org.citra.citra_android.utils.SettingsFile;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
public final class MainPresenter public final class MainPresenter {
{
public static final int REQUEST_ADD_DIRECTORY = 1; public static final int REQUEST_ADD_DIRECTORY = 1;
public static final int REQUEST_EMULATE_GAME = 2; public static final int REQUEST_EMULATE_GAME = 2;
private final MainView mView; private final MainView mView;
private String mDirToAdd; private String mDirToAdd;
public MainPresenter(MainView view) public MainPresenter(MainView view) {
{
mView = view; mView = view;
} }
public void onCreate() public void onCreate() {
{
String versionName = BuildConfig.VERSION_NAME; String versionName = BuildConfig.VERSION_NAME;
mView.setVersionString(versionName); mView.setVersionString(versionName);
} }
public void onFabClick() public void onFabClick() {
{
mView.launchFileListActivity(); mView.launchFileListActivity();
} }
public boolean handleOptionSelection(int itemId) public boolean handleOptionSelection(int itemId) {
{ switch (itemId) {
switch (itemId)
{
case R.id.menu_settings_core: case R.id.menu_settings_core:
mView.launchSettingsActivity(SettingsFile.FILE_NAME_CONFIG); mView.launchSettingsActivity(SettingsFile.FILE_NAME_CONFIG);
return true; return true;
@ -57,29 +51,24 @@ public final class MainPresenter
return false; return false;
} }
public void addDirIfNeeded(AddDirectoryHelper helper) public void addDirIfNeeded(AddDirectoryHelper helper) {
{ if (mDirToAdd != null) {
if (mDirToAdd != null)
{
helper.addDirectory(mDirToAdd, mView::refresh); helper.addDirectory(mDirToAdd, mView::refresh);
mDirToAdd = null; mDirToAdd = null;
} }
} }
public void onDirectorySelected(String dir) public void onDirectorySelected(String dir) {
{
mDirToAdd = dir; mDirToAdd = dir;
} }
public void refreshFragmentScreenshot(int resultCode) public void refreshFragmentScreenshot(int resultCode) {
{
mView.refreshFragmentScreenshot(resultCode); mView.refreshFragmentScreenshot(resultCode);
} }
public void loadGames() public void loadGames() {
{
GameDatabase databaseHelper = DolphinApplication.databaseHelper; GameDatabase databaseHelper = DolphinApplication.databaseHelper;
databaseHelper.getGames() databaseHelper.getGames()

View File

@ -7,8 +7,7 @@ import android.database.Cursor;
* Implementations will differ primarily to target touch-screen * Implementations will differ primarily to target touch-screen
* or non-touch screen devices. * or non-touch screen devices.
*/ */
public interface MainView public interface MainView {
{
/** /**
* Pass the view the native library's version string. Displaying * Pass the view the native library's version string. Displaying
* it is optional. * it is optional.

View File

@ -31,8 +31,7 @@ import org.citra.citra_android.utils.PermissionsHandler;
import org.citra.citra_android.utils.StartupHandler; import org.citra.citra_android.utils.StartupHandler;
import org.citra.citra_android.viewholders.TvGameViewHolder; import org.citra.citra_android.viewholders.TvGameViewHolder;
public final class TvMainActivity extends FragmentActivity implements MainView public final class TvMainActivity extends FragmentActivity implements MainView {
{
private MainPresenter mPresenter = new MainPresenter(this); private MainPresenter mPresenter = new MainPresenter(this);
private BrowseSupportFragment mBrowseFragment; private BrowseSupportFragment mBrowseFragment;
@ -40,8 +39,7 @@ public final class TvMainActivity extends FragmentActivity implements MainView
private ArrayObjectAdapter mRowsAdapter; private ArrayObjectAdapter mRowsAdapter;
@Override @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState) {
{
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tv_main); setContentView(R.layout.activity_tv_main);
@ -55,14 +53,12 @@ public final class TvMainActivity extends FragmentActivity implements MainView
} }
@Override @Override
protected void onResume() protected void onResume() {
{
super.onResume(); super.onResume();
mPresenter.addDirIfNeeded(new AddDirectoryHelper(this)); mPresenter.addDirIfNeeded(new AddDirectoryHelper(this));
} }
void setupUI() void setupUI() {
{
final FragmentManager fragmentManager = getSupportFragmentManager(); final FragmentManager fragmentManager = getSupportFragmentManager();
mBrowseFragment = new BrowseSupportFragment(); mBrowseFragment = new BrowseSupportFragment();
fragmentManager fragmentManager
@ -79,13 +75,10 @@ public final class TvMainActivity extends FragmentActivity implements MainView
(itemViewHolder, item, rowViewHolder, row) -> (itemViewHolder, item, rowViewHolder, row) ->
{ {
// Special case: user clicked on a settings row item. // Special case: user clicked on a settings row item.
if (item instanceof TvSettingsItem) if (item instanceof TvSettingsItem) {
{
TvSettingsItem settingsItem = (TvSettingsItem) item; TvSettingsItem settingsItem = (TvSettingsItem) item;
mPresenter.handleOptionSelection(settingsItem.getItemId()); mPresenter.handleOptionSelection(settingsItem.getItemId());
} } else {
else
{
TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder; TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder;
// Start the emulation activity and send the path of the clicked ISO to it. // Start the emulation activity and send the path of the clicked ISO to it.
@ -104,43 +97,36 @@ public final class TvMainActivity extends FragmentActivity implements MainView
*/ */
@Override @Override
public void setVersionString(String version) public void setVersionString(String version) {
{
mBrowseFragment.setTitle(version); mBrowseFragment.setTitle(version);
} }
@Override @Override
public void refresh() public void refresh() {
{
recreate(); recreate();
} }
@Override @Override
public void refreshFragmentScreenshot(int fragmentPosition) public void refreshFragmentScreenshot(int fragmentPosition) {
{
mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size()); mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size());
} }
@Override @Override
public void launchSettingsActivity(String menuTag) public void launchSettingsActivity(String menuTag) {
{
SettingsActivity.launch(this, menuTag, ""); SettingsActivity.launch(this, menuTag, "");
} }
@Override @Override
public void launchFileListActivity() public void launchFileListActivity() {
{
FileBrowserHelper.openDirectoryPicker(this); FileBrowserHelper.openDirectoryPicker(this);
} }
@Override @Override
public void showGames(Cursor games) public void showGames(Cursor games) {
{
ListRow row = buildGamesRow(games); ListRow row = buildGamesRow(games);
// Add row to the adapter only if it is not empty. // Add row to the adapter only if it is not empty.
if (row != null) if (row != null) {
{
mRowsAdapter.add(games); mRowsAdapter.add(games);
} }
} }
@ -153,14 +139,11 @@ public final class TvMainActivity extends FragmentActivity implements MainView
* @param result The information the returning Activity is providing us. * @param result The information the returning Activity is providing us.
*/ */
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) protected void onActivityResult(int requestCode, int resultCode, Intent result) {
{ switch (requestCode) {
switch (requestCode)
{
case MainPresenter.REQUEST_ADD_DIRECTORY: case MainPresenter.REQUEST_ADD_DIRECTORY:
// If the user picked a file, as opposed to just backing out. // If the user picked a file, as opposed to just backing out.
if (resultCode == MainActivity.RESULT_OK) if (resultCode == MainActivity.RESULT_OK) {
{
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result)); mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
} }
break; break;
@ -172,18 +155,13 @@ public final class TvMainActivity extends FragmentActivity implements MainView
} }
@Override @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
{ switch (requestCode) {
switch (requestCode)
{
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION: case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
{
DirectoryInitializationService.startService(this); DirectoryInitializationService.startService(this);
loadGames(); loadGames();
} } else {
else
{
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT) Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show(); .show();
} }
@ -194,12 +172,10 @@ public final class TvMainActivity extends FragmentActivity implements MainView
} }
} }
private void buildRowsAdapter() private void buildRowsAdapter() {
{
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter()); mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
if (PermissionsHandler.hasWriteAccess(this)) if (PermissionsHandler.hasWriteAccess(this)) {
{
loadGames(); loadGames();
} }
@ -208,34 +184,28 @@ public final class TvMainActivity extends FragmentActivity implements MainView
mBrowseFragment.setAdapter(mRowsAdapter); mBrowseFragment.setAdapter(mRowsAdapter);
} }
private void loadGames() private void loadGames() {
{
mPresenter.loadGames(); mPresenter.loadGames();
} }
private ListRow buildGamesRow(Cursor games) private ListRow buildGamesRow(Cursor games) {
{
// Create an adapter for this row. // Create an adapter for this row.
CursorObjectAdapter row = new CursorObjectAdapter(new GameRowPresenter()); CursorObjectAdapter row = new CursorObjectAdapter(new GameRowPresenter());
// If cursor is empty, don't return a Row. // If cursor is empty, don't return a Row.
if (!games.moveToFirst()) if (!games.moveToFirst()) {
{
return null; return null;
} }
row.changeCursor(games); row.changeCursor(games);
row.setMapper(new CursorMapper() row.setMapper(new CursorMapper() {
{
@Override @Override
protected void bindColumns(Cursor cursor) protected void bindColumns(Cursor cursor) {
{
// No-op? Not sure what this does. // No-op? Not sure what this does.
} }
@Override @Override
protected Object bind(Cursor cursor) protected Object bind(Cursor cursor) {
{
return Game.fromCursor(cursor); return Game.fromCursor(cursor);
} }
}); });
@ -244,8 +214,7 @@ public final class TvMainActivity extends FragmentActivity implements MainView
return new ListRow(null, row); return new ListRow(null, row);
} }
private ListRow buildSettingsRow() private ListRow buildSettingsRow() {
{
ArrayObjectAdapter rowItems = new ArrayObjectAdapter(new SettingsRowPresenter()); ArrayObjectAdapter rowItems = new ArrayObjectAdapter(new SettingsRowPresenter());
rowItems.add(new TvSettingsItem(R.id.menu_settings_core, rowItems.add(new TvSettingsItem(R.id.menu_settings_core,

View File

@ -13,8 +13,7 @@ import android.view.ViewGroup;
import org.citra.citra_android.R; import org.citra.citra_android.R;
import org.citra.citra_android.adapters.GameAdapter; import org.citra.citra_android.adapters.GameAdapter;
public final class PlatformGamesFragment extends Fragment implements PlatformGamesView public final class PlatformGamesFragment extends Fragment implements PlatformGamesView {
{
private static final String ARG_PLATFORM = "platform"; private static final String ARG_PLATFORM = "platform";
private PlatformGamesPresenter mPresenter = new PlatformGamesPresenter(this); private PlatformGamesPresenter mPresenter = new PlatformGamesPresenter(this);
@ -23,15 +22,13 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
private RecyclerView mRecyclerView; private RecyclerView mRecyclerView;
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState) {
{
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
} }
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
{
View rootView = inflater.inflate(R.layout.fragment_grid, container, false); View rootView = inflater.inflate(R.layout.fragment_grid, container, false);
findViews(rootView); findViews(rootView);
@ -42,8 +39,7 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
} }
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) public void onViewCreated(View view, Bundle savedInstanceState) {
{
int columns = getResources().getInteger(R.integer.game_grid_columns); int columns = getResources().getInteger(R.integer.game_grid_columns);
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), columns); RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), columns);
mAdapter = new GameAdapter(); mAdapter = new GameAdapter();
@ -55,34 +51,28 @@ public final class PlatformGamesFragment extends Fragment implements PlatformGam
} }
@Override @Override
public void refreshScreenshotAtPosition(int position) public void refreshScreenshotAtPosition(int position) {
{
mAdapter.notifyItemChanged(position); mAdapter.notifyItemChanged(position);
} }
@Override @Override
public void refresh() public void refresh() {
{
mPresenter.refresh(); mPresenter.refresh();
} }
@Override @Override
public void onItemClick(String gameId) public void onItemClick(String gameId) {
{
// No-op for now // No-op for now
} }
@Override @Override
public void showGames(Cursor games) public void showGames(Cursor games) {
{ if (mAdapter != null) {
if (mAdapter != null)
{
mAdapter.swapCursor(games); mAdapter.swapCursor(games);
} }
} }
private void findViews(View root) private void findViews(View root) {
{
mRecyclerView = root.findViewById(R.id.grid_games); mRecyclerView = root.findViewById(R.id.grid_games);
} }
} }

View File

@ -8,28 +8,23 @@ import org.citra.citra_android.utils.Log;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
public final class PlatformGamesPresenter public final class PlatformGamesPresenter {
{
private final PlatformGamesView mView; private final PlatformGamesView mView;
public PlatformGamesPresenter(PlatformGamesView view) public PlatformGamesPresenter(PlatformGamesView view) {
{
mView = view; mView = view;
} }
public void onCreateView() public void onCreateView() {
{
loadGames(); loadGames();
} }
public void refresh() public void refresh() {
{
Log.debug("[PlatformGamesPresenter] : Refreshing..."); Log.debug("[PlatformGamesPresenter] : Refreshing...");
loadGames(); loadGames();
} }
private void loadGames() private void loadGames() {
{
Log.debug("[PlatformGamesPresenter] : Loading games..."); Log.debug("[PlatformGamesPresenter] : Loading games...");
GameDatabase databaseHelper = DolphinApplication.databaseHelper; GameDatabase databaseHelper = DolphinApplication.databaseHelper;

View File

@ -5,8 +5,7 @@ import android.database.Cursor;
/** /**
* Abstraction for a screen representing a single platform's games. * Abstraction for a screen representing a single platform's games.
*/ */
public interface PlatformGamesView public interface PlatformGamesView {
{
/** /**
* Tell the view to refresh its contents. * Tell the view to refresh its contents.
*/ */

View File

@ -18,13 +18,11 @@ import org.citra.citra_android.R;
import org.citra.citra_android.model.settings.SettingSection; import org.citra.citra_android.model.settings.SettingSection;
import org.citra.citra_android.services.DirectoryInitializationService; import org.citra.citra_android.services.DirectoryInitializationService;
import org.citra.citra_android.utils.DirectoryStateReceiver; import org.citra.citra_android.utils.DirectoryStateReceiver;
import org.citra.citra_android.utils.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView {
{
private static final String ARG_FILE_NAME = "file_name"; private static final String ARG_FILE_NAME = "file_name";
private static final String ARG_GAME_ID = "game_id"; private static final String ARG_GAME_ID = "game_id";
@ -33,8 +31,7 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
private ProgressDialog dialog; private ProgressDialog dialog;
public static void launch(Context context, String menuTag, String gameId) public static void launch(Context context, String menuTag, String gameId) {
{
Intent settings = new Intent(context, SettingsActivity.class); Intent settings = new Intent(context, SettingsActivity.class);
settings.putExtra(ARG_FILE_NAME, menuTag); settings.putExtra(ARG_FILE_NAME, menuTag);
settings.putExtra(ARG_GAME_ID, gameId); settings.putExtra(ARG_GAME_ID, gameId);
@ -43,8 +40,7 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
} }
@Override @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState) {
{
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings); setContentView(R.layout.activity_settings);
@ -57,8 +53,7 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) public boolean onCreateOptionsMenu(Menu menu) {
{
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_settings, menu); inflater.inflate(R.menu.menu_settings, menu);
@ -66,22 +61,19 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) public boolean onOptionsItemSelected(MenuItem item) {
{
return mPresenter.handleOptionsItem(item.getItemId()); return mPresenter.handleOptionsItem(item.getItemId());
} }
@Override @Override
protected void onSaveInstanceState(Bundle outState) protected void onSaveInstanceState(Bundle outState) {
{
// Critical: If super method is not called, rotations will be busted. // Critical: If super method is not called, rotations will be busted.
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
mPresenter.saveState(outState); mPresenter.saveState(outState);
} }
@Override @Override
protected void onStart() protected void onStart() {
{
super.onStart(); super.onStart();
mPresenter.onStart(); mPresenter.onStart();
} }
@ -92,29 +84,24 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
* IntentService which will do so on a background thread. * IntentService which will do so on a background thread.
*/ */
@Override @Override
protected void onStop() protected void onStop() {
{
super.onStop(); super.onStop();
mPresenter.onStop(isFinishing()); mPresenter.onStop(isFinishing());
} }
@Override @Override
public void onBackPressed() public void onBackPressed() {
{
mPresenter.onBackPressed(); mPresenter.onBackPressed();
} }
@Override @Override
public void showSettingsFragment(String menuTag, boolean addToStack, String gameID) public void showSettingsFragment(String menuTag, boolean addToStack, String gameID) {
{
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (addToStack) if (addToStack) {
{ if (areSystemAnimationsEnabled()) {
if (areSystemAnimationsEnabled())
{
transaction.setCustomAnimations( transaction.setCustomAnimations(
R.animator.settings_enter, R.animator.settings_enter,
R.animator.settings_exit, R.animator.settings_exit,
@ -130,8 +117,7 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
transaction.commit(); transaction.commit();
} }
private boolean areSystemAnimationsEnabled() private boolean areSystemAnimationsEnabled() {
{
float duration = Settings.Global.getFloat( float duration = Settings.Global.getFloat(
getContentResolver(), getContentResolver(),
Settings.Global.ANIMATOR_DURATION_SCALE, 1); Settings.Global.ANIMATOR_DURATION_SCALE, 1);
@ -142,8 +128,7 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
} }
@Override @Override
public void startDirectoryInitializationService(DirectoryStateReceiver receiver, IntentFilter filter) public void startDirectoryInitializationService(DirectoryStateReceiver receiver, IntentFilter filter) {
{
LocalBroadcastManager.getInstance(this).registerReceiver( LocalBroadcastManager.getInstance(this).registerReceiver(
receiver, receiver,
filter); filter);
@ -151,16 +136,13 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
} }
@Override @Override
public void stopListeningToDirectoryInitializationService(DirectoryStateReceiver receiver) public void stopListeningToDirectoryInitializationService(DirectoryStateReceiver receiver) {
{
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver); LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
} }
@Override @Override
public void showLoading() public void showLoading() {
{ if (dialog == null) {
if (dialog == null)
{
dialog = new ProgressDialog(this); dialog = new ProgressDialog(this);
dialog.setMessage(getString(R.string.load_settings)); dialog.setMessage(getString(R.string.load_settings));
dialog.setIndeterminate(true); dialog.setIndeterminate(true);
@ -170,97 +152,81 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
} }
@Override @Override
public void hideLoading() public void hideLoading() {
{
dialog.dismiss(); dialog.dismiss();
} }
@Override @Override
public void showPermissionNeededHint() public void showPermissionNeededHint() {
{
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT) Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show(); .show();
} }
@Override @Override
public void showExternalStorageNotMountedHint() public void showExternalStorageNotMountedHint() {
{
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT) Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
.show(); .show();
} }
@Override @Override
public HashMap<String, SettingSection> getSettings(int file) public HashMap<String, SettingSection> getSettings(int file) {
{
return mPresenter.getSettings(file); return mPresenter.getSettings(file);
} }
@Override @Override
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings) public void setSettings(ArrayList<HashMap<String, SettingSection>> settings) {
{
mPresenter.setSettings(settings); mPresenter.setSettings(settings);
} }
@Override @Override
public void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings) public void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings) {
{
SettingsFragmentView fragment = getFragment(); SettingsFragmentView fragment = getFragment();
if (fragment != null) if (fragment != null) {
{
fragment.onSettingsFileLoaded(settings); fragment.onSettingsFileLoaded(settings);
} }
} }
@Override @Override
public void onSettingsFileNotFound() public void onSettingsFileNotFound() {
{
SettingsFragmentView fragment = getFragment(); SettingsFragmentView fragment = getFragment();
if (fragment != null) if (fragment != null) {
{
fragment.loadDefaultSettings(); fragment.loadDefaultSettings();
} }
} }
@Override @Override
public void showToastMessage(String message) public void showToastMessage(String message) {
{
Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
} }
@Override @Override
public void popBackStack() public void popBackStack() {
{
getSupportFragmentManager().popBackStackImmediate(); getSupportFragmentManager().popBackStackImmediate();
} }
@Override @Override
public void onSettingChanged() public void onSettingChanged() {
{
mPresenter.onSettingChanged(); mPresenter.onSettingChanged();
} }
@Override @Override
public void onGcPadSettingChanged(String key, int value) public void onGcPadSettingChanged(String key, int value) {
{
mPresenter.onGcPadSettingChanged(key, value); mPresenter.onGcPadSettingChanged(key, value);
} }
@Override @Override
public void onWiimoteSettingChanged(String section, int value) public void onWiimoteSettingChanged(String section, int value) {
{
mPresenter.onWiimoteSettingChanged(section, value); mPresenter.onWiimoteSettingChanged(section, value);
} }
@Override @Override
public void onExtensionSettingChanged(String key, int value) public void onExtensionSettingChanged(String key, int value) {
{
mPresenter.onExtensionSettingChanged(key, value); mPresenter.onExtensionSettingChanged(key, value);
} }
private SettingsFragment getFragment() private SettingsFragment getFragment() {
{
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG); return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
} }
} }

View File

@ -4,7 +4,6 @@ import android.content.IntentFilter;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import org.citra.citra_android.NativeLibrary;
import org.citra.citra_android.R; import org.citra.citra_android.R;
import org.citra.citra_android.model.settings.SettingSection; import org.citra.citra_android.model.settings.SettingSection;
import org.citra.citra_android.services.DirectoryInitializationService; import org.citra.citra_android.services.DirectoryInitializationService;
@ -17,8 +16,7 @@ import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
public final class SettingsActivityPresenter public final class SettingsActivityPresenter {
{
private static final String KEY_SHOULD_SAVE = "should_save"; private static final String KEY_SHOULD_SAVE = "should_save";
private SettingsActivityView mView; private SettingsActivityView mView;
@ -34,39 +32,28 @@ public final class SettingsActivityPresenter
private String menuTag; private String menuTag;
private String gameId; private String gameId;
public SettingsActivityPresenter(SettingsActivityView view) public SettingsActivityPresenter(SettingsActivityView view) {
{
mView = view; mView = view;
} }
public void onCreate(Bundle savedInstanceState, String menuTag, String gameId) public void onCreate(Bundle savedInstanceState, String menuTag, String gameId) {
{ if (savedInstanceState == null) {
if (savedInstanceState == null)
{
this.menuTag = menuTag; this.menuTag = menuTag;
this.gameId = gameId; this.gameId = gameId;
} } else {
else
{
mShouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE); mShouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE);
} }
} }
public void onStart() public void onStart() {
{
prepareDolphinDirectoriesIfNeeded(); prepareDolphinDirectoriesIfNeeded();
} }
void loadSettingsUI() void loadSettingsUI() {
{ if (mSettings.isEmpty()) {
if (mSettings.isEmpty()) if (!TextUtils.isEmpty(gameId)) {
{
if (!TextUtils.isEmpty(gameId))
{
mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile("../GameSettings/" + gameId, mView)); mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile("../GameSettings/" + gameId, mView));
} } else {
else
{
mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile(SettingsFile.FILE_NAME_CONFIG, mView)); mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile(SettingsFile.FILE_NAME_CONFIG, mView));
} }
} }
@ -75,8 +62,7 @@ public final class SettingsActivityPresenter
mView.onSettingsFileLoaded(mSettings); mView.onSettingsFileLoaded(mSettings);
} }
private void prepareDolphinDirectoriesIfNeeded() private void prepareDolphinDirectoriesIfNeeded() {
{
File configFile = new File(DirectoryInitializationService.getUserDirectory() + "/config/" + SettingsFile.FILE_NAME_CONFIG + ".ini"); File configFile = new File(DirectoryInitializationService.getUserDirectory() + "/config/" + SettingsFile.FILE_NAME_CONFIG + ".ini");
if (!configFile.exists()) { if (!configFile.exists()) {
@ -91,18 +77,13 @@ public final class SettingsActivityPresenter
directoryStateReceiver = directoryStateReceiver =
new DirectoryStateReceiver(directoryInitializationState -> new DirectoryStateReceiver(directoryInitializationState ->
{ {
if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) {
{
mView.hideLoading(); mView.hideLoading();
loadSettingsUI(); loadSettingsUI();
} } else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) {
else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
{
mView.showPermissionNeededHint(); mView.showPermissionNeededHint();
mView.hideLoading(); mView.hideLoading();
} } else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE) {
else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
{
mView.showExternalStorageNotMountedHint(); mView.showExternalStorageNotMountedHint();
mView.hideLoading(); mView.hideLoading();
} }
@ -112,31 +93,25 @@ public final class SettingsActivityPresenter
} }
} }
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings) public void setSettings(ArrayList<HashMap<String, SettingSection>> settings) {
{
mSettings = settings; mSettings = settings;
} }
public HashMap<String, SettingSection> getSettings(int file) public HashMap<String, SettingSection> getSettings(int file) {
{
return mSettings.get(file); return mSettings.get(file);
} }
public void onStop(boolean finishing) public void onStop(boolean finishing) {
{ if (directoryStateReceiver != null) {
if (directoryStateReceiver != null)
{
mView.stopListeningToDirectoryInitializationService(directoryStateReceiver); mView.stopListeningToDirectoryInitializationService(directoryStateReceiver);
directoryStateReceiver = null; directoryStateReceiver = null;
} }
if (mSettings != null && finishing && mShouldSave) if (mSettings != null && finishing && mShouldSave) {
{
if (!TextUtils.isEmpty(gameId)) { if (!TextUtils.isEmpty(gameId)) {
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI..."); Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
// Needed workaround for now due to an odd bug in how it handles saving two different settings sections to the same file. It won't save GFX settings if it follows the normal saving pattern // Needed workaround for now due to an odd bug in how it handles saving two different settings sections to the same file. It won't save GFX settings if it follows the normal saving pattern
if (menuTag.equals("Dolphin")) if (menuTag.equals("Dolphin")) {
{
SettingsFile.saveFile("../GameSettings/" + gameId, mSettings.get(SettingsFile.SETTINGS_DOLPHIN), mView); SettingsFile.saveFile("../GameSettings/" + gameId, mSettings.get(SettingsFile.SETTINGS_DOLPHIN), mView);
} }
mView.showToastMessage("Saved settings for " + gameId); mView.showToastMessage("Saved settings for " + gameId);
@ -148,28 +123,21 @@ public final class SettingsActivityPresenter
} }
} }
public void addToStack() public void addToStack() {
{
mStackCount++; mStackCount++;
} }
public void onBackPressed() public void onBackPressed() {
{ if (mStackCount > 0) {
if (mStackCount > 0)
{
mView.popBackStack(); mView.popBackStack();
mStackCount--; mStackCount--;
} } else {
else
{
mView.finish(); mView.finish();
} }
} }
public boolean handleOptionsItem(int itemId) public boolean handleOptionsItem(int itemId) {
{ switch (itemId) {
switch (itemId)
{
case R.id.menu_save_exit: case R.id.menu_save_exit:
mView.finish(); mView.finish();
return true; return true;
@ -178,28 +146,23 @@ public final class SettingsActivityPresenter
return false; return false;
} }
public void onSettingChanged() public void onSettingChanged() {
{
mShouldSave = true; mShouldSave = true;
} }
public void saveState(Bundle outState) public void saveState(Bundle outState) {
{
outState.putBoolean(KEY_SHOULD_SAVE, mShouldSave); outState.putBoolean(KEY_SHOULD_SAVE, mShouldSave);
} }
public void onGcPadSettingChanged(String key, int value) public void onGcPadSettingChanged(String key, int value) {
{
if (value != 0) // Not disabled if (value != 0) // Not disabled
{ {
mView.showSettingsFragment(key + (value / 6), true, gameId); mView.showSettingsFragment(key + (value / 6), true, gameId);
} }
} }
public void onWiimoteSettingChanged(String section, int value) public void onWiimoteSettingChanged(String section, int value) {
{ switch (value) {
switch (value)
{
case 1: case 1:
mView.showSettingsFragment(section, true, gameId); mView.showSettingsFragment(section, true, gameId);
break; break;
@ -210,8 +173,7 @@ public final class SettingsActivityPresenter
} }
} }
public void onExtensionSettingChanged(String key, int value) public void onExtensionSettingChanged(String key, int value) {
{
if (value != 0) // None if (value != 0) // None
{ {
mView.showSettingsFragment(key + value, true, gameId); mView.showSettingsFragment(key + value, true, gameId);

View File

@ -11,8 +11,7 @@ import java.util.HashMap;
/** /**
* Abstraction for the Activity that manages SettingsFragments. * Abstraction for the Activity that manages SettingsFragments.
*/ */
public interface SettingsActivityView public interface SettingsActivityView {
{
/** /**
* Show a new SettingsFragment. * Show a new SettingsFragment.
* *

View File

@ -40,8 +40,7 @@ import org.citra.citra_android.utils.SettingsFile;
import java.util.ArrayList; import java.util.ArrayList;
public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder> public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder>
implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener {
{
private SettingsFragmentView mView; private SettingsFragmentView mView;
private Context mContext; private Context mContext;
private ArrayList<SettingsItem> mSettings; private ArrayList<SettingsItem> mSettings;
@ -52,20 +51,17 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
private AlertDialog mDialog; private AlertDialog mDialog;
private TextView mTextSliderValue; private TextView mTextSliderValue;
public SettingsAdapter(SettingsFragmentView view, Context context) public SettingsAdapter(SettingsFragmentView view, Context context) {
{
mView = view; mView = view;
mContext = context; mContext = context;
} }
@Override @Override
public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
{
View view; View view;
LayoutInflater inflater = LayoutInflater.from(parent.getContext()); LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) switch (viewType) {
{
case SettingsItem.TYPE_HEADER: case SettingsItem.TYPE_HEADER:
view = inflater.inflate(R.layout.list_item_settings_header, parent, false); view = inflater.inflate(R.layout.list_item_settings_header, parent, false);
return new HeaderViewHolder(view, this); return new HeaderViewHolder(view, this);
@ -102,56 +98,45 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
} }
@Override @Override
public void onBindViewHolder(SettingViewHolder holder, int position) public void onBindViewHolder(SettingViewHolder holder, int position) {
{
holder.bind(getItem(position)); holder.bind(getItem(position));
} }
private SettingsItem getItem(int position) private SettingsItem getItem(int position) {
{
return mSettings.get(position); return mSettings.get(position);
} }
@Override @Override
public int getItemCount() public int getItemCount() {
{ if (mSettings != null) {
if (mSettings != null)
{
return mSettings.size(); return mSettings.size();
} } else {
else
{
return 0; return 0;
} }
} }
@Override @Override
public int getItemViewType(int position) public int getItemViewType(int position) {
{
return getItem(position).getType(); return getItem(position).getType();
} }
public void setSettings(ArrayList<SettingsItem> settings) public void setSettings(ArrayList<SettingsItem> settings) {
{
mSettings = settings; mSettings = settings;
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void onBooleanClick(CheckBoxSetting item, int position, boolean checked) public void onBooleanClick(CheckBoxSetting item, int position, boolean checked) {
{
IntSetting setting = item.setChecked(checked); IntSetting setting = item.setChecked(checked);
notifyItemChanged(position); notifyItemChanged(position);
if (setting != null) if (setting != null) {
{
mView.putSetting(setting); mView.putSetting(setting);
} }
mView.onSettingChanged(); mView.onSettingChanged();
} }
public void onSingleChoiceClick(SingleChoiceSetting item) public void onSingleChoiceClick(SingleChoiceSetting item) {
{
mClickedItem = item; mClickedItem = item;
int value = getSelectionForSingleChoiceValue(item); int value = getSelectionForSingleChoiceValue(item);
@ -172,8 +157,8 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
LayoutInflater inflater = LayoutInflater.from(mView.getActivity()); LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
View view = inflater.inflate(R.layout.sysclock_datetime_picker, null); View view = inflater.inflate(R.layout.sysclock_datetime_picker, null);
DatePicker dp = (DatePicker) view.findViewById(R.id.date_picker); DatePicker dp = view.findViewById(R.id.date_picker);
TimePicker tp = (TimePicker) view.findViewById(R.id.time_picker); TimePicker tp = view.findViewById(R.id.time_picker);
//set date and time to substrings of settingValue; format = 2018-12-24 04:20:69 (alright maybe not that 69) //set date and time to substrings of settingValue; format = 2018-12-24 04:20:69 (alright maybe not that 69)
String settingValue = item.getValue(); String settingValue = item.getValue();
@ -214,8 +199,8 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
builder.setNegativeButton("Cancel", cancel); builder.setNegativeButton("Cancel", cancel);
mDialog = builder.show(); mDialog = builder.show();
} }
public void onSliderClick(SliderSetting item)
{ public void onSliderClick(SliderSetting item) {
mClickedItem = item; mClickedItem = item;
mSeekbarProgress = item.getSelectedValue(); mSeekbarProgress = item.getSelectedValue();
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity()); AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
@ -243,13 +228,11 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
seekbar.setOnSeekBarChangeListener(this); seekbar.setOnSeekBarChangeListener(this);
} }
public void onSubmenuClick(SubmenuSetting item) public void onSubmenuClick(SubmenuSetting item) {
{
mView.loadSubMenu(item.getMenuKey()); mView.loadSubMenu(item.getMenuKey());
} }
public void onInputBindingClick(final InputBindingSetting item, final int position) public void onInputBindingClick(final InputBindingSetting item, final int position) {
{
final MotionAlertDialog dialog = new MotionAlertDialog(mContext, item); final MotionAlertDialog dialog = new MotionAlertDialog(mContext, item);
dialog.setTitle(R.string.input_binding); dialog.setTitle(R.string.input_binding);
dialog.setMessage(String.format(mContext.getString(R.string.input_binding_descrip), mContext.getString(item.getNameId()))); dialog.setMessage(String.format(mContext.getString(R.string.input_binding_descrip), mContext.getString(item.getNameId())));
@ -268,8 +251,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
StringSetting setting = new StringSetting(item.getKey(), item.getSection(), item.getFile(), item.getValue()); StringSetting setting = new StringSetting(item.getKey(), item.getSection(), item.getFile(), item.getValue());
notifyItemChanged(position); notifyItemChanged(position);
if (setting != null) if (setting != null) {
{
mView.putSetting(setting); mView.putSetting(setting);
} }
@ -280,50 +262,37 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
} }
@Override @Override
public void onClick(DialogInterface dialog, int which) public void onClick(DialogInterface dialog, int which) {
{ if (mClickedItem instanceof SingleChoiceSetting) {
if (mClickedItem instanceof SingleChoiceSetting)
{
SingleChoiceSetting scSetting = (SingleChoiceSetting) mClickedItem; SingleChoiceSetting scSetting = (SingleChoiceSetting) mClickedItem;
int value = getValueForSingleChoiceSelection(scSetting, which); int value = getValueForSingleChoiceSelection(scSetting, which);
// Get the backing Setting, which may be null (if for example it was missing from the file) // Get the backing Setting, which may be null (if for example it was missing from the file)
IntSetting setting = scSetting.setSelectedValue(value); IntSetting setting = scSetting.setSelectedValue(value);
if (setting != null) if (setting != null) {
{
mView.putSetting(setting); mView.putSetting(setting);
} }
closeDialog(); closeDialog();
} } else if (mClickedItem instanceof SliderSetting) {
else if (mClickedItem instanceof SliderSetting)
{
SliderSetting sliderSetting = (SliderSetting) mClickedItem; SliderSetting sliderSetting = (SliderSetting) mClickedItem;
if (sliderSetting.getSetting() instanceof FloatSetting) if (sliderSetting.getSetting() instanceof FloatSetting) {
{
float value; float value;
if (sliderSetting.getKey().equals(SettingsFile.KEY_FRAME_LIMIT)) if (sliderSetting.getKey().equals(SettingsFile.KEY_FRAME_LIMIT)) {
{
value = mSeekbarProgress / 100.0f; value = mSeekbarProgress / 100.0f;
} } else {
else
{
value = (float) mSeekbarProgress; value = (float) mSeekbarProgress;
} }
FloatSetting setting = sliderSetting.setSelectedValue(value); FloatSetting setting = sliderSetting.setSelectedValue(value);
if (setting != null) if (setting != null) {
{
mView.putSetting(setting); mView.putSetting(setting);
} }
} } else {
else
{
IntSetting setting = sliderSetting.setSelectedValue(mSeekbarProgress); IntSetting setting = sliderSetting.setSelectedValue(mSeekbarProgress);
if (setting != null) if (setting != null) {
{
mView.putSetting(setting); mView.putSetting(setting);
} }
} }
@ -334,66 +303,51 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
mSeekbarProgress = -1; mSeekbarProgress = -1;
} }
public void closeDialog() public void closeDialog() {
{ if (mDialog != null) {
if (mDialog != null)
{
mDialog.dismiss(); mDialog.dismiss();
mDialog = null; mDialog = null;
} }
} }
@Override @Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
{
mSeekbarProgress = progress; mSeekbarProgress = progress;
mTextSliderValue.setText(String.valueOf(mSeekbarProgress)); mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
} }
@Override @Override
public void onStartTrackingTouch(SeekBar seekBar) public void onStartTrackingTouch(SeekBar seekBar) {
{
} }
@Override @Override
public void onStopTrackingTouch(SeekBar seekBar) public void onStopTrackingTouch(SeekBar seekBar) {
{
} }
private int getValueForSingleChoiceSelection(SingleChoiceSetting item, int which) private int getValueForSingleChoiceSelection(SingleChoiceSetting item, int which) {
{
int valuesId = item.getValuesId(); int valuesId = item.getValuesId();
if (valuesId > 0) if (valuesId > 0) {
{
int[] valuesArray = mContext.getResources().getIntArray(valuesId); int[] valuesArray = mContext.getResources().getIntArray(valuesId);
return valuesArray[which]; return valuesArray[which];
} } else {
else
{
return which; return which;
} }
} }
private int getSelectionForSingleChoiceValue(SingleChoiceSetting item) private int getSelectionForSingleChoiceValue(SingleChoiceSetting item) {
{
int value = item.getSelectedValue(); int value = item.getSelectedValue();
int valuesId = item.getValuesId(); int valuesId = item.getValuesId();
if (valuesId > 0) if (valuesId > 0) {
{
int[] valuesArray = mContext.getResources().getIntArray(valuesId); int[] valuesArray = mContext.getResources().getIntArray(valuesId);
for (int index = 0; index < valuesArray.length; index++) for (int index = 0; index < valuesArray.length; index++) {
{
int current = valuesArray[index]; int current = valuesArray[index];
if (current == value) if (current == value) {
{
return index; return index;
} }
} }
} } else {
else
{
return value; return value;
} }

View File

@ -21,8 +21,7 @@ import org.citra.citra_android.utils.SettingsFile;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
public final class SettingsFragment extends Fragment implements SettingsFragmentView public final class SettingsFragment extends Fragment implements SettingsFragmentView {
{
private static final String ARGUMENT_MENU_TAG = "menu_tag"; private static final String ARGUMENT_MENU_TAG = "menu_tag";
private static final String ARGUMENT_GAME_ID = "game_id"; private static final String ARGUMENT_GAME_ID = "game_id";
@ -31,8 +30,7 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
private SettingsAdapter mAdapter; private SettingsAdapter mAdapter;
public static Fragment newInstance(String menuTag, String gameId) public static Fragment newInstance(String menuTag, String gameId) {
{
SettingsFragment fragment = new SettingsFragment(); SettingsFragment fragment = new SettingsFragment();
Bundle arguments = new Bundle(); Bundle arguments = new Bundle();
@ -44,8 +42,7 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
} }
@Override @Override
public void onAttach(Context context) public void onAttach(Context context) {
{
super.onAttach(context); super.onAttach(context);
mActivity = (SettingsActivityView) context; mActivity = (SettingsActivityView) context;
@ -58,8 +55,7 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
* @param activity * @param activity
*/ */
@Override @Override
public void onAttach(Activity activity) public void onAttach(Activity activity) {
{
super.onAttach(activity); super.onAttach(activity);
mActivity = (SettingsActivityView) activity; mActivity = (SettingsActivityView) activity;
@ -67,8 +63,7 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState) {
{
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setRetainInstance(true); setRetainInstance(true);
@ -82,14 +77,12 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
{
return inflater.inflate(R.layout.fragment_settings, container, false); return inflater.inflate(R.layout.fragment_settings, container, false);
} }
@Override @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
{
LinearLayoutManager manager = new LinearLayoutManager(getActivity()); LinearLayoutManager manager = new LinearLayoutManager(getActivity());
RecyclerView recyclerView = view.findViewById(R.id.list_settings); RecyclerView recyclerView = view.findViewById(R.id.list_settings);
@ -106,83 +99,69 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
} }
@Override @Override
public void onDetach() public void onDetach() {
{
super.onDetach(); super.onDetach();
mActivity = null; mActivity = null;
if (mAdapter != null) if (mAdapter != null) {
{
mAdapter.closeDialog(); mAdapter.closeDialog();
} }
} }
@Override @Override
public void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings) public void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings) {
{
mPresenter.setSettings(settings); mPresenter.setSettings(settings);
} }
@Override @Override
public void passSettingsToActivity(ArrayList<HashMap<String, SettingSection>> settings) public void passSettingsToActivity(ArrayList<HashMap<String, SettingSection>> settings) {
{ if (mActivity != null) {
if (mActivity != null)
{
mActivity.setSettings(settings); mActivity.setSettings(settings);
} }
} }
@Override @Override
public void showSettingsList(ArrayList<SettingsItem> settingsList) public void showSettingsList(ArrayList<SettingsItem> settingsList) {
{
mAdapter.setSettings(settingsList); mAdapter.setSettings(settingsList);
} }
@Override @Override
public void loadDefaultSettings() public void loadDefaultSettings() {
{
mPresenter.loadDefaultSettings(); mPresenter.loadDefaultSettings();
} }
@Override @Override
public void loadSubMenu(String menuKey) public void loadSubMenu(String menuKey) {
{
mActivity.showSettingsFragment(menuKey, true, getArguments().getString(ARGUMENT_GAME_ID)); mActivity.showSettingsFragment(menuKey, true, getArguments().getString(ARGUMENT_GAME_ID));
} }
@Override @Override
public void showToastMessage(String message) public void showToastMessage(String message) {
{
mActivity.showToastMessage(message); mActivity.showToastMessage(message);
} }
@Override @Override
public void putSetting(Setting setting) public void putSetting(Setting setting) {
{
mPresenter.putSetting(setting); mPresenter.putSetting(setting);
} }
@Override @Override
public void onSettingChanged() public void onSettingChanged() {
{
mActivity.onSettingChanged(); mActivity.onSettingChanged();
} }
@Override @Override
public void onGcPadSettingChanged(String key, int value) public void onGcPadSettingChanged(String key, int value) {
{
mActivity.onGcPadSettingChanged(key, value); mActivity.onGcPadSettingChanged(key, value);
} }
@Override @Override
public void onWiimoteSettingChanged(String section, int value) public void onWiimoteSettingChanged(String section, int value) {
{
mActivity.onWiimoteSettingChanged(section, value); mActivity.onWiimoteSettingChanged(section, value);
} }
@Override @Override
public void onExtensionSettingChanged(String key, int value) public void onExtensionSettingChanged(String key, int value) {
{
mActivity.onExtensionSettingChanged(key, value); mActivity.onExtensionSettingChanged(key, value);
} }

View File

@ -18,8 +18,7 @@ import org.citra.citra_android.utils.SettingsFile;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
public final class SettingsFragmentPresenter public final class SettingsFragmentPresenter {
{
private SettingsFragmentView mView; private SettingsFragmentView mView;
private String mMenuTag; private String mMenuTag;
@ -31,20 +30,17 @@ public final class SettingsFragmentPresenter
private int mControllerNumber; private int mControllerNumber;
private int mControllerType; private int mControllerType;
public SettingsFragmentPresenter(SettingsFragmentView view) public SettingsFragmentPresenter(SettingsFragmentView view) {
{
mView = view; mView = view;
} }
public void onCreate(String menuTag, String gameId) public void onCreate(String menuTag, String gameId) {
{
mGameID = gameId; mGameID = gameId;
mMenuTag = menuTag; mMenuTag = menuTag;
} }
public void onViewCreated(ArrayList<HashMap<String, SettingSection>> settings) public void onViewCreated(ArrayList<HashMap<String, SettingSection>> settings) {
{
setSettings(settings); setSettings(settings);
} }
@ -53,48 +49,37 @@ public final class SettingsFragmentPresenter
* won't, though; so rather than have the Activity reload from disk, have the fragment pass * won't, though; so rather than have the Activity reload from disk, have the fragment pass
* the settings map back to the Activity. * the settings map back to the Activity.
*/ */
public void onAttach() public void onAttach() {
{ if (mSettings != null) {
if (mSettings != null)
{
mView.passSettingsToActivity(mSettings); mView.passSettingsToActivity(mSettings);
} }
} }
public void putSetting(Setting setting) public void putSetting(Setting setting) {
{
mSettings.get(setting.getFile()).get(setting.getSection()).putSetting(setting); mSettings.get(setting.getFile()).get(setting.getSection()).putSetting(setting);
} }
public void loadDefaultSettings() public void loadDefaultSettings() {
{
loadSettingsList(); loadSettingsList();
} }
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings) public void setSettings(ArrayList<HashMap<String, SettingSection>> settings) {
{ if (mSettingsList == null && settings != null) {
if (mSettingsList == null && settings != null)
{
mSettings = settings; mSettings = settings;
loadSettingsList(); loadSettingsList();
} } else {
else
{
mView.showSettingsList(mSettingsList); mView.showSettingsList(mSettingsList);
} }
} }
private void loadSettingsList() private void loadSettingsList() {
{ if (!TextUtils.isEmpty(mGameID)) {
if (!TextUtils.isEmpty(mGameID))
{
mView.getActivity().setTitle("Game Settings: " + mGameID); mView.getActivity().setTitle("Game Settings: " + mGameID);
} }
ArrayList<SettingsItem> sl = new ArrayList<>(); ArrayList<SettingsItem> sl = new ArrayList<>();
switch (mMenuTag) switch (mMenuTag) {
{
case SettingsFile.FILE_NAME_CONFIG: case SettingsFile.FILE_NAME_CONFIG:
addCoreSettings(sl); addCoreSettings(sl);
sl.add(new HeaderSetting(null, null, R.string.video_backend, 0)); sl.add(new HeaderSetting(null, null, R.string.video_backend, 0));
@ -109,30 +94,25 @@ public final class SettingsFragmentPresenter
mView.showSettingsList(mSettingsList); mView.showSettingsList(mSettingsList);
} }
private void addCoreSettings(ArrayList<SettingsItem> sl) private void addCoreSettings(ArrayList<SettingsItem> sl) {
{
Setting useCpuJit = null; Setting useCpuJit = null;
Setting audioStretch = null; Setting audioStretch = null;
Setting region = null; Setting region = null;
Setting systemClock = null; Setting systemClock = null;
Setting dateTime = null; Setting dateTime = null;
if (!mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty()) if (!mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty()) {
{
useCpuJit = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_CPU_JIT); useCpuJit = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_CPU_JIT);
audioStretch = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_AUDIO).getSetting(SettingsFile.KEY_ENABLE_AUDIO_STRETCHING); audioStretch = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_AUDIO).getSetting(SettingsFile.KEY_ENABLE_AUDIO_STRETCHING);
region = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_REGION_VALUE); region = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_REGION_VALUE);
systemClock = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_INIT_CLOCK); systemClock = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_INIT_CLOCK);
dateTime = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_INIT_TIME); dateTime = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_INIT_TIME);
} } else {
else
{
mView.passSettingsToActivity(mSettings); mView.passSettingsToActivity(mSettings);
} }
String defaultCpuCore = System.getProperty("os.arch"); String defaultCpuCore = System.getProperty("os.arch");
switch (defaultCpuCore) switch (defaultCpuCore) {
{
case "x86_64": case "x86_64":
sl.add(new CheckBoxSetting(SettingsFile.KEY_CPU_JIT, SettingsFile.SECTION_CORE, sl.add(new CheckBoxSetting(SettingsFile.KEY_CPU_JIT, SettingsFile.SECTION_CORE,
SettingsFile.SETTINGS_DOLPHIN, R.string.cpu_jit, 0, true, useCpuJit)); SettingsFile.SETTINGS_DOLPHIN, R.string.cpu_jit, 0, true, useCpuJit));
@ -147,8 +127,7 @@ public final class SettingsFragmentPresenter
sl.add(new DateTimeSetting(SettingsFile.KEY_INIT_TIME, SettingsFile.SECTION_SYSTEM, SettingsFile.SETTINGS_DOLPHIN, R.string.init_time, R.string.init_time_descrip, "2000-01-01 00:00:01", dateTime)); sl.add(new DateTimeSetting(SettingsFile.KEY_INIT_TIME, SettingsFile.SECTION_SYSTEM, SettingsFile.SETTINGS_DOLPHIN, R.string.init_time, R.string.init_time_descrip, "2000-01-01 00:00:01", dateTime));
} }
private void addGraphicsSettings(ArrayList<SettingsItem> sl) private void addGraphicsSettings(ArrayList<SettingsItem> sl) {
{
Setting hardwareRenderer = null; Setting hardwareRenderer = null;
Setting hardwareShader = null; Setting hardwareShader = null;
Setting shadersAccurateMul = null; Setting shadersAccurateMul = null;
@ -161,8 +140,7 @@ public final class SettingsFragmentPresenter
Setting stereoscopyEnable = null; Setting stereoscopyEnable = null;
Setting stereoscopyDepth = null; Setting stereoscopyDepth = null;
if (!mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty()) if (!mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty()) {
{
hardwareRenderer = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_HW_RENDERER); hardwareRenderer = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_HW_RENDERER);
hardwareShader = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_HW_SHADER); hardwareShader = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_HW_SHADER);
shadersAccurateMul = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL); shadersAccurateMul = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL);
@ -174,14 +152,11 @@ public final class SettingsFragmentPresenter
frameLimitValue = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FRAME_LIMIT); frameLimitValue = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FRAME_LIMIT);
stereoscopyEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_STEREOSCOPY); stereoscopyEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_STEREOSCOPY);
stereoscopyDepth = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FACTOR_3D); stereoscopyDepth = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FACTOR_3D);
} } else {
else
{
mView.passSettingsToActivity(mSettings); mView.passSettingsToActivity(mSettings);
} }
if (mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty()) if (mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty()) {
{
mView.passSettingsToActivity(mSettings); mView.passSettingsToActivity(mSettings);
} }
@ -206,8 +181,7 @@ public final class SettingsFragmentPresenter
EGLHelper helper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT); EGLHelper helper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT);
if ((helper.supportsOpenGL() && helper.GetVersion() >= 320) || if ((helper.supportsOpenGL() && helper.GetVersion() >= 320) ||
(helper.supportsGLES3() && helper.GetVersion() >= 310 && helper.SupportsExtension("GL_ANDROID_extension_pack_es31a"))) (helper.supportsGLES3() && helper.GetVersion() >= 310 && helper.SupportsExtension("GL_ANDROID_extension_pack_es31a"))) {
{
sl.add(new CheckBoxSetting(SettingsFile.KEY_STEREOSCOPY, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.stereoscopy, R.string.stereoscopy_descrip, false, stereoscopyEnable)); sl.add(new CheckBoxSetting(SettingsFile.KEY_STEREOSCOPY, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.stereoscopy, R.string.stereoscopy_descrip, false, stereoscopyEnable));
sl.add(new SliderSetting(SettingsFile.KEY_FACTOR_3D, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.sterescopy_depth, R.string.sterescopy_depth_descrip, 100, "%", 0, stereoscopyDepth)); sl.add(new SliderSetting(SettingsFile.KEY_FACTOR_3D, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.sterescopy_depth, R.string.sterescopy_depth_descrip, 100, "%", 0, stereoscopyDepth));
} }
@ -215,8 +189,7 @@ public final class SettingsFragmentPresenter
} }
private void addGcPadSubSettings(ArrayList<SettingsItem> sl, int gcPadNumber, int gcPadType) private void addGcPadSubSettings(ArrayList<SettingsItem> sl, int gcPadNumber, int gcPadType) {
{
/* /*
if (gcPadType == 1) // Emulated if (gcPadType == 1) // Emulated
{ {
@ -282,14 +255,10 @@ public final class SettingsFragmentPresenter
*/ */
} }
private boolean getInvertedBooleanValue(int file, String section, String key, boolean defaultValue) private boolean getInvertedBooleanValue(int file, String section, String key, boolean defaultValue) {
{ try {
try
{
return ((IntSetting) mSettings.get(file).get(section).getSetting(key)).getValue() != 1; return ((IntSetting) mSettings.get(file).get(section).getSetting(key)).getValue() != 1;
} } catch (NullPointerException ex) {
catch (NullPointerException ex)
{
return defaultValue; return defaultValue;
} }
} }

View File

@ -13,8 +13,7 @@ import java.util.HashMap;
* Abstraction for a screen showing a list of settings. Instances of * Abstraction for a screen showing a list of settings. Instances of
* this type of view will each display a layer of the setting hierarchy. * this type of view will each display a layer of the setting hierarchy.
*/ */
public interface SettingsFragmentView public interface SettingsFragmentView {
{
/** /**
* Called by the containing Activity to notify the Fragment that an * Called by the containing Activity to notify the Fragment that an
* asynchronous load operation completed. * asynchronous load operation completed.

View File

@ -7,48 +7,39 @@ import android.widget.FrameLayout;
/** /**
* FrameLayout subclass with few Properties added to simplify animations. * FrameLayout subclass with few Properties added to simplify animations.
*/ */
public final class SettingsFrameLayout extends FrameLayout public final class SettingsFrameLayout extends FrameLayout {
{
private float mVisibleness = 1.0f; private float mVisibleness = 1.0f;
public SettingsFrameLayout(Context context) public SettingsFrameLayout(Context context) {
{
super(context); super(context);
} }
public SettingsFrameLayout(Context context, AttributeSet attrs) public SettingsFrameLayout(Context context, AttributeSet attrs) {
{
super(context, attrs); super(context, attrs);
} }
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
{
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
} }
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
{
super(context, attrs, defStyleAttr, defStyleRes); super(context, attrs, defStyleAttr, defStyleRes);
} }
public float getYFraction() public float getYFraction() {
{
return getY() / getHeight(); return getY() / getHeight();
} }
public void setYFraction(float yFraction) public void setYFraction(float yFraction) {
{
final int height = getHeight(); final int height = getHeight();
setY((height > 0) ? (yFraction * height) : -9999); setY((height > 0) ? (yFraction * height) : -9999);
} }
public float getVisibleness() public float getVisibleness() {
{
return mVisibleness; return mVisibleness;
} }
public void setVisibleness(float visibleness) public void setVisibleness(float visibleness) {
{
setScaleX(visibleness); setScaleX(visibleness);
setScaleY(visibleness); setScaleY(visibleness);
setAlpha(visibleness); setAlpha(visibleness);

View File

@ -9,8 +9,7 @@ import org.citra.citra_android.model.settings.view.CheckBoxSetting;
import org.citra.citra_android.model.settings.view.SettingsItem; import org.citra.citra_android.model.settings.view.SettingsItem;
import org.citra.citra_android.ui.settings.SettingsAdapter; import org.citra.citra_android.ui.settings.SettingsAdapter;
public final class CheckBoxSettingViewHolder extends SettingViewHolder public final class CheckBoxSettingViewHolder extends SettingViewHolder {
{
private CheckBoxSetting mItem; private CheckBoxSetting mItem;
private TextView mTextSettingName; private TextView mTextSettingName;
@ -18,28 +17,24 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder
private CheckBox mCheckbox; private CheckBox mCheckbox;
public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter) public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter) {
{
super(itemView, adapter); super(itemView, adapter);
} }
@Override @Override
protected void findViews(View root) protected void findViews(View root) {
{
mTextSettingName = root.findViewById(R.id.text_setting_name); mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description); mTextSettingDescription = root.findViewById(R.id.text_setting_description);
mCheckbox = root.findViewById(R.id.checkbox); mCheckbox = root.findViewById(R.id.checkbox);
} }
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item) {
{
mItem = (CheckBoxSetting) item; mItem = (CheckBoxSetting) item;
mTextSettingName.setText(item.getNameId()); mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() > 0) if (item.getDescriptionId() > 0) {
{
mTextSettingDescription.setText(item.getDescriptionId()); mTextSettingDescription.setText(item.getDescriptionId());
} }
@ -47,8 +42,7 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder
} }
@Override @Override
public void onClick(View clicked) public void onClick(View clicked) {
{
mCheckbox.toggle(); mCheckbox.toggle();
getAdapter().onBooleanClick(mItem, getAdapterPosition(), mCheckbox.isChecked()); getAdapter().onBooleanClick(mItem, getAdapterPosition(), mCheckbox.isChecked());

View File

@ -9,21 +9,18 @@ import org.citra.citra_android.model.settings.view.SettingsItem;
import org.citra.citra_android.ui.settings.SettingsAdapter; import org.citra.citra_android.ui.settings.SettingsAdapter;
import org.citra.citra_android.utils.Log; import org.citra.citra_android.utils.Log;
public final class DateTimeViewHolder extends SettingViewHolder public final class DateTimeViewHolder extends SettingViewHolder {
{
private DateTimeSetting mItem; private DateTimeSetting mItem;
private TextView mTextSettingName; private TextView mTextSettingName;
private TextView mTextSettingDescription; private TextView mTextSettingDescription;
public DateTimeViewHolder(View itemView, SettingsAdapter adapter) public DateTimeViewHolder(View itemView, SettingsAdapter adapter) {
{
super(itemView, adapter); super(itemView, adapter);
} }
@Override @Override
protected void findViews(View root) protected void findViews(View root) {
{
mTextSettingName = root.findViewById(R.id.text_setting_name); mTextSettingName = root.findViewById(R.id.text_setting_name);
Log.error("test " + mTextSettingName); Log.error("test " + mTextSettingName);
mTextSettingDescription = root.findViewById(R.id.text_setting_description); mTextSettingDescription = root.findViewById(R.id.text_setting_description);
@ -31,19 +28,16 @@ public final class DateTimeViewHolder extends SettingViewHolder
} }
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item) {
{
mItem = (DateTimeSetting) item; mItem = (DateTimeSetting) item;
mTextSettingName.setText(item.getNameId()); mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() > 0) if (item.getDescriptionId() > 0) {
{
mTextSettingDescription.setText(item.getDescriptionId()); mTextSettingDescription.setText(item.getDescriptionId());
} }
} }
@Override @Override
public void onClick(View clicked) public void onClick(View clicked) {
{
getAdapter().onDateTimeClick(mItem); getAdapter().onDateTimeClick(mItem);
} }
} }

View File

@ -7,31 +7,26 @@ import org.citra.citra_android.R;
import org.citra.citra_android.model.settings.view.SettingsItem; import org.citra.citra_android.model.settings.view.SettingsItem;
import org.citra.citra_android.ui.settings.SettingsAdapter; import org.citra.citra_android.ui.settings.SettingsAdapter;
public final class HeaderViewHolder extends SettingViewHolder public final class HeaderViewHolder extends SettingViewHolder {
{
private TextView mHeaderName; private TextView mHeaderName;
public HeaderViewHolder(View itemView, SettingsAdapter adapter) public HeaderViewHolder(View itemView, SettingsAdapter adapter) {
{
super(itemView, adapter); super(itemView, adapter);
itemView.setOnClickListener(null); itemView.setOnClickListener(null);
} }
@Override @Override
protected void findViews(View root) protected void findViews(View root) {
{
mHeaderName = root.findViewById(R.id.text_header_name); mHeaderName = root.findViewById(R.id.text_header_name);
} }
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item) {
{
mHeaderName.setText(item.getNameId()); mHeaderName.setText(item.getNameId());
} }
@Override @Override
public void onClick(View clicked) public void onClick(View clicked) {
{
// no-op // no-op
} }
} }

View File

@ -11,8 +11,7 @@ import org.citra.citra_android.model.settings.view.InputBindingSetting;
import org.citra.citra_android.model.settings.view.SettingsItem; import org.citra.citra_android.model.settings.view.SettingsItem;
import org.citra.citra_android.ui.settings.SettingsAdapter; import org.citra.citra_android.ui.settings.SettingsAdapter;
public final class InputBindingSettingViewHolder extends SettingViewHolder public final class InputBindingSettingViewHolder extends SettingViewHolder {
{
private InputBindingSetting mItem; private InputBindingSetting mItem;
private TextView mTextSettingName; private TextView mTextSettingName;
@ -20,23 +19,20 @@ public final class InputBindingSettingViewHolder extends SettingViewHolder
private Context mContext; private Context mContext;
public InputBindingSettingViewHolder(View itemView, SettingsAdapter adapter, Context context) public InputBindingSettingViewHolder(View itemView, SettingsAdapter adapter, Context context) {
{
super(itemView, adapter); super(itemView, adapter);
mContext = context; mContext = context;
} }
@Override @Override
protected void findViews(View root) protected void findViews(View root) {
{
mTextSettingName = root.findViewById(R.id.text_setting_name); mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description); mTextSettingDescription = root.findViewById(R.id.text_setting_description);
} }
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item) {
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
mItem = (InputBindingSetting) item; mItem = (InputBindingSetting) item;
@ -46,8 +42,7 @@ public final class InputBindingSettingViewHolder extends SettingViewHolder
} }
@Override @Override
public void onClick(View clicked) public void onClick(View clicked) {
{
getAdapter().onInputBindingClick(mItem, getAdapterPosition()); getAdapter().onInputBindingClick(mItem, getAdapterPosition());
} }
} }

View File

@ -6,12 +6,10 @@ import android.view.View;
import org.citra.citra_android.model.settings.view.SettingsItem; import org.citra.citra_android.model.settings.view.SettingsItem;
import org.citra.citra_android.ui.settings.SettingsAdapter; import org.citra.citra_android.ui.settings.SettingsAdapter;
public abstract class SettingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener public abstract class SettingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
{
private SettingsAdapter mAdapter; private SettingsAdapter mAdapter;
public SettingViewHolder(View itemView, SettingsAdapter adapter) public SettingViewHolder(View itemView, SettingsAdapter adapter) {
{
super(itemView); super(itemView);
mAdapter = adapter; mAdapter = adapter;
@ -21,8 +19,7 @@ public abstract class SettingViewHolder extends RecyclerView.ViewHolder implemen
findViews(itemView); findViews(itemView);
} }
protected SettingsAdapter getAdapter() protected SettingsAdapter getAdapter() {
{
return mAdapter; return mAdapter;
} }

View File

@ -8,41 +8,35 @@ import org.citra.citra_android.model.settings.view.SettingsItem;
import org.citra.citra_android.model.settings.view.SingleChoiceSetting; import org.citra.citra_android.model.settings.view.SingleChoiceSetting;
import org.citra.citra_android.ui.settings.SettingsAdapter; import org.citra.citra_android.ui.settings.SettingsAdapter;
public final class SingleChoiceViewHolder extends SettingViewHolder public final class SingleChoiceViewHolder extends SettingViewHolder {
{
private SingleChoiceSetting mItem; private SingleChoiceSetting mItem;
private TextView mTextSettingName; private TextView mTextSettingName;
private TextView mTextSettingDescription; private TextView mTextSettingDescription;
public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter) public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter) {
{
super(itemView, adapter); super(itemView, adapter);
} }
@Override @Override
protected void findViews(View root) protected void findViews(View root) {
{
mTextSettingName = root.findViewById(R.id.text_setting_name); mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description); mTextSettingDescription = root.findViewById(R.id.text_setting_description);
} }
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item) {
{
mItem = (SingleChoiceSetting) item; mItem = (SingleChoiceSetting) item;
mTextSettingName.setText(item.getNameId()); mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() > 0) if (item.getDescriptionId() > 0) {
{
mTextSettingDescription.setText(item.getDescriptionId()); mTextSettingDescription.setText(item.getDescriptionId());
} }
} }
@Override @Override
public void onClick(View clicked) public void onClick(View clicked) {
{
getAdapter().onSingleChoiceClick(mItem); getAdapter().onSingleChoiceClick(mItem);
} }
} }

View File

@ -8,41 +8,35 @@ import org.citra.citra_android.model.settings.view.SettingsItem;
import org.citra.citra_android.model.settings.view.SliderSetting; import org.citra.citra_android.model.settings.view.SliderSetting;
import org.citra.citra_android.ui.settings.SettingsAdapter; import org.citra.citra_android.ui.settings.SettingsAdapter;
public final class SliderViewHolder extends SettingViewHolder public final class SliderViewHolder extends SettingViewHolder {
{
private SliderSetting mItem; private SliderSetting mItem;
private TextView mTextSettingName; private TextView mTextSettingName;
private TextView mTextSettingDescription; private TextView mTextSettingDescription;
public SliderViewHolder(View itemView, SettingsAdapter adapter) public SliderViewHolder(View itemView, SettingsAdapter adapter) {
{
super(itemView, adapter); super(itemView, adapter);
} }
@Override @Override
protected void findViews(View root) protected void findViews(View root) {
{
mTextSettingName = root.findViewById(R.id.text_setting_name); mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description); mTextSettingDescription = root.findViewById(R.id.text_setting_description);
} }
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item) {
{
mItem = (SliderSetting) item; mItem = (SliderSetting) item;
mTextSettingName.setText(item.getNameId()); mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() > 0) if (item.getDescriptionId() > 0) {
{
mTextSettingDescription.setText(item.getDescriptionId()); mTextSettingDescription.setText(item.getDescriptionId());
} }
} }
@Override @Override
public void onClick(View clicked) public void onClick(View clicked) {
{
getAdapter().onSliderClick(mItem); getAdapter().onSliderClick(mItem);
} }
} }

View File

@ -8,41 +8,35 @@ import org.citra.citra_android.model.settings.view.SettingsItem;
import org.citra.citra_android.model.settings.view.SubmenuSetting; import org.citra.citra_android.model.settings.view.SubmenuSetting;
import org.citra.citra_android.ui.settings.SettingsAdapter; import org.citra.citra_android.ui.settings.SettingsAdapter;
public final class SubmenuViewHolder extends SettingViewHolder public final class SubmenuViewHolder extends SettingViewHolder {
{
private SubmenuSetting mItem; private SubmenuSetting mItem;
private TextView mTextSettingName; private TextView mTextSettingName;
private TextView mTextSettingDescription; private TextView mTextSettingDescription;
public SubmenuViewHolder(View itemView, SettingsAdapter adapter) public SubmenuViewHolder(View itemView, SettingsAdapter adapter) {
{
super(itemView, adapter); super(itemView, adapter);
} }
@Override @Override
protected void findViews(View root) protected void findViews(View root) {
{
mTextSettingName = root.findViewById(R.id.text_setting_name); mTextSettingName = root.findViewById(R.id.text_setting_name);
mTextSettingDescription = root.findViewById(R.id.text_setting_description); mTextSettingDescription = root.findViewById(R.id.text_setting_description);
} }
@Override @Override
public void bind(SettingsItem item) public void bind(SettingsItem item) {
{
mItem = (SubmenuSetting) item; mItem = (SubmenuSetting) item;
mTextSettingName.setText(item.getNameId()); mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() > 0) if (item.getDescriptionId() > 0) {
{
mTextSettingDescription.setText(item.getDescriptionId()); mTextSettingDescription.setText(item.getDescriptionId());
} }
} }
@Override @Override
public void onClick(View clicked) public void onClick(View clicked) {
{
getAdapter().onSubmenuClick(mItem); getAdapter().onSubmenuClick(mItem);
} }
} }

View File

@ -8,27 +8,17 @@ import android.net.Uri;
import org.citra.citra_android.model.GameDatabase; import org.citra.citra_android.model.GameDatabase;
import org.citra.citra_android.model.GameProvider; import org.citra.citra_android.model.GameProvider;
public class AddDirectoryHelper public class AddDirectoryHelper {
{
private Context mContext; private Context mContext;
public interface AddDirectoryListener public AddDirectoryHelper(Context context) {
{
void onDirectoryAdded();
}
public AddDirectoryHelper(Context context)
{
this.mContext = context; this.mContext = context;
} }
public void addDirectory(String dir, AddDirectoryListener addDirectoryListener) public void addDirectory(String dir, AddDirectoryListener addDirectoryListener) {
{ AsyncQueryHandler handler = new AsyncQueryHandler(mContext.getContentResolver()) {
AsyncQueryHandler handler = new AsyncQueryHandler(mContext.getContentResolver())
{
@Override @Override
protected void onInsertComplete(int token, Object cookie, Uri uri) protected void onInsertComplete(int token, Object cookie, Uri uri) {
{
addDirectoryListener.onDirectoryAdded(); addDirectoryListener.onDirectoryAdded();
} }
}; };
@ -41,4 +31,8 @@ public class AddDirectoryHelper
GameProvider.URI_FOLDER, // Tell the GameProvider we are adding a folder GameProvider.URI_FOLDER, // Tell the GameProvider we are adding a folder
file); file);
} }
public interface AddDirectoryListener {
void onDirectoryAdded();
}
} }

View File

@ -3,14 +3,11 @@ package org.citra.citra_android.utils;
import android.view.View; import android.view.View;
import android.view.ViewPropertyAnimator; import android.view.ViewPropertyAnimator;
public final class Animations public final class Animations {
{ private Animations() {
private Animations()
{
} }
public static ViewPropertyAnimator fadeViewIn(View view) public static ViewPropertyAnimator fadeViewIn(View view) {
{
view.setVisibility(View.VISIBLE); view.setVisibility(View.VISIBLE);
return view.animate() return view.animate()
@ -19,8 +16,7 @@ public final class Animations
.alpha(1.0f); .alpha(1.0f);
} }
public static ViewPropertyAnimator fadeViewOut(View view) public static ViewPropertyAnimator fadeViewOut(View view) {
{
return view.animate() return view.animate()
.withLayer() .withLayer()
.setDuration(300) .setDuration(300)

View File

@ -7,15 +7,12 @@ import android.view.MotionEvent;
/** /**
* Some controllers have incorrect mappings. This class has special-case fixes for them. * Some controllers have incorrect mappings. This class has special-case fixes for them.
*/ */
public class ControllerMappingHelper public class ControllerMappingHelper {
{
/** /**
* Some controllers report extra button presses that can be ignored. * Some controllers report extra button presses that can be ignored.
*/ */
public boolean shouldKeyBeIgnored(InputDevice inputDevice, int keyCode) public boolean shouldKeyBeIgnored(InputDevice inputDevice, int keyCode) {
{ if (isDualShock4(inputDevice)) {
if (isDualShock4(inputDevice))
{
// The two analog triggers generate analog motion events as well as a keycode. // The two analog triggers generate analog motion events as well as a keycode.
// We always prefer to use the analog values, so throw away the button press // We always prefer to use the analog values, so throw away the button press
// Even though the triggers are L/R2, without mappings they generate L/R1 events. // Even though the triggers are L/R2, without mappings they generate L/R1 events.
@ -27,56 +24,43 @@ public class ControllerMappingHelper
/** /**
* Scale an axis to be zero-centered with a proper range. * Scale an axis to be zero-centered with a proper range.
*/ */
public float scaleAxis(InputDevice inputDevice, int axis, float value) public float scaleAxis(InputDevice inputDevice, int axis, float value) {
{ if (isDualShock4(inputDevice)) {
if (isDualShock4(inputDevice))
{
// Android doesn't have correct mappings for this controller's triggers. It reports them // Android doesn't have correct mappings for this controller's triggers. It reports them
// as RX & RY, centered at -1.0, and with a range of [-1.0, 1.0] // as RX & RY, centered at -1.0, and with a range of [-1.0, 1.0]
// Scale them to properly zero-centered with a range of [0.0, 1.0]. // Scale them to properly zero-centered with a range of [0.0, 1.0].
if (axis == MotionEvent.AXIS_RX || axis == MotionEvent.AXIS_RY) if (axis == MotionEvent.AXIS_RX || axis == MotionEvent.AXIS_RY) {
{
return (value + 1) / 2.0f; return (value + 1) / 2.0f;
} }
} } else if (isXboxOneWireless(inputDevice)) {
else if (isXboxOneWireless(inputDevice))
{
// Same as the DualShock 4, the mappings are missing. // Same as the DualShock 4, the mappings are missing.
if (axis == MotionEvent.AXIS_Z || axis == MotionEvent.AXIS_RZ) if (axis == MotionEvent.AXIS_Z || axis == MotionEvent.AXIS_RZ) {
{
return (value + 1) / 2.0f; return (value + 1) / 2.0f;
} }
if (axis == MotionEvent.AXIS_GENERIC_1) if (axis == MotionEvent.AXIS_GENERIC_1) {
{
// This axis is stuck at ~.5. Ignore it. // This axis is stuck at ~.5. Ignore it.
return 0.0f; return 0.0f;
} }
} } else if (isMogaPro2Hid(inputDevice)) {
else if (isMogaPro2Hid(inputDevice))
{
// This controller has a broken axis that reports a constant value. Ignore it. // This controller has a broken axis that reports a constant value. Ignore it.
if (axis == MotionEvent.AXIS_GENERIC_1) if (axis == MotionEvent.AXIS_GENERIC_1) {
{
return 0.0f; return 0.0f;
} }
} }
return value; return value;
} }
private boolean isDualShock4(InputDevice inputDevice) private boolean isDualShock4(InputDevice inputDevice) {
{
// Sony DualShock 4 controller // Sony DualShock 4 controller
return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc; return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc;
} }
private boolean isXboxOneWireless(InputDevice inputDevice) private boolean isXboxOneWireless(InputDevice inputDevice) {
{
// Microsoft Xbox One controller // Microsoft Xbox One controller
return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0; return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0;
} }
private boolean isMogaPro2Hid(InputDevice inputDevice) private boolean isMogaPro2Hid(InputDevice inputDevice) {
{
// Moga Pro 2 HID // Moga Pro 2 HID
return inputDevice.getVendorId() == 0x20d6 && inputDevice.getProductId() == 0x6271; return inputDevice.getVendorId() == 0x20d6 && inputDevice.getProductId() == 0x6271;
} }

View File

@ -9,18 +9,15 @@ import org.citra.citra_android.services.DirectoryInitializationService.Directory
import rx.functions.Action1; import rx.functions.Action1;
public class DirectoryStateReceiver extends BroadcastReceiver public class DirectoryStateReceiver extends BroadcastReceiver {
{
Action1<DirectoryInitializationState> callback; Action1<DirectoryInitializationState> callback;
public DirectoryStateReceiver(Action1<DirectoryInitializationState> callback) public DirectoryStateReceiver(Action1<DirectoryInitializationState> callback) {
{
this.callback = callback; this.callback = callback;
} }
@Override @Override
public void onReceive(Context context, Intent intent) public void onReceive(Context context, Intent intent) {
{
DirectoryInitializationState state = (DirectoryInitializationState) intent DirectoryInitializationState state = (DirectoryInitializationState) intent
.getSerializableExtra(DirectoryInitializationService.EXTRA_STATE); .getSerializableExtra(DirectoryInitializationService.EXTRA_STATE);
callback.call(state); callback.call(state);

View File

@ -22,30 +22,26 @@ import javax.microedition.khronos.opengles.GL10;
* EGL initialization out of the way if all that is * EGL initialization out of the way if all that is
* wanted is to query the underlying GL API for information. * wanted is to query the underlying GL API for information.
*/ */
public final class EGLHelper public final class EGLHelper {
{ // Renderable type bitmasks
public static final int EGL_OPENGL_ES_BIT = 0x0001;
public static final int EGL_OPENGL_ES2_BIT = 0x0004;
public static final int EGL_OPENGL_BIT = 0x0008;
public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
// API types
public static final int EGL_OPENGL_ES_API = 0x30A0;
public static final int EGL_OPENGL_API = 0x30A2;
private final EGL10 mEGL; private final EGL10 mEGL;
private final EGLDisplay mDisplay; private final EGLDisplay mDisplay;
private EGLConfig[] mEGLConfigs; private EGLConfig[] mEGLConfigs;
private EGLContext mEGLContext; private EGLContext mEGLContext;
private EGLSurface mEGLSurface; private EGLSurface mEGLSurface;
private GL10 mGL; private GL10 mGL;
// GL support flags // GL support flags
private boolean supportGL; private boolean supportGL;
private boolean supportGLES2; private boolean supportGLES2;
private boolean supportGLES3; private boolean supportGLES3;
// Renderable type bitmasks
public static final int EGL_OPENGL_ES_BIT = 0x0001;
public static final int EGL_OPENGL_ES2_BIT = 0x0004;
public static final int EGL_OPENGL_BIT = 0x0008;
public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
// API types
public static final int EGL_OPENGL_ES_API = 0x30A0;
public static final int EGL_OPENGL_API = 0x30A2;
/** /**
* Constructor * Constructor
* <p> * <p>
@ -56,8 +52,7 @@ public final class EGLHelper
* @param renderableType Bitmask indicating which types of client API contexts * @param renderableType Bitmask indicating which types of client API contexts
* the framebuffer config must support. * the framebuffer config must support.
*/ */
public EGLHelper(int renderableType) public EGLHelper(int renderableType) {
{
this(1, 1, renderableType); this(1, 1, renderableType);
} }
@ -69,31 +64,24 @@ public final class EGLHelper
* @param renderableType Bitmask indicating which types of client API contexts * @param renderableType Bitmask indicating which types of client API contexts
* the framebuffer config must support. * the framebuffer config must support.
*/ */
public EGLHelper(int width, int height, int renderableType) public EGLHelper(int width, int height, int renderableType) {
{
// Initialize handle to an EGL display. // Initialize handle to an EGL display.
mEGL = (EGL10) EGLContext.getEGL(); mEGL = (EGL10) EGLContext.getEGL();
mDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); mDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
// If a display is present, initialize EGL. // If a display is present, initialize EGL.
if (mDisplay != EGL10.EGL_NO_DISPLAY) if (mDisplay != EGL10.EGL_NO_DISPLAY) {
{
int[] version = new int[2]; int[] version = new int[2];
if (mEGL.eglInitialize(mDisplay, version)) if (mEGL.eglInitialize(mDisplay, version)) {
{
// Detect supported GL APIs, initialize configs, etc. // Detect supported GL APIs, initialize configs, etc.
detect(); detect();
// Create context and surface // Create context and surface
create(width, height, renderableType); create(width, height, renderableType);
} } else {
else
{
Log.error("[EGLHelper] Error initializing EGL."); Log.error("[EGLHelper] Error initializing EGL.");
} }
} } else {
else
{
Log.error("[EGLHelper] Error initializing EGL display."); Log.error("[EGLHelper] Error initializing EGL display.");
} }
} }
@ -103,8 +91,7 @@ public final class EGLHelper
* <p> * <p>
* This should be called whenever this helper is no longer needed. * This should be called whenever this helper is no longer needed.
*/ */
public void closeHelper() public void closeHelper() {
{
mEGL.eglTerminate(mDisplay); mEGL.eglTerminate(mDisplay);
} }
@ -118,8 +105,7 @@ public final class EGLHelper
* *
* @return information retrieved through EGL. * @return information retrieved through EGL.
*/ */
public String[] getEGLInfo() public String[] getEGLInfo() {
{
return new String[]{ return new String[]{
mGL.glGetString(GL10.GL_VENDOR), mGL.glGetString(GL10.GL_VENDOR),
mGL.glGetString(GL10.GL_VERSION), mGL.glGetString(GL10.GL_VERSION),
@ -133,8 +119,7 @@ public final class EGLHelper
* *
* @return true if this device supports OpenGL; false otherwise. * @return true if this device supports OpenGL; false otherwise.
*/ */
public boolean supportsOpenGL() public boolean supportsOpenGL() {
{
return supportGL; return supportGL;
} }
@ -145,8 +130,7 @@ public final class EGLHelper
* *
* @return true if this device supports OpenGL ES 2; false otherwise. * @return true if this device supports OpenGL ES 2; false otherwise.
*/ */
public boolean supportsGLES2() public boolean supportsGLES2() {
{
return supportGLES2; return supportGLES2;
} }
@ -157,8 +141,7 @@ public final class EGLHelper
* *
* @return true if this device supports OpenGL ES 3; false otherwise. * @return true if this device supports OpenGL ES 3; false otherwise.
*/ */
public boolean supportsGLES3() public boolean supportsGLES3() {
{
return supportGLES3; return supportGLES3;
} }
@ -167,8 +150,7 @@ public final class EGLHelper
* *
* @return the underlying {@link EGL10} instance. * @return the underlying {@link EGL10} instance.
*/ */
public EGL10 getEGL() public EGL10 getEGL() {
{
return mEGL; return mEGL;
} }
@ -177,8 +159,7 @@ public final class EGLHelper
* *
* @return the underlying {@link GL10} instance. * @return the underlying {@link GL10} instance.
*/ */
public GL10 getGL() public GL10 getGL() {
{
return mGL; return mGL;
} }
@ -187,8 +168,7 @@ public final class EGLHelper
* *
* @return the underlying {@link EGLDisplay} * @return the underlying {@link EGLDisplay}
*/ */
public EGLDisplay getDisplay() public EGLDisplay getDisplay() {
{
return mDisplay; return mDisplay;
} }
@ -197,8 +177,7 @@ public final class EGLHelper
* *
* @return all supported framebuffer configurations for this device. * @return all supported framebuffer configurations for this device.
*/ */
public EGLConfig[] getConfigs() public EGLConfig[] getConfigs() {
{
return mEGLConfigs; return mEGLConfigs;
} }
@ -207,8 +186,7 @@ public final class EGLHelper
* *
* @return the underlying {@link EGLContext}. * @return the underlying {@link EGLContext}.
*/ */
public EGLContext getContext() public EGLContext getContext() {
{
return mEGLContext; return mEGLContext;
} }
@ -217,37 +195,31 @@ public final class EGLHelper
* *
* @return the underlying {@link EGLSurface}. * @return the underlying {@link EGLSurface}.
*/ */
public EGLSurface getSurface() public EGLSurface getSurface() {
{
return mEGLSurface; return mEGLSurface;
} }
// Detects the specific kind of GL modes that are supported // Detects the specific kind of GL modes that are supported
private boolean detect() private boolean detect() {
{
// Get total number of configs available. // Get total number of configs available.
int[] numConfigs = new int[1]; int[] numConfigs = new int[1];
if (!mEGL.eglGetConfigs(mDisplay, null, 0, numConfigs)) if (!mEGL.eglGetConfigs(mDisplay, null, 0, numConfigs)) {
{
Log.error("[EGLHelper] Error retrieving number of EGL configs available."); Log.error("[EGLHelper] Error retrieving number of EGL configs available.");
return false; return false;
} }
// Now get all the configurations // Now get all the configurations
mEGLConfigs = new EGLConfig[numConfigs[0]]; mEGLConfigs = new EGLConfig[numConfigs[0]];
if (!mEGL.eglGetConfigs(mDisplay, mEGLConfigs, mEGLConfigs.length, numConfigs)) if (!mEGL.eglGetConfigs(mDisplay, mEGLConfigs, mEGLConfigs.length, numConfigs)) {
{
Log.error("[EGLHelper] Error retrieving all EGL configs."); Log.error("[EGLHelper] Error retrieving all EGL configs.");
return false; return false;
} }
for (EGLConfig mEGLConfig : mEGLConfigs) for (EGLConfig mEGLConfig : mEGLConfigs) {
{
int[] attribVal = new int[1]; int[] attribVal = new int[1];
boolean ret = boolean ret =
mEGL.eglGetConfigAttrib(mDisplay, mEGLConfig, EGL10.EGL_RENDERABLE_TYPE, attribVal); mEGL.eglGetConfigAttrib(mDisplay, mEGLConfig, EGL10.EGL_RENDERABLE_TYPE, attribVal);
if (ret) if (ret) {
{
if ((attribVal[0] & EGL_OPENGL_BIT) != 0) if ((attribVal[0] & EGL_OPENGL_BIT) != 0)
supportGL = true; supportGL = true;
@ -263,8 +235,7 @@ public final class EGLHelper
} }
// Creates the context and surface. // Creates the context and surface.
private void create(int width, int height, int renderableType) private void create(int width, int height, int renderableType) {
{
int[] attribs = { int[] attribs = {
EGL10.EGL_WIDTH, width, EGL10.EGL_WIDTH, width,
EGL10.EGL_HEIGHT, height, EGL10.EGL_HEIGHT, height,
@ -280,8 +251,7 @@ public final class EGLHelper
// Determine the type of context that will be created // Determine the type of context that will be created
// and change the attribute arrays accordingly. // and change the attribute arrays accordingly.
switch (renderableType) switch (renderableType) {
{
case EGL_OPENGL_ES_BIT: case EGL_OPENGL_ES_BIT:
ctx_attribs[1] = 1; ctx_attribs[1] = 1;
break; break;
@ -325,8 +295,7 @@ public final class EGLHelper
* @param glEnum A symbolic constant within {@link GL10}. * @param glEnum A symbolic constant within {@link GL10}.
* @return the string information represented by {@code glEnum}. * @return the string information represented by {@code glEnum}.
*/ */
public String glGetString(int glEnum) public String glGetString(int glEnum) {
{
return mGL.glGetString(glEnum); return mGL.glGetString(glEnum);
} }
@ -346,18 +315,15 @@ public final class EGLHelper
* @param index The index of the string to return. * @param index The index of the string to return.
* @return the string information represented by {@code glEnum} and {@code index}. * @return the string information represented by {@code glEnum} and {@code index}.
*/ */
public String glGetStringi(int glEnum, int index) public String glGetStringi(int glEnum, int index) {
{
return GLES30.glGetStringi(glEnum, index); return GLES30.glGetStringi(glEnum, index);
} }
public boolean SupportsExtension(String extension) public boolean SupportsExtension(String extension) {
{
int[] num_ext = new int[1]; int[] num_ext = new int[1];
GLES30.glGetIntegerv(GLES30.GL_NUM_EXTENSIONS, num_ext, 0); GLES30.glGetIntegerv(GLES30.GL_NUM_EXTENSIONS, num_ext, 0);
for (int i = 0; i < num_ext[0]; ++i) for (int i = 0; i < num_ext[0]; ++i) {
{
String ext = GLES30.glGetStringi(GLES30.GL_EXTENSIONS, i); String ext = GLES30.glGetStringi(GLES30.GL_EXTENSIONS, i);
if (ext.equals(extension)) if (ext.equals(extension))
return true; return true;
@ -365,8 +331,7 @@ public final class EGLHelper
return false; return false;
} }
public int GetVersion() public int GetVersion() {
{
int[] major = new int[1]; int[] major = new int[1];
int[] minor = new int[1]; int[] minor = new int[1];
GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, major, 0); GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, major, 0);
@ -380,8 +345,7 @@ public final class EGLHelper
* @param glEnum A symbolic GL constant. * @param glEnum A symbolic GL constant.
* @return the integer information represented by {@code glEnum}. * @return the integer information represented by {@code glEnum}.
*/ */
public int glGetInteger(int glEnum) public int glGetInteger(int glEnum) {
{
int[] val = new int[1]; int[] val = new int[1];
mGL.glGetIntegerv(glEnum, val, 0); mGL.glGetIntegerv(glEnum, val, 0);
return val[0]; return val[0];

View File

@ -15,10 +15,8 @@ import org.citra.citra_android.ui.main.MainPresenter;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
public final class FileBrowserHelper public final class FileBrowserHelper {
{ public static void openDirectoryPicker(FragmentActivity activity) {
public static void openDirectoryPicker(FragmentActivity activity)
{
Intent i = new Intent(activity, CustomFilePickerActivity.class); Intent i = new Intent(activity, CustomFilePickerActivity.class);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false); i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
@ -30,8 +28,7 @@ public final class FileBrowserHelper
activity.startActivityForResult(i, MainPresenter.REQUEST_ADD_DIRECTORY); activity.startActivityForResult(i, MainPresenter.REQUEST_ADD_DIRECTORY);
} }
public static void openFilePicker(FragmentActivity activity, int requestCode) public static void openFilePicker(FragmentActivity activity, int requestCode) {
{
Intent i = new Intent(activity, CustomFilePickerActivity.class); Intent i = new Intent(activity, CustomFilePickerActivity.class);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false); i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
@ -44,12 +41,10 @@ public final class FileBrowserHelper
} }
@Nullable @Nullable
public static String getSelectedDirectory(Intent result) public static String getSelectedDirectory(Intent result) {
{
// Use the provided utility method to parse the result // Use the provided utility method to parse the result
List<Uri> files = Utils.getSelectedFilesFromResult(result); List<Uri> files = Utils.getSelectedFilesFromResult(result);
if (!files.isEmpty()) if (!files.isEmpty()) {
{
File file = Utils.getFileForUri(files.get(0)); File file = Utils.getFileForUri(files.get(0));
return file.getAbsolutePath(); return file.getAbsolutePath();
} }

View File

@ -10,17 +10,14 @@ import org.citra.citra_android.NativeLibrary;
import java.nio.IntBuffer; import java.nio.IntBuffer;
public class GameBannerRequestHandler extends RequestHandler public class GameBannerRequestHandler extends RequestHandler {
{
@Override @Override
public boolean canHandleRequest(Request data) public boolean canHandleRequest(Request data) {
{
return "iso".equals(data.uri.getScheme()); return "iso".equals(data.uri.getScheme());
} }
@Override @Override
public Result load(Request request, int networkPolicy) public Result load(Request request, int networkPolicy) {
{
String url = request.uri.getHost() + request.uri.getPath(); String url = request.uri.getHost() + request.uri.getPath();
int[] vector = NativeLibrary.GetBanner(url); int[] vector = NativeLibrary.GetBanner(url);
Bitmap bitmap = Bitmap.createBitmap(48, 48, Bitmap.Config.RGB_565); Bitmap bitmap = Bitmap.createBitmap(48, 48, Bitmap.Config.RGB_565);

View File

@ -19,8 +19,7 @@ import org.citra.citra_android.services.USBPermService;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class Java_GCAdapter public class Java_GCAdapter {
{
public static UsbManager manager; public static UsbManager manager;
static byte[] controller_payload = new byte[37]; static byte[] controller_payload = new byte[37];
@ -29,19 +28,14 @@ public class Java_GCAdapter
static UsbEndpoint usb_in; static UsbEndpoint usb_in;
static UsbEndpoint usb_out; static UsbEndpoint usb_out;
private static void RequestPermission() private static void RequestPermission() {
{
Context context = NativeLibrary.sEmulationActivity.get(); Context context = NativeLibrary.sEmulationActivity.get();
if (context != null) if (context != null) {
{
HashMap<String, UsbDevice> devices = manager.getDeviceList(); HashMap<String, UsbDevice> devices = manager.getDeviceList();
for (Map.Entry<String, UsbDevice> pair : devices.entrySet()) for (Map.Entry<String, UsbDevice> pair : devices.entrySet()) {
{
UsbDevice dev = pair.getValue(); UsbDevice dev = pair.getValue();
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) {
{ if (!manager.hasPermission(dev)) {
if (!manager.hasPermission(dev))
{
Intent intent = new Intent(); Intent intent = new Intent();
PendingIntent pend_intent; PendingIntent pend_intent;
intent.setClass(context, USBPermService.class); intent.setClass(context, USBPermService.class);
@ -50,32 +44,25 @@ public class Java_GCAdapter
} }
} }
} }
} } else {
else
{
Log.warning("Cannot request GameCube Adapter permission as EmulationActivity is null."); Log.warning("Cannot request GameCube Adapter permission as EmulationActivity is null.");
} }
} }
public static void Shutdown() public static void Shutdown() {
{
usb_con.close(); usb_con.close();
} }
public static int GetFD() public static int GetFD() {
{
return usb_con.getFileDescriptor(); return usb_con.getFileDescriptor();
} }
public static boolean QueryAdapter() public static boolean QueryAdapter() {
{
HashMap<String, UsbDevice> devices = manager.getDeviceList(); HashMap<String, UsbDevice> devices = manager.getDeviceList();
for (Map.Entry<String, UsbDevice> pair : devices.entrySet()) for (Map.Entry<String, UsbDevice> pair : devices.entrySet()) {
{
UsbDevice dev = pair.getValue(); UsbDevice dev = pair.getValue();
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) {
{
if (manager.hasPermission(dev)) if (manager.hasPermission(dev))
return true; return true;
else else
@ -85,47 +72,38 @@ public class Java_GCAdapter
return false; return false;
} }
public static void InitAdapter() public static void InitAdapter() {
{
byte[] init = {0x13}; byte[] init = {0x13};
usb_con.bulkTransfer(usb_in, init, init.length, 0); usb_con.bulkTransfer(usb_in, init, init.length, 0);
} }
public static int Input() public static int Input() {
{
return usb_con.bulkTransfer(usb_in, controller_payload, controller_payload.length, 16); return usb_con.bulkTransfer(usb_in, controller_payload, controller_payload.length, 16);
} }
public static int Output(byte[] rumble) public static int Output(byte[] rumble) {
{
return usb_con.bulkTransfer(usb_out, rumble, 5, 16); return usb_con.bulkTransfer(usb_out, rumble, 5, 16);
} }
public static boolean OpenAdapter() public static boolean OpenAdapter() {
{
HashMap<String, UsbDevice> devices = manager.getDeviceList(); HashMap<String, UsbDevice> devices = manager.getDeviceList();
for (Map.Entry<String, UsbDevice> pair : devices.entrySet()) for (Map.Entry<String, UsbDevice> pair : devices.entrySet()) {
{
UsbDevice dev = pair.getValue(); UsbDevice dev = pair.getValue();
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) {
{ if (manager.hasPermission(dev)) {
if (manager.hasPermission(dev))
{
usb_con = manager.openDevice(dev); usb_con = manager.openDevice(dev);
Log.info("GCAdapter: Number of configurations: " + dev.getConfigurationCount()); Log.info("GCAdapter: Number of configurations: " + dev.getConfigurationCount());
Log.info("GCAdapter: Number of interfaces: " + dev.getInterfaceCount()); Log.info("GCAdapter: Number of interfaces: " + dev.getInterfaceCount());
if (dev.getConfigurationCount() > 0 && dev.getInterfaceCount() > 0) if (dev.getConfigurationCount() > 0 && dev.getInterfaceCount() > 0) {
{
UsbConfiguration conf = dev.getConfiguration(0); UsbConfiguration conf = dev.getConfiguration(0);
usb_intf = conf.getInterface(0); usb_intf = conf.getInterface(0);
usb_con.claimInterface(usb_intf, true); usb_con.claimInterface(usb_intf, true);
Log.info("GCAdapter: Number of endpoints: " + usb_intf.getEndpointCount()); Log.info("GCAdapter: Number of endpoints: " + usb_intf.getEndpointCount());
if (usb_intf.getEndpointCount() == 2) if (usb_intf.getEndpointCount() == 2) {
{
for (int i = 0; i < usb_intf.getEndpointCount(); ++i) for (int i = 0; i < usb_intf.getEndpointCount(); ++i)
if (usb_intf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN) if (usb_intf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN)
usb_in = usb_intf.getEndpoint(i); usb_in = usb_intf.getEndpoint(i);
@ -134,22 +112,17 @@ public class Java_GCAdapter
InitAdapter(); InitAdapter();
return true; return true;
} } else {
else
{
usb_con.releaseInterface(usb_intf); usb_con.releaseInterface(usb_intf);
} }
} }
final Activity emulationActivity = NativeLibrary.sEmulationActivity.get(); final Activity emulationActivity = NativeLibrary.sEmulationActivity.get();
if (emulationActivity != null) if (emulationActivity != null) {
{
emulationActivity.runOnUiThread(() -> Toast.makeText(emulationActivity, emulationActivity.runOnUiThread(() -> Toast.makeText(emulationActivity,
"GameCube Adapter couldn't be opened. Please re-plug the device.", "GameCube Adapter couldn't be opened. Please re-plug the device.",
Toast.LENGTH_LONG).show()); Toast.LENGTH_LONG).show());
} } else {
else
{
Log.warning("Cannot show toast for GameCube Adapter failure."); Log.warning("Cannot show toast for GameCube Adapter failure.");
} }
usb_con.close(); usb_con.close();

View File

@ -7,47 +7,37 @@ import org.citra.citra_android.BuildConfig;
* with the same TAG automatically provided. Also no-ops VERBOSE and DEBUG log * with the same TAG automatically provided. Also no-ops VERBOSE and DEBUG log
* levels in release builds. * levels in release builds.
*/ */
public final class Log public final class Log {
{
private static final String TAG = "Citra Frontend"; private static final String TAG = "Citra Frontend";
private Log() private Log() {
{
} }
public static void verbose(String message) public static void verbose(String message) {
{ if (BuildConfig.DEBUG) {
if (BuildConfig.DEBUG)
{
android.util.Log.v(TAG, message); android.util.Log.v(TAG, message);
} }
} }
public static void debug(String message) public static void debug(String message) {
{ if (BuildConfig.DEBUG) {
if (BuildConfig.DEBUG)
{
android.util.Log.d(TAG, message); android.util.Log.d(TAG, message);
} }
} }
public static void info(String message) public static void info(String message) {
{
android.util.Log.i(TAG, message); android.util.Log.i(TAG, message);
} }
public static void warning(String message) public static void warning(String message) {
{
android.util.Log.w(TAG, message); android.util.Log.w(TAG, message);
} }
public static void error(String message) public static void error(String message) {
{
android.util.Log.e(TAG, message); android.util.Log.e(TAG, message);
} }
public static void wtf(String message) public static void wtf(String message) {
{
android.util.Log.wtf(TAG, message); android.util.Log.wtf(TAG, message);
} }
} }

View File

@ -14,24 +14,19 @@ import org.citra.citra_android.R;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
public class PermissionsHandler public class PermissionsHandler {
{
public static final int REQUEST_CODE_WRITE_PERMISSION = 500; public static final int REQUEST_CODE_WRITE_PERMISSION = 500;
@TargetApi(Build.VERSION_CODES.M) @TargetApi(Build.VERSION_CODES.M)
public static boolean checkWritePermission(final FragmentActivity activity) public static boolean checkWritePermission(final FragmentActivity activity) {
{ if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
{
return true; return true;
} }
int hasWritePermission = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE); int hasWritePermission = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
if (hasWritePermission != PackageManager.PERMISSION_GRANTED) if (hasWritePermission != PackageManager.PERMISSION_GRANTED) {
{ if (activity.shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE)) {
if (activity.shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE))
{
showMessageOKCancel(activity, activity.getString(R.string.write_permission_needed), showMessageOKCancel(activity, activity.getString(R.string.write_permission_needed),
(dialog, which) -> activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE}, (dialog, which) -> activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_WRITE_PERMISSION)); REQUEST_CODE_WRITE_PERMISSION));
@ -46,10 +41,8 @@ public class PermissionsHandler
return true; return true;
} }
public static boolean hasWriteAccess(Context context) public static boolean hasWriteAccess(Context context) {
{ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
int hasWritePermission = ContextCompat.checkSelfPermission(context, WRITE_EXTERNAL_STORAGE); int hasWritePermission = ContextCompat.checkSelfPermission(context, WRITE_EXTERNAL_STORAGE);
return hasWritePermission == PackageManager.PERMISSION_GRANTED; return hasWritePermission == PackageManager.PERMISSION_GRANTED;
} }
@ -58,8 +51,7 @@ public class PermissionsHandler
} }
private static void showMessageOKCancel(final FragmentActivity activity, String message, private static void showMessageOKCancel(final FragmentActivity activity, String message,
DialogInterface.OnClickListener okListener) DialogInterface.OnClickListener okListener) {
{
new AlertDialog.Builder(activity) new AlertDialog.Builder(activity)
.setMessage(message) .setMessage(message)
.setPositiveButton(android.R.string.ok, okListener) .setPositiveButton(android.R.string.ok, okListener)

View File

@ -11,13 +11,10 @@ import org.citra.citra_android.R;
import java.io.File; import java.io.File;
import java.net.URI; import java.net.URI;
public class PicassoUtils public class PicassoUtils {
{ public static void loadGameBanner(ImageView imageView, String screenshotPath, String gamePath) {
public static void loadGameBanner(ImageView imageView, String screenshotPath, String gamePath)
{
File file = new File(URI.create(screenshotPath.replaceAll(" ", "%20"))); File file = new File(URI.create(screenshotPath.replaceAll(" ", "%20")));
if (file.exists()) if (file.exists()) {
{
// Fill in the view contents. // Fill in the view contents.
Picasso.with(imageView.getContext()) Picasso.with(imageView.getContext())
.load(screenshotPath) .load(screenshotPath)
@ -28,9 +25,7 @@ public class PicassoUtils
.config(Bitmap.Config.RGB_565) .config(Bitmap.Config.RGB_565)
.error(R.drawable.no_banner) .error(R.drawable.no_banner)
.into(imageView); .into(imageView);
} } else {
else
{
Picasso picassoInstance = new Picasso.Builder(imageView.getContext()) Picasso picassoInstance = new Picasso.Builder(imageView.getContext())
.addRequestHandler(new GameBannerRequestHandler()) .addRequestHandler(new GameBannerRequestHandler())
.build(); .build();

View File

@ -23,20 +23,16 @@ import java.util.Set;
* A HashMap<String, SettingSection> that constructs a new SettingSection instead of returning null * A HashMap<String, SettingSection> that constructs a new SettingSection instead of returning null
* when getting a key not already in the map * when getting a key not already in the map
*/ */
final class SettingsSectionMap extends HashMap<String, SettingSection> final class SettingsSectionMap extends HashMap<String, SettingSection> {
{
@Override @Override
public SettingSection get(Object key) public SettingSection get(Object key) {
{ if (!(key instanceof String)) {
if (!(key instanceof String))
{
return null; return null;
} }
String stringKey = (String) key; String stringKey = (String) key;
if (!super.containsKey(stringKey)) if (!super.containsKey(stringKey)) {
{
SettingSection section = new SettingSection(stringKey); SettingSection section = new SettingSection(stringKey);
super.put(stringKey, section); super.put(stringKey, section);
return section; return section;
@ -48,8 +44,7 @@ final class SettingsSectionMap extends HashMap<String, SettingSection>
/** /**
* Contains static methods for interacting with .ini files in which settings are stored. * Contains static methods for interacting with .ini files in which settings are stored.
*/ */
public final class SettingsFile public final class SettingsFile {
{
public static final int SETTINGS_DOLPHIN = 0; public static final int SETTINGS_DOLPHIN = 0;
public static final String FILE_NAME_CONFIG = "config"; public static final String FILE_NAME_CONFIG = "config";
@ -106,8 +101,7 @@ public final class SettingsFile
public static final String KEY_LOG_FILTER = "log_filter"; public static final String KEY_LOG_FILTER = "log_filter";
private SettingsFile() private SettingsFile() {
{
} }
/** /**
@ -120,56 +114,39 @@ public final class SettingsFile
* @return An Observable that emits a HashMap of the file's contents, then completes. * @return An Observable that emits a HashMap of the file's contents, then completes.
*/ */
public static HashMap<String, SettingSection> readFile(final String fileName, public static HashMap<String, SettingSection> readFile(final String fileName,
SettingsActivityView view) SettingsActivityView view) {
{
HashMap<String, SettingSection> sections = new SettingsSectionMap(); HashMap<String, SettingSection> sections = new SettingsSectionMap();
File ini = getSettingsFile(fileName); File ini = getSettingsFile(fileName);
BufferedReader reader = null; BufferedReader reader = null;
try try {
{
reader = new BufferedReader(new FileReader(ini)); reader = new BufferedReader(new FileReader(ini));
SettingSection current = null; SettingSection current = null;
for (String line; (line = reader.readLine()) != null; ) for (String line; (line = reader.readLine()) != null; ) {
{ if (line.startsWith("[") && line.endsWith("]")) {
if (line.startsWith("[") && line.endsWith("]"))
{
current = sectionFromLine(line); current = sectionFromLine(line);
sections.put(current.getName(), current); sections.put(current.getName(), current);
} } else if ((current != null)) {
else if ((current != null))
{
Setting setting = settingFromLine(current, line, fileName); Setting setting = settingFromLine(current, line, fileName);
if (setting != null) if (setting != null) {
{
current.putSetting(setting); current.putSetting(setting);
} }
} }
} }
} } catch (FileNotFoundException e) {
catch (FileNotFoundException e)
{
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage()); Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
view.onSettingsFileNotFound(); view.onSettingsFileNotFound();
} } catch (IOException e) {
catch (IOException e)
{
Log.error("[SettingsFile] Error reading from: " + fileName + ".ini: " + e.getMessage()); Log.error("[SettingsFile] Error reading from: " + fileName + ".ini: " + e.getMessage());
view.onSettingsFileNotFound(); view.onSettingsFileNotFound();
} } finally {
finally if (reader != null) {
{ try {
if (reader != null)
{
try
{
reader.close(); reader.close();
} } catch (IOException e) {
catch (IOException e)
{
Log.error("[SettingsFile] Error closing: " + fileName + ".ini: " + e.getMessage()); Log.error("[SettingsFile] Error closing: " + fileName + ".ini: " + e.getMessage());
} }
} }
@ -188,39 +165,32 @@ public final class SettingsFile
* @return An Observable representing the operation. * @return An Observable representing the operation.
*/ */
public static void saveFile(final String fileName, final HashMap<String, SettingSection> sections, public static void saveFile(final String fileName, final HashMap<String, SettingSection> sections,
SettingsActivityView view) SettingsActivityView view) {
{
File ini = getSettingsFile(fileName); File ini = getSettingsFile(fileName);
Wini writer = null; Wini writer = null;
try try {
{
writer = new Wini(ini); writer = new Wini(ini);
Set<String> keySet = sections.keySet(); Set<String> keySet = sections.keySet();
for (String key : keySet) for (String key : keySet) {
{
SettingSection section = sections.get(key); SettingSection section = sections.get(key);
writeSection(writer, section); writeSection(writer, section);
} }
writer.store(); writer.store();
} } catch (IOException e) {
catch (IOException e)
{
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage()); Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
view.showToastMessage("Error saving " + fileName + ".ini: " + e.getMessage()); view.showToastMessage("Error saving " + fileName + ".ini: " + e.getMessage());
} }
} }
@NonNull @NonNull
private static File getSettingsFile(String fileName) private static File getSettingsFile(String fileName) {
{
return new File( return new File(
DirectoryInitializationService.getUserDirectory() + "/config/" + fileName + ".ini"); DirectoryInitializationService.getUserDirectory() + "/config/" + fileName + ".ini");
} }
private static SettingSection sectionFromLine(String line) private static SettingSection sectionFromLine(String line) {
{
String sectionName = line.substring(1, line.length() - 1); String sectionName = line.substring(1, line.length() - 1);
return new SettingSection(sectionName); return new SettingSection(sectionName);
} }
@ -234,12 +204,10 @@ public final class SettingsFile
* @param fileName The name of the ini file the setting is in. * @param fileName The name of the ini file the setting is in.
* @return A typed Setting containing the key/value contained in the line. * @return A typed Setting containing the key/value contained in the line.
*/ */
private static Setting settingFromLine(SettingSection current, String line, String fileName) private static Setting settingFromLine(SettingSection current, String line, String fileName) {
{
String[] splitLine = line.split("="); String[] splitLine = line.split("=");
if (splitLine.length != 2) if (splitLine.length != 2) {
{
Log.warning("Skipping invalid config line \"" + line + "\""); Log.warning("Skipping invalid config line \"" + line + "\"");
return null; return null;
} }
@ -254,24 +222,18 @@ public final class SettingsFile
int file = SETTINGS_DOLPHIN; int file = SETTINGS_DOLPHIN;
try try {
{
int valueAsInt = Integer.valueOf(value); int valueAsInt = Integer.valueOf(value);
return new IntSetting(key, current.getName(), file, valueAsInt); return new IntSetting(key, current.getName(), file, valueAsInt);
} } catch (NumberFormatException ex) {
catch (NumberFormatException ex)
{
} }
try try {
{
float valueAsFloat = Float.valueOf(value); float valueAsFloat = Float.valueOf(value);
return new FloatSetting(key, current.getName(), file, valueAsFloat); return new FloatSetting(key, current.getName(), file, valueAsFloat);
} } catch (NumberFormatException ex) {
catch (NumberFormatException ex)
{
} }
return new StringSetting(key, current.getName(), file, value); return new StringSetting(key, current.getName(), file, value);
@ -283,8 +245,7 @@ public final class SettingsFile
* @param parser A Wini pointed at a file on disk. * @param parser A Wini pointed at a file on disk.
* @param section A section containing settings to be written to the file. * @param section A section containing settings to be written to the file.
*/ */
private static void writeSection(Wini parser, SettingSection section) private static void writeSection(Wini parser, SettingSection section) {
{
// Write the section header. // Write the section header.
String header = section.getName(); String header = section.getName();
@ -292,8 +253,7 @@ public final class SettingsFile
HashMap<String, Setting> settings = section.getSettings(); HashMap<String, Setting> settings = section.getSettings();
Set<String> keySet = settings.keySet(); Set<String> keySet = settings.keySet();
for (String key : keySet) for (String key : keySet) {
{
Setting setting = settings.get(key); Setting setting = settings.get(key);
parser.put(header, setting.getKey(), setting.getValueAsString()); parser.put(header, setting.getKey(), setting.getValueAsString());
} }

View File

@ -7,10 +7,8 @@ import android.text.TextUtils;
import org.citra.citra_android.activities.EmulationActivity; import org.citra.citra_android.activities.EmulationActivity;
public final class StartupHandler public final class StartupHandler {
{ public static void HandleInit(FragmentActivity parent) {
public static void HandleInit(FragmentActivity parent)
{
// Ask the user to grant write permission if it's not already granted // Ask the user to grant write permission if it's not already granted
PermissionsHandler.checkWritePermission(parent); PermissionsHandler.checkWritePermission(parent);
@ -19,8 +17,7 @@ public final class StartupHandler
if (extras != null) if (extras != null)
start_file = extras.getString("AutoStartFile"); start_file = extras.getString("AutoStartFile");
if (!TextUtils.isEmpty(start_file)) if (!TextUtils.isEmpty(start_file)) {
{
// Start the emulation activity, send the ISO passed in and finish the main activity // Start the emulation activity, send the ISO passed in and finish the main activity
Intent emulation_intent = new Intent(parent, EmulationActivity.class); Intent emulation_intent = new Intent(parent, EmulationActivity.class);
emulation_intent.putExtra("SelectedGame", start_file); emulation_intent.putExtra("SelectedGame", start_file);

View File

@ -11,8 +11,7 @@ import org.citra.citra_android.R;
* A simple class that stores references to views so that the GameAdapter doesn't need to * A simple class that stores references to views so that the GameAdapter doesn't need to
* keep calling findViewById(), which is expensive. * keep calling findViewById(), which is expensive.
*/ */
public class GameViewHolder extends RecyclerView.ViewHolder public class GameViewHolder extends RecyclerView.ViewHolder {
{
public ImageView imageScreenshot; public ImageView imageScreenshot;
public TextView textGameTitle; public TextView textGameTitle;
public TextView textCompany; public TextView textCompany;
@ -27,8 +26,7 @@ public class GameViewHolder extends RecyclerView.ViewHolder
public String company; public String company;
public String screenshotPath; public String screenshotPath;
public GameViewHolder(View itemView) public GameViewHolder(View itemView) {
{
super(itemView); super(itemView);
itemView.setTag(this); itemView.setTag(this);

View File

@ -9,8 +9,7 @@ import android.widget.ImageView;
* A simple class that stores references to views so that the GameAdapter doesn't need to * A simple class that stores references to views so that the GameAdapter doesn't need to
* keep calling findViewById(), which is expensive. * keep calling findViewById(), which is expensive.
*/ */
public final class TvGameViewHolder extends Presenter.ViewHolder public final class TvGameViewHolder extends Presenter.ViewHolder {
{
public ImageCardView cardParent; public ImageCardView cardParent;
public ImageView imageScreenshot; public ImageView imageScreenshot;
@ -25,8 +24,7 @@ public final class TvGameViewHolder extends Presenter.ViewHolder
public String company; public String company;
public String screenshotPath; public String screenshotPath;
public TvGameViewHolder(View itemView) public TvGameViewHolder(View itemView) {
{
super(itemView); super(itemView);
itemView.setTag(this); itemView.setTag(this);

View File

@ -4,15 +4,13 @@ import android.support.v17.leanback.widget.ImageCardView;
import android.support.v17.leanback.widget.Presenter; import android.support.v17.leanback.widget.Presenter;
import android.view.View; import android.view.View;
public final class TvSettingsViewHolder extends Presenter.ViewHolder public final class TvSettingsViewHolder extends Presenter.ViewHolder {
{
public ImageCardView cardParent; public ImageCardView cardParent;
// Determines what action to take when this item is clicked. // Determines what action to take when this item is clicked.
public int itemId; public int itemId;
public TvSettingsViewHolder(View itemView) public TvSettingsViewHolder(View itemView) {
{
super(itemView); super(itemView);
itemView.setTag(this); itemView.setTag(this);