use existing src folder for android64 instead of duplicating it

This commit is contained in:
Brad Parker 2018-08-17 09:40:02 -04:00
parent 7250181319
commit 1fba7df859
10 changed files with 1 additions and 1663 deletions

View File

@ -14,4 +14,4 @@
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.
source.dir=../phoenix/src

View File

@ -1,200 +0,0 @@
package com.retroarch.browser.mainmenu;
import com.retroarch.browser.preferences.util.UserPreferences;
import com.retroarch.browser.retroactivity.RetroActivityFuture;
import com.retroarch.browser.retroactivity.RetroActivityPast;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.provider.Settings;
import java.util.List;
import java.util.ArrayList;
import android.content.pm.PackageManager;
import android.Manifest;
import android.content.DialogInterface;
import android.app.AlertDialog;
import android.util.Log;
/**
* {@link PreferenceActivity} subclass that provides all of the
* functionality of the main menu screen.
*/
public final class MainMenuActivity extends PreferenceActivity
{
final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
boolean checkPermissions = false;
public void showMessageOKCancel(String message, DialogInterface.OnClickListener onClickListener)
{
new AlertDialog.Builder(this).setMessage(message)
.setPositiveButton("OK", onClickListener).setCancelable(false)
.setNegativeButton("Cancel", null).create().show();
}
private boolean addPermission(List<String> permissionsList, String permission)
{
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED)
{
permissionsList.add(permission);
// Check for Rationale Option
if (!shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
public void checkRuntimePermissions()
{
if (android.os.Build.VERSION.SDK_INT >= 23)
{
// Android 6.0+ needs runtime permission checks
List<String> permissionsNeeded = new ArrayList<String>();
final List<String> permissionsList = new ArrayList<String>();
if (!addPermission(permissionsList, Manifest.permission.READ_EXTERNAL_STORAGE))
permissionsNeeded.add("Read External Storage");
if (!addPermission(permissionsList, Manifest.permission.WRITE_EXTERNAL_STORAGE))
permissionsNeeded.add("Write External Storage");
if (permissionsList.size() > 0)
{
checkPermissions = true;
if (permissionsNeeded.size() > 0)
{
// Need Rationale
Log.i("MainMenuActivity", "Need to request external storage permissions.");
String message = "You need to grant access to " + permissionsNeeded.get(0);
for (int i = 1; i < permissionsNeeded.size(); i++)
message = message + ", " + permissionsNeeded.get(i);
showMessageOKCancel(message,
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
if (which == AlertDialog.BUTTON_POSITIVE)
{
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
Log.i("MainMenuActivity", "User accepted request for external storage permissions.");
}
}
});
}
else
{
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
Log.i("MainMenuActivity", "Requested external storage permissions.");
}
}
}
if (!checkPermissions)
{
finalStartup();
}
}
public void finalStartup()
{
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Intent retro;
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB))
{
retro = new Intent(this, RetroActivityFuture.class);
}
else
{
retro = new Intent(this, RetroActivityPast.class);
}
retro.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startRetroActivity(
retro,
null,
prefs.getString("libretro_path", getApplicationInfo().dataDir + "/cores/"),
UserPreferences.getDefaultConfigPath(this),
Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD),
getApplicationInfo().dataDir,
getApplicationInfo().sourceDir);
startActivity(retro);
finish();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
{
switch (requestCode)
{
case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
for (int i = 0; i < permissions.length; i++)
{
if(grantResults[i] == PackageManager.PERMISSION_GRANTED)
{
Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was granted.");
}
else
{
Log.i("MainMenuActivity", "Permission: " + permissions[i] + " was not granted.");
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
}
finalStartup();
}
public static void startRetroActivity(Intent retro, String contentPath, String corePath,
String configFilePath, String imePath, String dataDirPath, String dataSourcePath)
{
if (contentPath != null) {
retro.putExtra("ROM", contentPath);
}
retro.putExtra("LIBRETRO", corePath);
retro.putExtra("CONFIGFILE", configFilePath);
retro.putExtra("IME", imePath);
retro.putExtra("DATADIR", dataDirPath);
retro.putExtra("APK", dataSourcePath);
retro.putExtra("SDCARD", Environment.getExternalStorageDirectory().getAbsolutePath());
retro.putExtra("DOWNLOADS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath());
retro.putExtra("SCREENSHOTS", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath());
String external = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/com.retroarch.aarch64/files";
retro.putExtra("EXTERNAL", external);
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Bind audio stream to hardware controls.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
UserPreferences.updateConfigFile(this);
checkRuntimePermissions();
}
}

View File

@ -1,281 +0,0 @@
package com.retroarch.browser.preferences.util;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import android.util.Log;
/**
* Represents a configuration file that works off of a key-value pair
* in the form [key name] = "[value]".
*/
public final class ConfigFile
{
// Map containing all of the key-value pairs.
private final HashMap<String, String> map = new HashMap<String, String>();
/**
* Constructor
*/
public ConfigFile()
{
}
/**
* Constructor
*
* @param filePath The path to the configuration file to open.
*/
public ConfigFile(String filePath)
{
if (filePath == null)
throw new IllegalArgumentException("filePath cannot be null.");
try
{
open(filePath);
}
catch (IOException ioe)
{
Log.e("ConfigFile", "Stream reading the configuration file was suddenly closed for an unknown reason.");
}
}
/**
* Parses a configuration file from the given stream
* and appends the parsed values to the key-value map.
*
* @param stream The {@link InputStream} containing the configuration file to parse.
*/
public void append(InputStream stream) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
String line;
while ((line = br.readLine()) != null)
parseLine(line);
br.close();
}
/**
* Opens a configuration file given by configPath
* and parses all of its key-value pairs, adding
* them to the key-value map.
*
* @param configPath Path to the configuration file to parse.
*/
public void open(String configPath) throws IOException
{
clear();
append(new FileInputStream(configPath));
}
private void parseLine(String line)
{
String[] tokens = line.split("=", 2);
if (tokens.length < 2)
return;
for (int i = 0; i < tokens.length; i++)
tokens[i] = tokens[i].trim();
String key = tokens[0];
String value = tokens[1];
if (value.startsWith("\""))
value = value.substring(1, value.lastIndexOf('\"'));
else
value = value.split(" ")[0];
if (value.length() > 0)
map.put(key, value);
}
/**
* Clears the key-value map of all currently set keys and values.
*/
public void clear()
{
map.clear();
}
/**
* Writes the currently set key-value pairs to
*
* @param path The path to save the
*
* @throws IOException
*/
public void write(String path) throws IOException
{
PrintWriter writer = new PrintWriter(path);
for (Map.Entry<String, String> entry : map.entrySet())
{
writer.println(entry.getKey() + " = \"" + entry.getValue() + "\"");
}
writer.close();
}
/**
* Checks if a key exists in the {@link HashMap}
* backing this ConfigFile instance.
*
* @param key The key to check for.
*
* @return true if the key exists in the HashMap backing
* this ConfigFile; false if it doesn't.
*/
public boolean keyExists(String key)
{
return map.containsKey(key);
}
/**
* Sets a key to the given String value.
*
* @param key The key to set the String value to.
* @param value The String value to set to the key.
*/
public void setString(String key, String value)
{
map.put(key, value);
}
/**
* Sets a key to the given boolean value.
*
* @param key The key to set the boolean value to.
* @param value The boolean value to set to the key.
*/
public void setBoolean(String key, boolean value)
{
map.put(key, Boolean.toString(value));
}
/**
* Sets a key to the given Integer value.
*
* @param key The key to set the Integer value to.
* @param value The Integer value to set to the key.
*/
public void setInt(String key, int value)
{
map.put(key, Integer.toString(value));
}
/**
* Sets a key to the given double value.
*
* @param key The key to set the double value to.
* @param value The double value to set to the key.
*/
public void setDouble(String key, double value)
{
map.put(key, Double.toString(value));
}
/**
* Sets a key to the given float value.
*
* @param key The key to set the float value to.
* @param value The float value to set to the key.
*/
public void setFloat(String key, float value)
{
map.put(key, Float.toString(value));
}
/**
* Gets the String value associated with the given key.
*
* @param key The key to get the String value from.
*
* @return the String object associated with the given key.
*/
public String getString(String key)
{
String ret = map.get(key);
if (ret != null)
return ret;
else
return null;
}
/**
* Gets the Integer value associated with the given key.
*
* @param key The key to get the Integer value from.
*
* @return the Integer value associated with the given key.
*/
public int getInt(String key)
{
String str = getString(key);
if (str != null)
return Integer.parseInt(str);
else
throw new IllegalArgumentException("Config key '" + key + "' is invalid.");
}
/**
* Gets the double value associated with the given key.
*
* @param key The key to get the double value from.
*
* @return the double value associated with the given key.
*/
public double getDouble(String key)
{
String str = getString(key);
if (str != null)
return Double.parseDouble(str);
else
throw new IllegalArgumentException("Config key '" + key + "' is invalid.");
}
/**
* Gets the float value associated with the given key.
*
* @param key The key to get the float value from.
*
* @return the float value associated with the given key.
*/
public float getFloat(String key)
{
String str = getString(key);
if (str != null)
return Float.parseFloat(str);
else
throw new IllegalArgumentException("Config key '" + key + "' is invalid.");
}
/**
* Gets the boolean value associated with the given key.
*
* @param key The key to get the boolean value from.
*
* @return the boolean value associated with the given key.
*/
public boolean getBoolean(String key)
{
String str = getString(key);
if (str != null)
return Boolean.parseBoolean(str);
else
throw new IllegalArgumentException("Config key '" + key + "' is invalid.");
}
}

View File

@ -1,300 +0,0 @@
package com.retroarch.browser.preferences.util;
import java.io.File;
import java.io.IOException;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Build;
import android.preference.PreferenceManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;
/**
* Utility class for retrieving, saving, or loading preferences.
*/
public final class UserPreferences
{
// Logging tag.
private static final String TAG = "UserPreferences";
// Disallow explicit instantiation.
private UserPreferences()
{
}
/**
* Retrieves the path to the default location of the libretro config.
*
* @param ctx the current {@link Context}
*
* @return the path to the default location of the libretro config.
*/
public static String getDefaultConfigPath(Context ctx)
{
// Internal/External storage dirs.
final String internal = ctx.getFilesDir().getAbsolutePath();
String external = null;
// Get the App's external storage folder
final String state = android.os.Environment.getExternalStorageState();
if (android.os.Environment.MEDIA_MOUNTED.equals(state)) {
File extsd = ctx.getExternalFilesDir(null);
external = extsd.getAbsolutePath();
}
// Native library directory and data directory for this front-end.
final String dataDir = ctx.getApplicationInfo().dataDir;
final String coreDir = dataDir + "/cores/";
// Get libretro name and path
final SharedPreferences prefs = getPreferences(ctx);
final String libretro_path = prefs.getString("libretro_path", coreDir);
// Check if global config is being used. Return true upon failure.
final boolean globalConfigEnabled = prefs.getBoolean("global_config_enable", true);
String append_path;
// If we aren't using the global config.
if (!globalConfigEnabled && !libretro_path.equals(coreDir))
{
String sanitized_name = sanitizeLibretroPath(libretro_path);
append_path = File.separator + sanitized_name + ".cfg";
}
else // Using global config.
{
append_path = File.separator + "retroarch.cfg";
}
if (external != null)
{
String confPath = external + append_path;
if (new File(confPath).exists())
return confPath;
}
else if (internal != null)
{
String confPath = internal + append_path;
if (new File(confPath).exists())
return confPath;
}
else
{
String confPath = "/mnt/extsd" + append_path;
if (new File(confPath).exists())
return confPath;
}
// Config file does not exist. Create empty one.
// emergency fallback
String new_path = "/mnt/sd" + append_path;
if (external != null)
new_path = external + append_path;
else if (internal != null)
new_path = internal + append_path;
else if (dataDir != null)
new_path = dataDir + append_path;
try {
new File(new_path).createNewFile();
}
catch (IOException e)
{
Log.e(TAG, "Failed to create config file to: " + new_path);
}
return new_path;
}
/**
* Updates the libretro configuration file
* with new values if settings have changed.
*
* @param ctx the current {@link Context}.
*/
public static void updateConfigFile(Context ctx)
{
String path = getDefaultConfigPath(ctx);
ConfigFile config = new ConfigFile(path);
Log.i(TAG, "Writing config to: " + path);
final String dataDir = ctx.getApplicationInfo().dataDir;
final String coreDir = dataDir + "/cores/";
final SharedPreferences prefs = getPreferences(ctx);
config.setString("libretro_directory", coreDir);
config.setInt("audio_out_rate", getOptimalSamplingRate(ctx));
try
{
int version = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0).versionCode;
final String dst_path = dataDir;
final String dst_path_subdir = "assets";
Log.i(TAG, "dst dir is: " + dst_path);
Log.i(TAG, "dst subdir is: " + dst_path_subdir);
config.setBoolean("log_verbosity", true);
config.setString("bundle_assets_src_path", ctx.getApplicationInfo().sourceDir);
config.setString("bundle_assets_dst_path", dst_path);
config.setString("bundle_assets_dst_path_subdir", dst_path_subdir);
config.setInt("bundle_assets_extract_version_current", version);
}
catch (NameNotFoundException ignored)
{
}
// Refactor this entire mess and make this usable for per-core config
if (Build.VERSION.SDK_INT >= 17 && prefs.getBoolean("audio_latency_auto", true))
{
config.setInt("audio_block_frames", getLowLatencyBufferSize(ctx));
}
try
{
config.write(path);
}
catch (IOException e)
{
Log.e(TAG, "Failed to save config file to: " + path);
}
}
private static void readbackString(ConfigFile cfg, SharedPreferences.Editor edit, String key)
{
if (cfg.keyExists(key))
edit.putString(key, cfg.getString(key));
else
edit.remove(key);
}
private static void readbackBool(ConfigFile cfg, SharedPreferences.Editor edit, String key)
{
if (cfg.keyExists(key))
edit.putBoolean(key, cfg.getBoolean(key));
else
edit.remove(key);
}
private static void readbackDouble(ConfigFile cfg, SharedPreferences.Editor edit, String key)
{
if (cfg.keyExists(key))
edit.putFloat(key, (float)cfg.getDouble(key));
else
edit.remove(key);
}
/*
private static void readbackFloat(ConfigFile cfg, SharedPreferences.Editor edit, String key)
{
if (cfg.keyExists(key))
edit.putFloat(key, cfg.getFloat(key));
else
edit.remove(key);
}
*/
/**
private static void readbackInt(ConfigFile cfg, SharedPreferences.Editor edit, String key)
{
if (cfg.keyExists(key))
edit.putInt(key, cfg.getInt(key));
else
edit.remove(key);
}
*/
/**
* Sanitizes a libretro core path.
*
* @param path The path to the libretro core.
*
* @return the sanitized libretro path.
*/
private static String sanitizeLibretroPath(String path)
{
String sanitized_name = path.substring(
path.lastIndexOf('/') + 1,
path.lastIndexOf('.'));
sanitized_name = sanitized_name.replace("neon", "");
sanitized_name = sanitized_name.replace("libretro_", "");
return sanitized_name;
}
/**
* Gets a {@link SharedPreferences} instance containing current settings.
*
* @param ctx the current {@link Context}.
*
* @return A SharedPreference instance containing current settings.
*/
public static SharedPreferences getPreferences(Context ctx)
{
return PreferenceManager.getDefaultSharedPreferences(ctx);
}
/**
* Gets the optimal sampling rate for low-latency audio playback.
*
* @param ctx the current {@link Context}.
*
* @return the optimal sampling rate for low-latency audio playback in Hz.
*/
@TargetApi(17)
private static int getLowLatencyOptimalSamplingRate(Context ctx)
{
AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
return Integer.parseInt(manager
.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
}
/**
* Gets the optimal buffer size for low-latency audio playback.
*
* @param ctx the current {@link Context}.
*
* @return the optimal output buffer size in decimal PCM frames.
*/
@TargetApi(17)
private static int getLowLatencyBufferSize(Context ctx)
{
AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
int buffersize = Integer.parseInt(manager
.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER));
Log.i(TAG, "Queried ideal buffer size (frames): " + buffersize);
return buffersize;
}
/**
* Gets the optimal audio sampling rate.
* <p>
* On Android 4.2+ devices this will retrieve the optimal low-latency sampling rate,
* since Android 4.2 adds support for low latency audio in general.
* <p>
* On other devices, it simply returns the regular optimal sampling rate
* as returned by the hardware.
*
* @param ctx The current {@link Context}.
*
* @return the optimal audio sampling rate in Hz.
*/
private static int getOptimalSamplingRate(Context ctx)
{
int ret;
if (Build.VERSION.SDK_INT >= 17)
ret = getLowLatencyOptimalSamplingRate(ctx);
else
ret = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
Log.i(TAG, "Using sampling rate: " + ret + " Hz");
return ret;
}
}

