Convert the Android source code to the directory structure of a Gradle-based Android Studio project.
50
Source/Android/app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.dolphinemu.dolphinemu">
|
||||
|
||||
<uses-feature android:glEsVersion="0x00030000" />
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:allowBackup="true"
|
||||
android:supportsRtl="true">
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.gamelist.GameListActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Holo.Light" >
|
||||
|
||||
<!-- This intentfilter marks this Activity as the one that gets launched from Home screen. -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.about.AboutActivity"
|
||||
android:theme="@android:style/Theme.Holo.Light" />
|
||||
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.emulation.EmulationActivity"
|
||||
android:screenOrientation="landscape" />
|
||||
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.settings.input.overlayconfig.OverlayConfigActivity"
|
||||
android:screenOrientation="landscape"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/>
|
||||
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.settings.PrefsActivity"
|
||||
android:label="@string/settings"
|
||||
android:theme="@android:style/Theme.Holo.Light" />
|
||||
|
||||
<service android:name=".AssetCopyService"/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.content.Intent;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
import org.dolphinemu.dolphinemu.settings.UserPreferences;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public final class AssetCopyService extends IntentService
|
||||
{
|
||||
private static final String TAG = "DolphinEmulator";
|
||||
|
||||
public AssetCopyService()
|
||||
{
|
||||
// Superclass constructor is called to name the thread on which this service executes.
|
||||
super("AssetCopyService");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent)
|
||||
{
|
||||
String BaseDir = NativeLibrary.GetUserDirectory();
|
||||
String ConfigDir = BaseDir + File.separator + "Config";
|
||||
String GCDir = BaseDir + File.separator + "GC";
|
||||
|
||||
// Copy assets if needed
|
||||
File file = new File(GCDir + File.separator + "font_sjis.bin");
|
||||
if(!file.exists())
|
||||
{
|
||||
NativeLibrary.CreateUserFolders();
|
||||
copyAsset("dsp_coef.bin", GCDir + File.separator + "dsp_coef.bin");
|
||||
copyAsset("dsp_rom.bin", GCDir + File.separator + "dsp_rom.bin");
|
||||
copyAsset("font_ansi.bin", GCDir + File.separator + "font_ansi.bin");
|
||||
copyAsset("font_sjis.bin", GCDir + File.separator + "font_sjis.bin");
|
||||
copyAssetFolder("Shaders", BaseDir + File.separator + "Shaders");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.v(TAG, "Skipping asset copy operation.");
|
||||
}
|
||||
|
||||
// Always copy over the GCPad config in case of change or corruption.
|
||||
// Not a user configurable file.
|
||||
copyAsset("GCPadNew.ini", ConfigDir + File.separator + "GCPadNew.ini");
|
||||
|
||||
// Load the configuration keys set in the Dolphin ini and gfx ini files
|
||||
// into the application's shared preferences.
|
||||
UserPreferences.LoadIniToPrefs(this);
|
||||
}
|
||||
|
||||
private void copyAsset(String asset, String output)
|
||||
{
|
||||
Log.v(TAG, "Copying " + asset + " to " + output);
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
|
||||
try
|
||||
{
|
||||
in = getAssets().open(asset);
|
||||
out = new FileOutputStream(output);
|
||||
copyFile(in, out);
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.e(TAG, "Failed to copy asset file: " + asset, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyAssetFolder(String assetFolder, String outputFolder)
|
||||
{
|
||||
Log.v(TAG, "Copying " + assetFolder + " to " + outputFolder);
|
||||
|
||||
try
|
||||
{
|
||||
for (String file : getAssets().list(assetFolder))
|
||||
{
|
||||
copyAsset(assetFolder + File.separator + file, outputFolder + File.separator + file);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.e(TAG, "Failed to copy asset folder: " + assetFolder, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyFile(InputStream in, OutputStream out) throws IOException
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buffer)) != -1)
|
||||
{
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
|
||||
/**
|
||||
* Class which contains methods that interact
|
||||
* with the native side of the Dolphin code.
|
||||
*/
|
||||
public final class NativeLibrary
|
||||
{
|
||||
/**
|
||||
* Button type for use in onTouchEvent
|
||||
*/
|
||||
public static final class ButtonType
|
||||
{
|
||||
public static final int BUTTON_A = 0;
|
||||
public static final int BUTTON_B = 1;
|
||||
public static final int BUTTON_START = 2;
|
||||
public static final int BUTTON_X = 3;
|
||||
public static final int BUTTON_Y = 4;
|
||||
public static final int BUTTON_Z = 5;
|
||||
public static final int BUTTON_UP = 6;
|
||||
public static final int BUTTON_DOWN = 7;
|
||||
public static final int BUTTON_LEFT = 8;
|
||||
public static final int BUTTON_RIGHT = 9;
|
||||
public static final int STICK_MAIN = 10;
|
||||
public static final int STICK_MAIN_UP = 11;
|
||||
public static final int STICK_MAIN_DOWN = 12;
|
||||
public static final int STICK_MAIN_LEFT = 13;
|
||||
public static final int STICK_MAIN_RIGHT = 14;
|
||||
public static final int STICK_C = 15;
|
||||
public static final int STICK_C_UP = 16;
|
||||
public static final int STICK_C_DOWN = 17;
|
||||
public static final int STICK_C_LEFT = 18;
|
||||
public static final int STICK_C_RIGHT = 19;
|
||||
public static final int TRIGGER_L = 20;
|
||||
public static final int TRIGGER_R = 21;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static final String TouchScreenDevice = "Touchscreen";
|
||||
|
||||
/**
|
||||
* Handles button press events for a gamepad.
|
||||
*
|
||||
* @param Device The input descriptor of the gamepad.
|
||||
* @param Button Key code identifying which button was pressed.
|
||||
* @param Action Mask identifying which action is happing (button pressed down, or button released).
|
||||
*
|
||||
* @return If we handled the button press.
|
||||
*/
|
||||
public static native boolean onGamePadEvent(String Device, int Button, int Action);
|
||||
|
||||
/**
|
||||
* Handles gamepad movement events.
|
||||
*
|
||||
* @param Device The device ID of the gamepad.
|
||||
* @param Axis The axis ID
|
||||
* @param Value The value of the axis represented by the given ID.
|
||||
*/
|
||||
public static native void onGamePadMoveEvent(String Device, int Axis, float Value);
|
||||
|
||||
/**
|
||||
* Gets a value from a key in the given ini-based config file.
|
||||
*
|
||||
* @param configFile The ini-based config file to get the value from.
|
||||
* @param Section The section key that the actual key is in.
|
||||
* @param Key The key to get the value from.
|
||||
* @param Default The value to return in the event the given key doesn't exist.
|
||||
*
|
||||
* @return the value stored at the key, or a default value if it doesn't exist.
|
||||
*/
|
||||
public static native String GetConfig(String configFile, String Section, String Key, String Default);
|
||||
|
||||
/**
|
||||
* Sets a value to a key in the given ini config file.
|
||||
*
|
||||
* @param configFile The ini-based config file to add the value to.
|
||||
* @param Section The section key for the ini key
|
||||
* @param Key The actual ini key to set.
|
||||
* @param Value The string to set the ini key to.
|
||||
*/
|
||||
public static native void SetConfig(String configFile, String Section, String Key, String Value);
|
||||
|
||||
/**
|
||||
* Sets the filename to be run during emulation.
|
||||
*
|
||||
* @param filename The filename to be run during emulation.
|
||||
*/
|
||||
public static native void SetFilename(String filename);
|
||||
|
||||
/**
|
||||
* Gets the embedded banner within the given ISO/ROM.
|
||||
*
|
||||
* @param filename the file path to the ISO/ROM.
|
||||
*
|
||||
* @return an integer array containing the color data for the banner.
|
||||
*/
|
||||
public static native int[] GetBanner(String filename);
|
||||
|
||||
/**
|
||||
* Gets the embedded title of the given ISO/ROM.
|
||||
*
|
||||
* @param filename The file path to the ISO/ROM.
|
||||
*
|
||||
* @return the embedded title of the ISO/ROM.
|
||||
*/
|
||||
public static native String GetTitle(String filename);
|
||||
|
||||
/**
|
||||
* Gets the Dolphin version string.
|
||||
*
|
||||
* @return the Dolphin version string.
|
||||
*/
|
||||
public static native String GetVersionString();
|
||||
|
||||
/**
|
||||
* Returns if the phone supports NEON or not
|
||||
*
|
||||
* @return true if it supports NEON, false otherwise.
|
||||
*/
|
||||
public static native boolean SupportsNEON();
|
||||
|
||||
/**
|
||||
* Saves a screen capture of the game
|
||||
*
|
||||
*/
|
||||
public static native void SaveScreenShot();
|
||||
|
||||
/**
|
||||
* Saves a game state to the slot number.
|
||||
*
|
||||
* @param slot The slot location to save state to.
|
||||
*/
|
||||
public static native void SaveState(int slot);
|
||||
|
||||
/**
|
||||
* Loads a game state from the slot number.
|
||||
*
|
||||
* @param slot The slot location to load state from.
|
||||
*/
|
||||
public static native void LoadState(int slot);
|
||||
|
||||
/**
|
||||
* Creates the initial folder structure in /sdcard/dolphin-emu/
|
||||
*/
|
||||
public static native void CreateUserFolders();
|
||||
|
||||
/**
|
||||
* Sets the current working user directory
|
||||
* If not set, it auto-detects a location
|
||||
*/
|
||||
public static native void SetUserDirectory(String directory);
|
||||
|
||||
/**
|
||||
* Returns the current working user directory
|
||||
*/
|
||||
public static native String GetUserDirectory();
|
||||
|
||||
/**
|
||||
* Begins emulation.
|
||||
*
|
||||
* @param surf The surface to render to.
|
||||
*/
|
||||
public static native void Run(Surface surf);
|
||||
|
||||
/** Unpauses emulation from a paused state. */
|
||||
public static native void UnPauseEmulation();
|
||||
|
||||
/** Pauses emulation. */
|
||||
public static native void PauseEmulation();
|
||||
|
||||
/** Stops emulation. */
|
||||
public static native void StopEmulation();
|
||||
|
||||
/** Native EGL functions not exposed by Java bindings **/
|
||||
public static native void eglBindAPI(int api);
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
System.loadLibrary("main");
|
||||
}
|
||||
catch (UnsatisfiedLinkError ex)
|
||||
{
|
||||
Log.e("NativeLibrary", ex.toString());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.about;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.utils.EGLHelper;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.v13.app.FragmentPagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
|
||||
|
||||
/**
|
||||
* Activity for the about menu, which displays info
|
||||
* related to the CPU and GPU. Along with misc other info.
|
||||
*/
|
||||
public final class AboutActivity extends Activity
|
||||
{
|
||||
private final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT);
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Set the view pager
|
||||
setContentView(R.layout.viewpager);
|
||||
|
||||
// Initialize the viewpager.
|
||||
final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
|
||||
viewPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
super.onDestroy();
|
||||
|
||||
eglHelper.closeHelper();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FragmentPagerAdapter} subclass responsible for handling
|
||||
* the individual {@link Fragment}s within the {@link ViewPager}.
|
||||
*/
|
||||
private final class ViewPagerAdapter extends FragmentPagerAdapter
|
||||
{
|
||||
private final String[] pageTitles = {
|
||||
getString(R.string.general),
|
||||
getString(R.string.cpu),
|
||||
getString(R.string.gles_two),
|
||||
getString(R.string.gles_three),
|
||||
getString(R.string.desktop_gl),
|
||||
};
|
||||
|
||||
public ViewPagerAdapter(FragmentManager fm)
|
||||
{
|
||||
super(fm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position)
|
||||
{
|
||||
if (position == 0)
|
||||
{
|
||||
return new DolphinInfoFragment();
|
||||
}
|
||||
else if (position == 1)
|
||||
{
|
||||
return new CPUInfoFragment(); // CPU
|
||||
}
|
||||
else if (position == 2) // GLES 2
|
||||
{
|
||||
return new GLES2InfoFragment();
|
||||
}
|
||||
else if (position == 3) // GLES 3 or OpenGL (depending on circumstances)
|
||||
{
|
||||
if (eglHelper.supportsGLES3())
|
||||
return new GLES3InfoFragment();
|
||||
else
|
||||
return new GLInfoFragment(); // GLES3 not supported, but OpenGL is.
|
||||
}
|
||||
else if (position == 4) // OpenGL fragment
|
||||
{
|
||||
return new GLInfoFragment();
|
||||
}
|
||||
|
||||
// This should never happen.
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
if (eglHelper.supportsGLES3() && eglHelper.supportsOpenGL())
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
else if (!eglHelper.supportsGLES3() && !eglHelper.supportsOpenGL())
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
else // Either regular OpenGL or GLES3 isn't supported
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position)
|
||||
{
|
||||
return pageTitles[position];
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.about;
|
||||
|
||||
/**
|
||||
* Represents an item within an info fragment in the About menu.
|
||||
*/
|
||||
final class AboutFragmentItem
|
||||
{
|
||||
private final String title;
|
||||
private final String subtitle;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param title The title of this item.
|
||||
* @param subtitle The subtitle for this item.
|
||||
*/
|
||||
public AboutFragmentItem(String title, String subtitle)
|
||||
{
|
||||
this.title = title;
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title of this item.
|
||||
*
|
||||
* @return the title of this item.
|
||||
*/
|
||||
public String getTitle()
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subtitle of this item.
|
||||
*
|
||||
* @return the subtitle of this item.
|
||||
*/
|
||||
public String getSubTitle()
|
||||
{
|
||||
return subtitle;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.about;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* {@link ArrayAdapter} subclass specifically for the
|
||||
* information fragments within the about menu.
|
||||
*/
|
||||
final class AboutInfoFragmentAdapter extends ArrayAdapter<AboutFragmentItem>
|
||||
{
|
||||
private final int id;
|
||||
private final List<AboutFragmentItem> items;
|
||||
|
||||
public AboutInfoFragmentAdapter(Context ctx, int id, List<AboutFragmentItem> items)
|
||||
{
|
||||
super(ctx, id, items);
|
||||
|
||||
this.id = id;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AboutFragmentItem getItem(int index)
|
||||
{
|
||||
return items.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent)
|
||||
{
|
||||
if (convertView == null)
|
||||
{
|
||||
LayoutInflater vi = LayoutInflater.from(getContext());
|
||||
convertView = vi.inflate(id, parent, false);
|
||||
}
|
||||
|
||||
final AboutFragmentItem item = items.get(position);
|
||||
if (item != null)
|
||||
{
|
||||
TextView title = (TextView) convertView.findViewById(R.id.AboutItemTitle);
|
||||
TextView subtitle = (TextView) convertView.findViewById(R.id.AboutItemSubTitle);
|
||||
|
||||
if (title != null)
|
||||
title.setText(item.getTitle());
|
||||
|
||||
if (subtitle != null)
|
||||
subtitle.setText(item.getSubTitle());
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.about;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.utils.CPUHelper;
|
||||
|
||||
import android.app.ListFragment;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
/**
|
||||
* {@link ListFragment class that is responsible
|
||||
* for displaying information related to the CPU.
|
||||
*/
|
||||
public final class CPUInfoFragment extends ListFragment
|
||||
{
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
List<AboutFragmentItem> items = new ArrayList<AboutFragmentItem>();
|
||||
|
||||
CPUHelper cpuHelper = new CPUHelper(getActivity());
|
||||
|
||||
items.add(new AboutFragmentItem(getString(R.string.cpu_info), cpuHelper.getProcessorInfo()));
|
||||
items.add(new AboutFragmentItem(getString(R.string.cpu_type), cpuHelper.getProcessorType()));
|
||||
items.add(new AboutFragmentItem(getString(R.string.cpu_abi_one), Build.CPU_ABI));
|
||||
items.add(new AboutFragmentItem(getString(R.string.cpu_abi_two), Build.CPU_ABI2));
|
||||
items.add(new AboutFragmentItem(getString(R.string.num_cores), Integer.toString(cpuHelper.getNumCores())));
|
||||
items.add(new AboutFragmentItem(getString(R.string.cpu_features), cpuHelper.getFeatures()));
|
||||
items.add(new AboutFragmentItem(getString(R.string.cpu_hardware), Build.HARDWARE));
|
||||
if (CPUHelper.isARM())
|
||||
items.add(new AboutFragmentItem(getString(R.string.cpu_implementer), cpuHelper.getImplementer()));
|
||||
|
||||
AboutInfoFragmentAdapter adapter = new AboutInfoFragmentAdapter(getActivity(), R.layout.about_layout, items);
|
||||
rootView.setAdapter(adapter);
|
||||
|
||||
return rootView;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.about;
|
||||
|
||||
import android.app.ListFragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.utils.EGLHelper;
|
||||
|
||||
/**
|
||||
* Represents the about screen.
|
||||
*/
|
||||
public final class DolphinInfoFragment extends ListFragment
|
||||
{
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT);
|
||||
|
||||
final String yes = getString(R.string.yes);
|
||||
final String no = getString(R.string.no);
|
||||
|
||||
List<AboutFragmentItem> Input = new ArrayList<AboutFragmentItem>();
|
||||
Input.add(new AboutFragmentItem(getString(R.string.build_revision), NativeLibrary.GetVersionString()));
|
||||
Input.add(new AboutFragmentItem(getString(R.string.supports_gles3), eglHelper.supportsGLES3() ? yes : no));
|
||||
Input.add(new AboutFragmentItem(getString(R.string.supports_neon), NativeLibrary.SupportsNEON() ? yes : no));
|
||||
|
||||
AboutInfoFragmentAdapter adapter = new AboutInfoFragmentAdapter(getActivity(), R.layout.about_layout, Input);
|
||||
rootView.setAdapter(adapter);
|
||||
rootView.setEnabled(false); // Makes the list view non-clickable.
|
||||
|
||||
return rootView;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.about;
|
||||
|
||||
import android.app.ListFragment;
|
||||
import android.opengl.GLES20;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.about.Limit.Type;
|
||||
import org.dolphinemu.dolphinemu.utils.EGLHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link ListFragment} responsible for displaying
|
||||
* information relating to OpenGL ES 2.
|
||||
*/
|
||||
public final class GLES2InfoFragment extends ListFragment
|
||||
{
|
||||
private final Limit[] Limits = {
|
||||
new Limit("Vendor", GLES20.GL_VENDOR, Type.STRING),
|
||||
new Limit("Version", GLES20.GL_VERSION, Type.STRING),
|
||||
new Limit("Renderer", GLES20.GL_RENDERER, Type.STRING),
|
||||
new Limit("GLSL version", GLES20.GL_SHADING_LANGUAGE_VERSION, Type.STRING),
|
||||
// GLES 2.0 Limits
|
||||
new Limit("Aliased Point Size", GLES20.GL_ALIASED_POINT_SIZE_RANGE, Type.INTEGER_RANGE),
|
||||
new Limit("Aliased Line Width ", GLES20.GL_ALIASED_LINE_WIDTH_RANGE, Type.INTEGER_RANGE),
|
||||
new Limit("Max Texture Size", GLES20.GL_MAX_TEXTURE_SIZE, Type.INTEGER),
|
||||
new Limit("Viewport Dimensions", GLES20.GL_MAX_VIEWPORT_DIMS, Type.INTEGER_RANGE),
|
||||
new Limit("Subpixel Bits", GLES20.GL_SUBPIXEL_BITS, Type.INTEGER),
|
||||
new Limit("Max Vertex Attributes", GLES20.GL_MAX_VERTEX_ATTRIBS, Type.INTEGER),
|
||||
new Limit("Max Vertex Uniform Vectors", GLES20.GL_MAX_VERTEX_UNIFORM_VECTORS, Type.INTEGER),
|
||||
new Limit("Max Varying Vectors", GLES20.GL_MAX_VARYING_VECTORS, Type.INTEGER),
|
||||
new Limit("Max Combined Texture Units", GLES20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, Type.INTEGER),
|
||||
new Limit("Max Vertex Texture Units", GLES20.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, Type.INTEGER),
|
||||
new Limit("Max Texture Units", GLES20.GL_MAX_TEXTURE_IMAGE_UNITS, Type.INTEGER),
|
||||
new Limit("Max Fragment Uniform Vectors", GLES20.GL_MAX_FRAGMENT_UNIFORM_VECTORS, Type.INTEGER),
|
||||
new Limit("Max Cubemap Texture Size", GLES20.GL_MAX_CUBE_MAP_TEXTURE_SIZE, Type.INTEGER),
|
||||
new Limit("Shader Binary Formats", GLES20.GL_NUM_SHADER_BINARY_FORMATS, Type.INTEGER),
|
||||
new Limit("Max Framebuffer Size", GLES20.GL_MAX_RENDERBUFFER_SIZE, Type.INTEGER),
|
||||
};
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT);
|
||||
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
List<AboutFragmentItem> Input = new ArrayList<AboutFragmentItem>();
|
||||
|
||||
for (Limit limit : Limits)
|
||||
{
|
||||
Log.i("GLES2InfoFragment", "Getting enum " + limit.name);
|
||||
Input.add(new AboutFragmentItem(limit.name, limit.GetValue(eglHelper)));
|
||||
}
|
||||
|
||||
// Get extensions manually
|
||||
String[] extensions = eglHelper.glGetString(GLES20.GL_EXTENSIONS).split(" ");
|
||||
StringBuilder extensionsBuilder = new StringBuilder();
|
||||
for (String extension : extensions)
|
||||
{
|
||||
extensionsBuilder.append(extension).append('\n');
|
||||
}
|
||||
Input.add(new AboutFragmentItem("OpenGL ES 2.0 Extensions", extensionsBuilder.toString()));
|
||||
|
||||
AboutInfoFragmentAdapter adapter = new AboutInfoFragmentAdapter(getActivity(), R.layout.about_layout, Input);
|
||||
rootView.setAdapter(adapter);
|
||||
|
||||
return rootView;
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.about;
|
||||
|
||||
import android.app.ListFragment;
|
||||
import android.opengl.GLES30;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.about.Limit.Type;
|
||||
import org.dolphinemu.dolphinemu.utils.EGLHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link ListFragment} responsible for displaying
|
||||
* information relating to OpenGL ES 3.
|
||||
*/
|
||||
public final class GLES3InfoFragment extends ListFragment
|
||||
{
|
||||
private final Limit[] Limits = {
|
||||
new Limit("Vendor", GLES30.GL_VENDOR, Type.STRING),
|
||||
new Limit("Version", GLES30.GL_VERSION, Type.STRING),
|
||||
new Limit("Renderer", GLES30.GL_RENDERER, Type.STRING),
|
||||
new Limit("GLSL version", GLES30.GL_SHADING_LANGUAGE_VERSION, Type.STRING),
|
||||
// GLES 2.0 Limits
|
||||
new Limit("Aliased Point Size", GLES30.GL_ALIASED_POINT_SIZE_RANGE, Type.INTEGER_RANGE),
|
||||
new Limit("Aliased Line Width ", GLES30.GL_ALIASED_LINE_WIDTH_RANGE, Type.INTEGER_RANGE),
|
||||
new Limit("Max Texture Size", GLES30.GL_MAX_TEXTURE_SIZE, Type.INTEGER),
|
||||
new Limit("Viewport Dimensions", GLES30.GL_MAX_VIEWPORT_DIMS, Type.INTEGER_RANGE),
|
||||
new Limit("Subpixel Bits", GLES30.GL_SUBPIXEL_BITS, Type.INTEGER),
|
||||
new Limit("Max Vertex Attributes", GLES30.GL_MAX_VERTEX_ATTRIBS, Type.INTEGER),
|
||||
new Limit("Max Vertex Uniform Vectors", GLES30.GL_MAX_VERTEX_UNIFORM_VECTORS, Type.INTEGER),
|
||||
new Limit("Max Varying Vectors", GLES30.GL_MAX_VARYING_VECTORS, Type.INTEGER),
|
||||
new Limit("Max Combined Texture Units", GLES30.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, Type.INTEGER),
|
||||
new Limit("Max Vertex Texture Units", GLES30.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, Type.INTEGER),
|
||||
new Limit("Max Texture Units", GLES30.GL_MAX_TEXTURE_IMAGE_UNITS, Type.INTEGER),
|
||||
new Limit("Max Fragment Uniform Vectors", GLES30.GL_MAX_FRAGMENT_UNIFORM_VECTORS, Type.INTEGER),
|
||||
new Limit("Max Cubemap Texture Size", GLES30.GL_MAX_CUBE_MAP_TEXTURE_SIZE, Type.INTEGER),
|
||||
new Limit("Shader Binary Formats", GLES30.GL_NUM_SHADER_BINARY_FORMATS, Type.INTEGER),
|
||||
new Limit("Max Framebuffer Size", GLES30.GL_MAX_RENDERBUFFER_SIZE, Type.INTEGER),
|
||||
// GLES 3.0 limits
|
||||
new Limit("Max 3D Texture size", GLES30.GL_MAX_3D_TEXTURE_SIZE, Type.INTEGER),
|
||||
new Limit("Max Element Vertices", GLES30.GL_MAX_ELEMENTS_VERTICES, Type.INTEGER),
|
||||
new Limit("Max Element Indices", GLES30.GL_MAX_ELEMENTS_INDICES, Type.INTEGER),
|
||||
new Limit("Max Draw Buffers", GLES30.GL_MAX_DRAW_BUFFERS, Type.INTEGER),
|
||||
new Limit("Max Fragment Uniform Components", GLES30.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, Type.INTEGER),
|
||||
new Limit("Max Vertex Uniform Components", GLES30.GL_MAX_VERTEX_UNIFORM_COMPONENTS, Type.INTEGER),
|
||||
new Limit("Number of Extensions", GLES30.GL_NUM_EXTENSIONS, Type.INTEGER),
|
||||
new Limit("Max Array Texture Layers", GLES30.GL_MAX_ARRAY_TEXTURE_LAYERS, Type.INTEGER),
|
||||
new Limit("Min Program Texel Offset", GLES30.GL_MIN_PROGRAM_TEXEL_OFFSET, Type.INTEGER),
|
||||
new Limit("Max Program Texel Offset", GLES30.GL_MAX_PROGRAM_TEXEL_OFFSET, Type.INTEGER),
|
||||
new Limit("Max Varying Components", GLES30.GL_MAX_VARYING_COMPONENTS, Type.INTEGER),
|
||||
new Limit("Max TF Varying Length", GLES30.GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, Type.INTEGER),
|
||||
new Limit("Max TF Separate Components", GLES30.GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, Type.INTEGER),
|
||||
new Limit("Max TF Interleaved Components", GLES30.GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, Type.INTEGER),
|
||||
new Limit("Max TF Separate Attributes", GLES30.GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, Type.INTEGER),
|
||||
new Limit("Max Color Attachments", GLES30.GL_MAX_COLOR_ATTACHMENTS, Type.INTEGER),
|
||||
new Limit("Max Samples", GLES30.GL_MAX_SAMPLES, Type.INTEGER),
|
||||
new Limit("Max Vertex UBOs", GLES30.GL_MAX_VERTEX_UNIFORM_BLOCKS, Type.INTEGER),
|
||||
new Limit("Max Fragment UBOs", GLES30.GL_MAX_FRAGMENT_UNIFORM_BLOCKS, Type.INTEGER),
|
||||
new Limit("Max Combined UBOs", GLES30.GL_MAX_COMBINED_UNIFORM_BLOCKS, Type.INTEGER),
|
||||
new Limit("Max Uniform Buffer Bindings", GLES30.GL_MAX_UNIFORM_BUFFER_BINDINGS, Type.INTEGER),
|
||||
new Limit("Max UBO Size", GLES30.GL_MAX_UNIFORM_BLOCK_SIZE, Type.INTEGER),
|
||||
new Limit("Max Combined Vertex Uniform Components", GLES30.GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, Type.INTEGER),
|
||||
new Limit("Max Combined Fragment Uniform Components", GLES30.GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, Type.INTEGER),
|
||||
new Limit("UBO Alignment", GLES30.GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, Type.INTEGER),
|
||||
new Limit("Max Vertex Output Components", GLES30.GL_MAX_VERTEX_OUTPUT_COMPONENTS, Type.INTEGER),
|
||||
new Limit("Max Fragment Input Components", GLES30.GL_MAX_FRAGMENT_INPUT_COMPONENTS, Type.INTEGER),
|
||||
new Limit("Max Server Wait Timeout", GLES30.GL_MAX_SERVER_WAIT_TIMEOUT, Type.INTEGER),
|
||||
new Limit("Program Binary Formats", GLES30.GL_NUM_PROGRAM_BINARY_FORMATS, Type.INTEGER),
|
||||
new Limit("Max Element Index", GLES30.GL_MAX_ELEMENT_INDEX, Type.INTEGER),
|
||||
new Limit("Sample Counts", GLES30.GL_NUM_SAMPLE_COUNTS, Type.INTEGER),
|
||||
};
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES3_BIT_KHR);
|
||||
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
List<AboutFragmentItem> Input = new ArrayList<AboutFragmentItem>();
|
||||
|
||||
for (Limit limit : Limits)
|
||||
{
|
||||
Log.i("GLES3InfoFragment", "Getting enum " + limit.name);
|
||||
Input.add(new AboutFragmentItem(limit.name, limit.GetValue(eglHelper)));
|
||||
}
|
||||
|
||||
// Get extensions manually
|
||||
int numExtensions = eglHelper.glGetInteger(GLES30.GL_NUM_EXTENSIONS);
|
||||
StringBuilder extensionsBuilder = new StringBuilder();
|
||||
for (int i = 0; i < numExtensions; i++)
|
||||
{
|
||||
extensionsBuilder.append(eglHelper.glGetStringi(GLES30.GL_EXTENSIONS, i)).append('\n');
|
||||
}
|
||||
Input.add(new AboutFragmentItem("OpenGL ES 3.0 Extensions", extensionsBuilder.toString()));
|
||||
|
||||
AboutInfoFragmentAdapter adapter = new AboutInfoFragmentAdapter(getActivity(), R.layout.about_layout, Input);
|
||||
rootView.setAdapter(adapter);
|
||||
|
||||
return rootView;
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.about;
|
||||
|
||||
import android.app.ListFragment;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLES30;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.about.Limit.Type;
|
||||
import org.dolphinemu.dolphinemu.utils.EGLHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
/**
|
||||
* {@link ListFragment} responsible for displaying
|
||||
* information relating to OpenGL.
|
||||
*/
|
||||
public final class GLInfoFragment extends ListFragment
|
||||
{
|
||||
private final Limit[] Limits = {
|
||||
new Limit("Vendor", GL10.GL_VENDOR, Type.STRING),
|
||||
new Limit("Version", GL10.GL_VERSION, Type.STRING),
|
||||
new Limit("Renderer", GL10.GL_RENDERER, Type.STRING),
|
||||
new Limit("GLSL version", GLES20.GL_SHADING_LANGUAGE_VERSION, Type.STRING),
|
||||
};
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_BIT);
|
||||
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
List<AboutFragmentItem> Input = new ArrayList<AboutFragmentItem>();
|
||||
|
||||
for (Limit limit : Limits)
|
||||
{
|
||||
Log.i("GLInfoFragment", "Getting enum " + limit.name);
|
||||
Input.add(new AboutFragmentItem(limit.name, limit.GetValue(eglHelper)));
|
||||
}
|
||||
|
||||
// Get extensions manually
|
||||
int numExtensions = eglHelper.glGetInteger(GLES30.GL_NUM_EXTENSIONS);
|
||||
StringBuilder extensionsBuilder = new StringBuilder();
|
||||
for (int i = 0; i < numExtensions; i++)
|
||||
{
|
||||
extensionsBuilder.append(eglHelper.glGetStringi(GL10.GL_EXTENSIONS, i)).append('\n');
|
||||
}
|
||||
Input.add(new AboutFragmentItem("OpenGL Extensions", extensionsBuilder.toString()));
|
||||
|
||||
AboutInfoFragmentAdapter adapter = new AboutInfoFragmentAdapter(getActivity(), R.layout.about_layout, Input);
|
||||
rootView.setAdapter(adapter);
|
||||
|
||||
return rootView;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright 2014 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.about;
|
||||
|
||||
import org.dolphinemu.dolphinemu.utils.EGLHelper;
|
||||
|
||||
final class Limit
|
||||
{
|
||||
/**
|
||||
* Possible types a Limit can be.
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
/** Generic string */
|
||||
STRING,
|
||||
/** Integer constant */
|
||||
INTEGER,
|
||||
/** Range of integers */
|
||||
INTEGER_RANGE,
|
||||
}
|
||||
|
||||
/** Name of this limit */
|
||||
public final String name;
|
||||
/** The GL constant that represents this limit.*/
|
||||
public final int glEnum;
|
||||
/** The {@link Type} of this limit. */
|
||||
public final Type type;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param name Name of the limit.
|
||||
* @param glEnum The GL constant that represents this limit.
|
||||
* @param type The {@link Type} of this limit.
|
||||
*/
|
||||
public Limit(String name, int glEnum, Type type)
|
||||
{
|
||||
this.name = name;
|
||||
this.glEnum = glEnum;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the information represented by this limit.
|
||||
*
|
||||
* @param context {@link EGLHelper} context to retrieve the limit with.
|
||||
*
|
||||
* @return the information represented by this limit.
|
||||
*/
|
||||
public String GetValue(EGLHelper context)
|
||||
{
|
||||
if (type == Type.INTEGER)
|
||||
{
|
||||
return Integer.toString(context.glGetInteger(glEnum));
|
||||
}
|
||||
else if (type == Type.INTEGER_RANGE)
|
||||
{
|
||||
int[] data = new int[2];
|
||||
context.getGL().glGetIntegerv(glEnum, data, 0);
|
||||
|
||||
return String.format("[%d, %d]", data[0], data[1]);
|
||||
}
|
||||
|
||||
// If neither of the above type, assume it's a string.
|
||||
return context.glGetString(glEnum);
|
||||
}
|
||||
}
|
@ -0,0 +1,316 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.emulation;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.settings.input.InputConfigFragment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is the activity where all of the emulation handling happens.
|
||||
* This activity is responsible for displaying the SurfaceView that we render to.
|
||||
*/
|
||||
public final class EmulationActivity extends Activity
|
||||
{
|
||||
private boolean Running;
|
||||
private boolean IsActionBarHidden = false;
|
||||
private SharedPreferences sharedPrefs;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
// Request window features for the emulation view.
|
||||
getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
getWindow().addFlags(LayoutParams.FLAG_FULLSCREEN);
|
||||
getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
|
||||
|
||||
// Set the transparency for the action bar.
|
||||
ColorDrawable actionBarBackground = new ColorDrawable(Color.parseColor("#303030"));
|
||||
actionBarBackground.setAlpha(175);
|
||||
getActionBar().setBackgroundDrawable(actionBarBackground);
|
||||
|
||||
// Get the intent passed from the GameList when the game
|
||||
// was selected. This is so the path of the game can be retrieved
|
||||
// and set on the native side of the code so the emulator can actually
|
||||
// load the game.
|
||||
Intent gameToEmulate = getIntent();
|
||||
NativeLibrary.SetFilename(gameToEmulate.getStringExtra("SelectedGame"));
|
||||
Running = true;
|
||||
|
||||
// Set the emulation window.
|
||||
setContentView(R.layout.emulation_view);
|
||||
|
||||
// If the input overlay was previously disabled, then don't show it.
|
||||
if (!sharedPrefs.getBoolean("showInputOverlay", true))
|
||||
{
|
||||
findViewById(R.id.emulationControlOverlay).setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
// Hide the action bar by default so it doesn't get in the way.
|
||||
getActionBar().hide();
|
||||
IsActionBarHidden = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop()
|
||||
{
|
||||
super.onStop();
|
||||
|
||||
if (Running)
|
||||
NativeLibrary.StopEmulation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
|
||||
if (Running)
|
||||
NativeLibrary.PauseEmulation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
|
||||
if (Running)
|
||||
NativeLibrary.UnPauseEmulation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
super.onDestroy();
|
||||
|
||||
if (Running)
|
||||
{
|
||||
NativeLibrary.StopEmulation();
|
||||
Running = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
// The back button in the emulation
|
||||
// window is the toggle for the action bar.
|
||||
if (IsActionBarHidden)
|
||||
{
|
||||
IsActionBarHidden = false;
|
||||
getActionBar().show();
|
||||
}
|
||||
else
|
||||
{
|
||||
IsActionBarHidden = true;
|
||||
getActionBar().hide();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.emuwindow_overlay, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu)
|
||||
{
|
||||
// Determine which string the "Enable Input Overlay" menu item should have
|
||||
// depending on its visibility at the time of preparing the options menu.
|
||||
if (!sharedPrefs.getBoolean("showInputOverlay", true))
|
||||
{
|
||||
menu.findItem(R.id.enableInputOverlay).setTitle(R.string.enable_input_overlay);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.findItem(R.id.enableInputOverlay).setTitle(R.string.disable_input_overlay);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int itemId, MenuItem item)
|
||||
{
|
||||
switch(item.getItemId())
|
||||
{
|
||||
// Enable/Disable input overlay.
|
||||
case R.id.enableInputOverlay:
|
||||
{
|
||||
View overlay = findViewById(R.id.emulationControlOverlay);
|
||||
|
||||
// Show the overlay
|
||||
if (item.getTitle().equals(getString(R.string.enable_input_overlay)))
|
||||
{
|
||||
overlay.setVisibility(View.VISIBLE);
|
||||
item.setTitle(R.string.disable_input_overlay);
|
||||
sharedPrefs.edit().putBoolean("showInputOverlay", true).apply();
|
||||
}
|
||||
else // Hide the overlay
|
||||
{
|
||||
overlay.setVisibility(View.INVISIBLE);
|
||||
item.setTitle(R.string.enable_input_overlay);
|
||||
sharedPrefs.edit().putBoolean("showInputOverlay", false).apply();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Screenshot capturing
|
||||
case R.id.takeScreenshot:
|
||||
NativeLibrary.SaveScreenShot();
|
||||
return true;
|
||||
|
||||
// Save state slots
|
||||
case R.id.saveSlot1:
|
||||
NativeLibrary.SaveState(0);
|
||||
return true;
|
||||
|
||||
case R.id.saveSlot2:
|
||||
NativeLibrary.SaveState(1);
|
||||
return true;
|
||||
|
||||
case R.id.saveSlot3:
|
||||
NativeLibrary.SaveState(2);
|
||||
return true;
|
||||
|
||||
case R.id.saveSlot4:
|
||||
NativeLibrary.SaveState(3);
|
||||
return true;
|
||||
|
||||
case R.id.saveSlot5:
|
||||
NativeLibrary.SaveState(4);
|
||||
return true;
|
||||
|
||||
// Load state slots
|
||||
case R.id.loadSlot1:
|
||||
NativeLibrary.LoadState(0);
|
||||
return true;
|
||||
|
||||
case R.id.loadSlot2:
|
||||
NativeLibrary.LoadState(1);
|
||||
return true;
|
||||
|
||||
case R.id.loadSlot3:
|
||||
NativeLibrary.LoadState(2);
|
||||
return true;
|
||||
|
||||
case R.id.loadSlot4:
|
||||
NativeLibrary.LoadState(3);
|
||||
return true;
|
||||
|
||||
case R.id.loadSlot5:
|
||||
NativeLibrary.LoadState(4);
|
||||
return true;
|
||||
|
||||
case R.id.exitEmulation:
|
||||
{
|
||||
// Create a confirmation method for quitting the current emulation instance.
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.overlay_exit_emulation);
|
||||
builder.setMessage(R.string.overlay_exit_emulation_confirm);
|
||||
builder.setNegativeButton(R.string.no, null);
|
||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
onDestroy();
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return super.onMenuItemSelected(itemId, item);
|
||||
}
|
||||
}
|
||||
|
||||
// Gets button presses
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event)
|
||||
{
|
||||
int action = 0;
|
||||
|
||||
if (Running)
|
||||
{
|
||||
switch (event.getAction())
|
||||
{
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
// Handling the case where the back button is pressed.
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
|
||||
{
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Normal key events.
|
||||
action = NativeLibrary.ButtonState.PRESSED;
|
||||
break;
|
||||
case KeyEvent.ACTION_UP:
|
||||
action = NativeLibrary.ButtonState.RELEASED;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
InputDevice input = event.getDevice();
|
||||
boolean handled = NativeLibrary.onGamePadEvent(InputConfigFragment.getInputDesc(input), event.getKeyCode(), action);
|
||||
return handled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchGenericMotionEvent(MotionEvent event)
|
||||
{
|
||||
if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) || !Running)
|
||||
{
|
||||
return super.dispatchGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
// Don't attempt to do anything if we are disconnecting a device.
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_CANCEL)
|
||||
return true;
|
||||
|
||||
InputDevice input = event.getDevice();
|
||||
List<InputDevice.MotionRange> motions = input.getMotionRanges();
|
||||
|
||||
for (InputDevice.MotionRange range : motions)
|
||||
{
|
||||
NativeLibrary.onGamePadMoveEvent(InputConfigFragment.getInputDesc(input), range.getAxis(), event.getAxisValue(range.getAxis()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.emulation;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
/**
|
||||
* The {@link SurfaceView} that rendering is performed on.
|
||||
*/
|
||||
public final class NativeGLSurfaceView extends SurfaceView
|
||||
{
|
||||
private static Thread myRun;
|
||||
private static boolean Running = false;
|
||||
private static boolean Created = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param attribs An AttributeSet for retrieving data from XML files.
|
||||
*/
|
||||
public NativeGLSurfaceView(Context context, AttributeSet attribs)
|
||||
{
|
||||
super(context, attribs);
|
||||
|
||||
if (!Created)
|
||||
{
|
||||
myRun = new Thread()
|
||||
{
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
NativeLibrary.Run(getHolder().getSurface());
|
||||
Created = false;
|
||||
Running = false;
|
||||
}
|
||||
};
|
||||
|
||||
getHolder().addCallback(new SurfaceHolder.Callback()
|
||||
{
|
||||
public void surfaceCreated(SurfaceHolder holder)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
if (!Running)
|
||||
{
|
||||
myRun.start();
|
||||
Running = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
});
|
||||
|
||||
Created = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,288 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.emulation.overlay;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.View.OnTouchListener;
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary.ButtonState;
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary.ButtonType;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Draws the interactive input overlay on top of the
|
||||
* {@link NativeGLSurfaceView} that is rendering emulation.
|
||||
*/
|
||||
public final class InputOverlay extends SurfaceView implements OnTouchListener
|
||||
{
|
||||
private final Set<InputOverlayDrawableButton> overlayButtons = new HashSet<InputOverlayDrawableButton>();
|
||||
private final Set<InputOverlayDrawableJoystick> overlayJoysticks = new HashSet<InputOverlayDrawableJoystick>();
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// Retrieve screen dimensions.
|
||||
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
|
||||
Bitmap bitmapResized = Bitmap.createScaledBitmap(bitmap,
|
||||
(int)(dm.heightPixels * scale),
|
||||
(int)(dm.heightPixels * scale),
|
||||
true);
|
||||
return bitmapResized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param attrs {@link AttributeSet} for parsing XML attributes.
|
||||
*/
|
||||
public InputOverlay(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
|
||||
// Add all the overlay items to the HashSet.
|
||||
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_a, ButtonType.BUTTON_A));
|
||||
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_b, ButtonType.BUTTON_B));
|
||||
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_x, ButtonType.BUTTON_X));
|
||||
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_y, ButtonType.BUTTON_Y));
|
||||
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_z, ButtonType.BUTTON_Z));
|
||||
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_start, ButtonType.BUTTON_START));
|
||||
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_l, ButtonType.TRIGGER_L));
|
||||
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_r, ButtonType.TRIGGER_R));
|
||||
overlayJoysticks.add(initializeOverlayJoystick(context,
|
||||
R.drawable.gcpad_joystick_range, R.drawable.gcpad_joystick,
|
||||
ButtonType.STICK_MAIN));
|
||||
|
||||
// Set the on touch listener.
|
||||
setOnTouchListener(this);
|
||||
|
||||
// Force draw
|
||||
setWillNotDraw(false);
|
||||
|
||||
// Request focus for the overlay so it has priority on presses.
|
||||
requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas)
|
||||
{
|
||||
super.draw(canvas);
|
||||
|
||||
for (InputOverlayDrawableButton button : overlayButtons)
|
||||
{
|
||||
button.draw(canvas);
|
||||
}
|
||||
|
||||
for (InputOverlayDrawableJoystick joystick: overlayJoysticks)
|
||||
{
|
||||
joystick.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event)
|
||||
{
|
||||
int pointerIndex = event.getActionIndex();
|
||||
|
||||
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:
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
// If a pointer enters the bounds of a button, press that button.
|
||||
if (button.getBounds().contains((int)event.getX(pointerIndex), (int)event.getY(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.getBounds().contains((int)event.getX(pointerIndex), (int)event.getY(pointerIndex)))
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), ButtonState.RELEASED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
|
||||
{
|
||||
joystick.TrackEvent(event);
|
||||
int[] axisIDs = joystick.getAxisIDs();
|
||||
float[] axises = joystick.getAxisValues();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, axisIDs[i], axises[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an InputOverlayDrawableButton, given by resId, with all of the
|
||||
* parameters set for it to be properly shown on the InputOverlay.
|
||||
* <p>
|
||||
* This works due to the way the X and Y coordinates are stored within
|
||||
* the {@link SharedPreferences}.
|
||||
* <p>
|
||||
* In the input overlay configuration menu,
|
||||
* once a touch event begins and then ends (ie. Organizing the buttons to one's own liking for the overlay).
|
||||
* the X and Y coordinates of the button at the END of its touch event
|
||||
* (when you remove your finger/stylus from the touchscreen) are then stored
|
||||
* within a SharedPreferences instance so that those values can be retrieved here.
|
||||
* <p>
|
||||
* This has a few benefits over the conventional way of storing the values
|
||||
* (ie. within the Dolphin ini file).
|
||||
* <ul>
|
||||
* <li>No native calls</li>
|
||||
* <li>Keeps Android-only values inside the Android environment</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Technically no modifications should need to be performed on the returned
|
||||
* InputOverlayDrawableButton. Simply add it to the HashSet of overlay items and wait
|
||||
* for Android to call the onDraw method.
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param resId The resource ID of the {@link Drawable} to get the {@link Bitmap} of.
|
||||
* @param buttonId Identifier for determining what type of button the initialized InputOverlayDrawableButton represents.
|
||||
*
|
||||
* @return An {@link InputOverlayDrawableButton} with the correct drawing bounds set.
|
||||
*
|
||||
*/
|
||||
private static InputOverlayDrawableButton initializeOverlayButton(Context context, int resId, int buttonId)
|
||||
{
|
||||
// Resources handle for fetching the initial Drawable resource.
|
||||
final Resources res = context.getResources();
|
||||
|
||||
// SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableButton.
|
||||
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
// Decide scale based on button ID
|
||||
float scale;
|
||||
float overlaySize = sPrefs.getInt("controls_size", 25);
|
||||
overlaySize += 25;
|
||||
overlaySize /= 50;
|
||||
|
||||
switch (resId)
|
||||
{
|
||||
case R.drawable.gcpad_b:
|
||||
scale = 0.13f * overlaySize;
|
||||
break;
|
||||
case R.drawable.gcpad_x:
|
||||
case R.drawable.gcpad_y:
|
||||
scale = 0.18f * overlaySize;
|
||||
break;
|
||||
case R.drawable.gcpad_start:
|
||||
scale = 0.12f * overlaySize;
|
||||
break;
|
||||
default:
|
||||
scale = 0.20f * overlaySize;
|
||||
break;
|
||||
}
|
||||
|
||||
// Initialize the InputOverlayDrawableButton.
|
||||
final Bitmap bitmap = resizeBitmap(context, BitmapFactory.decodeResource(res, resId), scale);
|
||||
final InputOverlayDrawableButton overlayDrawable = new InputOverlayDrawableButton(res, bitmap, buttonId);
|
||||
|
||||
// String ID of the Drawable. This is what is passed into SharedPreferences
|
||||
// to check whether or not a value has been set.
|
||||
final String drawableId = res.getResourceEntryName(resId);
|
||||
|
||||
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
|
||||
// These were set in the input overlay configuration menu.
|
||||
int drawableX = (int) sPrefs.getFloat(drawableId+"-X", 0f);
|
||||
int drawableY = (int) sPrefs.getFloat(drawableId+"-Y", 0f);
|
||||
|
||||
// Intrinsic width and height of the InputOverlayDrawableButton.
|
||||
// For any who may not know, intrinsic width/height
|
||||
// are the original unmodified width and height of the image.
|
||||
int intrinWidth = overlayDrawable.getIntrinsicWidth();
|
||||
int intrinHeight = overlayDrawable.getIntrinsicHeight();
|
||||
|
||||
// Now set the bounds for the InputOverlayDrawableButton.
|
||||
// This will dictate where on the screen (and the what the size) the InputOverlayDrawableButton will be.
|
||||
overlayDrawable.setBounds(drawableX, drawableY, drawableX+intrinWidth, drawableY+intrinHeight);
|
||||
|
||||
return overlayDrawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an {@link InputOverlayDrawableJoystick}
|
||||
*
|
||||
* @param context The current {@link Context}
|
||||
* @param resOuter Resource ID for the outer image of the joystick (the static image that shows the circular bounds).
|
||||
* @param resInner Resource ID for the inner image of the joystick (the one you actually move around).
|
||||
* @param joystick Identifier for which joystick this is.
|
||||
*
|
||||
* @return the initialized {@link InputOverlayDrawableJoystick}.
|
||||
*/
|
||||
private static InputOverlayDrawableJoystick initializeOverlayJoystick(Context context, int resOuter, int resInner, int joystick)
|
||||
{
|
||||
// Resources handle for fetching the initial Drawable resource.
|
||||
final Resources res = context.getResources();
|
||||
|
||||
// SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableJoystick.
|
||||
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
// Initialize the InputOverlayDrawableJoystick.
|
||||
float overlaySize = sPrefs.getInt("controls_size", 20);
|
||||
overlaySize += 30;
|
||||
overlaySize /= 50;
|
||||
final Bitmap bitmapOuter = resizeBitmap(context, BitmapFactory.decodeResource(res, resOuter), 0.30f * overlaySize);
|
||||
final Bitmap bitmapInner = BitmapFactory.decodeResource(res, resInner);
|
||||
|
||||
// String ID of the Drawable. This is what is passed into SharedPreferences
|
||||
// to check whether or not a value has been set.
|
||||
final String drawableId = res.getResourceEntryName(resOuter);
|
||||
|
||||
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
|
||||
// These were set in the input overlay configuration menu.
|
||||
int drawableX = (int) sPrefs.getFloat(drawableId+"-X", 0f);
|
||||
int drawableY = (int) sPrefs.getFloat(drawableId+"-Y", 0f);
|
||||
|
||||
// Now set the bounds for the InputOverlayDrawableJoystick.
|
||||
// This will dictate where on the screen (and the what the size) the InputOverlayDrawableJoystick will be.
|
||||
int outerSize = bitmapOuter.getWidth();
|
||||
Rect outerRect = new Rect(drawableX, drawableY, drawableX + outerSize, drawableY + outerSize);
|
||||
Rect innerRect = new Rect(0, 0, outerSize / 4, outerSize / 4);
|
||||
|
||||
final InputOverlayDrawableJoystick overlayDrawable
|
||||
= new InputOverlayDrawableJoystick(res,
|
||||
bitmapOuter, bitmapInner,
|
||||
outerRect, innerRect,
|
||||
joystick);
|
||||
|
||||
|
||||
return overlayDrawable;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.emulation.overlay;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
|
||||
/**
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
* of storing it's own ID.
|
||||
*/
|
||||
public final class InputOverlayDrawableButton extends BitmapDrawable
|
||||
{
|
||||
// The ID identifying what type of button this Drawable represents.
|
||||
private int buttonType;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param bitmap {@link Bitmap} to use with this Drawable.
|
||||
* @param buttonType Identifier for this type of button.
|
||||
*/
|
||||
public InputOverlayDrawableButton(Resources res, Bitmap bitmap, int buttonType)
|
||||
{
|
||||
super(res, bitmap);
|
||||
|
||||
this.buttonType = buttonType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this InputOverlayDrawableButton's button ID.
|
||||
*
|
||||
* @return this InputOverlayDrawableButton's button ID.
|
||||
*/
|
||||
public int getId()
|
||||
{
|
||||
return buttonType;
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.emulation.overlay;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
* of storing it's own ID.
|
||||
*/
|
||||
public final class InputOverlayDrawableJoystick extends BitmapDrawable
|
||||
{
|
||||
private final int[] axisIDs = {0, 0, 0, 0};
|
||||
private final float[] axises = {0f, 0f};
|
||||
private final BitmapDrawable ringInner;
|
||||
private int trackId = -1;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param bitmapOuter {@link Bitmap} which represents the outer non-movable part of the joystick.
|
||||
* @param bitmapInner {@link Bitmap} which represents the inner movable part of the joystick.
|
||||
* @param rectOuter {@link Rect} which represents the outer joystick bounds.
|
||||
* @param rectInner {@link Rect} which represents the inner joystick bounds.
|
||||
* @param joystick Identifier for which joystick this is.
|
||||
*/
|
||||
public InputOverlayDrawableJoystick(Resources res,
|
||||
Bitmap bitmapOuter, Bitmap bitmapInner,
|
||||
Rect rectOuter, Rect rectInner,
|
||||
int joystick)
|
||||
{
|
||||
super(res, bitmapOuter);
|
||||
this.setBounds(rectOuter);
|
||||
|
||||
this.ringInner = new BitmapDrawable(res, bitmapInner);
|
||||
this.ringInner.setBounds(rectInner);
|
||||
SetInnerBounds();
|
||||
this.axisIDs[0] = joystick + 1;
|
||||
this.axisIDs[1] = joystick + 2;
|
||||
this.axisIDs[2] = joystick + 3;
|
||||
this.axisIDs[3] = joystick + 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas)
|
||||
{
|
||||
super.draw(canvas);
|
||||
|
||||
ringInner.draw(canvas);
|
||||
}
|
||||
|
||||
public void TrackEvent(MotionEvent event)
|
||||
{
|
||||
int pointerIndex = event.getActionIndex();
|
||||
|
||||
switch(event.getAction() & MotionEvent.ACTION_MASK)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (getBounds().contains((int)event.getX(pointerIndex), (int)event.getY(pointerIndex)))
|
||||
trackId = event.getPointerId(pointerIndex);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (trackId == event.getPointerId(pointerIndex))
|
||||
{
|
||||
axises[0] = axises[1] = 0.0f;
|
||||
SetInnerBounds();
|
||||
trackId = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (trackId == -1)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < event.getPointerCount(); i++)
|
||||
{
|
||||
if (trackId == event.getPointerId(i))
|
||||
{
|
||||
float touchX = event.getX(i);
|
||||
float touchY = event.getY(i);
|
||||
float maxY = getBounds().bottom;
|
||||
float maxX = getBounds().right;
|
||||
touchX -= getBounds().centerX();
|
||||
maxX -= getBounds().centerX();
|
||||
touchY -= getBounds().centerY();
|
||||
maxY -= getBounds().centerY();
|
||||
final float AxisX = touchX / maxX;
|
||||
final float AxisY = touchY / maxY;
|
||||
axises[0] = AxisY;
|
||||
axises[1] = AxisX;
|
||||
|
||||
SetInnerBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float[] getAxisValues()
|
||||
{
|
||||
float[] joyaxises = {0f, 0f, 0f, 0f};
|
||||
joyaxises[1] = Math.min(axises[0], 1.0f);
|
||||
joyaxises[0] = Math.min(axises[0], 0.0f);
|
||||
joyaxises[3] = Math.min(axises[1], 1.0f);
|
||||
joyaxises[2] = Math.min(axises[1], 0.0f);
|
||||
return joyaxises;
|
||||
}
|
||||
|
||||
public int[] getAxisIDs()
|
||||
{
|
||||
return axisIDs;
|
||||
}
|
||||
|
||||
private void SetInnerBounds()
|
||||
{
|
||||
float floatX = this.getBounds().centerX();
|
||||
float floatY = this.getBounds().centerY();
|
||||
floatY += axises[0] * (this.getBounds().height() / 2);
|
||||
floatX += axises[1] * (this.getBounds().width() / 2);
|
||||
int X = (int)(floatX);
|
||||
int Y = (int)(floatY);
|
||||
int width = this.ringInner.getBounds().width() / 2;
|
||||
int height = this.ringInner.getBounds().height() / 2;
|
||||
this.ringInner.setBounds(X - width, Y - height,
|
||||
X + width, Y + height);
|
||||
}
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.folderbrowser;
|
||||
|
||||
import android.app.ListFragment;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.gamelist.GameListActivity;
|
||||
|
||||
/**
|
||||
* A basic folder browser {@link ListFragment} that allows
|
||||
* the user to select ISOs/ROMs for playing within the
|
||||
* emulator.
|
||||
* <p>
|
||||
* Any valid ISO/ROM selected in this will be added to
|
||||
* the game list for easy browsing the next time the
|
||||
* application is used.
|
||||
* <p>
|
||||
* Note that this file browser does not display files
|
||||
* or directories that are hidden
|
||||
*/
|
||||
public final class FolderBrowser extends ListFragment
|
||||
{
|
||||
private FolderBrowserAdapter adapter;
|
||||
private static File currentDir = null;
|
||||
|
||||
// Populates the FolderView with the given currDir's contents.
|
||||
private void Fill(File currDir)
|
||||
{
|
||||
// Clear the adapter of previous items.
|
||||
adapter.clear();
|
||||
|
||||
// Set the activity title to the current directory the FolderBrowser is in.
|
||||
getActivity().setTitle(String.format(getString(R.string.current_dir), currDir.getName()));
|
||||
|
||||
File[] dirs = currDir.listFiles();
|
||||
List<FolderBrowserItem> dir = new ArrayList<FolderBrowserItem>();
|
||||
List<FolderBrowserItem> fls = new ArrayList<FolderBrowserItem>();
|
||||
|
||||
// Supported extensions to filter by
|
||||
Set<String> validExts = new HashSet<String>(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs"));
|
||||
|
||||
// If dirs is null, then we don't have access permissions to the selected folder.
|
||||
if (dirs != null)
|
||||
{
|
||||
// Search for any directories or files within the current dir.
|
||||
for(File entry : dirs)
|
||||
{
|
||||
try
|
||||
{
|
||||
String entryName = entry.getName();
|
||||
boolean hasExtension = (entryName.lastIndexOf(".") != -1);
|
||||
|
||||
// Skip hidden folders/files.
|
||||
if (!entry.isHidden())
|
||||
{
|
||||
if(entry.isDirectory())
|
||||
{
|
||||
dir.add(new FolderBrowserItem(entryName, entry.getAbsolutePath()));
|
||||
}
|
||||
else if (entry.isFile() && hasExtension)
|
||||
{
|
||||
if (validExts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
|
||||
{
|
||||
fls.add(new FolderBrowserItem(entryName, String.format(getString(R.string.file_size), entry.length()), entry.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.e("FolderBrowser", ex.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(dir);
|
||||
Collections.sort(fls);
|
||||
dir.addAll(fls);
|
||||
|
||||
// Check for a parent directory to the one we're currently in.
|
||||
if (!currDir.getPath().equalsIgnoreCase("/"))
|
||||
dir.add(0, new FolderBrowserItem("..", getString(R.string.parent_directory), currDir.getParent()));
|
||||
|
||||
// Add the items to the adapter and notify the adapter users of its new contents.
|
||||
adapter.addAll(dir);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListItemClick(ListView lv, View v, int position, long id)
|
||||
{
|
||||
FolderBrowserItem item = adapter.getItem(position);
|
||||
if(item.isDirectory())
|
||||
{
|
||||
currentDir = new File(item.getPath());
|
||||
Fill(currentDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
FolderSelected();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
if(currentDir == null)
|
||||
currentDir = new File(Environment.getExternalStorageDirectory().getPath());
|
||||
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.folderbrowser_listview, container, false);
|
||||
adapter = new FolderBrowserAdapter(getActivity(), R.layout.folderbrowser_list_item);
|
||||
rootView.setAdapter(adapter);
|
||||
|
||||
Fill(currentDir);
|
||||
return rootView;
|
||||
}
|
||||
|
||||
private void FolderSelected()
|
||||
{
|
||||
String Directories = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPaths", "0");
|
||||
int intDirectories = Integer.parseInt(Directories);
|
||||
|
||||
// Check to see if a path set in the Dolphin config
|
||||
// matches the one the user is trying to add. If it's
|
||||
// already set, then don't add it to the list again.
|
||||
boolean pathNotPresent = true;
|
||||
for (int i = 0; i < intDirectories; i++)
|
||||
{
|
||||
String isoPath = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPath" + i, "");
|
||||
|
||||
pathNotPresent = !isoPath.equals(currentDir.getPath());
|
||||
}
|
||||
|
||||
// User doesn't have this path in the config, so add it.
|
||||
if (pathNotPresent)
|
||||
{
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "General", "ISOPaths", Integer.toString(intDirectories+1));
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "General", "ISOPath" + Integer.toString(intDirectories), currentDir.getPath());
|
||||
}
|
||||
|
||||
((GameListActivity)getActivity()).SwitchPage(0);
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.folderbrowser;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
/**
|
||||
* The {@link ArrayAdapter} that backs the file browser.
|
||||
* <p>
|
||||
* This is responsible for correctly handling the display
|
||||
* of the items for the {@link FolderBrowser} UI.
|
||||
*/
|
||||
public final class FolderBrowserAdapter extends ArrayAdapter<FolderBrowserItem>
|
||||
{
|
||||
// ViewHolder which is used to hold onto
|
||||
// items within a listview. This is done
|
||||
// so that findViewById is not needed to
|
||||
// be excessively called over and over.
|
||||
private static final class ViewHolder
|
||||
{
|
||||
TextView title;
|
||||
TextView subtitle;
|
||||
ImageView icon;
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
private final int id;
|
||||
private ViewHolder viewHolder;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param resourceId The resource ID for a layout file containing a layout to use when instantiating views.
|
||||
*/
|
||||
public FolderBrowserAdapter(Context context, int resourceId)
|
||||
{
|
||||
super(context, resourceId);
|
||||
|
||||
this.context = context;
|
||||
this.id = resourceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent)
|
||||
{
|
||||
if (convertView == null)
|
||||
{
|
||||
LayoutInflater vi = LayoutInflater.from(context);
|
||||
convertView = vi.inflate(id, parent, false);
|
||||
|
||||
// Initialize the ViewHolder and store it.
|
||||
viewHolder = new ViewHolder();
|
||||
viewHolder.title = (TextView) convertView.findViewById(R.id.BrowserItemTitle);
|
||||
viewHolder.subtitle = (TextView) convertView.findViewById(R.id.BrowserItemSubTitle);
|
||||
viewHolder.icon = (ImageView) convertView.findViewById(R.id.BrowserItemIcon);
|
||||
convertView.setTag(viewHolder);
|
||||
}
|
||||
else // Can recover the holder.
|
||||
{
|
||||
viewHolder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
final FolderBrowserItem item = getItem(position);
|
||||
if (item != null)
|
||||
{
|
||||
if (viewHolder.title != null)
|
||||
{
|
||||
viewHolder.title.setText(item.getName());
|
||||
}
|
||||
|
||||
if (viewHolder.subtitle != null)
|
||||
{
|
||||
// Remove the subtitle for all folders, except for the parent directory folder.
|
||||
if (item.isDirectory() && !item.getSubtitle().equals(context.getString(R.string.parent_directory)))
|
||||
{
|
||||
viewHolder.subtitle.setVisibility(View.GONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
viewHolder.subtitle.setVisibility(View.VISIBLE);
|
||||
viewHolder.subtitle.setText(item.getSubtitle());
|
||||
}
|
||||
}
|
||||
|
||||
if (viewHolder.icon != null)
|
||||
{
|
||||
if (item.isDirectory())
|
||||
{
|
||||
viewHolder.icon.setImageResource(R.drawable.ic_menu_folder);
|
||||
}
|
||||
else
|
||||
{
|
||||
viewHolder.icon.setImageResource(R.drawable.ic_menu_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.folderbrowser;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Represents an item in the {@link FolderBrowser} list.
|
||||
*/
|
||||
public final class FolderBrowserItem implements Comparable<FolderBrowserItem>
|
||||
{
|
||||
private final String name;
|
||||
private final String subtitle;
|
||||
private final String path;
|
||||
private final File underlyingFile;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param name The name of the file/folder represented by this item.
|
||||
* @param subtitle The subtitle of this FolderBrowserItem.
|
||||
* @param path The path of the file/folder represented by this item.
|
||||
*/
|
||||
public FolderBrowserItem(String name, String subtitle, String path)
|
||||
{
|
||||
this.name = name;
|
||||
this.subtitle = subtitle;
|
||||
this.path = path;
|
||||
this.underlyingFile = new File(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Initializes a FolderBrowserItem with an empty subtitle.
|
||||
*
|
||||
* @param name The name of the file/folder represented by this item.
|
||||
* @param path The path of the file/folder represented by this item.
|
||||
*/
|
||||
public FolderBrowserItem(String name, String path)
|
||||
{
|
||||
this.name = name;
|
||||
this.subtitle = "";
|
||||
this.path = path;
|
||||
this.underlyingFile = new File(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the file/folder represented by this FolderBrowserItem.
|
||||
*
|
||||
* @return the name of the file/folder represented by this FolderBrowserItem.
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subtitle text of this FolderBrowserItem.
|
||||
*
|
||||
* @return the subtitle text of this FolderBrowserItem.
|
||||
*/
|
||||
public String getSubtitle()
|
||||
{
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path of the file/folder represented by this FolderBrowserItem.
|
||||
*
|
||||
* @return the path of the file/folder represented by this FolderBrowserItem.
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link File} representation of the underlying file/folder
|
||||
* represented by this FolderBrowserItem.
|
||||
*
|
||||
* @return the {@link File} representation of the underlying file/folder
|
||||
* represented by this FolderBrowserItem.
|
||||
*/
|
||||
public File getUnderlyingFile()
|
||||
{
|
||||
return underlyingFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether or not this FolderBrowserItem represents a directory.
|
||||
*
|
||||
* @return true if this FolderBrowserItem represents a directory, false otherwise.
|
||||
*/
|
||||
public boolean isDirectory()
|
||||
{
|
||||
return underlyingFile.isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FolderBrowserItem other)
|
||||
{
|
||||
if(name != null)
|
||||
return name.toLowerCase().compareTo(other.getName().toLowerCase());
|
||||
else
|
||||
throw new NullPointerException("The name of this FolderBrowserItem is null");
|
||||
}
|
||||
}
|
@ -0,0 +1,374 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.gamelist;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.ActionBarDrawerToggle;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.AssetCopyService;
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.about.AboutActivity;
|
||||
import org.dolphinemu.dolphinemu.emulation.EmulationActivity;
|
||||
import org.dolphinemu.dolphinemu.folderbrowser.FolderBrowser;
|
||||
import org.dolphinemu.dolphinemu.settings.PrefsActivity;
|
||||
import org.dolphinemu.dolphinemu.sidemenu.SideMenuAdapter;
|
||||
import org.dolphinemu.dolphinemu.sidemenu.SideMenuItem;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The activity that implements all of the functions
|
||||
* for the game list.
|
||||
*/
|
||||
public final class GameListActivity extends Activity
|
||||
implements GameListFragment.OnGameListZeroListener
|
||||
{
|
||||
private int mCurFragmentNum = 0;
|
||||
|
||||
private ActionBarDrawerToggle mDrawerToggle;
|
||||
private DrawerLayout mDrawerLayout;
|
||||
private SideMenuAdapter mDrawerAdapter;
|
||||
private ListView mDrawerList;
|
||||
private boolean mAutoStart = false;
|
||||
private String mAutoStartFile = "";
|
||||
|
||||
/**
|
||||
* Called from the {@link GameListFragment}.
|
||||
* <p>
|
||||
* This is called when there are no games
|
||||
* currently present within the game list.
|
||||
*/
|
||||
public void onZeroFiles()
|
||||
{
|
||||
mDrawerLayout.openDrawer(mDrawerList);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.gamelist_activity);
|
||||
|
||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
mDrawerList = (ListView) findViewById(R.id.left_drawer);
|
||||
|
||||
// Construct list of items to add to the side menu.
|
||||
List<SideMenuItem> dir = new ArrayList<SideMenuItem>();
|
||||
dir.add(new SideMenuItem(getString(R.string.game_list), 0));
|
||||
dir.add(new SideMenuItem(getString(R.string.browse_folder), 1));
|
||||
dir.add(new SideMenuItem(getString(R.string.settings), 2));
|
||||
dir.add(new SideMenuItem(getString(R.string.about), 3));
|
||||
|
||||
mDrawerAdapter = new SideMenuAdapter(this, R.layout.sidemenu, dir);
|
||||
mDrawerList.setAdapter(mDrawerAdapter);
|
||||
mDrawerList.setOnItemClickListener(mMenuItemClickListener);
|
||||
|
||||
// Enable ActionBar app icon to behave as action to toggle nav drawer
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getActionBar().setHomeButtonEnabled(true);
|
||||
|
||||
// ActionBarDrawerToggle ties together the the proper interactions
|
||||
// between the sliding drawer and the action bar app icon
|
||||
mDrawerToggle = new ActionBarDrawerToggle(
|
||||
this, /* Host Activity */
|
||||
mDrawerLayout, /* DrawerLayout object */
|
||||
R.drawable.ic_drawer, /* Navigation drawer image to replace 'Up' caret */
|
||||
R.string.drawer_open, /* "open drawer" description for accessibility */
|
||||
R.string.drawer_close /* "close drawer" description for accessibility */
|
||||
) {
|
||||
public void onDrawerClosed(View view) {
|
||||
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
|
||||
}
|
||||
|
||||
public void onDrawerOpened(View drawerView) {
|
||||
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
|
||||
}
|
||||
};
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
|
||||
CheckForIntent();
|
||||
|
||||
String BaseDir = NativeLibrary.GetUserDirectory();
|
||||
final String DefaultDir = Environment.getExternalStorageDirectory() + File.separator + "dolphin-emu";
|
||||
if (BaseDir.isEmpty())
|
||||
BaseDir = DefaultDir;
|
||||
NativeLibrary.SetUserDirectory(BaseDir);
|
||||
|
||||
// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
|
||||
if (savedInstanceState == null)
|
||||
{
|
||||
// Copy assets into appropriate locations.
|
||||
Intent copyAssets = new Intent(this, AssetCopyService.class);
|
||||
startService(copyAssets);
|
||||
|
||||
// Display the game list fragment.
|
||||
final GameListFragment gameList = new GameListFragment();
|
||||
FragmentTransaction ft = getFragmentManager().beginTransaction();
|
||||
ft.replace(R.id.content_frame, gameList);
|
||||
ft.commit();
|
||||
}
|
||||
|
||||
// Create an alert telling them that their phone sucks
|
||||
if (Build.CPU_ABI.contains("arm") && !NativeLibrary.SupportsNEON())
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.device_compat_warning);
|
||||
builder.setMessage(R.string.device_compat_warning_msg);
|
||||
builder.setPositiveButton(R.string.yes, null);
|
||||
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
finish();
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
if (mAutoStart)
|
||||
{
|
||||
// Start the emulation activity
|
||||
Intent intent = new Intent(this, EmulationActivity.class);
|
||||
intent.putExtra("SelectedGame", mAutoStartFile);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckForIntent()
|
||||
{
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean handled = prefs.getBoolean("HandledIntent", false);
|
||||
|
||||
// Get an editor.
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
Bundle extras = getIntent().getExtras();
|
||||
|
||||
if (!handled && extras != null)
|
||||
{
|
||||
// Application got passed extra data
|
||||
editor.putBoolean("HandledIntent", true);
|
||||
editor.apply();
|
||||
|
||||
// Did we get passed a new user directory?
|
||||
String user_dir = extras.getString("UserDir");
|
||||
if (user_dir != null && user_dir.length() != 0)
|
||||
NativeLibrary.SetUserDirectory(user_dir);
|
||||
|
||||
// Did we get passed a file?
|
||||
String start_file = extras.getString("AutoStartFile");
|
||||
if (start_file != null && start_file.length() != 0)
|
||||
{
|
||||
mAutoStart = true;
|
||||
mAutoStartFile = start_file;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
editor.putBoolean("HandledIntent", false);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches to the {@link Fragment} represented
|
||||
* by the given ID number.
|
||||
*
|
||||
* @param toPage the number representing the {@link Fragment} to switch to.
|
||||
*/
|
||||
public void SwitchPage(int toPage)
|
||||
{
|
||||
if (mCurFragmentNum == toPage)
|
||||
return;
|
||||
|
||||
switch(toPage)
|
||||
{
|
||||
case 0: // Game list
|
||||
{
|
||||
// We use the title section as the browser directory tracker in the folder browser.
|
||||
// Make sure we flip the title back if we're coming from that fragment.
|
||||
if (mCurFragmentNum == 1)
|
||||
setTitle(R.string.app_name);
|
||||
|
||||
mCurFragmentNum = 0;
|
||||
final GameListFragment gameList = new GameListFragment();
|
||||
FragmentTransaction ft = getFragmentManager().beginTransaction();
|
||||
ft.replace(R.id.content_frame, gameList);
|
||||
ft.commit();
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // Folder Browser
|
||||
{
|
||||
mCurFragmentNum = 1;
|
||||
final FolderBrowser folderBrowser = new FolderBrowser();
|
||||
FragmentTransaction ft = getFragmentManager().beginTransaction();
|
||||
ft.replace(R.id.content_frame, folderBrowser);
|
||||
ft.addToBackStack(null);
|
||||
ft.commit();
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // Settings
|
||||
{
|
||||
Intent intent = new Intent(this, PrefsActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // About
|
||||
{
|
||||
Intent intent = new Intent(this, AboutActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private final AdapterView.OnItemClickListener mMenuItemClickListener = new AdapterView.OnItemClickListener()
|
||||
{
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
|
||||
{
|
||||
SideMenuItem o = mDrawerAdapter.getItem(position);
|
||||
mDrawerLayout.closeDrawer(mDrawerList);
|
||||
SwitchPage(o.getID());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* When using the ActionBarDrawerToggle, you must call it during
|
||||
* onPostCreate() and onConfigurationChanged()...
|
||||
*/
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onPostCreate(savedInstanceState);
|
||||
|
||||
// Sync the toggle state after onRestoreInstanceState has occurred.
|
||||
mDrawerToggle.syncState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig)
|
||||
{
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
// Pass any configuration change to the drawer toggle
|
||||
mDrawerToggle.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
// Only show this in the game list.
|
||||
if (mCurFragmentNum == 0)
|
||||
{
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.gamelist_menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
// The action bar home/up action should open or close the drawer.
|
||||
// ActionBarDrawerToggle will take care of this.
|
||||
if (mDrawerToggle.onOptionsItemSelected(item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If clear game list is pressed.
|
||||
if (item.getItemId() == R.id.clearGameList)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.clear_game_list);
|
||||
builder.setMessage(getString(R.string.clear_game_list_confirm));
|
||||
builder.setNegativeButton(R.string.no, null);
|
||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
String directories = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPaths", "0");
|
||||
int intDirs = Integer.parseInt(directories);
|
||||
|
||||
for (int i = 0; i < intDirs; i++)
|
||||
{
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "General", "ISOPath" + i, "");
|
||||
}
|
||||
|
||||
// Since we flushed all paths, we signify this in the ini.
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "General", "ISOPaths", "0");
|
||||
|
||||
// Now finally, clear the game list.
|
||||
((GameListFragment) getFragmentManager().findFragmentById(R.id.content_frame)).clearGameList();
|
||||
}
|
||||
});
|
||||
|
||||
builder.show();
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState)
|
||||
{
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
outState.putInt("currentFragmentNum", mCurFragmentNum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Bundle savedInstanceState)
|
||||
{
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
|
||||
mCurFragmentNum = savedInstanceState.getInt("currentFragmentNum");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
if (mCurFragmentNum == 0)
|
||||
{
|
||||
finish();
|
||||
}
|
||||
else
|
||||
{
|
||||
SwitchPage(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.gamelist;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
/**
|
||||
* The adapter backing the game list.
|
||||
* <p>
|
||||
* Responsible for handling each game list item individually.
|
||||
*/
|
||||
public final class GameListAdapter extends ArrayAdapter<GameListItem>
|
||||
{
|
||||
private static final float BYTES_PER_GIB = 1024 * 1024 * 1024;
|
||||
private static final float BYTES_PER_MIB = 1024 * 1024;
|
||||
|
||||
private final Context context;
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param resourceId The resource ID for a layout file containing a layout to use when instantiating views.
|
||||
*/
|
||||
public GameListAdapter(Context context, int resourceId)
|
||||
{
|
||||
super(context, resourceId);
|
||||
|
||||
this.context = context;
|
||||
this.id = resourceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View gameView, ViewGroup parent)
|
||||
{
|
||||
ViewHolder holder;
|
||||
|
||||
// If getView() was called without passing in a recycled view,
|
||||
if (gameView == null)
|
||||
{
|
||||
// Inflate a new view using the appropriate XML layout.
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
gameView = inflater.inflate(id, parent, false);
|
||||
|
||||
// Instantiate a holder to contain references to the game's views.
|
||||
holder = new ViewHolder();
|
||||
holder.title = (TextView) gameView.findViewById(R.id.GameListItemTitle);
|
||||
holder.subtitle = (TextView) gameView.findViewById(R.id.GameListItemSubTitle);
|
||||
holder.icon = (ImageView) gameView.findViewById(R.id.GameListItemIcon);
|
||||
|
||||
// Attach this list of references to the view.
|
||||
gameView.setTag(holder);
|
||||
}
|
||||
// If we do have a recycled view, we can use the references it already contains.
|
||||
else
|
||||
{
|
||||
holder = (ViewHolder) gameView.getTag();
|
||||
}
|
||||
|
||||
// Get a reference to the game represented by this row.
|
||||
final GameListItem item = getItem(position);
|
||||
|
||||
// Whether this row's view is newly created or not, set the children to contain the game's data.
|
||||
if (item != null)
|
||||
{
|
||||
holder.title.setText(item.getName());
|
||||
|
||||
Bitmap icon = item.getImage();
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
holder.icon.setImageBitmap(icon);
|
||||
}
|
||||
else
|
||||
{
|
||||
holder.icon.setImageResource(R.drawable.no_banner);
|
||||
}
|
||||
|
||||
float fileSize = item.getFilesize() / BYTES_PER_GIB;
|
||||
|
||||
String subtitle;
|
||||
|
||||
if (fileSize >= 1.0f)
|
||||
{
|
||||
subtitle = String.format(context.getString(R.string.file_size_gib), fileSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
fileSize = item.getFilesize() / BYTES_PER_MIB;
|
||||
subtitle = String.format(context.getString(R.string.file_size_mib), fileSize);
|
||||
}
|
||||
|
||||
holder.subtitle.setText(subtitle);
|
||||
}
|
||||
|
||||
// Make every other game in the list grey
|
||||
if (position % 2 == 1)
|
||||
gameView.setBackgroundColor(0xFFE3E3E3);
|
||||
|
||||
return gameView;
|
||||
}
|
||||
|
||||
private final class ViewHolder
|
||||
{
|
||||
public TextView title;
|
||||
public TextView subtitle;
|
||||
public ImageView icon;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.gamelist;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListFragment;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.emulation.EmulationActivity;
|
||||
|
||||
|
||||
/**
|
||||
* The {@link ListFragment} responsible for displaying the game list.
|
||||
*/
|
||||
public final class GameListFragment extends ListFragment
|
||||
{
|
||||
private GameListAdapter mGameAdapter;
|
||||
private OnGameListZeroListener mCallback;
|
||||
|
||||
/**
|
||||
* Interface that defines how to handle the case
|
||||
* when there are zero games in the game list.
|
||||
*/
|
||||
public interface OnGameListZeroListener
|
||||
{
|
||||
/**
|
||||
* This is called when there are no games
|
||||
* currently present within the game list.
|
||||
*/
|
||||
void onZeroFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all entries from the {@link GameListAdapter}
|
||||
* backing this GameListFragment.
|
||||
*/
|
||||
public void clearGameList()
|
||||
{
|
||||
mGameAdapter.clear();
|
||||
mGameAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void fill()
|
||||
{
|
||||
List<GameListItem> fls = new ArrayList<GameListItem>();
|
||||
String Directories = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPaths", "0");
|
||||
int intDirectories = Integer.parseInt(Directories);
|
||||
|
||||
// Extensions to filter by.
|
||||
Set<String> exts = new HashSet<String>(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs"));
|
||||
|
||||
for (int a = 0; a < intDirectories; ++a)
|
||||
{
|
||||
String BrowseDir = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPath" + a, "");
|
||||
File currentDir = new File(BrowseDir);
|
||||
File[] dirs = currentDir.listFiles();
|
||||
try
|
||||
{
|
||||
for (File entry : dirs)
|
||||
{
|
||||
String entryName = entry.getName();
|
||||
|
||||
if (!entry.isHidden() && !entry.isDirectory())
|
||||
{
|
||||
if (exts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
|
||||
fls.add(new GameListItem(getActivity(), entryName, entry.length(), entry.getAbsolutePath()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
Collections.sort(fls);
|
||||
|
||||
// Add all the items to the adapter
|
||||
mGameAdapter.addAll(fls);
|
||||
mGameAdapter.notifyDataSetChanged();
|
||||
|
||||
if (fls.isEmpty())
|
||||
{
|
||||
mCallback.onZeroFiles();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
ListView rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
mGameAdapter = new GameListAdapter(getActivity(), R.layout.gamelist_list_item);
|
||||
rootView.setAdapter(mGameAdapter);
|
||||
|
||||
fill();
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListItemClick(ListView listView, View view, int position, long id)
|
||||
{
|
||||
GameListItem item = mGameAdapter.getItem(position);
|
||||
|
||||
// Show a toast indicating which game was clicked.
|
||||
Toast.makeText(getActivity(), String.format(getString(R.string.file_clicked), item.getPath()), Toast.LENGTH_SHORT).show();
|
||||
|
||||
// Start the emulation activity and send the path of the clicked ROM to it.
|
||||
Intent intent = new Intent(getActivity(), EmulationActivity.class);
|
||||
intent.putExtra("SelectedGame", item.getPath());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity)
|
||||
{
|
||||
super.onAttach(activity);
|
||||
|
||||
// This makes sure that the container activity has implemented
|
||||
// the callback interface. If not, it throws an exception
|
||||
try
|
||||
{
|
||||
mCallback = (OnGameListZeroListener) activity;
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
throw new ClassCastException(activity.toString()
|
||||
+ " must implement OnGameListZeroListener");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.gamelist;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
|
||||
/**
|
||||
* Represents an item in the game list.
|
||||
*/
|
||||
public final class GameListItem implements Comparable<GameListItem>
|
||||
{
|
||||
private String name;
|
||||
private long filesize;
|
||||
private final String path;
|
||||
private Bitmap image;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ctx The current {@link Context}
|
||||
* @param name The name of this GameListItem.
|
||||
* @param filesize The filesize for this GameListItem, in GiB
|
||||
* @param path The file path for the game represented by this GameListItem.
|
||||
*/
|
||||
public GameListItem(Context ctx, String name, long filesize, String path)
|
||||
{
|
||||
this.name = name;
|
||||
this.filesize = filesize;
|
||||
this.path = path;
|
||||
|
||||
File file = new File(path);
|
||||
if (!file.isDirectory() && !path.isEmpty())
|
||||
{
|
||||
int[] Banner = NativeLibrary.GetBanner(path);
|
||||
if (Banner[0] != 0)
|
||||
{
|
||||
image = Bitmap.createBitmap(Banner, 96, 32, Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
this.name = NativeLibrary.GetTitle(path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this GameListItem.
|
||||
*
|
||||
* @return the name of this GameListItem.
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filesize of this GameListItem, in GiB.
|
||||
*
|
||||
* @return the filesize of this GameListItem.
|
||||
*/
|
||||
public long getFilesize()
|
||||
{
|
||||
return filesize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file path of the game represented by this GameListItem.
|
||||
*
|
||||
* @return the file path of the game represented by this GameListItem.
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the image data for this game as a {@link Bitmap}.
|
||||
*
|
||||
* @return the image data for this game as a {@link Bitmap}.
|
||||
*/
|
||||
public Bitmap getImage()
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(GameListItem o)
|
||||
{
|
||||
if (name != null)
|
||||
return name.toLowerCase().compareTo(o.getName().toLowerCase());
|
||||
else
|
||||
throw new NullPointerException("The name of this GameListItem is null");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.settings;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.settings.cpu.CPUSettingsFragment;
|
||||
import org.dolphinemu.dolphinemu.settings.input.InputConfigFragment;
|
||||
import org.dolphinemu.dolphinemu.settings.video.VideoSettingsFragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v13.app.FragmentPagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
|
||||
/**
|
||||
* Main activity that manages all of the preference fragments used to display
|
||||
* the settings to the user.
|
||||
*/
|
||||
public final class PrefsActivity extends Activity implements OnSharedPreferenceChangeListener
|
||||
{
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.viewpager);
|
||||
|
||||
// Set the ViewPager adapter.
|
||||
final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
|
||||
viewPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
|
||||
|
||||
// Register the preference change listener.
|
||||
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
sPrefs.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
|
||||
{
|
||||
// If any change is made to the preferences in the front-end, immediately save them.
|
||||
UserPreferences.SavePrefsToIni(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link FragmentPagerAdapter} that returns a fragment
|
||||
* corresponding to one of the sections/tabs/pages.
|
||||
*/
|
||||
private final class ViewPagerAdapter extends FragmentPagerAdapter
|
||||
{
|
||||
private final String[] pageTitles = {
|
||||
getString(R.string.cpu_settings),
|
||||
getString(R.string.input_settings),
|
||||
getString(R.string.video_settings)
|
||||
};
|
||||
|
||||
public ViewPagerAdapter(FragmentManager fm)
|
||||
{
|
||||
super(fm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position)
|
||||
{
|
||||
switch(position)
|
||||
{
|
||||
case 0:
|
||||
return new CPUSettingsFragment();
|
||||
|
||||
case 1:
|
||||
return new InputConfigFragment();
|
||||
|
||||
case 2:
|
||||
return new VideoSettingsFragment();
|
||||
|
||||
default: // Should never happen.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
// Show total pages.
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position)
|
||||
{
|
||||
return pageTitles[position];
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,284 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.settings;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
/**
|
||||
* A class that retrieves all of the set user preferences in Android, in a safe way.
|
||||
* <p>
|
||||
* If any preferences are added to this emulator, an accessor for that preference
|
||||
* should be added here. This way lengthy calls to getters from SharedPreferences
|
||||
* aren't made necessary.
|
||||
*/
|
||||
public final class UserPreferences
|
||||
{
|
||||
private UserPreferences()
|
||||
{
|
||||
// Disallows instantiation.
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the settings stored in the Dolphin ini config files to the shared preferences of this front-end.
|
||||
*
|
||||
* @param ctx The context used to retrieve the SharedPreferences instance.
|
||||
*/
|
||||
public static void LoadIniToPrefs(Context ctx)
|
||||
{
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
|
||||
// Get an editor.
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
// Add the settings.
|
||||
if (Build.CPU_ABI.contains("arm64"))
|
||||
editor.putString("cpuCorePref", getConfig("Dolphin.ini", "Core", "CPUCore", "4"));
|
||||
else
|
||||
editor.putString("cpuCorePref", getConfig("Dolphin.ini", "Core", "CPUCore", "3"));
|
||||
|
||||
editor.putBoolean("dualCorePref", getConfig("Dolphin.ini", "Core", "CPUThread", "False").equals("True"));
|
||||
editor.putBoolean("fastmemPref", getConfig("Dolphin.ini", "Core", "Fastmem", "False").equals("True"));
|
||||
|
||||
editor.putString("gpuPref", getConfig("Dolphin.ini", "Core", "GFXBackend", "OGL"));
|
||||
editor.putBoolean("showFPS", getConfig("gfx_opengl.ini", "Settings", "ShowFPS", "False").equals("True"));
|
||||
editor.putBoolean("drawOnscreenControls", getConfig("Dolphin.ini", "Android", "ScreenControls", "True").equals("True"));
|
||||
|
||||
editor.putString("internalResolution", getConfig("gfx_opengl.ini", "Settings", "EFBScale", "2") );
|
||||
editor.putString("FSAA", getConfig("gfx_opengl.ini", "Settings", "MSAA", "0"));
|
||||
editor.putString("anisotropicFiltering", getConfig("gfx_opengl.ini", "Enhancements", "MaxAnisotropy", "0"));
|
||||
editor.putString("postProcessingShader", getConfig("gfx_opengl.ini", "Enhancements", "PostProcessingShader", ""));
|
||||
editor.putBoolean("scaledEFBCopy", getConfig("gfx_opengl.ini", "Hacks", "EFBScaledCopy", "True").equals("True"));
|
||||
editor.putBoolean("perPixelLighting", getConfig("gfx_opengl.ini", "Settings", "EnablePixelLighting", "False").equals("True"));
|
||||
editor.putBoolean("forceTextureFiltering", getConfig("gfx_opengl.ini", "Enhancements", "ForceFiltering", "False").equals("True"));
|
||||
editor.putBoolean("disableFog", getConfig("gfx_opengl.ini", "Settings", "DisableFog", "False").equals("True"));
|
||||
editor.putBoolean("skipEFBAccess", getConfig("gfx_opengl.ini", "Hacks", "EFBAccessEnable", "False").equals("True"));
|
||||
editor.putBoolean("ignoreFormatChanges", getConfig("gfx_opengl.ini", "Hacks", "EFBEmulateFormatChanges", "False").equals("True"));
|
||||
editor.putString("stereoscopyMode", getConfig("gfx_opengl.ini", "Enhancements", "StereoMode", "0"));
|
||||
editor.putBoolean("stereoSwapEyes", getConfig("gfx_opengl.ini", "Enhancements", "StereoSwapEyes", "False").equals("True"));
|
||||
editor.putString("stereoDepth", getConfig("gfx_opengl.ini", "Enhancements", "StereoDepth", "20"));
|
||||
editor.putString("stereoConvergence", getConfig("gfx_opengl.ini", "Enhancements", "StereoConvergence", "20"));
|
||||
|
||||
String efbCopyOn = getConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "True");
|
||||
String efbToTexture = getConfig("gfx_opengl.ini", "Hacks", "EFBToTextureEnable", "True");
|
||||
String efbCopyCache = getConfig("gfx_opengl.ini", "Hacks", "EFBCopyCacheEnable", "False");
|
||||
|
||||
if (efbCopyOn.equals("False"))
|
||||
{
|
||||
editor.putString("efbCopyMethod", "Off");
|
||||
}
|
||||
else if (efbCopyOn.equals("True") && efbToTexture.equals("True"))
|
||||
{
|
||||
editor.putString("efbCopyMethod", "Texture");
|
||||
}
|
||||
else if(efbCopyOn.equals("True") && efbToTexture.equals("False") && efbCopyCache.equals("False"))
|
||||
{
|
||||
editor.putString("efbCopyMethod", "RAM (uncached)");
|
||||
}
|
||||
else if(efbCopyOn.equals("True") && efbToTexture.equals("False") && efbCopyCache.equals("True"))
|
||||
{
|
||||
editor.putString("efbCopyMethod", "RAM (cached)");
|
||||
}
|
||||
|
||||
editor.putString("textureCacheAccuracy", getConfig("gfx_opengl.ini", "Settings", "SafeTextureCacheColorSamples", "128"));
|
||||
|
||||
String usingXFB = getConfig("gfx_opengl.ini", "Settings", "UseXFB", "False");
|
||||
String usingRealXFB = getConfig("gfx_opengl.ini", "Settings", "UseRealXFB", "False");
|
||||
|
||||
if (usingXFB.equals("False"))
|
||||
{
|
||||
editor.putString("externalFrameBuffer", "Disabled");
|
||||
}
|
||||
else if (usingXFB.equals("True") && usingRealXFB.equals("False"))
|
||||
{
|
||||
editor.putString("externalFrameBuffer", "Virtual");
|
||||
}
|
||||
else if (usingXFB.equals("True") && usingRealXFB.equals("True"))
|
||||
{
|
||||
editor.putString("externalFrameBuffer", "Real");
|
||||
}
|
||||
|
||||
editor.putBoolean("disableDestinationAlpha", getConfig("gfx_opengl.ini", "Settings", "DstAlphaPass", "False").equals("True"));
|
||||
editor.putBoolean("fastDepthCalculation", getConfig("gfx_opengl.ini", "Settings", "FastDepthCalc", "True").equals("True"));
|
||||
editor.putString("aspectRatio", getConfig("gfx_opengl.ini", "Settings", "AspectRatio", "0"));
|
||||
|
||||
// Apply the changes.
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
// Small utility method that shortens calls to NativeLibrary.GetConfig.
|
||||
private static String getConfig(String ini, String section, String key, String defaultValue)
|
||||
{
|
||||
return NativeLibrary.GetConfig(ini, section, key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the preferences set in the front-end to the Dolphin ini files.
|
||||
*
|
||||
* @param ctx The context used to retrieve the user settings.
|
||||
* */
|
||||
public static void SavePrefsToIni(Context ctx)
|
||||
{
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
|
||||
// Whether or not the user is using dual core.
|
||||
boolean isUsingDualCore = prefs.getBoolean("dualCorePref", true);
|
||||
|
||||
// Current CPU core being used. Falls back to interpreter upon error.
|
||||
String currentEmuCore = prefs.getString("cpuCorePref", "0");
|
||||
|
||||
// Fastmem JIT core usage
|
||||
boolean isUsingFastmem = prefs.getBoolean("fastmemPref", false);
|
||||
|
||||
// Current video backend being used. Falls back to software rendering upon error.
|
||||
String currentVideoBackend = prefs.getString("gpuPref", "Software Rendering");
|
||||
|
||||
// Whether or not FPS will be displayed on-screen.
|
||||
boolean showingFPS = prefs.getBoolean("showFPS", false);
|
||||
|
||||
// Whether or not to draw on-screen controls.
|
||||
boolean drawingOnscreenControls = prefs.getBoolean("drawOnscreenControls", true);
|
||||
|
||||
// Whether or not to ignore all EFB access requests from the CPU.
|
||||
boolean skipEFBAccess = prefs.getBoolean("skipEFBAccess", false);
|
||||
|
||||
// Whether or not to ignore changes to the EFB format.
|
||||
boolean ignoreFormatChanges = prefs.getBoolean("ignoreFormatChanges", false);
|
||||
|
||||
// EFB copy method to use.
|
||||
String efbCopyMethod = prefs.getString("efbCopyMethod", "Texture");
|
||||
|
||||
// Texture cache accuracy. Falls back to "Fast" up error.
|
||||
String textureCacheAccuracy = prefs.getString("textureCacheAccuracy", "128");
|
||||
|
||||
// External frame buffer emulation. Falls back to disabled upon error.
|
||||
String externalFrameBuffer = prefs.getString("externalFrameBuffer", "Disabled");
|
||||
|
||||
// Whether or not to disable destination alpha.
|
||||
boolean disableDstAlphaPass = prefs.getBoolean("disableDestinationAlpha", false);
|
||||
|
||||
// Whether or not to use fast depth calculation.
|
||||
boolean useFastDepthCalc = prefs.getBoolean("fastDepthCalculation", true);
|
||||
|
||||
// Aspect ratio selection
|
||||
String aspectRatio = prefs.getString("aspectRatio", "0");
|
||||
|
||||
// Internal resolution. Falls back to 1x Native upon error.
|
||||
String internalResolution = prefs.getString("internalResolution", "2");
|
||||
|
||||
// FSAA Level. Falls back to 1x upon error.
|
||||
String FSAALevel = prefs.getString("FSAA", "0");
|
||||
|
||||
// Anisotropic Filtering Level. Falls back to 1x upon error.
|
||||
String anisotropicFiltLevel = prefs.getString("anisotropicFiltering", "0");
|
||||
|
||||
// Post processing shader setting
|
||||
String postProcessing = prefs.getString("postProcessingShader", "");
|
||||
|
||||
// Whether or not Scaled EFB copies are used.
|
||||
boolean usingScaledEFBCopy = prefs.getBoolean("scaledEFBCopy", true);
|
||||
|
||||
// Whether or not per-pixel lighting is used.
|
||||
boolean usingPerPixelLighting = prefs.getBoolean("perPixelLighting", false);
|
||||
|
||||
// Whether or not texture filtering is being forced.
|
||||
boolean isForcingTextureFiltering = prefs.getBoolean("forceTextureFiltering", false);
|
||||
|
||||
// Whether or not fog is disabled.
|
||||
boolean fogIsDisabled = prefs.getBoolean("disableFog", false);
|
||||
|
||||
// Stereoscopy setting
|
||||
String stereoscopyMode = prefs.getString("stereoscopyMode", "0");
|
||||
|
||||
// Stereoscopy swap eyes
|
||||
boolean stereoscopyEyeSwap = prefs.getBoolean("stereoSwapEyes", false);
|
||||
|
||||
// Stereoscopy separation
|
||||
String stereoscopySeparation = prefs.getString("stereoDepth", "20");
|
||||
|
||||
// Stereoscopy convergence
|
||||
String stereoscopyConvergence = prefs.getString("stereoConvergence", "20");
|
||||
|
||||
// CPU related Settings
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUCore", currentEmuCore);
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUThread", isUsingDualCore ? "True" : "False");
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Core", "Fastmem", isUsingFastmem ? "True" : "False");
|
||||
|
||||
// General Video Settings
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Core", "GFXBackend", currentVideoBackend);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "ShowFPS", showingFPS ? "True" : "False");
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Android", "ScreenControls", drawingOnscreenControls ? "True" : "False");
|
||||
|
||||
// Video Hack Settings
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBAccessEnable", skipEFBAccess ? "False" : "True");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBEmulateFormatChanges", ignoreFormatChanges ? "True" : "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "AspectRatio", aspectRatio);
|
||||
|
||||
// Set EFB Copy Method
|
||||
if (efbCopyMethod.equals("Off"))
|
||||
{
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "False");
|
||||
}
|
||||
else if (efbCopyMethod.equals("Texture"))
|
||||
{
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "True");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBToTextureEnable", "True");
|
||||
}
|
||||
else if (efbCopyMethod.equals("RAM (uncached)"))
|
||||
{
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "True");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBToTextureEnable", "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyCacheEnable", "False");
|
||||
}
|
||||
else if (efbCopyMethod.equals("RAM (cached)"))
|
||||
{
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "True");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBToTextureEnable", "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyCacheEnable", "True");
|
||||
}
|
||||
|
||||
// Set texture cache accuracy
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "SafeTextureCacheColorSamples", textureCacheAccuracy);
|
||||
|
||||
// Set external frame buffer.
|
||||
if (externalFrameBuffer.equals("Disabled"))
|
||||
{
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseXFB", "False");
|
||||
}
|
||||
else if (externalFrameBuffer.equals("Virtual"))
|
||||
{
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseXFB", "True");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseRealXFB", "False");
|
||||
}
|
||||
else if (externalFrameBuffer.equals("Real"))
|
||||
{
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseXFB", "True");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseRealXFB", "True");
|
||||
}
|
||||
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "DstAlphaPass", disableDstAlphaPass ? "True" : "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "FastDepthCalc", useFastDepthCalc ? "True" : "False");
|
||||
|
||||
//-- Enhancement Settings --//
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "EFBScale", internalResolution);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "MSAA", FSAALevel);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "MaxAnisotropy", anisotropicFiltLevel);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "PostProcessingShader", postProcessing);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBScaledCopy", usingScaledEFBCopy ? "True" : "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "EnablePixelLighting", usingPerPixelLighting ? "True" : "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "ForceFiltering", isForcingTextureFiltering ? "True" : "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "DisableFog", fogIsDisabled ? "True" : "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "StereoMode", stereoscopyMode);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "StereoSwapEyes", stereoscopyEyeSwap ? "True" : "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "StereoDepth", stereoscopySeparation);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "StereoConvergence", stereoscopyConvergence);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.settings.cpu;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.PreferenceFragment;
|
||||
|
||||
/**
|
||||
* Responsible for the loading of the CPU preferences.
|
||||
*/
|
||||
public final class CPUSettingsFragment extends PreferenceFragment
|
||||
{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Load the preferences from an XML resource
|
||||
addPreferencesFromResource(R.xml.cpu_prefs);
|
||||
|
||||
final ListPreference cpuCores = (ListPreference) findPreference("cpuCorePref");
|
||||
|
||||
//
|
||||
// Set valid emulation cores depending on the CPU architecture
|
||||
// that the Android device is running on.
|
||||
//
|
||||
if (Build.CPU_ABI.contains("x86-64"))
|
||||
{
|
||||
cpuCores.setEntries(R.array.emuCoreEntriesX86_64);
|
||||
cpuCores.setEntryValues(R.array.emuCoreValuesX86_64);
|
||||
}
|
||||
else if (Build.CPU_ABI.contains("arm64"))
|
||||
{
|
||||
cpuCores.setEntries(R.array.emuCoreEntriesARM64);
|
||||
cpuCores.setEntryValues(R.array.emuCoreValuesARM64);
|
||||
}
|
||||
else if (Build.CPU_ABI.contains("arm"))
|
||||
{
|
||||
cpuCores.setEntries(R.array.emuCoreEntriesARM);
|
||||
cpuCores.setEntryValues(R.array.emuCoreValuesARM);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpuCores.setEntries(R.array.emuCoreEntriesOther);
|
||||
cpuCores.setEntryValues(R.array.emuCoreValuesOther);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.settings.custom;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.ListPreference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* A {@link ListPreference} that updates its summary upon it's selection being changed.
|
||||
*/
|
||||
public final class UpdatingListPreference extends ListPreference
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context the current {@link Context}.
|
||||
*/
|
||||
public UpdatingListPreference(Context context, AttributeSet attribs)
|
||||
{
|
||||
super(context, attribs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogClosed(boolean positiveResult)
|
||||
{
|
||||
super.onDialogClosed(positiveResult);
|
||||
|
||||
// If an entry was selected
|
||||
if (positiveResult)
|
||||
{
|
||||
setSummary(getEntry());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package org.dolphinemu.dolphinemu.settings.input;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.preference.Preference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* {@link Preference} subclass that represents a preference
|
||||
* used for assigning a key bind.
|
||||
*/
|
||||
public final class InputBindingPreference extends Preference
|
||||
{
|
||||
/**
|
||||
* Constructor that is called when inflating an InputBindingPreference from XML.
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param attrs The attributes of the XML tag that is inflating the preference.
|
||||
*/
|
||||
public InputBindingPreference(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick()
|
||||
{
|
||||
// Begin the creation of the input alert.
|
||||
final MotionAlertDialog dialog = new MotionAlertDialog(getContext(), this);
|
||||
|
||||
// Set the cancel button.
|
||||
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, getContext().getString(R.string.cancel), new AlertDialog.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
// Do nothing. Just makes the cancel button show up.
|
||||
}
|
||||
});
|
||||
|
||||
// Set the title and description message.
|
||||
dialog.setTitle(R.string.input_binding);
|
||||
dialog.setMessage(String.format(getContext().getString(R.string.input_binding_descrip), getTitle()));
|
||||
|
||||
// Don't allow the dialog to close when a user taps
|
||||
// outside of it. They must press cancel or provide an input.
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
|
||||
// Everything is set, show the dialog.
|
||||
dialog.show();
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.settings.input;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.view.InputDevice;
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link Fragment} responsible for implementing the functionality
|
||||
* within the input control mapping config.
|
||||
*/
|
||||
public final class InputConfigFragment extends PreferenceFragment
|
||||
{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Expand the preferences from the XML.
|
||||
addPreferencesFromResource(R.xml.input_prefs);
|
||||
|
||||
// Set the summary messages of the preferences to whatever binding
|
||||
// is currently set within the Dolphin config.
|
||||
final String[] gamecubeKeys =
|
||||
{
|
||||
"InputA", "InputB", "InputX", "InputY", "InputZ", "InputStart",
|
||||
"DPadUp", "DPadDown", "DPadLeft", "DPadRight",
|
||||
"MainUp", "MainDown", "MainLeft", "MainRight",
|
||||
"CStickUp", "CStickDown", "CStickLeft", "CStickRight",
|
||||
"InputL", "InputR"
|
||||
};
|
||||
|
||||
final String[] wiimoteKeys =
|
||||
{
|
||||
"WiimoteInputA", "WiimoteInputB", "WiimoteInputOne", "WiimoteInputTwo", "WiimoteInputPlus", "WiimoteInputMinus", "WiimoteInputHome",
|
||||
"WiimoteIRUp", "WiimoteIRDown", "WiimoteIRLeft", "WiimoteIRRight", "WiimoteIRForward", "WiimoteIRBackward",
|
||||
"WiimoteSwingUp", "WiimoteSwingDown", "WiimoteSwingLeft", "WiimoteSwingRight",
|
||||
"WiimoteTiltForward", "WiimoteTiltBackward", "WiimoteTiltLeft", "WiimoteTiltRight",
|
||||
"WiimoteShakeX", "WiimoteShakeY", "WiimoteShakeZ",
|
||||
"WiimoteDPadUp", "WiimoteDPadDown", "WiimoteDPadLeft", "WiimoteDPadRight"
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// Loop through the keys for all 4 GameCube controllers.
|
||||
for (String key : gamecubeKeys)
|
||||
{
|
||||
final String binding = NativeLibrary.GetConfig("Dolphin.ini", "Android", key+"_"+i, "None");
|
||||
final Preference pref = findPreference(key+"_"+i);
|
||||
pref.setSummary(binding);
|
||||
}
|
||||
|
||||
// Loop through the keys for the Wiimote
|
||||
/*for (String key : wiimoteKeys)
|
||||
{
|
||||
final String binding = NativeLibrary.GetConfig("Dolphin.ini", "Android", key+"_"+i, "None");
|
||||
final Preference pref = findPreference(key+"_"+i);
|
||||
pref.setSummary(binding);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the descriptor for the given {@link InputDevice}.
|
||||
*
|
||||
* @param input The {@link InputDevice} to get the descriptor of.
|
||||
*
|
||||
* @return the descriptor for the given {@link InputDevice}.
|
||||
*/
|
||||
public static String getInputDesc(InputDevice input)
|
||||
{
|
||||
if (input == null)
|
||||
return "null"; // Happens when the InputDevice is from an unknown source
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
||||
{
|
||||
return input.getDescriptor();
|
||||
}
|
||||
else
|
||||
{
|
||||
List<InputDevice.MotionRange> motions = input.getMotionRanges();
|
||||
StringBuilder fakeid = new StringBuilder();
|
||||
|
||||
for (InputDevice.MotionRange range : motions)
|
||||
fakeid.append(range.getAxis());
|
||||
|
||||
return fakeid.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
package org.dolphinemu.dolphinemu.settings.input;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.preference.Preference;
|
||||
import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* {@link AlertDialog} derivative that listens for
|
||||
* motion events from controllers and joysticks.
|
||||
*/
|
||||
final class MotionAlertDialog extends AlertDialog
|
||||
{
|
||||
// The selected input preference
|
||||
private final Preference inputPref;
|
||||
|
||||
private boolean firstEvent = true;
|
||||
private final ArrayList<Float> m_values = new ArrayList<Float>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ctx The current {@link Context}.
|
||||
* @param inputPref The Preference to show this dialog for.
|
||||
*/
|
||||
public MotionAlertDialog(Context ctx, Preference inputPref)
|
||||
{
|
||||
super(ctx);
|
||||
|
||||
this.inputPref = inputPref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
Log.d("InputConfigFragment", "Received key event: " + event.getAction());
|
||||
switch (event.getAction())
|
||||
{
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
case KeyEvent.ACTION_UP:
|
||||
InputDevice input = event.getDevice();
|
||||
String bindStr = "Device '" + InputConfigFragment.getInputDesc(input) + "'-Button " + event.getKeyCode();
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Android", inputPref.getKey(), bindStr);
|
||||
inputPref.setSummary(bindStr);
|
||||
dismiss();
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Method that will be called within dispatchGenericMotionEvent
|
||||
// that handles joystick/controller movements.
|
||||
private boolean onMotionEvent(MotionEvent event)
|
||||
{
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
|
||||
return false;
|
||||
|
||||
Log.d("InputConfigFragment", "Received motion event: " + event.getAction());
|
||||
|
||||
InputDevice input = event.getDevice();
|
||||
List<InputDevice.MotionRange> motions = input.getMotionRanges();
|
||||
if (firstEvent)
|
||||
{
|
||||
m_values.clear();
|
||||
|
||||
for (InputDevice.MotionRange range : motions)
|
||||
{
|
||||
m_values.add(event.getAxisValue(range.getAxis()));
|
||||
}
|
||||
|
||||
firstEvent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int a = 0; a < motions.size(); ++a)
|
||||
{
|
||||
InputDevice.MotionRange range = motions.get(a);
|
||||
|
||||
if (m_values.get(a) > (event.getAxisValue(range.getAxis()) + 0.5f))
|
||||
{
|
||||
String bindStr = "Device '" + InputConfigFragment.getInputDesc(input) + "'-Axis " + range.getAxis() + "-";
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Android", inputPref.getKey(), bindStr);
|
||||
inputPref.setSummary(bindStr);
|
||||
dismiss();
|
||||
}
|
||||
else if (m_values.get(a) < (event.getAxisValue(range.getAxis()) - 0.5f))
|
||||
{
|
||||
String bindStr = "Device '" + InputConfigFragment.getInputDesc(input) + "'-Axis " + range.getAxis() + "+";
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Android", inputPref.getKey(), bindStr);
|
||||
inputPref.setSummary(bindStr);
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event)
|
||||
{
|
||||
if (onKeyDown(event.getKeyCode(), event))
|
||||
return true;
|
||||
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchGenericMotionEvent(MotionEvent event)
|
||||
{
|
||||
if (onMotionEvent(event))
|
||||
return true;
|
||||
|
||||
return super.dispatchGenericMotionEvent(event);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.settings.input.overlayconfig;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
/**
|
||||
* {@link Activity} used for configuring the input overlay.
|
||||
*/
|
||||
public final class OverlayConfigActivity extends Activity
|
||||
{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Initialize all of the buttons to add.
|
||||
final OverlayConfigButton buttonA = new OverlayConfigButton(this, "gcpad_a", R.drawable.gcpad_a);
|
||||
final OverlayConfigButton buttonB = new OverlayConfigButton(this, "gcpad_b", R.drawable.gcpad_b);
|
||||
final OverlayConfigButton buttonX = new OverlayConfigButton(this, "gcpad_x", R.drawable.gcpad_x);
|
||||
final OverlayConfigButton buttonY = new OverlayConfigButton(this, "gcpad_y", R.drawable.gcpad_y);
|
||||
final OverlayConfigButton buttonZ = new OverlayConfigButton(this, "gcpad_z", R.drawable.gcpad_z);
|
||||
final OverlayConfigButton buttonS = new OverlayConfigButton(this, "gcpad_start", R.drawable.gcpad_start);
|
||||
final OverlayConfigButton buttonL = new OverlayConfigButton(this, "gcpad_l", R.drawable.gcpad_l);
|
||||
final OverlayConfigButton buttonR = new OverlayConfigButton(this, "gcpad_r", R.drawable.gcpad_r);
|
||||
final OverlayConfigButton joystick = new OverlayConfigButton(this, "gcpad_joystick_range", R.drawable.gcpad_joystick_range);
|
||||
|
||||
// Add the buttons to the layout
|
||||
final RelativeLayout configLayout = new RelativeLayout(this);
|
||||
configLayout.addView(buttonA);
|
||||
configLayout.addView(buttonB);
|
||||
configLayout.addView(buttonX);
|
||||
configLayout.addView(buttonY);
|
||||
configLayout.addView(buttonZ);
|
||||
configLayout.addView(buttonS);
|
||||
configLayout.addView(buttonL);
|
||||
configLayout.addView(buttonR);
|
||||
configLayout.addView(joystick);
|
||||
|
||||
// Now set the layout
|
||||
setContentView(configLayout);
|
||||
}
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.settings.input.overlayconfig;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnTouchListener;
|
||||
import android.widget.Button;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
/**
|
||||
* A movable {@link Button} for use within the
|
||||
* input overlay configuration screen.
|
||||
*/
|
||||
public final class OverlayConfigButton extends Button implements OnTouchListener
|
||||
{
|
||||
// SharedPreferences instance that the button positions are cached to.
|
||||
private final SharedPreferences sharedPrefs;
|
||||
|
||||
// The String ID for this button.
|
||||
//
|
||||
// This ID is used upon releasing this button as the key for saving
|
||||
// the X and Y coordinates of this button. This same key is also used
|
||||
// for setting the coordinates of the button on the actual overlay during emulation.
|
||||
//
|
||||
// They can be accessed through SharedPreferences respectively as follows:
|
||||
//
|
||||
// SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
// float buttonX = sPrefs.getFloat(buttonId+"-X", -1f);
|
||||
// float buttonY = sPrefs.getFloat(buttonId+"-Y", -1f);
|
||||
//
|
||||
private final String buttonId;
|
||||
|
||||
// The offset of the press while moving the button
|
||||
private float moveOffsetX, moveOffsetY;
|
||||
|
||||
private Drawable resizeDrawable(Drawable image, float scale)
|
||||
{
|
||||
// Retrieve screen dimensions.
|
||||
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
|
||||
|
||||
Bitmap b = ((BitmapDrawable)image).getBitmap();
|
||||
Bitmap bitmapResized = Bitmap.createScaledBitmap(b,
|
||||
(int)(displayMetrics.heightPixels * scale),
|
||||
(int)(displayMetrics.heightPixels * scale),
|
||||
true);
|
||||
|
||||
return new BitmapDrawable(getResources(), bitmapResized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context the current {@link Context}.
|
||||
* @param buttonId the String ID for this button.
|
||||
* @param drawableId the Drawable ID for the image to represent this OverlayConfigButton.
|
||||
*/
|
||||
public OverlayConfigButton(Context context, String buttonId, int drawableId)
|
||||
{
|
||||
super(context);
|
||||
|
||||
// Set the button ID.
|
||||
this.buttonId = buttonId;
|
||||
|
||||
// Set the button as its own OnTouchListener.
|
||||
setOnTouchListener(this);
|
||||
|
||||
// Get the SharedPreferences instance.
|
||||
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
// Decide scale based on button ID
|
||||
|
||||
// SeekBars are not able to set a minimum value, only a maximum value, which complicates
|
||||
// things a bit. What happens here is after the SeekBar's value is retrieved, 25 is
|
||||
// added so the value will never go below 25. It is then divided by 50 (25 + 25) so the
|
||||
// default value will be 100%.
|
||||
float scale;
|
||||
float overlaySize = sharedPrefs.getInt("controls_size", 25);
|
||||
overlaySize += 25;
|
||||
overlaySize /= 50;
|
||||
|
||||
switch (drawableId)
|
||||
{
|
||||
case R.drawable.gcpad_b:
|
||||
scale = 0.13f * overlaySize;
|
||||
break;
|
||||
case R.drawable.gcpad_x:
|
||||
case R.drawable.gcpad_y:
|
||||
scale = 0.18f * overlaySize;
|
||||
break;
|
||||
case R.drawable.gcpad_start:
|
||||
scale = 0.12f * overlaySize;
|
||||
break;
|
||||
case R.drawable.gcpad_joystick_range:
|
||||
scale = 0.30f * overlaySize;
|
||||
break;
|
||||
default:
|
||||
scale = 0.20f * overlaySize;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the button's icon that represents it.
|
||||
setBackground(resizeDrawable(getResources().getDrawable(drawableId), scale));
|
||||
|
||||
// Check if this button has previous values set that aren't the default.
|
||||
final float x = sharedPrefs.getFloat(buttonId+"-X", -1f);
|
||||
final float y = sharedPrefs.getFloat(buttonId+"-Y", -1f);
|
||||
|
||||
// If they are not -1, then they have a previous value set.
|
||||
// Thus, we set those coordinate values.
|
||||
if (x != -1f && y != -1f)
|
||||
{
|
||||
setX(x);
|
||||
setY(y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event)
|
||||
{
|
||||
switch(event.getAction())
|
||||
{
|
||||
// Get the offset of the press within the button
|
||||
// The event X and Y locations are the offset within the button, not the screen
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
{
|
||||
moveOffsetX = event.getX();
|
||||
moveOffsetY = event.getY();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only change the X/Y coordinates when we move the button.
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
{
|
||||
setX(getX() + event.getX() - moveOffsetX);
|
||||
setY(getY() + event.getY() - moveOffsetY);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Whenever the press event has ended
|
||||
// is when we save all of the information.
|
||||
case MotionEvent.ACTION_UP:
|
||||
{
|
||||
// Add the current X and Y positions of this button into SharedPreferences.
|
||||
SharedPreferences.Editor editor = sharedPrefs.edit();
|
||||
editor.putFloat(buttonId+"-X", getX());
|
||||
editor.putFloat(buttonId+"-Y", getY());
|
||||
editor.apply();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.settings.video;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.preference.PreferenceScreen;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.utils.EGLHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
/**
|
||||
* Responsible for handling the loading of the video preferences.
|
||||
*/
|
||||
public final class VideoSettingsFragment extends PreferenceFragment
|
||||
{
|
||||
private final EGLHelper eglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT);
|
||||
private final String vendor = eglHelper.getGL().glGetString(GL10.GL_VENDOR);
|
||||
private final String version = eglHelper.getGL().glGetString(GL10.GL_VERSION);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Load the preferences from an XML resource
|
||||
addPreferencesFromResource(R.xml.video_prefs);
|
||||
|
||||
//
|
||||
// Setting valid video backends.
|
||||
//
|
||||
final ListPreference videoBackends = (ListPreference) findPreference("gpuPref");
|
||||
final boolean deviceSupportsGL = eglHelper.supportsOpenGL();
|
||||
final boolean deviceSupportsGLES3 = eglHelper.supportsGLES3();
|
||||
|
||||
if (deviceSupportsGL)
|
||||
{
|
||||
videoBackends.setEntries(R.array.videoBackendEntriesGL);
|
||||
videoBackends.setEntryValues(R.array.videoBackendValuesGL);
|
||||
}
|
||||
else if (deviceSupportsGLES3)
|
||||
{
|
||||
videoBackends.setEntries(R.array.videoBackendEntriesGLES3);
|
||||
videoBackends.setEntryValues(R.array.videoBackendValuesGLES3);
|
||||
}
|
||||
else
|
||||
{
|
||||
videoBackends.setEntries(R.array.videoBackendEntriesNoGLES3);
|
||||
videoBackends.setEntryValues(R.array.videoBackendValuesNoGLES3);
|
||||
}
|
||||
|
||||
//
|
||||
// Set available post processing shaders
|
||||
//
|
||||
|
||||
List<CharSequence> shader_names = new ArrayList<CharSequence>();
|
||||
List<CharSequence> shader_values = new ArrayList<CharSequence>();
|
||||
|
||||
// Disabled option
|
||||
shader_names.add("Disabled");
|
||||
shader_values.add("");
|
||||
|
||||
File shaders_folder = new File(Environment.getExternalStorageDirectory()+ File.separator+"dolphin-emu"+ File.separator+"Shaders");
|
||||
if (shaders_folder.exists())
|
||||
{
|
||||
File[] shaders = shaders_folder.listFiles();
|
||||
for (File file : shaders)
|
||||
{
|
||||
if (file.isFile())
|
||||
{
|
||||
String filename = file.getName();
|
||||
if (filename.contains(".glsl"))
|
||||
{
|
||||
// Strip the extension and put it in to the list
|
||||
shader_names.add(filename.substring(0, filename.lastIndexOf('.')));
|
||||
shader_values.add(filename.substring(0, filename.lastIndexOf('.')));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final ListPreference shader_preference = (ListPreference) findPreference("postProcessingShader");
|
||||
shader_preference.setEntries(shader_names.toArray(new CharSequence[shader_names.size()]));
|
||||
shader_preference.setEntryValues(shader_values.toArray(new CharSequence[shader_values.size()]));
|
||||
|
||||
//
|
||||
// Disable all options if Software Rendering is used.
|
||||
//
|
||||
// Note that the numeric value in 'getPreference()'
|
||||
// denotes the placement on the UI. So if more elements are
|
||||
// added to the video settings, these may need to change.
|
||||
//
|
||||
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
final PreferenceScreen mainScreen = getPreferenceScreen();
|
||||
|
||||
if (videoBackends.getValue().equals("Software Renderer"))
|
||||
{
|
||||
mainScreen.getPreference(0).setEnabled(false);
|
||||
mainScreen.getPreference(1).setEnabled(false);
|
||||
mainScreen.getPreference(3).setEnabled(false);
|
||||
}
|
||||
else if (videoBackends.getValue().equals("OGL"))
|
||||
{
|
||||
mainScreen.getPreference(0).setEnabled(true);
|
||||
mainScreen.getPreference(1).setEnabled(true);
|
||||
mainScreen.getPreference(3).setEnabled(true);
|
||||
|
||||
// Check if we support stereo
|
||||
// If we support desktop GL then we must support at least OpenGL 3.2
|
||||
// If we only support OpenGLES then we need both OpenGLES 3.1 and AEP
|
||||
if ((eglHelper.supportsOpenGL() && eglHelper.GetVersion() >= 320) ||
|
||||
(eglHelper.supportsGLES3() && eglHelper.GetVersion() >= 310 && eglHelper.SupportsExtension("GL_ANDROID_extension_pack_es31a")))
|
||||
mainScreen.findPreference("StereoscopyScreen").setEnabled(true);
|
||||
else
|
||||
mainScreen.findPreference("StereoscopyScreen").setEnabled(false);
|
||||
}
|
||||
|
||||
// Also set a listener, so that if someone changes the video backend, it will disable
|
||||
// the video settings, upon the user choosing "Software Rendering".
|
||||
sPrefs.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences preference, String key)
|
||||
{
|
||||
if (key.equals("gpuPref"))
|
||||
{
|
||||
if (preference.getString(key, "Software Renderer").equals("Software Renderer"))
|
||||
{
|
||||
mainScreen.getPreference(0).setEnabled(false);
|
||||
mainScreen.getPreference(1).setEnabled(false);
|
||||
mainScreen.getPreference(3).setEnabled(false);
|
||||
}
|
||||
else if (preference.getString(key, "Software Renderer").equals("OGL"))
|
||||
{
|
||||
mainScreen.getPreference(0).setEnabled(true);
|
||||
mainScreen.getPreference(1).setEnabled(true);
|
||||
mainScreen.getPreference(3).setEnabled(true);
|
||||
|
||||
// Create an alert telling them that their phone sucks
|
||||
if (eglHelper.supportsGLES3()
|
||||
&& vendor.equals("Qualcomm")
|
||||
&& getQualcommVersion() == 14.0f)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setTitle(R.string.device_compat_warning);
|
||||
builder.setMessage(R.string.device_gles3compat_warning_msg);
|
||||
builder.setPositiveButton(R.string.yes, null);
|
||||
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
// Get an editor.
|
||||
SharedPreferences.Editor editor = sPrefs.edit();
|
||||
editor.putString("gpuPref", "Software Renderer");
|
||||
editor.apply();
|
||||
videoBackends.setValue("Software Renderer");
|
||||
videoBackends.setSummary("Software Renderer");
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private float getQualcommVersion()
|
||||
{
|
||||
final int start = version.indexOf("V@") + 2;
|
||||
final StringBuilder versionBuilder = new StringBuilder();
|
||||
|
||||
for (int i = start; i < version.length(); i++)
|
||||
{
|
||||
char c = version.charAt(i);
|
||||
|
||||
// End of numeric portion of version string.
|
||||
if (c == ' ')
|
||||
break;
|
||||
|
||||
versionBuilder.append(c);
|
||||
}
|
||||
|
||||
return Float.parseFloat(versionBuilder.toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.sidemenu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
/**
|
||||
* Adapter that backs the sidebar menu.
|
||||
* <p>
|
||||
* Responsible for handling the elements of each sidebar item.
|
||||
*/
|
||||
public final class SideMenuAdapter extends ArrayAdapter<SideMenuItem>
|
||||
{
|
||||
private final Context context;
|
||||
private final int id;
|
||||
private final List<SideMenuItem>items;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param resourceId The resource ID for a layout file containing a layout to use when instantiating views.
|
||||
* @param objects The objects to represent in the {@link ListView}.
|
||||
*/
|
||||
public SideMenuAdapter(Context context, int resourceId, List<SideMenuItem> objects)
|
||||
{
|
||||
super(context, resourceId, objects);
|
||||
|
||||
this.context = context;
|
||||
this.id = resourceId;
|
||||
this.items = objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SideMenuItem getItem(int i)
|
||||
{
|
||||
return items.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent)
|
||||
{
|
||||
if (convertView == null)
|
||||
{
|
||||
LayoutInflater vi = LayoutInflater.from(context);
|
||||
convertView = vi.inflate(id, null);
|
||||
}
|
||||
|
||||
final SideMenuItem item = items.get(position);
|
||||
if (item != null)
|
||||
{
|
||||
TextView title = (TextView) convertView.findViewById(R.id.SideMenuTitle);
|
||||
|
||||
if (title != null)
|
||||
title.setText(item.getName());
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.sidemenu;
|
||||
|
||||
|
||||
/**
|
||||
* Represents an item that goes in the sidemenu of the app.
|
||||
*/
|
||||
public final class SideMenuItem
|
||||
{
|
||||
private final String name;
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param name The name of the SideMenuItem.
|
||||
* @param id ID number of this specific SideMenuItem.
|
||||
*/
|
||||
public SideMenuItem(String name, int id)
|
||||
{
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this SideMenuItem.
|
||||
*
|
||||
* @return the name of this SideMenuItem.
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of this SideMenuItem.
|
||||
*
|
||||
* @return the ID of this SideMenuItem.
|
||||
*/
|
||||
public int getID()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,395 @@
|
||||
package org.dolphinemu.dolphinemu.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Utility class for retrieving information
|
||||
* from a device's CPU.
|
||||
*/
|
||||
public final class CPUHelper
|
||||
{
|
||||
private int revision;
|
||||
private int variant;
|
||||
private int numCores;
|
||||
private String implementerID = "N/A";
|
||||
private String part = "N/A";
|
||||
private String hardware = "N/A";
|
||||
private String processorInfo = "N/A";
|
||||
private String features = "N/A";
|
||||
|
||||
private final Context ctx;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ctx The current {@link Context}.
|
||||
*/
|
||||
public CPUHelper(Context ctx)
|
||||
{
|
||||
this.ctx = ctx;
|
||||
|
||||
try
|
||||
{
|
||||
// TODO: Should do other architectures as well (x86 and MIPS).
|
||||
// Can do differentiating between platforms by using
|
||||
// android.os.Build.CPU_ABI.
|
||||
//
|
||||
// CPU_ABI.contains("armeabi") == get ARM info.
|
||||
// CPU_ABI.contains("x86") == get x86 info.
|
||||
// CPU_ABI.contains("mips") == get MIPS info.
|
||||
//
|
||||
// However additional testing should be done across devices,
|
||||
// I highly doubt /proc/cpuinfo retains the same formatting
|
||||
// on different architectures.
|
||||
//
|
||||
// If push comes to shove, we can simply spit out the cpuinfo
|
||||
// contents. I would like to avoid this if possible, however.
|
||||
|
||||
if (Build.CPU_ABI.contains("arm"))
|
||||
{
|
||||
getARMInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.e("CPUHelper", "CPU architecture not supported yet.");
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
Log.e("CPUHelper", ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the revision number of the CPU.
|
||||
*
|
||||
* @return the revision number of the CPU.
|
||||
*/
|
||||
public int getRevision()
|
||||
{
|
||||
return revision;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the CPU variant number.
|
||||
*
|
||||
* @return the CPU variant number.
|
||||
*/
|
||||
public int getVariant()
|
||||
{
|
||||
return variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of cores in the CPU.
|
||||
*
|
||||
* @return the total number of cores in the CPU.
|
||||
*/
|
||||
public int getNumCores()
|
||||
{
|
||||
return numCores;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the implementer of the CPU.
|
||||
*
|
||||
* @return the name of the implementer of the CPU.
|
||||
*/
|
||||
public String getImplementer()
|
||||
{
|
||||
return implementerID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the specific processor type of the CPU.
|
||||
*
|
||||
* @return the specific processor type.
|
||||
*/
|
||||
public String getProcessorType()
|
||||
{
|
||||
return part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the internal name of the hardware.
|
||||
*
|
||||
* @return the internal name of the hardware.
|
||||
*/
|
||||
public String getHardware()
|
||||
{
|
||||
return hardware;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the processor info string.
|
||||
*
|
||||
* @return the processor info string.
|
||||
*/
|
||||
public String getProcessorInfo()
|
||||
{
|
||||
return processorInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the features supported by the CPU.
|
||||
*
|
||||
* @return the features supported by the CPU.
|
||||
*/
|
||||
public String getFeatures()
|
||||
{
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this CPU is using the ARM architecture.
|
||||
*
|
||||
* @return true if this CPU uses the ARM architecture; false otherwise.
|
||||
*/
|
||||
public static boolean isARM()
|
||||
{
|
||||
return Build.CPU_ABI.contains("arm");
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this CPU is using the ARM64 architecture.
|
||||
*
|
||||
* @return true if this CPU uses the ARM64 architecture; false otherwise.
|
||||
*/
|
||||
public static boolean isARM64() { return Build.CPU_ABI.contains("arm64"); }
|
||||
|
||||
/**
|
||||
* Whether or not this CPU is using the x86 architecture.
|
||||
*
|
||||
* @return true if this CPU uses the x86 architecture; false otherwise.
|
||||
*/
|
||||
public static boolean isX86()
|
||||
{
|
||||
return Build.CPU_ABI.contains("x86");
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this CPU is using the MIPS architecture.
|
||||
*
|
||||
* @return true if this CPU uses the MIPS architecture; false otherwise.
|
||||
*/
|
||||
public static boolean isMIPS()
|
||||
{
|
||||
return Build.CPU_ABI.contains("mips");
|
||||
}
|
||||
|
||||
// Retrieves information for ARM CPUs.
|
||||
private void getARMInfo() throws IOException
|
||||
{
|
||||
File info = new File("/proc/cpuinfo");
|
||||
if (info.exists())
|
||||
{
|
||||
BufferedReader br = new BufferedReader(new FileReader(info));
|
||||
|
||||
String line;
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
if (line.contains("Processor\t:"))
|
||||
{
|
||||
this.processorInfo = parseLine(line);
|
||||
}
|
||||
else if (line.contains("Hardware\t:"))
|
||||
{
|
||||
this.hardware = parseLine(line);
|
||||
}
|
||||
else if (line.contains("Features\t:"))
|
||||
{
|
||||
this.features = parseLine(line);
|
||||
}
|
||||
else if (line.contains("CPU implementer\t:"))
|
||||
{
|
||||
this.implementerID = parseArmID(Integer.decode(parseLine(line)));
|
||||
}
|
||||
else if (line.contains("CPU part\t:"))
|
||||
{
|
||||
this.part = parseArmPartNumber(Integer.decode(parseLine(line)));
|
||||
}
|
||||
else if (line.contains("CPU revision\t:"))
|
||||
{
|
||||
this.revision = Integer.decode(parseLine(line));
|
||||
}
|
||||
else if (line.contains("CPU variant\t:"))
|
||||
{
|
||||
this.variant = Integer.decode(parseLine(line));
|
||||
}
|
||||
else if (line.contains("processor\t:")) // Lower case indicates a specific core number
|
||||
{
|
||||
this.numCores++;
|
||||
}
|
||||
}
|
||||
|
||||
br.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Basic function for parsing cpuinfo format strings.
|
||||
// cpuinfo format strings consist of [label:info] parts.
|
||||
// We only want to retrieve the info portion so we split
|
||||
// them using ':' as a delimeter.
|
||||
private String parseLine(String line)
|
||||
{
|
||||
String[] temp = line.split(":");
|
||||
if (temp.length != 2)
|
||||
return "N/A";
|
||||
|
||||
return temp[1].trim();
|
||||
}
|
||||
|
||||
// Parses an ARM CPU ID.
|
||||
private String parseArmID(int id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x41:
|
||||
return "ARM Limited";
|
||||
|
||||
case 0x44:
|
||||
return "Digital Equipment Corporation";
|
||||
|
||||
case 0x4D:
|
||||
return "Freescale Semiconductor Inc.";
|
||||
|
||||
case 0x4E:
|
||||
return "Nvidia Corporation";
|
||||
|
||||
case 0x51:
|
||||
return "Qualcomm Inc.";
|
||||
|
||||
case 0x56:
|
||||
return "Marvell Semiconductor Inc.";
|
||||
|
||||
case 0x69:
|
||||
return "Intel Corporation";
|
||||
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
// Parses the ARM CPU Part number.
|
||||
private String parseArmPartNumber(int partNum)
|
||||
{
|
||||
switch (partNum)
|
||||
{
|
||||
// Qualcomm part numbers.
|
||||
case 0x00F:
|
||||
return "Qualcomm Scorpion";
|
||||
|
||||
case 0x02D:
|
||||
return "Qualcomm Dual Scorpion";
|
||||
|
||||
case 0x04D:
|
||||
return "Qualcomm Dual Krait";
|
||||
|
||||
case 0x06F:
|
||||
return "Qualcomm Quad Krait";
|
||||
|
||||
// Marvell Semiconductor part numbers
|
||||
case 0x131:
|
||||
return "Marvell Feroceon";
|
||||
|
||||
case 0x581:
|
||||
return "Marvell PJ4/PJ4b";
|
||||
|
||||
case 0x584:
|
||||
return "Marvell Dual PJ4/PJ4b";
|
||||
|
||||
// Official ARM part numbers.
|
||||
case 0x920:
|
||||
return "ARM920";
|
||||
|
||||
case 0x922:
|
||||
return "ARM922";
|
||||
|
||||
case 0x926:
|
||||
return "ARM926";
|
||||
|
||||
case 0x940:
|
||||
return "ARM940";
|
||||
|
||||
case 0x946:
|
||||
return "ARM946";
|
||||
|
||||
case 0x966:
|
||||
return "ARM966";
|
||||
|
||||
case 0x968:
|
||||
return "ARM968";
|
||||
|
||||
case 0xB02:
|
||||
return "ARM11 MPCore";
|
||||
|
||||
case 0xB36:
|
||||
return "ARM1136";
|
||||
|
||||
case 0xB56:
|
||||
return "ARM1156";
|
||||
|
||||
case 0xB76:
|
||||
return "ARM1176";
|
||||
|
||||
case 0xC05:
|
||||
return "ARM Cortex A5";
|
||||
|
||||
case 0xC07:
|
||||
return "ARM Cortex-A7 MPCore";
|
||||
|
||||
case 0xC08:
|
||||
return "ARM Cortex A8";
|
||||
|
||||
case 0xC09:
|
||||
return "ARM Cortex A9";
|
||||
|
||||
case 0xC0C:
|
||||
return "ARM Cortex A12";
|
||||
|
||||
case 0xC0F:
|
||||
return "ARM Cortex A15";
|
||||
|
||||
case 0xC14:
|
||||
return "ARM Cortex R4";
|
||||
|
||||
case 0xC15:
|
||||
return "ARM Cortex R5";
|
||||
|
||||
case 0xC20:
|
||||
return "ARM Cortex M0";
|
||||
|
||||
case 0xC21:
|
||||
return "ARM Cortex M1";
|
||||
|
||||
case 0xC23:
|
||||
return "ARM Cortex M3";
|
||||
|
||||
case 0xC24:
|
||||
return "ARM Cortex M4";
|
||||
|
||||
case 0xC60:
|
||||
return "ARM Cortex M0+";
|
||||
|
||||
case 0xD03:
|
||||
return "ARM Cortex A53";
|
||||
|
||||
case 0xD07:
|
||||
return "ARM Cortex A57 MPCore";
|
||||
|
||||
|
||||
default: // Unknown/Not yet added to list.
|
||||
return String.format(ctx.getString(R.string.unknown_part_num), partNum);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,393 @@
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.utils;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLContext;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
import javax.microedition.khronos.egl.EGLSurface;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
import android.opengl.GLES30;
|
||||
import android.util.Log;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
|
||||
/**
|
||||
* Utility class that abstracts all the stuff about
|
||||
* EGL initialization out of the way if all that is
|
||||
* wanted is to query the underlying GL API for information.
|
||||
*/
|
||||
public final class EGLHelper
|
||||
{
|
||||
private final EGL10 mEGL;
|
||||
private final EGLDisplay mDisplay;
|
||||
private EGLConfig[] mEGLConfigs;
|
||||
private EGLContext mEGLContext;
|
||||
private EGLSurface mEGLSurface;
|
||||
private GL10 mGL;
|
||||
|
||||
// GL support flags
|
||||
private boolean supportGL;
|
||||
private boolean supportGLES2;
|
||||
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
|
||||
* <p>
|
||||
* Initializes the underlying {@link EGLSurface} with a width and height of 1.
|
||||
* This is useful if all you need to use this class for is to query information
|
||||
* from specific API contexts.
|
||||
*
|
||||
* @param renderableType Bitmask indicating which types of client API contexts
|
||||
* the framebuffer config must support.
|
||||
*/
|
||||
public EGLHelper(int renderableType)
|
||||
{
|
||||
this(1, 1, renderableType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param width Width of the underlying {@link EGLSurface}.
|
||||
* @param height Height of the underlying {@link EGLSurface}.
|
||||
* @param renderableType Bitmask indicating which types of client API contexts
|
||||
* the framebuffer config must support.
|
||||
*/
|
||||
public EGLHelper(int width, int height, int renderableType)
|
||||
{
|
||||
// Initialize handle to an EGL display.
|
||||
mEGL = (EGL10) EGLContext.getEGL();
|
||||
mDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||
|
||||
// If a display is present, initialize EGL.
|
||||
if (mDisplay != EGL10.EGL_NO_DISPLAY)
|
||||
{
|
||||
int[] version = new int[2];
|
||||
if (mEGL.eglInitialize(mDisplay, version))
|
||||
{
|
||||
// Detect supported GL APIs, initialize configs, etc.
|
||||
detect();
|
||||
|
||||
// Create context and surface
|
||||
create(width, height, renderableType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.e("EGLHelper", "Error initializing EGL.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.e("EGLHelper", "Error initializing EGL display.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all resources associated with this helper.
|
||||
* <p>
|
||||
* This should be called whenever this helper is no longer needed.
|
||||
*/
|
||||
public void closeHelper()
|
||||
{
|
||||
mEGL.eglTerminate(mDisplay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information through EGL.<br/>
|
||||
* <p>
|
||||
* Index 0: Vendor <br/>
|
||||
* Index 1: Version <br/>
|
||||
* Index 2: Renderer <br/>
|
||||
* Index 3: Extensions <br/>
|
||||
*
|
||||
* @return information retrieved through EGL.
|
||||
*/
|
||||
public String[] getEGLInfo()
|
||||
{
|
||||
String[] info = {
|
||||
mGL.glGetString(GL10.GL_VENDOR),
|
||||
mGL.glGetString(GL10.GL_VERSION),
|
||||
mGL.glGetString(GL10.GL_RENDERER),
|
||||
mGL.glGetString(GL10.GL_EXTENSIONS),
|
||||
};
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this device supports OpenGL.
|
||||
*
|
||||
* @return true if this device supports OpenGL; false otherwise.
|
||||
*/
|
||||
public boolean supportsOpenGL()
|
||||
{
|
||||
return supportGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this device supports OpenGL ES 2.
|
||||
* <br/>
|
||||
* Note that if this returns true, then OpenGL ES 1 is also supported.
|
||||
*
|
||||
* @return true if this device supports OpenGL ES 2; false otherwise.
|
||||
*/
|
||||
public boolean supportsGLES2()
|
||||
{
|
||||
return supportGLES2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this device supports OpenGL ES 3.
|
||||
* <br/>
|
||||
* Note that if this returns true, then OpenGL ES 1 and 2 are also supported.
|
||||
*
|
||||
* @return true if this device supports OpenGL ES 3; false otherwise.
|
||||
*/
|
||||
public boolean supportsGLES3()
|
||||
{
|
||||
return supportGLES3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGL10} instance.
|
||||
*
|
||||
* @return the underlying {@link EGL10} instance.
|
||||
*/
|
||||
public EGL10 getEGL()
|
||||
{
|
||||
return mEGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link GL10} instance.
|
||||
*
|
||||
* @return the underlying {@link GL10} instance.
|
||||
*/
|
||||
public GL10 getGL()
|
||||
{
|
||||
return mGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGLDisplay}.
|
||||
*
|
||||
* @return the underlying {@link EGLDisplay}
|
||||
*/
|
||||
public EGLDisplay getDisplay()
|
||||
{
|
||||
return mDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all supported framebuffer configurations for this device.
|
||||
*
|
||||
* @return all supported framebuffer configurations for this device.
|
||||
*/
|
||||
public EGLConfig[] getConfigs()
|
||||
{
|
||||
return mEGLConfigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGLContext}.
|
||||
*
|
||||
* @return the underlying {@link EGLContext}.
|
||||
*/
|
||||
public EGLContext getContext()
|
||||
{
|
||||
return mEGLContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGLSurface}.
|
||||
*
|
||||
* @return the underlying {@link EGLSurface}.
|
||||
*/
|
||||
public EGLSurface getSurface()
|
||||
{
|
||||
return mEGLSurface;
|
||||
}
|
||||
|
||||
// Detects the specific kind of GL modes that are supported
|
||||
private boolean detect()
|
||||
{
|
||||
// Get total number of configs available.
|
||||
int[] numConfigs = new int[1];
|
||||
if (!mEGL.eglGetConfigs(mDisplay, null, 0, numConfigs))
|
||||
{
|
||||
Log.e("EGLHelper", "Error retrieving number of EGL configs available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now get all the configurations
|
||||
mEGLConfigs = new EGLConfig[numConfigs[0]];
|
||||
if (!mEGL.eglGetConfigs(mDisplay, mEGLConfigs, mEGLConfigs.length, numConfigs))
|
||||
{
|
||||
Log.e("EGLHelper", "Error retrieving all EGL configs.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mEGLConfigs.length; i++)
|
||||
{
|
||||
int[] attribVal = new int[1];
|
||||
boolean ret = mEGL.eglGetConfigAttrib(mDisplay, mEGLConfigs[i], EGL10.EGL_RENDERABLE_TYPE, attribVal);
|
||||
if (ret)
|
||||
{
|
||||
if ((attribVal[0] & EGL_OPENGL_BIT) != 0)
|
||||
supportGL = true;
|
||||
|
||||
if ((attribVal[0] & EGL_OPENGL_ES2_BIT) != 0)
|
||||
supportGLES2 = true;
|
||||
|
||||
if ((attribVal[0] & EGL_OPENGL_ES3_BIT_KHR) != 0)
|
||||
supportGLES3 = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creates the context and surface.
|
||||
private void create(int width, int height, int renderableType)
|
||||
{
|
||||
int[] attribs = {
|
||||
EGL10.EGL_WIDTH, width,
|
||||
EGL10.EGL_HEIGHT, height,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
|
||||
// Initially we just assume GLES2 will be the default context.
|
||||
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
int[] ctx_attribs = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
|
||||
// Determine the type of context that will be created
|
||||
// and change the attribute arrays accordingly.
|
||||
switch (renderableType)
|
||||
{
|
||||
case EGL_OPENGL_ES_BIT:
|
||||
ctx_attribs[1] = 1;
|
||||
break;
|
||||
|
||||
case EGL_OPENGL_BIT:
|
||||
ctx_attribs[0] = EGL10.EGL_NONE;
|
||||
break;
|
||||
|
||||
case EGL_OPENGL_ES3_BIT_KHR:
|
||||
ctx_attribs[1] = 3;
|
||||
break;
|
||||
|
||||
case EGL_OPENGL_ES2_BIT:
|
||||
default: // Fall-back to GLES 2.
|
||||
ctx_attribs[1] = 2;
|
||||
break;
|
||||
}
|
||||
if (renderableType == EGL_OPENGL_BIT)
|
||||
NativeLibrary.eglBindAPI(EGL_OPENGL_API);
|
||||
else
|
||||
NativeLibrary.eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
mEGLContext = mEGL.eglCreateContext(mDisplay, mEGLConfigs[0], EGL10.EGL_NO_CONTEXT, ctx_attribs);
|
||||
mEGLSurface = mEGL.eglCreatePbufferSurface(mDisplay, mEGLConfigs[0], attribs);
|
||||
mEGL.eglMakeCurrent(mDisplay, mEGLSurface, mEGLSurface, mEGLContext);
|
||||
mGL = (GL10) mEGLContext.getGL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified call to {@link GL10#glGetString(int)}
|
||||
* <p>
|
||||
* Accepts the following constants:
|
||||
* <ul>
|
||||
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
||||
* <li>GL_VERSION - Version or release number.</li>
|
||||
* <li>GL_RENDERER - Name of the renderer</li>
|
||||
* <li>GL_SHADING_LANGUAGE_VERSION - Version or release number of the shading language </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param glEnum A symbolic constant within {@link GL10}.
|
||||
*
|
||||
* @return the string information represented by {@code glEnum}.
|
||||
*/
|
||||
public String glGetString(int glEnum)
|
||||
{
|
||||
return mGL.glGetString(glEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified call to {@link GLES30#glGetStringi(int, int)}
|
||||
* <p>
|
||||
* Accepts the following constants:
|
||||
* <ul>
|
||||
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
||||
* <li>GL_VERSION - Version or release number.</li>
|
||||
* <li>GL_RENDERER - Name of the renderer</li>
|
||||
* <li>GL_SHADING_LANGUAGE_VERSION - Version or release number of the shading language </li>
|
||||
* <li>GL_EXTENSIONS - Extension string supported by the implementation at {@code index}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param glEnum A symbolic GL constant
|
||||
* @param index The index of the string to return.
|
||||
*
|
||||
* @return the string information represented by {@code glEnum} and {@code index}.
|
||||
*/
|
||||
public String glGetStringi(int glEnum, int index)
|
||||
{
|
||||
return GLES30.glGetStringi(glEnum, index);
|
||||
}
|
||||
|
||||
public boolean SupportsExtension(String extension)
|
||||
{
|
||||
int[] num_ext = new int[1];
|
||||
GLES30.glGetIntegerv(GLES30.GL_NUM_EXTENSIONS, num_ext, 0);
|
||||
|
||||
for (int i = 0; i < num_ext[0]; ++i)
|
||||
{
|
||||
String ext = GLES30.glGetStringi(GLES30.GL_EXTENSIONS, i);
|
||||
if (ext.equals(extension))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetVersion()
|
||||
{
|
||||
int[] major = new int[1];
|
||||
int[] minor = new int[1];
|
||||
GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, major, 0);
|
||||
GLES30.glGetIntegerv(GLES30.GL_MINOR_VERSION, minor, 0);
|
||||
return major[0] * 100 + minor[0] * 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified call to {@link GL10#glGetIntegerv(int, int[], int)
|
||||
*
|
||||
* @param glEnum A symbolic GL constant.
|
||||
*
|
||||
* @return the integer information represented by {@code glEnum}.
|
||||
*/
|
||||
public int glGetInteger(int glEnum)
|
||||
{
|
||||
int[] val = new int[1];
|
||||
mGL.glGetIntegerv(glEnum, val, 0);
|
||||
return val[0];
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package org.dolphinemu.dolphinemu.utils;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.preference.DialogPreference;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
public class SliderPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener, View.OnClickListener
|
||||
{
|
||||
private static final String androidns = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
// SeekBar
|
||||
private int m_max, m_value;
|
||||
private SeekBar m_seekbar;
|
||||
|
||||
// TextView
|
||||
private TextView m_textview;
|
||||
|
||||
public SliderPreference(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
|
||||
// Seekbar values
|
||||
m_value = attrs.getAttributeIntValue(androidns, "defaultValue", 0);
|
||||
m_max = attrs.getAttributeIntValue(androidns, "max", 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View onCreateDialogView()
|
||||
{
|
||||
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
LinearLayout layout = (LinearLayout)inflater.inflate(R.layout.slider_layout, null, false);
|
||||
|
||||
m_seekbar = (SeekBar)layout.findViewById(R.id.sliderSeekBar);
|
||||
m_textview = (TextView)layout.findViewById(R.id.sliderTextView);
|
||||
|
||||
if (shouldPersist())
|
||||
m_value = Integer.valueOf(getPersistedString(Integer.toString(m_value)));
|
||||
|
||||
m_seekbar.setMax(m_max);
|
||||
m_seekbar.setProgress(m_value);
|
||||
setProgressText(m_value);
|
||||
m_seekbar.setOnSeekBarChangeListener(this);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
// SeekBar overrides
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seek, int value, boolean fromTouch)
|
||||
{
|
||||
m_value = value;
|
||||
setProgressText(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seek) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seek) {}
|
||||
|
||||
void setProgressText(int value)
|
||||
{
|
||||
m_textview.setText(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDialog(Bundle state)
|
||||
{
|
||||
super.showDialog(state);
|
||||
|
||||
Button positiveButton = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
positiveButton.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
if (shouldPersist())
|
||||
{
|
||||
persistString(Integer.toString(m_seekbar.getProgress()));
|
||||
callChangeListener(m_seekbar.getProgress());
|
||||
}
|
||||
((AlertDialog) getDialog()).dismiss();
|
||||
}
|
||||
}
|
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_a.png
Normal file
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 31 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_b.png
Normal file
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 31 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_c.png
Normal file
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 31 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_dpad.png
Normal file
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 19 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_joystick.png
Normal file
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 15 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_l.png
Normal file
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 20 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_r.png
Normal file
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 22 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_start.png
Normal file
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 35 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_x.png
Normal file
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 21 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_y.png
Normal file
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 22 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/gcpad_z.png
Normal file
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 16 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/ic_drawer.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Source/Android/app/src/main/res/drawable-hdpi/ic_menu_file.png
Normal file
After Width: | Height: | Size: 408 B |
BIN
Source/Android/app/src/main/res/drawable-hdpi/ic_menu_folder.png
Normal file
After Width: | Height: | Size: 788 B |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_a.png
Normal file
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 11 KiB |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_b.png
Normal file
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 11 KiB |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_c.png
Normal file
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 11 KiB |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_dpad.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.9 KiB |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_joystick.png
Normal file
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 5.7 KiB |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_l.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 7.4 KiB |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_r.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 7.9 KiB |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_start.png
Normal file
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 13 KiB |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_x.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 7.7 KiB |
BIN
Source/Android/app/src/main/res/drawable-ldpi/gcpad_y.png
Normal file
After Width: | Height: | Size: 9.0 KiB |