View File

@ -1,225 +0,0 @@
package com.retroarch.browser.retroactivity;
import java.io.IOException;
import com.retroarch.browser.preferences.util.UserPreferences;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.graphics.SurfaceTexture;
import android.graphics.SurfaceTexture.OnFrameAvailableListener;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
//For Android 3.0 and up
/**
* Class which provides {@link Camera} functionality
* to {@link RetroActivityFuture}.
*/
@SuppressLint("NewApi")
public class RetroActivityCamera extends RetroActivityCommon
{
private Camera mCamera = null;
private long lastTimestamp = 0;
private SurfaceTexture texture;
private boolean updateSurface = true;
private boolean camera_service_running = false;
/**
* Executed when the {@link Camera}
* is staring to capture.
*/
public void onCameraStart()
{
if (camera_service_running)
return;
if (mCamera != null)
mCamera.startPreview();
camera_service_running = true;
}
/**
* Executed when the {@link Camera} is done capturing.
* <p>
* Note that this does not release the currently held
* {@link Camera} instance and must be freed by calling
* {@link #onCameraFree}
*/
public void onCameraStop()
{
if (!camera_service_running)
return;
if (mCamera != null)
mCamera.stopPreview();
camera_service_running = false;
}
/**
* Releases the currently held {@link Camera} instance.
*/
public void onCameraFree()
{
onCameraStop();
if (mCamera != null)
mCamera.release();
}
/**
* Initializes the camera for use.
*/
public void onCameraInit()
{
if (mCamera != null)
return;
mCamera = Camera.open();
}
/**
* Polls the camera for updates to the {@link SurfaceTexture}.
*
* @return true if polling was successful, false otherwise.
*/
public boolean onCameraPoll()
{
if (!camera_service_running)
return false;
if (texture == null)
{
Log.i("RetroActivity", "No texture");
return true;
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
{
if (updateSurface)
{
texture.updateTexImage();
}
long newTimestamp = texture.getTimestamp();
if (newTimestamp != lastTimestamp)
{
lastTimestamp = newTimestamp;
return true;
}
return false;
}
return true;
}
/**
* Initializes the {@link SurfaceTexture} used by the
* {@link Camera} with a given OpenGL texure ID.
*
* @param gl_texid texture ID to initialize the
* {@link SurfaceTexture} with.
*/
public void onCameraTextureInit(int gl_texid)
{
texture = new SurfaceTexture(gl_texid);
texture.setOnFrameAvailableListener(onCameraFrameAvailableListener);
}
/**
* Sets the {@link Camera} texture with the texture represented
* by the given OpenGL texture ID.
*
* @param gl_texid The texture ID representing the texture to set the camera to.
* @throws IOException If setting the texture fails.
*/
public void onCameraSetTexture(int gl_texid) throws IOException
{
if (texture == null)
onCameraTextureInit(gl_texid);
if (mCamera != null)
mCamera.setPreviewTexture(texture);
}
private final OnFrameAvailableListener onCameraFrameAvailableListener = new OnFrameAvailableListener()
{
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture)
{
updateSurface = true;
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
// Save the current setting for updates
SharedPreferences prefs = UserPreferences.getPreferences(this);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("CAMERA_UPDATES_ON", false);
edit.apply();
camera_service_running = false;
super.onCreate(savedInstanceState);
}
@Override
public void onPause()
{
// Save the current setting for updates
SharedPreferences prefs = UserPreferences.getPreferences(this);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("CAMERA_UPDATES_ON", camera_service_running);
edit.apply();
onCameraStop();
super.onPause();
}
@Override
public void onResume()
{
SharedPreferences prefs = UserPreferences.getPreferences(this);
SharedPreferences.Editor edit = prefs.edit();
/*
* Get any previous setting for camera updates
* Gets "false" if an error occurs
*/
if (prefs.contains("CAMERA_UPDATES_ON"))
{
camera_service_running = prefs.getBoolean("CAMERA_UPDATES_ON", false);
if (camera_service_running)
{
onCameraStart();
}
}
else // Otherwise, turn off camera updates
{
edit.putBoolean("CAMERA_UPDATES_ON", false);
edit.apply();
camera_service_running = false;
}
super.onResume();
}
@Override
public void onDestroy()
{
onCameraFree();
super.onDestroy();
}
@Override
public void onStop()
{
onCameraStop();
super.onStop();
}
}

View File

@ -1,141 +0,0 @@
package com.retroarch.browser.retroactivity;
import com.retroarch.browser.preferences.util.UserPreferences;
import android.annotation.TargetApi;
import android.content.res.Configuration;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.app.UiModeManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.PowerManager;
import android.util.Log;
import java.util.concurrent.CountDownLatch;
/**
* Class which provides common methods for RetroActivity related classes.
*/
public class RetroActivityCommon extends RetroActivityLocation
{
public static int FRONTEND_POWERSTATE_NONE = 0;
public static int FRONTEND_POWERSTATE_NO_SOURCE = 1;
public static int FRONTEND_POWERSTATE_CHARGING = 2;
public static int FRONTEND_POWERSTATE_CHARGED = 3;
public static int FRONTEND_POWERSTATE_ON_POWER_SOURCE = 4;
public boolean sustainedPerformanceMode = true;
// Exiting cleanly from NDK seems to be nearly impossible.
// Have to use exit(0) to avoid weird things happening, even with runOnUiThread() approaches.
// Use a separate JNI function to explicitly trigger the readback.
public void onRetroArchExit()
{
finish();
}
@TargetApi(24)
public void setSustainedPerformanceMode(boolean on)
{
sustainedPerformanceMode = on;
if (Build.VERSION.SDK_INT >= 24) {
if (isSustainedPerformanceModeSupported()) {
final CountDownLatch latch = new CountDownLatch(1);
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i("RetroActivity", "setting sustained performance mode to " + sustainedPerformanceMode);
getWindow().setSustainedPerformanceMode(sustainedPerformanceMode);
latch.countDown();
}
});
try {
latch.await();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
@TargetApi(24)
public boolean isSustainedPerformanceModeSupported()
{
boolean supported = false;
if (Build.VERSION.SDK_INT >= 24)
{
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
if (powerManager.isSustainedPerformanceModeSupported())
supported = true;
}
Log.i("RetroActivity", "isSustainedPerformanceModeSupported? " + supported);
return supported;
}
public int getBatteryLevel()
{
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
// This doesn't actually register anything (or need to) because we know this particular intent is sticky and we do not specify a BroadcastReceiver anyway
Intent batteryStatus = registerReceiver(null, ifilter);
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
float percent = ((float)level / (float)scale) * 100.0f;
Log.i("RetroActivity", "battery: level = " + level + ", scale = " + scale + ", percent = " + percent);
return (int)percent;
}
public int getPowerstate()
{
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
// This doesn't actually register anything (or need to) because we know this particular intent is sticky and we do not specify a BroadcastReceiver anyway
Intent batteryStatus = registerReceiver(null, ifilter);
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean hasBattery = batteryStatus.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false);
boolean isCharging = (status == BatteryManager.BATTERY_STATUS_CHARGING);
boolean isCharged = (status == BatteryManager.BATTERY_STATUS_FULL);
int powerstate = FRONTEND_POWERSTATE_NONE;
if (isCharged)
powerstate = FRONTEND_POWERSTATE_CHARGED;
else if (isCharging)
powerstate = FRONTEND_POWERSTATE_CHARGING;
else if (!hasBattery)
powerstate = FRONTEND_POWERSTATE_NO_SOURCE;
else
powerstate = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
Log.i("RetroActivity", "power state = " + powerstate);
return powerstate;
}
public boolean isAndroidTV()
{
Configuration config = getResources().getConfiguration();
UiModeManager uiModeManager = (UiModeManager)getSystemService(UI_MODE_SERVICE);
if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION)
{
Log.i("RetroActivity", "isAndroidTV == true");
return true;
}
else
{
Log.i("RetroActivity", "isAndroidTV == false");
return false;
}
}
}

View File

@ -1,87 +0,0 @@
package com.retroarch.browser.retroactivity;
import android.view.View;
import android.view.WindowManager;
import android.content.Intent;
import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Build;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public final class RetroActivityFuture extends RetroActivityCamera {
// If set to true then Retroarch will completely exit when it loses focus
private boolean quitfocus = false;
@Override
public void onResume() {
super.onResume();
setSustainedPerformanceMode(sustainedPerformanceMode);
if (Build.VERSION.SDK_INT >= 19) {
// Immersive mode
// Constants from API > 14
final int API_SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100;
final int API_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;
final int API_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;
final int API_SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004;
final int API_SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000;
View thisView = getWindow().getDecorView();
thisView.setSystemUiVisibility(API_SYSTEM_UI_FLAG_LAYOUT_STABLE
| API_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| API_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| API_SYSTEM_UI_FLAG_FULLSCREEN
| API_SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
// Check for Android UI specific parameters
Intent retro = getIntent();
String refresh = retro.getStringExtra("REFRESH");
// If REFRESH parameter is provided then try to set refreshrate accordingly
if(refresh != null) {
WindowManager.LayoutParams params = getWindow().getAttributes();
params.preferredRefreshRate = Integer.parseInt(refresh);
getWindow().setAttributes(params);
}
// If QUITFOCUS parameter is provided then enable that Retroarch quits when focus is lost
quitfocus = retro.hasExtra("QUITFOCUS");
// If HIDEMOUSE parameters is provided then hide the mourse cursor
// This requires NVIDIA Android extensions (available on NVIDIA Shield), if they are not
// available then nothing will be done
if (retro.hasExtra("HIDEMOUSE")) hideMouseCursor();
}
}
public void hideMouseCursor() {
// Check for NVIDIA extensions and minimum SDK version
Method mInputManager_setCursorVisibility;
try { mInputManager_setCursorVisibility =
InputManager.class.getMethod("setCursorVisibility", boolean.class);
}
catch (NoSuchMethodException ex) {
return; // Extensions were not available so do nothing
}
// Hide the mouse cursor
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
try { mInputManager_setCursorVisibility.invoke(inputManager, false); }
catch (InvocationTargetException ite) { }
catch (IllegalAccessException iae) { }
}
@Override
public void onStop() {
super.onStop();
// If QUITFOCUS parameter was set then completely exit Retroarch when focus is lost
if (quitfocus) System.exit(0);
}
}

View File

@ -1,105 +0,0 @@
package com.retroarch.browser.retroactivity;
import com.retroarch.browser.mainmenu.MainMenuActivity;
import android.content.Intent;
import android.util.Log;
public class RetroActivityIntent extends RetroActivityCommon {
private Intent pendingIntent = null;
private static final String TAG = "RetroArch";
@Override
public void onBackPressed()
{
Log.i("RetroActivity", "onBackKeyPressed");
Intent retro = new Intent(this, MainMenuActivity.class);
retro.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(retro);
}
@Override
public void onNewIntent(Intent intent)
{
Log.i("RetroActivity", "onNewIntent invoked.");
super.onNewIntent(intent);
setIntent(intent);
pendingIntent = intent;
}
/**
* Gets the ROM file specified in the pending intent.
*
* @return the ROM file specified in the pending intent.
*/
public String getPendingIntentFullPath()
{
return pendingIntent.getStringExtra("ROM");
}
/**
* Gets the specified path to the libretro core in the pending intent.
*
* @return the specified path to the libretro core in the pending intent.
*/
public String getPendingIntentLibretroPath()
{
return pendingIntent.getStringExtra("LIBRETRO");
}
/**
* Gets the path specified in the pending intent to the retroarch cfg file.
*
* @return the path specified in the pending intent to the retroarch cfg file.
*/
public String getPendingIntentConfigPath()
{
return pendingIntent.getStringExtra("CONFIGFILE");
}
public String getPendingIntentStorageLocation()
{
return pendingIntent.getStringExtra("SDCARD");
}
public String getPendingIntentDownloadLocation()
{
return pendingIntent.getStringExtra("DOWNLOADS");
}
public String getPendingIntentScreenshotsLocation()
{
return pendingIntent.getStringExtra("SCREENSHOTS");
}
/**
* Gets the specified IME in the pending intent.
*
* @return the specified IME in the pending intent.
*/
public String getPendingIntentIME()
{
return pendingIntent.getStringExtra("IME");
}
/**
* Checks whether or not a pending intent exists.
*
* @return true if a pending intent exists, false otherwise.
*/
public boolean hasPendingIntent()
{
if (pendingIntent == null)
return false;
return true;
}
/**
* Clears the current pending intent.
*/
public void clearPendingIntent()
{
pendingIntent = null;
}
}

View File

@ -1,316 +0,0 @@
package com.retroarch.browser.retroactivity;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.retroarch.browser.preferences.util.UserPreferences;
import android.app.NativeActivity;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
/**
* Class that implements location-based functionality for
* the {@link RetroActivityFuture} and {@link RetroActivityPast}
* activities.
*/
public class RetroActivityLocation extends NativeActivity
implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener
{
/* LOCATION VARIABLES */
private static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 0;
private LocationClient mLocationClient = null;
private Location mCurrentLocation;
// Define an object that holds accuracy and frequency parameters
LocationRequest mLocationRequest = null;
boolean mUpdatesRequested = false;
boolean locationChanged = false;
boolean location_service_running = false;
/**
* Called by Location Services when the request to connect the
* client finishes successfully. At this point, you can
* request the current location or start periodic updates
*/
@Override
public void onConnected(Bundle dataBundle)
{
if (mLocationClient == null)
return;
// Display the connection status
Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
location_service_running = true;
// If already requested, start periodic updates
if (mUpdatesRequested)
{
mLocationClient.requestLocationUpdates(mLocationRequest, this, null);
}
else
{
// Get last known location
mCurrentLocation = mLocationClient.getLastLocation();
locationChanged = true;
}
}
/**
* Called by Location Services if the connection to the
* location client drops because of an error.
*/
@Override
public void onDisconnected()
{
if (mLocationClient == null)
return;
// Display the connection status
Toast.makeText(this, "Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
// If the client is connected
if (mLocationClient.isConnected())
{
/*
* Remove location updates for a listener.
* The current Activity is the listener, so
* the argument is "this".
*/
mLocationClient.removeLocationUpdates(this);
}
location_service_running = false;
}
/**
* Called by Location Services if the attempt to
* Location Services fails.
*/
@Override
public void onConnectionFailed(ConnectionResult connectionResult)
{
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution())
{
try
{
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
}
catch (IntentSender.SendIntentException e)
{
// Thrown if Google Play services cancelled the original PendingIntent
e.printStackTrace();
}
}
else
{
/*
* If no resolution is available, display a dialog to the
* user with the error.
*/
Log.e("Connection failed", "error code: " + connectionResult.getErrorCode());
}
}
/**
* Sets the update interval at which location-based updates
* should occur
*/
public void onLocationSetInterval(int update_interval_in_ms, int distance_interval)
{
// Use high accuracy
if (mLocationRequest == null)
return;
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (update_interval_in_ms == 0)
mLocationRequest.setInterval(5 * 1000); // 5 seconds
else
mLocationRequest.setInterval(update_interval_in_ms);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(1000);
}
/**
* Initializing methods for location based functionality.
*/
public void onLocationInit()
{
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
if (mLocationClient == null)
mLocationClient = new LocationClient(this, this, this);
// Start with updates turned off
mUpdatesRequested = false;
// Create the LocationRequest object
if (mLocationRequest == null)
mLocationRequest = LocationRequest.create();
onLocationSetInterval(0, 0);
}
/**
* Executed upon starting the {@link LocationClient}.
*/
public void onLocationStart()
{
if (mLocationClient == null)
return;
mUpdatesRequested = true;
// Connect the client.
mLocationClient.connect();
}
/**
* Free up location services resources.
*/
public void onLocationFree()
{
/* TODO/FIXME */
}
/**
* Executed upon stopping the location client.
* Does nothing if called when the client is not started.
*/
public void onLocationStop()
{
// Disconnecting the client invalidates it.
if (mLocationClient != null && mUpdatesRequested)
mLocationClient.disconnect();
}
/**
* Gets the latitude at the current location in degrees.
*
* @return the latitude at the current location.
*/
public double onLocationGetLatitude()
{
return mCurrentLocation.getLatitude();
}
/**
* Gets the longitude at the current location in degrees.
*
* @return the longitude at the current location.
*/
public double onLocationGetLongitude()
{
return mCurrentLocation.getLongitude();
}
/**
* Gets the horizontal accuracy of the current location
* in meters. (NOTE: There seems to be no vertical accuracy
* for a given location with the Android location API)
*
* @return the horizontal accuracy of the current position.
*/
public double onLocationGetHorizontalAccuracy()
{
return mCurrentLocation.getAccuracy();
}
/**
* Tells us whether the location listener callback has
* updated the current location since the last time
* we polled.
*
* @return true if location has changed, false if location has not changed.
*/
public boolean onLocationHasChanged()
{
boolean hasChanged = locationChanged;
// Reset flag
if (hasChanged)
locationChanged = false;
return hasChanged;
}
// Define the callback method that receives location updates
@Override
public void onLocationChanged(Location location)
{
if (!location_service_running)
return;
locationChanged = true;
mCurrentLocation = location;
// Report to the UI that the location was updated
String msg = "Updated Location: " + location.getLatitude() + ", " + location.getLongitude();
Log.i("RetroArch GPS", msg);
//Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onPause()
{
// Save the current setting for updates
SharedPreferences prefs = UserPreferences.getPreferences(this);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("LOCATION_UPDATES_ON", mUpdatesRequested);
edit.apply();
super.onPause();
}
@Override
public void onResume()
{
SharedPreferences prefs = UserPreferences.getPreferences(this);
SharedPreferences.Editor edit = prefs.edit();
/*
* Get any previous setting for location updates
* Gets "false" if an error occurs
*/
if (prefs.contains("LOCATION_UPDATES_ON"))
{
mUpdatesRequested = prefs.getBoolean("LOCATION_UPDATES_ON", false);
if (mUpdatesRequested)
location_service_running = true;
}
else // Otherwise, turn off location updates
{
edit.putBoolean("LOCATION_UPDATES_ON", false);
edit.apply();
location_service_running = false;
}
super.onResume();
}
@Override
public void onStop()
{
onLocationStop();
super.onStop();
}
}

View File

@ -1,7 +0,0 @@
package com.retroarch.browser.retroactivity;
// For Android 2.3.x
public final class RetroActivityPast extends RetroActivityCommon
{
}