[Android] Initial huge underlying UI update:

- The UI is now mostly Fragment-centric (finally!)
- The Load Core, Load Game, Load Game (History) are now DialogFragments.
- The directory activities are killed off and consolidated into one fragment named DirectoryFragment.

DirectoryFragment is now a self-contained instantiable DirectoryFragment that can be instantiated anywhere by doing roughly the following.

DirectorFragment dFrag = DirectoryFragment.newInstance(/* Resource ID for a string title here*/);
dFrag.show(getFragmentManager(), "tag");

There are also other methods that were modified within the DirectoryFragment, such as addAllowedExt and disAllowedExt being changed to support a variable amount of arguments. This way, multiple calls of the same function aren't necessary in the case of adding multiple extensions, as well as supporting the case where only one extension is added.

DirectoryFragment also has a new interface added to it called OnDirectoryFragmentClosedListener. Say you have a DirectoryFragment instance, but want to use the selected item's path for something *after* the dialog has closed, with this interface, it is now possible. Just implement this interface within an Activity or Fragment, and then set the DirectoryFragment to use the listener through setOnDirectoryFragmentClosedListener() method.

Now what happens if this isn't set, wouldn't it be pointless to even use a DirectoryFragment in this case?
Not necessarily. What if you only wanted to save the selected item into the applications SharedPreferences?
This is a situation where it would be unnecessary to need that interface. So, to make a DirectoryFragment.java for the sole purpose of saving a selected directory/file path to the SharedPreferences, you would do this:

DirectoryFragment dFrag = DirectoryFragment.newInstance(/* Resource ID to a string title here*/);
dFrag.setPathSettingKey("key to store value in SharedPreferences at");
dFrag.show(getFragmentManager(), "tag");

Outside of these major changes, large portions of the code outside of this were simplified.
This commit is contained in:
Lioncash 2013-11-17 02:37:33 -05:00
parent 9558a47ada
commit 114cf4e926
31 changed files with 1727 additions and 1216 deletions

View File

@ -6,7 +6,7 @@
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="18" />
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
@ -15,10 +15,8 @@
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:hasCode="true">
<activity android:name="com.retroarch.browser.CoreSelection"/>
<activity android:name="com.retroarch.browser.HistorySelection"/>
<activity android:name="com.retroarch.browser.DisplayRefreshRateTest"/>
<activity android:name="com.retroarch.browser.MainMenuActivity" android:exported="true">
<activity android:name="com.retroarch.browser.mainmenu.MainMenuActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@ -28,15 +26,7 @@
<activity android:name="com.retroarch.browser.FileWrapper"/>
<activity android:name="com.retroarch.browser.RetroTVMode"/>
<activity android:name="com.retroarch.browser.diractivities.DirectoryActivity"/>
<activity android:name="com.retroarch.browser.diractivities.ROMActivity"/>
<activity android:name="com.retroarch.browser.diractivities.ROMDirActivity"/>
<activity android:name="com.retroarch.browser.diractivities.ShaderActivity"/>
<activity android:name="com.retroarch.browser.diractivities.OverlayActivity"/>
<activity android:name="com.retroarch.browser.diractivities.SRMDirActivity"/>
<activity android:name="com.retroarch.browser.diractivities.StateDirActivity"/>
<activity android:name="com.retroarch.browser.diractivities.SystemDirActivity"/>
<activity android:name="com.retroarch.browser.preferences.fragments.PreferenceActivity" android:theme="@style/Theme.AppCompat" />
<activity android:name="com.retroarch.browser.preferences.PreferenceActivity" android:theme="@style/Theme.AppCompat" />
<activity android:name="com.retroarch.browser.coremanager.CoreManagerActivity" android:theme="@style/Theme.AppCompat"/>
<activity android:name="com.retroarch.browser.RetroActivity" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2010, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:background="@android:color/transparent">
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="0px"
android:layout_weight="1"
android:paddingTop="0dip"
android:paddingBottom="@dimen/preference_fragment_padding_bottom"
android:paddingLeft="@dimen/preference_fragment_padding_side"
android:paddingRight="@dimen/preference_fragment_padding_side"
android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
android:clipToPadding="false"
android:drawSelectorOnTop="false"
android:cacheColorHint="@android:color/transparent"
android:scrollbarAlwaysDrawVerticalTrack="true" />
<TextView android:id="@android:id/empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="@dimen/preference_fragment_padding_side"
android:gravity="center"
android:visibility="gone" />
<RelativeLayout android:id="@+id/button_bar"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="0"
android:visibility="gone">
<Button android:id="@+id/back_button"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_alignParentLeft="true"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true">
<Button android:id="@+id/skip_button"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:visibility="gone"/>
<Button android:id="@+id/next_button"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/assets/res/any/dimens.xml
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources>
<!-- Preference fragment padding, bottom -->
<dimen name="preference_fragment_padding_bottom">0dp</dimen>
<!-- Preference fragment padding, sides -->
<dimen name="preference_fragment_padding_side">16dp</dimen>
<integer name="preference_fragment_scrollbarStyle">0x02000000</integer> <!-- outsideOverlay -->
</resources>

View File

@ -69,6 +69,13 @@
<string name="no_optimal_settings">Device either not detected in list or doesn\'t have any optimal settings in our database.</string>
<string name="load_a_core_first">Go to \'Load Core\' and select a core first.</string>
<string name="loading_data">Loading [%1$s]…</string>
<!-- Asset extraction dialog -->
<string name="asset_extraction">Asset Extraction</string>
<!-- GPL cores AlertDialog -->
<string name="keep_cores">Keep cores</string>
<string name="remove_cores">Remove non-GPL cores</string>
<!-- Refresh Rate Set OS Class -->
<string name="using_os_reported_refresh_rate">Using OS-reported refresh rate of: %1$s Hz.</string>
@ -118,6 +125,7 @@
<string name="touchscreen_overlay_desc">Enable touchscreen overlays (WARNING: Lower-resolution overlays might be more suitable for less powerful devices).</string>
<string name="input_overlay">Input overlay</string>
<string name="input_overlay_desc">Sets touchscreen overlay config.</string>
<string name="input_overlay_select">Select an input overlay</string>
<string name="overlay_opacity">Overlay opacity</string>
<string name="overlay_opacity_desc">Set the opacity of the touch overlay.</string>
<string name="custom_binds">Custom Binds</string>
@ -151,19 +159,23 @@
<string name="rom_paths">ROM paths</string>
<string name="rom_directory">ROM directory</string>
<string name="rom_directory_desc">Sets directory where ROM browser will first browse for ROM files.</string>
<string name="rom_directory_select">Select a ROM directory</string>
<string name="save_files">Save files</string>
<string name="enable_custom_dir">Enable custom directory</string>
<string name="savefiles_custom_dir">Enables use of custom save file folder. (.srm) save files will be saved and loaded to configured directory. If not enabled, save files will reside in ROM folder.</string>
<string name="savefile_directory">Savefile directory</string>
<string name="savefile_directory_desc">Sets directory where to save and load game save files.</string>
<string name="savefile_directory_select">Select a savefile directory</string>
<string name="save_states">Save states</string>
<string name="savestates_custom_dir">Enables use of custom save state folder. (.state) save states will be saved and loaded to configured directory. If not enabled, save states will reside in ROM folder.</string>
<string name="save_states_custom_dir">Enables use of custom save state folder. (.state) save states will be saved and loaded to configured directory. If not enabled, save states will reside in ROM folder.</string>
<string name="save_state_directory">Save state directory</string>
<string name="save_state_directory_desc">Sets directory where to save and load game save states.</string>
<string name="save_state_directory_select">Select a savestate directory</string>
<string name="system">System</string>
<string name="system_custom_dir">Enables use of custom system folder. Cores will look for system specific files, like BIOSes, in this folder. If not enabled, it will look in the ROM folder.</string>
<string name="system_directory">System directory</string>
<string name="system_directory_desc">Sets directory where system files are loaded from.</string>
<string name="system_directory_select">Select a system directory</string>
<!-- General Settings -->
<string name="general_options">General</string>
@ -210,6 +222,7 @@
<string name="first_pass_shader_desc">Enable first pass shader (WARNING: performance varies per device and per shader).</string>
<string name="glsl_shader">GLSL shader</string>
<string name="glsl_shader_desc">Sets GLES2 style shader.</string>
<string name="glsl_shader_select">Select a GLSL shader</string>
<string name="fonts">Fonts</string>
<string name="onscreen_fonts">On-screen fonts</string>
<string name="onscreen_fonts_desc">Enable rendering of on-screen fonts for messages.</string>

View File

@ -72,13 +72,11 @@
android:title="@string/enable" />
<Preference
android:key="inputOverlayDirPref"
android:summary="@string/input_overlay_desc"
android:title="@string/input_overlay"
android:dependency="input_overlay_enable" >
<intent
android:targetClass="com.retroarch.browser.diractivities.OverlayActivity"
android:targetPackage="com.retroarch" />
</Preference>
android:dependency="input_overlay_enable"/>
<com.retroarch.browser.preferences.util.SeekbarPreference
android:summary="@string/overlay_opacity_desc"
android:title="@string/overlay_opacity"

View File

@ -3,39 +3,33 @@
android:title="@string/mainmenu_title" >
<!-- TV Mode -->
<PreferenceScreen android:title="@string/tv_mode">
<Preference android:title="@string/tv_mode">
<intent
android:targetClass="com.retroarch.browser.RetroTVMode"
android:targetPackage="com.retroarch" />
</PreferenceScreen>
</Preference>
<!-- Load Core -->
<PreferenceScreen android:title="@string/load_core">
<intent
android:targetClass="com.retroarch.browser.CoreSelection"
android:targetPackage="com.retroarch" />
</PreferenceScreen>
<Preference
android:key="loadCorePref"
android:title="@string/load_core"/>
<!-- Load Game -->
<PreferenceScreen android:title="@string/load_game">
<intent
android:targetClass="com.retroarch.browser.diractivities.ROMActivity"
android:targetPackage="com.retroarch" />
</PreferenceScreen>
<Preference
android:key="loadRomPref"
android:title="@string/load_game"/>
<!-- Load Game (History) -->
<PreferenceScreen android:title="@string/load_game_history">
<intent
android:targetClass="com.retroarch.browser.HistorySelection"
android:targetPackage="com.retroarch" />
</PreferenceScreen>
<Preference
android:key="loadRomHistoryPref"
android:title="@string/load_game_history"/>
<!-- Settings -->
<PreferenceScreen android:title="@string/settings">
<Preference android:title="@string/settings">
<intent
android:targetClass="com.retroarch.browser.preferences.fragments.PreferenceActivity"
android:targetClass="com.retroarch.browser.preferences.PreferenceActivity"
android:targetPackage="com.retroarch" />
</PreferenceScreen>
</Preference>
<!-- About -->
<PreferenceScreen android:title="@string/about">

View File

@ -3,12 +3,10 @@
<!-- ROM Paths -->
<PreferenceCategory android:title="@string/rom_paths">
<Preference android:title="@string/rom_directory"
android:summary="@string/rom_directory_desc">
<intent
android:targetClass="com.retroarch.browser.diractivities.ROMDirActivity"
android:targetPackage="com.retroarch" />
</Preference>
<Preference
android:key="romDirPref"
android:title="@string/rom_directory"
android:summary="@string/rom_directory_desc"/>
</PreferenceCategory>
<!-- Save Files -->
@ -17,28 +15,24 @@
android:summary="@string/savefiles_custom_dir"
android:key="savefile_directory_enable"
android:defaultValue="false"/>
<Preference android:title="@string/savefile_directory"
<Preference
android:key="srmDirPref"
android:title="@string/savefile_directory"
android:summary="@string/savefile_directory_desc"
android:dependency="savefile_directory_enable">
<intent
android:targetClass="com.retroarch.browser.diractivities.SRMDirActivity"
android:targetPackage="com.retroarch" />
</Preference>
android:dependency="savefile_directory_enable"/>
</PreferenceCategory>
<!-- Save States -->
<PreferenceCategory android:title="@string/save_states">
<CheckBoxPreference android:title="@string/enable_custom_dir"
android:summary="@string/savestates_custom_dir"
android:summary="@string/save_states_custom_dir"
android:key="savestate_directory_enable"
android:defaultValue="false"/>
<Preference android:title="@string/save_state_directory"
<Preference
android:key="saveStateDirPref"
android:title="@string/save_state_directory"
android:summary="@string/save_state_directory_desc"
android:dependency="savestate_directory_enable">
<intent
android:targetClass="com.retroarch.browser.diractivities.StateDirActivity"
android:targetPackage="com.retroarch" />
</Preference>
android:dependency="savestate_directory_enable"/>
</PreferenceCategory>
<!-- System -->
@ -47,12 +41,10 @@
android:summary="@string/system_custom_dir"
android:key="system_directory_enable"
android:defaultValue="false"/>
<Preference android:title="@string/system_directory"
<Preference
android:key="systemDirPref"
android:title="@string/system_directory"
android:summary="@string/system_directory_desc"
android:dependency="system_directory_enable">
<intent
android:targetClass="com.retroarch.browser.diractivities.SystemDirActivity"
android:targetPackage="com.retroarch" />
</Preference>
android:dependency="system_directory_enable"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@ -64,15 +64,11 @@
android:defaultValue="false"
android:key="video_shader_enable"
android:title="@string/first_pass_shader" />
<Preference
android:key="glsl_shader_pref"
android:summary="@string/glsl_shader_desc"
android:title="@string/glsl_shader"
android:dependency="video_shader_enable" >
<intent
android:targetClass="com.retroarch.browser.diractivities.ShaderActivity"
android:targetPackage="com.retroarch" />
</Preference>
android:dependency="video_shader_enable" />
</PreferenceCategory>
<!-- Fonts -->

View File

@ -1,42 +1,48 @@
package com.retroarch.browser;
import com.retroarch.R;
import com.retroarch.browser.preferences.util.UserPreferences;
import java.io.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.app.*;
import android.media.AudioManager;
import android.os.*;
import android.widget.*;
import android.view.*;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import com.retroarch.R;
import com.retroarch.browser.mainmenu.MainMenuActivity;
import com.retroarch.browser.preferences.util.UserPreferences;
/**
* {@link ListActivity} subclass that displays the list
* {@link ListFragment} subclass that displays the list
* of selectable cores for emulating games.
*/
public final class CoreSelection extends ListActivity {
public final class CoreSelection extends DialogFragment
{
private IconAdapter<ModuleWrapper> adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the ListView we're using.
final ListView coreList = (ListView) inflater.inflate(R.layout.line_list, container, false);
coreList.setOnItemClickListener(onClickListener);
// Set the title of the dialog
getDialog().setTitle(R.string.select_libretro_core);
final String cpuInfo = UserPreferences.readCPUInfo();
final boolean cpuIsNeon = cpuInfo.contains("neon");
// Setup the layout
setContentView(R.layout.line_list);
// Set the activity title.
setTitle(R.string.select_libretro_core);
// Populate the list
final List<ModuleWrapper> cores = new ArrayList<ModuleWrapper>();
final File[] libs = new File(getApplicationInfo().dataDir, "/cores").listFiles();
final File[] libs = new File(getActivity().getApplicationInfo().dataDir, "/cores").listFiles();
for (final File lib : libs) {
String libName = lib.getName();
@ -46,13 +52,15 @@ public final class CoreSelection extends ListActivity {
// If we have a NEON version with NEON capable CPU,
// never append a non-NEON version.
if (cpuIsNeon && !libName.contains("neon")) {
if (cpuIsNeon && !libName.contains("neon"))
{
boolean hasNeonVersion = false;
for (final File lib_ : libs) {
for (final File lib_ : libs)
{
String otherName = lib_.getName();
String baseName = libName.replace(".so", "");
if (otherName.contains("neon")
&& otherName.startsWith(baseName)) {
if (otherName.contains("neon") && otherName.startsWith(baseName))
{
hasNeonVersion = true;
break;
}
@ -62,24 +70,28 @@ public final class CoreSelection extends ListActivity {
continue;
}
cores.add(new ModuleWrapper(this, lib));
cores.add(new ModuleWrapper(getActivity(), lib));
}
// Sort the list of cores alphabetically
Collections.sort(cores);
// Initialize the IconAdapter with the list of cores.
adapter = new IconAdapter<ModuleWrapper>(this, R.layout.line_list_item, cores);
setListAdapter(adapter);
adapter = new IconAdapter<ModuleWrapper>(getActivity(), R.layout.line_list_item, cores);
coreList.setAdapter(adapter);
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
return coreList;
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
final ModuleWrapper item = adapter.getItem(position);
MainMenuActivity.getInstance().setModule(item.getUnderlyingFile().getAbsolutePath(), item.getText());
UserPreferences.updateConfigFile(this);
finish();
}
private final OnItemClickListener onClickListener = new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> listView, View view, int position, long id)
{
final ModuleWrapper item = adapter.getItem(position);
((MainMenuActivity)getActivity()).setModule(item.getUnderlyingFile().getAbsolutePath(), item.getText());
UserPreferences.updateConfigFile(getActivity());
dismiss();
}
};
}

View File

@ -7,45 +7,62 @@ import java.io.IOException;
import java.io.InputStreamReader;
import com.retroarch.R;
import com.retroarch.browser.mainmenu.MainMenuActivity;
import com.retroarch.browser.preferences.util.UserPreferences;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;
/**
* Represents the {@link ListActivity} responsible
* Represents the {@link ListFragment} responsible
* for displaying the list of previously played games.
*/
public final class HistorySelection extends ListActivity {
public final class HistorySelection extends DialogFragment
{
private FragmentActivity ctx;
private IconAdapter<HistoryWrapper> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Setup the layout.
setContentView(R.layout.line_list);
// Cache the context
this.ctx = getActivity();
}
// Setup the list
adapter = new IconAdapter<HistoryWrapper>(this, R.layout.line_list_item);
setListAdapter(adapter);
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
ListView rootView = (ListView) inflater.inflate(R.layout.line_list, container, false);
rootView.setOnItemClickListener(onItemClickListener);
// Set activity title.
setTitle(R.string.recently_played_games);
// Set the title for this dialog.
getDialog().setTitle(R.string.load_game_history);
File history = new File(getApplicationInfo().dataDir, "retroarch-history.txt");
// Setup the list adapter
adapter = new IconAdapter<HistoryWrapper>(ctx, R.layout.line_list_item);
try {
// Populate the adapter
File history = new File(ctx.getApplicationInfo().dataDir, "retroarch-history.txt");
try
{
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(history)));
for (;;) {
for (;;)
{
String game = br.readLine();
String core = br.readLine();
String name = br.readLine();
@ -55,30 +72,42 @@ public final class HistorySelection extends ListActivity {
adapter.add(new HistoryWrapper(game, core, name));
}
br.close();
} catch (IOException ex) {
}
catch (IOException ignored)
{
}
// Set the adapter
rootView.setAdapter(adapter);
return rootView;
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
final HistoryWrapper item = adapter.getItem(position);
final String gamePath = item.getGamePath();
final String corePath = item.getCorePath();
MainMenuActivity.getInstance().setModule(corePath, item.getCoreName());
String current_ime = Settings.Secure.getString(getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
UserPreferences.updateConfigFile(this);
Toast.makeText(this, String.format(getString(R.string.loading_gamepath), gamePath), Toast.LENGTH_SHORT).show();
Intent myIntent = new Intent(this, RetroActivity.class);
myIntent.putExtra("ROM", gamePath);
myIntent.putExtra("LIBRETRO", corePath);
myIntent.putExtra("CONFIGFILE", UserPreferences.getDefaultConfigPath(this));
myIntent.putExtra("IME", current_ime);
startActivity(myIntent);
finish();
}
private final OnItemClickListener onItemClickListener = new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> listView, View view, int position, long id)
{
final HistoryWrapper item = adapter.getItem(position);
final String gamePath = item.getGamePath();
final String corePath = item.getCorePath();
// Set the core the selected game uses.
((MainMenuActivity)getActivity()).setModule(corePath, item.getCoreName());
// Update the config accordingly.
UserPreferences.updateConfigFile(ctx);
// Launch the game.
String current_ime = Settings.Secure.getString(ctx.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
Toast.makeText(ctx, String.format(getString(R.string.loading_gamepath), gamePath), Toast.LENGTH_SHORT).show();
Intent myIntent = new Intent(ctx, RetroActivity.class);
myIntent.putExtra("ROM", gamePath);
myIntent.putExtra("LIBRETRO", corePath);
myIntent.putExtra("CONFIGFILE", UserPreferences.getDefaultConfigPath(ctx));
myIntent.putExtra("IME", current_ime);
startActivity(myIntent);
dismiss();
}
};
}

View File

@ -1,409 +0,0 @@
package com.retroarch.browser;
import java.io.*;
import com.retroarch.R;
import com.retroarch.browser.preferences.util.UserPreferences;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceActivity;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;
/**
* {@link PreferenceActivity} subclass that provides all of the
* functionality of the main menu screen.
*/
public final class MainMenuActivity extends PreferenceActivity {
private static MainMenuActivity instance = null;
private static final int ACTIVITY_LOAD_ROM = 0;
private static final int ACTIVITY_RETROARCH = 1;
private static final String TAG = "MainMenu";
private static String libretro_path;
private static String libretro_name;
private void showGPLWaiver() {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle(R.string.gpl_waiver)
.setMessage(R.string.gpl_waiver_desc)
.setPositiveButton("Keep", null)
.setNegativeButton("Remove non-GPL cores",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
final File[] libs = new File(getApplicationInfo().dataDir, "/cores").listFiles();
for (final File lib : libs) {
ModuleWrapper module = new ModuleWrapper(getApplicationContext(), lib);
boolean gplv3 = module.getCoreLicense().equals("GPLv3");
boolean gplv2 = module.getCoreLicense().equals("GPLv2");
if (!gplv3 && !gplv2) {
String libName = lib.getName();
Log.i("GPL WAIVER", "Deleting non-GPL core" + libName + "...");
lib.delete();
}
}
}
});
alert.show();
}
@Override
@SuppressWarnings("deprecation")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the main menu XML.
addPreferencesFromResource(R.xml.main_menu);
// Cache an instance of this class (TODO: Bad practice, kill this somehow).
instance = this;
// Get libretro path and name.
SharedPreferences prefs = UserPreferences.getPreferences(this);
libretro_path = prefs.getString("libretro_path", getApplicationInfo().dataDir + "/cores");
libretro_name = prefs.getString("libretro_name", getString(R.string.no_core));
// Bind audio stream to hardware controls.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
// Extract assets.
extractAssets();
if (!prefs.getBoolean("first_time_refreshrate_calculate", false)) {
prefs.edit().putBoolean("first_time_refreshrate_calculate", true).commit();
if (!detectDevice(false)) {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle(R.string.welcome_to_retroarch)
.setMessage(R.string.welcome_to_retroarch_desc)
.setPositiveButton("OK", null);
alert.show();
}
showGPLWaiver();
}
Intent startedByIntent = getIntent();
if (startedByIntent.getStringExtra("ROM") != null && startedByIntent.getStringExtra("LIBRETRO") != null) {
if (savedInstanceState == null || !savedInstanceState.getBoolean("romexec"))
loadRomExternal(startedByIntent.getStringExtra("ROM"),
startedByIntent.getStringExtra("LIBRETRO"));
else
finish();
}
}
public static MainMenuActivity getInstance() {
return instance;
}
private int getVersionCode() {
int version = 0;
try {
version = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
} catch (NameNotFoundException e) {
}
return version;
}
private boolean areAssetsExtracted() {
int version = getVersionCode();
try {
String dataDir = getApplicationInfo().dataDir;
File cacheVersion = new File(dataDir, ".cacheversion");
if (cacheVersion.isFile() && cacheVersion.canRead() && cacheVersion.canWrite()) {
DataInputStream cacheStream = new DataInputStream(
new FileInputStream(cacheVersion));
int currentCacheVersion = 0;
try {
currentCacheVersion = cacheStream.readInt();
} catch (IOException e) {
}
cacheStream.close();
if (currentCacheVersion == version) {
Log.i("ASSETS", "Assets already extracted, skipping...");
return true;
}
}
} catch (IOException e) {
Log.e(TAG, "Failed to extract assets to cache.");
return false;
}
return false;
}
// Extract assets from native code. Doing it from Java side is apparently unbearably slow ...
private void extractAssetsThread() {
try {
String dataDir = getApplicationInfo().dataDir;
String apk = getApplicationInfo().sourceDir;
Log.i(TAG, "Extracting RetroArch assets from: " + apk + " ...");
boolean success = NativeInterface.extractArchiveTo(apk, "assets", dataDir);
if (!success) {
throw new IOException("Failed to extract assets ...");
}
Log.i(TAG, "Extracted assets ...");
File cacheVersion = new File(dataDir, ".cacheversion");
DataOutputStream outputCacheVersion = new DataOutputStream(
new FileOutputStream(cacheVersion, false));
outputCacheVersion.writeInt(getVersionCode());
outputCacheVersion.close();
} catch (IOException e) {
Log.e(TAG, "Failed to extract assets to cache.");
}
}
private void extractAssets() {
if (areAssetsExtracted())
return;
final Dialog dialog = new Dialog(this);
final Handler handler = new Handler();
dialog.setContentView(R.layout.assets);
dialog.setCancelable(false);
dialog.setTitle("Asset extraction");
// Java is fun :)
Thread assetsThread = new Thread(new Runnable() {
public void run() {
extractAssetsThread();
handler.post(new Runnable() {
public void run() {
dialog.dismiss();
}
});
}
});
assetsThread.start();
dialog.show();
}
public void setModule(String core_path, String core_name) {
UserPreferences.updateConfigFile(this);
libretro_path = core_path;
libretro_name = core_name;
SharedPreferences prefs = UserPreferences.getPreferences(this);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("libretro_path", libretro_path);
edit.putString("libretro_name", libretro_name);
edit.commit();
// Set the title section to contain the name of the selected core.
setCoreTitle(libretro_name);
}
public void setCoreTitle(String core_name) {
setTitle("RetroArch : " + core_name);
}
private boolean detectDevice(boolean show_dialog) {
boolean retval = false;
final Context ctx = this;
final boolean mentionPlayStore = !Build.MODEL.equals("OUYA Console");
final String message = (mentionPlayStore ? getString(R.string.detect_device_msg_general) : getString(R.string.detect_device_msg_ouya));
Log.i("Device MODEL", Build.MODEL);
if (Build.MODEL.equals("SHIELD")) {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle(R.string.nvidia_shield_detected)
.setMessage(message)
.setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("video_refresh_rate", Double.toString(60.00d));
edit.putBoolean("input_overlay_enable", false);
edit.putBoolean("input_autodetect_enable", true);
edit.putString("audio_latency", "64");
edit.putBoolean("audio_latency_auto", true);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
} else if (Build.MODEL.equals("GAMEMID_BT")) {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle(R.string.game_mid_detected)
.setMessage(message)
.setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("input_overlay_enable", false);
edit.putBoolean("input_autodetect_enable", true);
edit.putString("audio_latency", "160");
edit.putBoolean("audio_latency_auto", false);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
} else if (Build.MODEL.equals("OUYA Console")) {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle(R.string.ouya_detected)
.setMessage(message)
.setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("input_overlay_enable", false);
edit.putBoolean("input_autodetect_enable", true);
edit.putString("audio_latency", "64");
edit.putBoolean("audio_latency_auto", true);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
} else if (Build.MODEL.equals("R800x")) {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle(R.string.xperia_play_detected)
.setMessage(message)
.setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("video_threaded", false);
edit.putBoolean("input_overlay_enable", false);
edit.putBoolean("input_autodetect_enable", true);
edit.putString("video_refresh_rate", Double.toString(59.19132938771038));
edit.putString("audio_latency", "128");
edit.putBoolean("audio_latency_auto", false);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
} else if (Build.ID.equals("JSS15J")) {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle(R.string.nexus_7_2013_detected)
.setMessage(message)
.setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferences prefs = UserPreferences.getPreferences(MainMenuActivity.this);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("video_refresh_rate", Double.toString(59.65));
edit.putString("audio_latency", "64");
edit.putBoolean("audio_latency_auto", false);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
}
if (show_dialog) {
Toast.makeText(this, R.string.no_optimal_settings, Toast.LENGTH_SHORT).show();
}
return retval;
}
@Override
public void startActivity(Intent intent) {
if (intent.getComponent().getClassName()
.equals("com.retroarch.browser.diractivities.ROMActivity")) {
if (!new File(libretro_path).isDirectory()) {
super.startActivityForResult(intent, ACTIVITY_LOAD_ROM);
} else {
Toast.makeText(this, R.string.load_a_core_first, Toast.LENGTH_SHORT).show();
}
} else {
super.startActivity(intent);
}
}
@Override
protected void onActivityResult(int reqCode, int resCode, Intent data) {
switch (reqCode) {
case ACTIVITY_LOAD_ROM: {
if (data.getStringExtra("PATH") != null) {
UserPreferences.updateConfigFile(this);
String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
Toast.makeText(this,String.format(getString(R.string.loading_data), data.getStringExtra("PATH")), Toast.LENGTH_SHORT).show();
Intent myIntent = new Intent(this, RetroActivity.class);
myIntent.putExtra("ROM", data.getStringExtra("PATH"));
myIntent.putExtra("LIBRETRO", libretro_path);
myIntent.putExtra("CONFIGFILE", UserPreferences.getDefaultConfigPath(this));
myIntent.putExtra("IME", current_ime);
startActivityForResult(myIntent, ACTIVITY_RETROARCH);
}
break;
}
case ACTIVITY_RETROARCH: {
Log.i(TAG, "RetroArch finished running.");
UserPreferences.readbackConfigFile(this);
break;
}
}
}
@Override
protected void onSaveInstanceState(Bundle data) {
super.onSaveInstanceState(data);
data.putCharSequence("title", getTitle());
data.putBoolean("romexec", true);
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
if (state != null) {
setTitle(state.getCharSequence("title"));
}
}
private void loadRomExternal(String rom, String core) {
UserPreferences.updateConfigFile(this);
String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
Toast.makeText(this, String.format(getString(R.string.loading_data), rom), Toast.LENGTH_SHORT).show();
Intent myIntent = new Intent(this, RetroActivity.class);
myIntent.putExtra("ROM", rom);
myIntent.putExtra("LIBRETRO", core);
myIntent.putExtra("CONFIGFILE", UserPreferences.getDefaultConfigPath(this));
myIntent.putExtra("IME", current_ime);
startActivity(myIntent);
}
}

View File

@ -1,20 +1,24 @@
package com.retroarch.browser;
import com.retroarch.browser.preferences.util.UserPreferences;
import android.app.NativeActivity;
import android.os.Bundle;
public final class RetroActivity extends NativeActivity {
public final class RetroActivity extends NativeActivity
{
@Override
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
public void onDestroy()
{
UserPreferences.readbackConfigFile(this);
}
@Override
public void onLowMemory() {
public void onLowMemory()
{
}
@Override
public void onTrimMemory(int level) {
public void onTrimMemory(int level)
{
}
}

View File

@ -6,51 +6,36 @@ import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
/**
* The {@link Activity} derivative responsible for displaying the TV Mode feature.
*/
public final class RetroTVMode extends Activity {
private static final String TAG = "RetroTVMode";
private static final int ACTIVITY_RETROARCH = 1;
public final class RetroTVMode extends Activity
{
// Need to do this wonky logic as we have to keep this activity alive until
// RetroArch is done running.
// Have to readback config right after RetroArch has run to avoid potential
// broken config state.
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (savedInstanceState == null
|| !savedInstanceState.getBoolean("started", false)) {
if (savedInstanceState == null || !savedInstanceState.getBoolean("started", false))
{
UserPreferences.updateConfigFile(this);
Intent myIntent = new Intent(this, RetroActivity.class);
String current_ime = Settings.Secure.getString(
getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
myIntent.putExtra("CONFIGFILE",
UserPreferences.getDefaultConfigPath(this));
String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
myIntent.putExtra("CONFIGFILE", UserPreferences.getDefaultConfigPath(this));
myIntent.putExtra("IME", current_ime);
startActivityForResult(myIntent, ACTIVITY_RETROARCH);
startActivity(myIntent);
}
}
@Override
protected void onActivityResult(int reqCode, int resCode, Intent data) {
switch (reqCode) {
case ACTIVITY_RETROARCH: {
Log.i(TAG, "RetroArch finished running.");
UserPreferences.readbackConfigFile(this);
finish();
break;
}
}
}
@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
protected void onSaveInstanceState(Bundle savedInstanceState)
{
savedInstanceState.putBoolean("started", true);
}
}

View File

@ -1,271 +0,0 @@
package com.retroarch.browser.diractivities;
import com.retroarch.R;
import com.retroarch.browser.FileWrapper;
import com.retroarch.browser.IconAdapter;
import com.retroarch.browser.preferences.util.UserPreferences;
import java.util.*;
import java.io.*;
import android.content.*;
import android.app.*;
import android.media.AudioManager;
import android.os.*;
import android.widget.*;
import android.view.*;
/**
* {@link ListActivity} subclass that provides a file-browser
* like UI for browsing for specific files.
* <p>
* This file browser also allows for custom filtering
* depending on the type of class that inherits it.
* <p>
* This file browser also uses an implementation of a
* backstack for remembering previously browsed folders
* within this DirectoryActivity.
*/
public class DirectoryActivity extends ListActivity {
private IconAdapter<FileWrapper> adapter;
private File listedDirectory;
public static class BackStackItem implements Parcelable {
private final String path;
private final boolean parentIsBack;
public BackStackItem(String path, boolean parentIsBack) {
this.path = path;
this.parentIsBack = parentIsBack;
}
private BackStackItem(Parcel in) {
this.path = in.readString();
this.parentIsBack = in.readInt() != 0;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(path);
out.writeInt(parentIsBack ? 1 : 0);
}
public static final Parcelable.Creator<BackStackItem> CREATOR = new Parcelable.Creator<BackStackItem>() {
public BackStackItem createFromParcel(Parcel in) {
return new BackStackItem(in);
}
public BackStackItem[] newArray(int size) {
return new BackStackItem[size];
}
};
}
private ArrayList<BackStackItem> backStack;
protected String startDirectory;
protected String pathSettingKey;
protected void setStartDirectory(String path) {
startDirectory = path;
}
protected void setPathSettingKey(String key) {
pathSettingKey = key;
}
private boolean isDirectoryTarget;
protected void setIsDirectoryTarget(boolean enable) {
isDirectoryTarget = enable;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.line_list);
// Setup the list
adapter = new IconAdapter<FileWrapper>(this, R.layout.line_list_item);
setListAdapter(adapter);
// Load Directory
if (savedInstanceState != null) {
backStack = savedInstanceState.getParcelableArrayList("BACKSTACK");
}
if (backStack == null || backStack.isEmpty()) {
backStack = new ArrayList<BackStackItem>();
String startPath = (startDirectory == null || startDirectory.isEmpty()) ? Environment
.getExternalStorageDirectory().getPath() : startDirectory;
backStack.add(new BackStackItem(startPath, false));
}
wrapFiles();
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
@Override
protected void onSaveInstanceState(Bundle aState) {
super.onSaveInstanceState(aState);
aState.putParcelableArrayList("BACKSTACK", backStack);
}
private void finishWithPath(String path) {
if (pathSettingKey != null && !pathSettingKey.isEmpty()) {
SharedPreferences settings = UserPreferences.getPreferences(this);
SharedPreferences.Editor editor = settings.edit();
editor.putString(pathSettingKey, path);
editor.commit();
}
Intent intent = new Intent();
intent.putExtra("PATH", path);
setResult(RESULT_OK, intent);
finish();
}
@Override
public void onListItemClick(ListView listView, View aView, int position, long id) {
final FileWrapper item = adapter.getItem(position);
if (item.isParentItem() && backStack.get(backStack.size() - 1).parentIsBack) {
backStack.remove(backStack.size() - 1);
wrapFiles();
return;
} else if (item.isDirSelectItem()) {
finishWithPath(listedDirectory.getAbsolutePath());
return;
}
final File selected = item.isParentItem() ? listedDirectory.getParentFile() : item.getFile();
if (selected.isDirectory()) {
backStack.add(new BackStackItem(selected.getAbsolutePath(),
!item.isParentItem()));
wrapFiles();
} else {
String filePath = selected.getAbsolutePath();
finishWithPath(filePath);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (backStack.size() > 1) {
backStack.remove(backStack.size() - 1);
wrapFiles();
} else {
Intent intent = new Intent();
setResult(RESULT_CANCELED, intent);
finish();
}
return true;
}
return super.onKeyDown(keyCode, event);
}
private ArrayList<String> allowedExt;
private ArrayList<String> disallowedExt;
private boolean filterPath(String path) {
if (disallowedExt != null) {
for (String ext : disallowedExt)
if (path.endsWith(ext))
return false;
}
if (allowedExt != null) {
for (String ext : allowedExt)
if (path.endsWith(ext))
return true;
return false;
}
return true;
}
/**
* Allows specifying an allowed file extension.
* <p>
* Any files that contain this file extension will be shown
* within the DirectoryActivity file browser. Those that don't
* contain this extension will not be shows.
* <p>
* It is possible to specify more than one allowed extension by
* simply calling this method with a different file extension specified.
*
* @param ext The file extension to allow being shown in this DirectoryActivity.
*/
protected void addAllowedExt(String ext) {
if (allowedExt == null)
allowedExt = new ArrayList<String>();
allowedExt.add(ext);
}
/**
* Allows specifying a disallowed file extension.
* <p>
* Any files that contain this file extension will not be shown
* within the DirectoryActivity file browser.
* <p>
* It is possible to specify more than one disallowed extension by
* simply calling this method with a different file extension specified.
*
* @param ext The file extension to hide from being shown in this DirectoryActivity.
*/
protected void addDisallowedExt(String ext) {
if (disallowedExt == null)
disallowedExt = new ArrayList<String>();
disallowedExt.add(ext);
}
private void wrapFiles() {
listedDirectory = new File(backStack.get(backStack.size() - 1).path);
if (!listedDirectory.isDirectory()) {
throw new IllegalArgumentException("Directory is not valid.");
}
adapter.clear();
setTitle(listedDirectory.getAbsolutePath());
if (isDirectoryTarget)
adapter.add(new FileWrapper(null, FileWrapper.DIRSELECT, true));
if (listedDirectory.getParentFile() != null)
adapter.add(new FileWrapper(null, FileWrapper.PARENT, true));
// Copy new items
final File[] files = listedDirectory.listFiles();
if (files != null) {
for (File file : files) {
String path = file.getName();
boolean allowFile = file.isDirectory() || (filterPath(path) && !isDirectoryTarget);
if (allowFile)
adapter.add(new FileWrapper(file, FileWrapper.FILE, true));
}
}
// Sort items
adapter.sort(new Comparator<FileWrapper>() {
@Override
public int compare(FileWrapper left, FileWrapper right) {
return left.compareTo(right);
};
});
// Update
adapter.notifyDataSetChanged();
}
}

View File

@ -1,24 +0,0 @@
package com.retroarch.browser.diractivities;
import java.io.File;
import android.os.Bundle;
/**
* {@link DirectoryActivity} subclass used for the sole
* purpose of navigating the Android filesystem for input overlays.
* @author Lioncash-yay
*
*/
public final class OverlayActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
File overlayDir = new File(getApplicationInfo().dataDir, "overlays");
if (overlayDir.exists())
super.setStartDirectory(overlayDir.getAbsolutePath());
super.addAllowedExt(".cfg");
super.setPathSettingKey("input_overlay");
super.onCreate(savedInstanceState);
}
}

View File

@ -1,30 +0,0 @@
package com.retroarch.browser.diractivities;
import java.io.File;
import com.retroarch.browser.preferences.util.UserPreferences;
import android.content.SharedPreferences;
import android.os.Bundle;
/**
* {@link DirectoryActivity} subclass used for the sole
* purpose of navigating the Android filesystem for selecting
* a ROM file to execute during emulation.
*/
public final class ROMActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
SharedPreferences prefs = UserPreferences.getPreferences(this);
String startPath = prefs.getString("rgui_browser_directory", "");
if (!startPath.isEmpty() && new File(startPath).exists())
super.setStartDirectory(startPath);
super.addDisallowedExt(".state");
super.addDisallowedExt(".srm");
super.addDisallowedExt(".state.auto");
super.addDisallowedExt(".rtc");
super.onCreate(savedInstanceState);
}
}

View File

@ -1,17 +0,0 @@
package com.retroarch.browser.diractivities;
import android.os.Bundle;
/**
* {@link DirectoryActivity} subclass used for the sole
* purpose of navigating the Android filesystem to select
* a custom ROM directory.
*/
public final class ROMDirActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.setPathSettingKey("rgui_browser_directory");
super.setIsDirectoryTarget(true);
super.onCreate(savedInstanceState);
}
}

View File

@ -1,17 +0,0 @@
package com.retroarch.browser.diractivities;
import android.os.Bundle;
/**
* {@link DirectoryActivity} subclass used for the sole
* purpose of navigating the Android filesystem for selecting
* a custom save file directory.
*/
public final class SRMDirActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.setPathSettingKey("savefile_directory");
super.setIsDirectoryTarget(true);
super.onCreate(savedInstanceState);
}
}

View File

@ -1,23 +0,0 @@
package com.retroarch.browser.diractivities;
import java.io.File;
import android.os.Bundle;
/**
* {@link DirectoryActivity} subclass used for the sole
* purpose of navigating the Android filesystem for selecting
* a shader to use during emulation.
*/
public final class ShaderActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
File shaderDir = new File(getApplicationInfo().dataDir, "shaders_glsl");
if (shaderDir.exists())
super.setStartDirectory(shaderDir.getAbsolutePath());
super.addAllowedExt(".glsl");
super.setPathSettingKey("video_shader");
super.onCreate(savedInstanceState);
}
}

View File

@ -1,17 +0,0 @@
package com.retroarch.browser.diractivities;
import android.os.Bundle;
/**
* {@link DirectoryActivity} subclass used for the sole
* purpose of navigating the Android filesystem to select
* a custom save state directory.
*/
public final class StateDirActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.setPathSettingKey("savestate_directory");
super.setIsDirectoryTarget(true);
super.onCreate(savedInstanceState);
}
}

View File

@ -1,19 +0,0 @@
package com.retroarch.browser.diractivities;
import android.os.Bundle;
/**
* {@link DirectoryActivity} subclass used for the sole
* purpose of navigating the Android filesystem for selecting
* a custom 'System' directory that the cores will look in for
* required files, such as BIOS files and other miscellaneous
* system-required files.
*/
public final class SystemDirActivity extends DirectoryActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.setPathSettingKey("system_directory");
super.setIsDirectoryTarget(true);
super.onCreate(savedInstanceState);
}
}

View File

@ -0,0 +1,371 @@
package com.retroarch.browser.dirfragment;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.ListFragment;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import com.retroarch.R;
import com.retroarch.browser.FileWrapper;
import com.retroarch.browser.IconAdapter;
import com.retroarch.browser.preferences.util.UserPreferences;
import java.util.*;
import java.io.*;
/**
* {@link ListFragment} subclass that provides a file-browser
* like UI for browsing for specific files.
* <p>
* This file browser also allows for custom filtering
* depending on the type of class that inherits it.
* <p>
* This file browser also uses an implementation of a
* backstack for remembering previously browsed folders
* within this DirectoryFragment.
* <p>
* To instantiate a new instance of this class
* you must use the {@code newInstance} method.
*/
public final class DirectoryFragment extends DialogFragment
{
private IconAdapter<FileWrapper> adapter;
private File listedDirectory;
public static final class BackStackItem implements Parcelable
{
private final String path;
private final boolean parentIsBack;
public BackStackItem(String path, boolean parentIsBack)
{
this.path = path;
this.parentIsBack = parentIsBack;
}
private BackStackItem(Parcel in)
{
this.path = in.readString();
this.parentIsBack = in.readInt() != 0;
}
public int describeContents()
{
return 0;
}
public void writeToParcel(Parcel out, int flags)
{
out.writeString(path);
out.writeInt(parentIsBack ? 1 : 0);
}
public static final Parcelable.Creator<BackStackItem> CREATOR = new Parcelable.Creator<BackStackItem>()
{
public BackStackItem createFromParcel(Parcel in)
{
return new BackStackItem(in);
}
public BackStackItem[] newArray(int size)
{
return new BackStackItem[size];
}
};
}
/**
* Listener interface for executing ROMs or performing
* other things upon the DirectoryFragment instance closing.
*/
public interface OnDirectoryFragmentClosedListener
{
/**
* Performs some arbitrary action after the
* {@link DirectoryFragment} closes.
*
* @param path The path to the file chosen within the {@link DirectoryFragment}
*/
void onDirectoryFragmentClosed(String path);
}
private ArrayList<BackStackItem> backStack;
private String startDirectory;
private String pathSettingKey;
public void setStartDirectory(String path)
{
startDirectory = path;
}
public void setPathSettingKey(String key)
{
pathSettingKey = key;
}
private boolean isDirectoryTarget;
public void setIsDirectoryTarget(boolean enable)
{
isDirectoryTarget = enable;
}
private OnDirectoryFragmentClosedListener onClosedListener;
public void setOnDirectoryFragmentClosedListener(OnDirectoryFragmentClosedListener onClosedListener)
{
this.onClosedListener = onClosedListener;
}
/**
* Retrieves a new instance of a DirectoryFragment
* with a title specified by the given resource ID.
*
* @param titleResId String resource ID for the title
* of this DirectoryFragment.
*
* @return A new instance of a DirectoryFragment.
*/
public static DirectoryFragment newInstance(int titleResId)
{
final DirectoryFragment dFrag = new DirectoryFragment();
final Bundle bundle = new Bundle();
bundle.putInt("titleResId", titleResId);
dFrag.setArguments(bundle);
return dFrag;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
ListView rootView = (ListView) inflater.inflate(R.layout.line_list, container, false);
rootView.setOnItemClickListener(onItemClickListener);
// Set the dialog title.
getDialog().setTitle(getArguments().getInt("titleResId"));
// Setup the list
adapter = new IconAdapter<FileWrapper>(getActivity(), R.layout.line_list_item);
rootView.setAdapter(adapter);
// Load Directory
if (savedInstanceState != null)
{
backStack = savedInstanceState.getParcelableArrayList("BACKSTACK");
}
if (backStack == null || backStack.isEmpty())
{
backStack = new ArrayList<BackStackItem>();
String startPath = (startDirectory == null || startDirectory.isEmpty()) ? Environment
.getExternalStorageDirectory().getPath() : startDirectory;
backStack.add(new BackStackItem(startPath, false));
}
wrapFiles();
return rootView;
}
private final OnItemClickListener onItemClickListener = new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
final FileWrapper item = adapter.getItem(position);
if (item.isParentItem() && backStack.get(backStack.size() - 1).parentIsBack)
{
backStack.remove(backStack.size() - 1);
wrapFiles();
return;
}
else if (item.isDirSelectItem())
{
finishWithPath(listedDirectory.getAbsolutePath());
return;
}
final File selected = item.isParentItem() ? listedDirectory.getParentFile() : item.getFile();
if (selected.isDirectory())
{
backStack.add(new BackStackItem(selected.getAbsolutePath(), !item.isParentItem()));
wrapFiles();
}
else
{
String filePath = selected.getAbsolutePath();
finishWithPath(filePath);
}
}
};
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("BACKSTACK", backStack);
}
private void finishWithPath(String path)
{
if (pathSettingKey != null && !pathSettingKey.isEmpty())
{
SharedPreferences settings = UserPreferences.getPreferences(getActivity());
SharedPreferences.Editor editor = settings.edit();
editor.putString(pathSettingKey, path);
editor.commit();
}
if (onClosedListener != null)
{
onClosedListener.onDirectoryFragmentClosed(path);
}
dismiss();
}
// TODO: Hook this up to a callable interface (if backstack is desirable).
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
if (backStack.size() > 1)
{
backStack.remove(backStack.size() - 1);
wrapFiles();
}
return true;
}
return false;
}
private ArrayList<String> allowedExt;
private ArrayList<String> disallowedExt;
private boolean filterPath(String path)
{
if (disallowedExt != null)
{
for (String ext : disallowedExt)
{
if (path.endsWith(ext))
return false;
}
}
if (allowedExt != null)
{
for (String ext : allowedExt)
{
if (path.endsWith(ext))
return true;
}
return false;
}
return true;
}
/**
* Allows specifying an allowed file extension.
* <p>
* Any files that contain this file extension will be shown
* within the DirectoryFragment file browser. Those that don't
* contain this extension will not be shows.
* <p>
* It is possible to specify more than one allowed extension by
* simply calling this method with a different file extension specified.
*
* @param ext The file extension(s) to allow being shown in this DirectoryFragment.
*/
public void addAllowedExts(String... exts)
{
if (allowedExt == null)
allowedExt = new ArrayList<String>();
allowedExt.addAll(Arrays.asList(exts));
}
/**
* Allows specifying a disallowed file extension.
* <p>
* Any files that contain this file extension will not be shown
* within the DirectoryFragment file browser.
* <p>
* It is possible to specify more than one disallowed extension by
* simply calling this method with a different file extension specified.
*
* @param exts The file extension(s) to hide from being shown in this DirectoryFragment.
*/
public void addDisallowedExts(String... exts)
{
if (disallowedExt == null)
disallowedExt = new ArrayList<String>();
disallowedExt.addAll(Arrays.asList(exts));
}
private void wrapFiles()
{
listedDirectory = new File(backStack.get(backStack.size() - 1).path);
if (!listedDirectory.isDirectory())
{
throw new IllegalArgumentException("Directory is not valid.");
}
adapter.clear();
if (isDirectoryTarget)
adapter.add(new FileWrapper(null, FileWrapper.DIRSELECT, true));
if (listedDirectory.getParentFile() != null)
adapter.add(new FileWrapper(null, FileWrapper.PARENT, true));
// Copy new items
final File[] files = listedDirectory.listFiles();
if (files != null)
{
for (File file : files)
{
String path = file.getName();
boolean allowFile = file.isDirectory() || (filterPath(path) && !isDirectoryTarget);
if (allowFile)
{
adapter.add(new FileWrapper(file, FileWrapper.FILE, true));
}
}
}
// Sort items
adapter.sort(new Comparator<FileWrapper>()
{
@Override
public int compare(FileWrapper left, FileWrapper right)
{
return left.compareTo(right);
};
});
// Update
adapter.notifyDataSetChanged();
}
}

View File

@ -0,0 +1,74 @@
package com.retroarch.browser.mainmenu;
import com.retroarch.R;
import com.retroarch.browser.preferences.util.UserPreferences;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
/**
* {@link PreferenceActivity} subclass that provides all of the
* functionality of the main menu screen.
*/
public final class MainMenuActivity extends FragmentActivity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Load the main menu layout
setContentView(R.layout.mainmenu_activity_layout);
if (savedInstanceState == null)
{
final MainMenuFragment mmf = new MainMenuFragment();
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Add the base main menu fragment to the content view.
ft.replace(R.id.content_frame, mmf);
ft.commit();
}
// Bind audio stream to hardware controls.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
public void setModule(String core_path, String core_name)
{
UserPreferences.updateConfigFile(this);
SharedPreferences prefs = UserPreferences.getPreferences(this);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("libretro_path", core_path);
edit.putString("libretro_name", core_name);
edit.commit();
// Set the title section to contain the name of the selected core.
setCoreTitle(core_name);
}
public void setCoreTitle(String core_name)
{
setTitle("RetroArch : " + core_name);
}
@Override
protected void onSaveInstanceState(Bundle data)
{
super.onSaveInstanceState(data);
data.putCharSequence("title", getTitle());
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
setTitle(savedInstanceState.getCharSequence("title"));
}
}

View File

@ -0,0 +1,416 @@
package com.retroarch.browser.mainmenu;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;
import com.retroarch.R;
import com.retroarch.browser.CoreSelection;
import com.retroarch.browser.HistorySelection;
import com.retroarch.browser.ModuleWrapper;
import com.retroarch.browser.NativeInterface;
import com.retroarch.browser.RetroActivity;
import com.retroarch.browser.dirfragment.DirectoryFragment;
import com.retroarch.browser.dirfragment.DirectoryFragment.OnDirectoryFragmentClosedListener;
import com.retroarch.browser.preferences.fragments.util.PreferenceListFragment;
import com.retroarch.browser.preferences.util.UserPreferences;
/**
* Represents the fragment that handles the layout of the main menu.
*/
public final class MainMenuFragment extends PreferenceListFragment implements OnPreferenceClickListener, OnDirectoryFragmentClosedListener
{
private static final String TAG = "MainMenuFragment";
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Add the layout through the XML.
addPreferencesFromResource(R.xml.main_menu);
// Set the listeners for the menu items
findPreference("loadCorePref").setOnPreferenceClickListener(this);
findPreference("loadRomPref").setOnPreferenceClickListener(this);
findPreference("loadRomHistoryPref").setOnPreferenceClickListener(this);
// Extract assets.
extractAssets();
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
if (!prefs.getBoolean("first_time_refreshrate_calculate", false))
{
prefs.edit().putBoolean("first_time_refreshrate_calculate", true).commit();
if (!detectDevice(false))
{
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity())
.setTitle(R.string.welcome_to_retroarch)
.setMessage(R.string.welcome_to_retroarch_desc)
.setPositiveButton(R.string.ok, null);
alert.show();
}
showGPLWaiver();
}
}
private void showGPLWaiver()
{
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity())
.setTitle(R.string.gpl_waiver)
.setMessage(R.string.gpl_waiver_desc)
.setPositiveButton(R.string.keep_cores, null)
.setNegativeButton(R.string.remove_cores, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
final File[] libs = new File(getActivity().getApplicationInfo().dataDir, "/cores").listFiles();
for (final File lib : libs)
{
ModuleWrapper module = new ModuleWrapper(getActivity().getApplicationContext(), lib);
boolean gplv3 = module.getCoreLicense().equals("GPLv3");
boolean gplv2 = module.getCoreLicense().equals("GPLv2");
if (!gplv3 && !gplv2)
{
String libName = lib.getName();
Log.i("GPL WAIVER", "Deleting non-GPL core" + libName + "...");
lib.delete();
}
}
}
});
alert.show();
}
private void extractAssets()
{
if (areAssetsExtracted())
return;
final Dialog dialog = new Dialog(getActivity());
final Handler handler = new Handler();
dialog.setContentView(R.layout.assets);
dialog.setCancelable(false);
dialog.setTitle(R.string.asset_extraction);
// Java is fun :)
Thread assetsThread = new Thread(new Runnable()
{
public void run()
{
extractAssetsThread();
handler.post(new Runnable()
{
public void run()
{
dialog.dismiss();
}
});
}
});
assetsThread.start();
dialog.show();
}
// Extract assets from native code. Doing it from Java side is apparently unbearably slow ...
private void extractAssetsThread()
{
try
{
final String dataDir = getActivity().getApplicationInfo().dataDir;
final String apk = getActivity().getApplicationInfo().sourceDir;
Log.i(TAG, "Extracting RetroArch assets from: " + apk + " ...");
boolean success = NativeInterface.extractArchiveTo(apk, "assets", dataDir);
if (!success) {
throw new IOException("Failed to extract assets ...");
}
Log.i(TAG, "Extracted assets ...");
File cacheVersion = new File(dataDir, ".cacheversion");
DataOutputStream outputCacheVersion = new DataOutputStream(new FileOutputStream(cacheVersion, false));
outputCacheVersion.writeInt(getVersionCode());
outputCacheVersion.close();
}
catch (IOException e)
{
Log.e(TAG, "Failed to extract assets to cache.");
}
}
private boolean areAssetsExtracted()
{
int version = getVersionCode();
try
{
String dataDir = getActivity().getApplicationInfo().dataDir;
File cacheVersion = new File(dataDir, ".cacheversion");
if (cacheVersion.isFile() && cacheVersion.canRead() && cacheVersion.canWrite())
{
DataInputStream cacheStream = new DataInputStream(new FileInputStream(cacheVersion));
int currentCacheVersion = 0;
try
{
currentCacheVersion = cacheStream.readInt();
cacheStream.close();
}
catch (IOException ignored)
{
}
if (currentCacheVersion == version)
{
Log.i("ASSETS", "Assets already extracted, skipping...");
return true;
}
}
}
catch (IOException e)
{
Log.e(TAG, "Failed to extract assets to cache.");
return false;
}
return false;
}
private int getVersionCode()
{
int version = 0;
try
{
final Context ctx = getActivity();
version = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0).versionCode;
}
catch (NameNotFoundException ignored)
{
}
return version;
}
private boolean detectDevice(boolean show_dialog)
{
boolean retval = false;
final Context ctx = getActivity();
final boolean mentionPlayStore = !Build.MODEL.equals("OUYA Console");
final String message = (mentionPlayStore ? getString(R.string.detect_device_msg_general) : getString(R.string.detect_device_msg_ouya));
Log.i("Device MODEL", Build.MODEL);
if (Build.MODEL.equals("SHIELD"))
{
AlertDialog.Builder alert = new AlertDialog.Builder(ctx);
alert.setTitle(R.string.nvidia_shield_detected);
alert.setMessage(message);
alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
SharedPreferences prefs = UserPreferences.getPreferences(ctx);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("video_refresh_rate", Double.toString(60.00d));
edit.putBoolean("input_overlay_enable", false);
edit.putBoolean("input_autodetect_enable", true);
edit.putString("audio_latency", "64");
edit.putBoolean("audio_latency_auto", true);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
}
else if (Build.MODEL.equals("GAMEMID_BT"))
{
AlertDialog.Builder alert = new AlertDialog.Builder(ctx);
alert.setTitle(R.string.game_mid_detected);
alert.setMessage(message);
alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
SharedPreferences prefs = UserPreferences.getPreferences(ctx);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("input_overlay_enable", false);
edit.putBoolean("input_autodetect_enable", true);
edit.putString("audio_latency", "160");
edit.putBoolean("audio_latency_auto", false);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
}
else if (Build.MODEL.equals("OUYA Console"))
{
AlertDialog.Builder alert = new AlertDialog.Builder(ctx);
alert.setTitle(R.string.ouya_detected);
alert.setMessage(message);
alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
SharedPreferences prefs = UserPreferences.getPreferences(ctx);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("input_overlay_enable", false);
edit.putBoolean("input_autodetect_enable", true);
edit.putString("audio_latency", "64");
edit.putBoolean("audio_latency_auto", true);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
}
else if (Build.MODEL.equals("R800x"))
{
AlertDialog.Builder alert = new AlertDialog.Builder(ctx);
alert.setTitle(R.string.xperia_play_detected);
alert.setMessage(message);
alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
SharedPreferences prefs = UserPreferences.getPreferences(ctx);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("video_threaded", false);
edit.putBoolean("input_overlay_enable", false);
edit.putBoolean("input_autodetect_enable", true);
edit.putString("video_refresh_rate", Double.toString(59.19132938771038));
edit.putString("audio_latency", "128");
edit.putBoolean("audio_latency_auto", false);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
}
else if (Build.ID.equals("JSS15J"))
{
AlertDialog.Builder alert = new AlertDialog.Builder(ctx);
alert.setTitle(R.string.nexus_7_2013_detected);
alert.setMessage(message);
alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
SharedPreferences prefs = UserPreferences.getPreferences(ctx);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("video_refresh_rate", Double.toString(59.65));
edit.putString("audio_latency", "64");
edit.putBoolean("audio_latency_auto", false);
edit.commit();
UserPreferences.updateConfigFile(ctx);
}
});
alert.show();
retval = true;
}
if (show_dialog)
{
Toast.makeText(ctx, R.string.no_optimal_settings, Toast.LENGTH_SHORT).show();
}
return retval;
}
@Override
public boolean onPreferenceClick(Preference preference)
{
final String prefKey = preference.getKey();
// Load Core Preference
if (prefKey.equals("loadCorePref"))
{
final CoreSelection coreSelection = new CoreSelection();
coreSelection.show(getFragmentManager(), "core_selection");
}
// Load ROM Preference
else if (prefKey.equals("loadRomPref"))
{
final Context ctx = getActivity();
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
final String libretro_path = prefs.getString("libretro_path", ctx.getApplicationInfo().dataDir + "/cores");
if (!new File(libretro_path).isDirectory())
{
final DirectoryFragment romBrowser = DirectoryFragment.newInstance(R.string.load_game);
romBrowser.addDisallowedExts(".state", ".srm", ".state.auto", ".rtc");
romBrowser.setOnDirectoryFragmentClosedListener(this);
final String startPath = prefs.getString("rgui_browser_directory", "");
if (!startPath.isEmpty() && new File(startPath).exists())
romBrowser.setStartDirectory(startPath);
romBrowser.show(getFragmentManager(), "romBrowser");
}
else
{
Toast.makeText(ctx, R.string.load_a_core_first, Toast.LENGTH_SHORT).show();
}
}
// Load ROM (History) Preference
else if (prefKey.equals("loadRomHistoryPref"))
{
final HistorySelection historySelection = new HistorySelection();
historySelection.show(getFragmentManager(), "history_selection");
}
return true;
}
@Override
public void onDirectoryFragmentClosed(String path)
{
final Context ctx = getActivity();
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
final String libretro_path = prefs.getString("libretro_path", "");
UserPreferences.updateConfigFile(ctx);
String current_ime = Settings.Secure.getString(ctx.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
Toast.makeText(ctx, String.format(getString(R.string.loading_data), path), Toast.LENGTH_SHORT).show();
Intent myIntent = new Intent(ctx, RetroActivity.class);
myIntent.putExtra("ROM", path);
myIntent.putExtra("LIBRETRO", libretro_path);
myIntent.putExtra("CONFIGFILE", UserPreferences.getDefaultConfigPath(ctx));
myIntent.putExtra("IME", current_ime);
startActivity(myIntent);
}
}

View File

@ -1,4 +1,4 @@
package com.retroarch.browser.preferences.fragments;
package com.retroarch.browser.preferences;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
@ -15,6 +15,11 @@ import android.support.v7.app.ActionBar.TabListener;
import android.support.v7.app.ActionBarActivity;
import com.retroarch.R;
import com.retroarch.browser.preferences.fragments.AudioPreferenceFragment;
import com.retroarch.browser.preferences.fragments.GeneralPreferenceFragment;
import com.retroarch.browser.preferences.fragments.InputPreferenceFragment;
import com.retroarch.browser.preferences.fragments.PathPreferenceFragment;
import com.retroarch.browser.preferences.fragments.VideoPreferenceFragment;
import com.retroarch.browser.preferences.fragments.util.PreferenceListFragment;
import com.retroarch.browser.preferences.util.UserPreferences;

View File

@ -1,6 +1,9 @@
package com.retroarch.browser.preferences.fragments;
import java.io.File;
import com.retroarch.R;
import com.retroarch.browser.dirfragment.DirectoryFragment;
import com.retroarch.browser.preferences.fragments.util.PreferenceListFragment;
import android.app.AlertDialog;
@ -14,47 +17,59 @@ import android.view.inputmethod.InputMethodManager;
/**
* A {@link PreferenceListFragment} responsible for handling the input preferences.
*/
public final class InputPreferenceFragment extends PreferenceListFragment
public final class InputPreferenceFragment extends PreferenceListFragment implements OnPreferenceClickListener
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Add input preferences from the XML.
addPreferencesFromResource(R.xml.input_preferences);
// Set Input Method preference
final Preference setImePref = findPreference("set_ime_pref");
setImePref.setOnPreferenceClickListener(new OnPreferenceClickListener()
{
@Override
public boolean onPreferenceClick(Preference preference)
{
// Show an IME picker so the user can change their set IME.
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showInputMethodPicker();
return true;
}
});
// Set preference listeners
findPreference("set_ime_pref").setOnPreferenceClickListener(this);
findPreference("report_ime_pref").setOnPreferenceClickListener(this);
findPreference("inputOverlayDirPref").setOnPreferenceClickListener(this);
}
// Report IME preference
final Preference reportImePref = findPreference("report_ime_pref");
reportImePref.setOnPreferenceClickListener(new OnPreferenceClickListener()
@Override
public boolean onPreferenceClick(Preference preference)
{
final String prefKey = preference.getKey();
// Set Input Method preference
if (prefKey.equals("set_ime_pref"))
{
@Override
public boolean onPreferenceClick(Preference preference)
{
final String currentIme = Settings.Secure.getString(getActivity().getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
AlertDialog.Builder reportImeDialog = new AlertDialog.Builder(getActivity());
reportImeDialog.setTitle(R.string.current_ime);
reportImeDialog.setMessage(currentIme);
reportImeDialog.setNegativeButton(R.string.close, null);
reportImeDialog.show();
return true;
}
});
// Show an IME picker so the user can change their set IME.
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showInputMethodPicker();
}
// Report IME preference
else if (prefKey.equals("report_ime_pref"))
{
final String currentIme = Settings.Secure.getString(getActivity().getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
AlertDialog.Builder reportImeDialog = new AlertDialog.Builder(getActivity());
reportImeDialog.setTitle(R.string.current_ime);
reportImeDialog.setMessage(currentIme);
reportImeDialog.setNegativeButton(R.string.close, null);
reportImeDialog.show();
}
// Input Overlay selection
else if (prefKey.equals("inputOverlayDirPref"))
{
final DirectoryFragment overlayBrowser = DirectoryFragment.newInstance(R.string.input_overlay_select);
File overlayDir = new File(getActivity().getApplicationInfo().dataDir, "overlays");
if (overlayDir.exists())
overlayBrowser.setStartDirectory(overlayDir.getAbsolutePath());
overlayBrowser.addAllowedExts(".cfg");
overlayBrowser.setPathSettingKey("input_overlay");
overlayBrowser.show(getFragmentManager(), "overlayBrowser");
}
return true;
}
}

View File

@ -1,14 +1,17 @@
package com.retroarch.browser.preferences.fragments;
import com.retroarch.R;
import com.retroarch.browser.dirfragment.DirectoryFragment;
import com.retroarch.browser.preferences.fragments.util.PreferenceListFragment;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
/**
* A {@link PreferenceListFragment} that handles the path preferences.
*/
public final class PathPreferenceFragment extends PreferenceListFragment
public final class PathPreferenceFragment extends PreferenceListFragment implements OnPreferenceClickListener
{
@Override
public void onCreate(Bundle savedInstanceState)
@ -17,5 +20,52 @@ public final class PathPreferenceFragment extends PreferenceListFragment
// Add path preferences from the XML.
addPreferencesFromResource(R.xml.path_preferences);
// Set preference click listeners
findPreference("romDirPref").setOnPreferenceClickListener(this);
findPreference("srmDirPref").setOnPreferenceClickListener(this);
findPreference("saveStateDirPref").setOnPreferenceClickListener(this);
findPreference("systemDirPref").setOnPreferenceClickListener(this);
}
@Override
public boolean onPreferenceClick(Preference preference)
{
final String prefKey = preference.getKey();
// Custom ROM directory
if (prefKey.equals("romDirPref"))
{
final DirectoryFragment romDirBrowser = DirectoryFragment.newInstance(R.string.rom_directory_select);
romDirBrowser.setPathSettingKey("rgui_browser_directory");
romDirBrowser.setIsDirectoryTarget(true);
romDirBrowser.show(getFragmentManager(), "romDirBrowser");
}
// Custom savefile directory
else if (prefKey.equals("srmDirPref"))
{
final DirectoryFragment srmDirBrowser = DirectoryFragment.newInstance(R.string.savefile_directory_select);
srmDirBrowser.setPathSettingKey("savefile_directory");
srmDirBrowser.setIsDirectoryTarget(true);
srmDirBrowser.show(getFragmentManager(), "srmDirBrowser");
}
// Custom save state directory
else if (prefKey.equals("saveStateDirPref"))
{
final DirectoryFragment saveStateDirBrowser = DirectoryFragment.newInstance(R.string.save_state_directory_select);
saveStateDirBrowser.setPathSettingKey("savestate_directory");
saveStateDirBrowser.setIsDirectoryTarget(true);
saveStateDirBrowser.show(getFragmentManager(), "saveStateDirBrowser");
}
// Custom system directory
else if (prefKey.equals("systemDirPref"))
{
final DirectoryFragment systemDirBrowser = DirectoryFragment.newInstance(R.string.system_directory_select);
systemDirBrowser.setPathSettingKey("system_directory");
systemDirBrowser.setIsDirectoryTarget(true);
systemDirBrowser.show(getFragmentManager(), "systemDirBrowser");
}
return true;
}
}

View File

@ -1,6 +1,9 @@
package com.retroarch.browser.preferences.fragments;
import java.io.File;
import com.retroarch.R;
import com.retroarch.browser.dirfragment.DirectoryFragment;
import com.retroarch.browser.preferences.fragments.util.PreferenceListFragment;
import android.content.SharedPreferences;
@ -15,7 +18,7 @@ import android.widget.Toast;
/**
* A {@link PreferenceListFragment} responsible for handling the video preferences.
*/
public final class VideoPreferenceFragment extends PreferenceListFragment
public final class VideoPreferenceFragment extends PreferenceListFragment implements OnPreferenceClickListener
{
@Override
public void onCreate(Bundle savedInstanceState)
@ -25,25 +28,44 @@ public final class VideoPreferenceFragment extends PreferenceListFragment
// Add preferences from the resources
addPreferencesFromResource(R.xml.video_preferences);
// Set preference click listeners
findPreference("set_os_reported_ref_rate_pref").setOnPreferenceClickListener(this);
findPreference("glsl_shader_pref").setOnPreferenceClickListener(this);
}
@Override
public boolean onPreferenceClick(Preference preference)
{
final String prefKey = preference.getKey();
// Set OS-reported refresh rate preference.
final Preference osReportedRatePref = findPreference("set_os_reported_ref_rate_pref");
osReportedRatePref.setOnPreferenceClickListener(new OnPreferenceClickListener()
if (prefKey.equals("set_os_reported_ref_rate_pref"))
{
@Override
public boolean onPreferenceClick(Preference preference)
{
final WindowManager wm = getActivity().getWindowManager();
final Display display = wm.getDefaultDisplay();
final double rate = display.getRefreshRate();
final WindowManager wm = getActivity().getWindowManager();
final Display display = wm.getDefaultDisplay();
final double rate = display.getRefreshRate();
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
final SharedPreferences.Editor edit = prefs.edit();
edit.putString("video_refresh_rate", Double.toString(rate));
edit.commit();
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
final SharedPreferences.Editor edit = prefs.edit();
edit.putString("video_refresh_rate", Double.toString(rate));
edit.commit();
Toast.makeText(getActivity(), String.format(getString(R.string.using_os_reported_refresh_rate), rate), Toast.LENGTH_LONG).show();
return true;
}
});
Toast.makeText(getActivity(), String.format(getString(R.string.using_os_reported_refresh_rate), rate), Toast.LENGTH_LONG).show();
}
// GLSL shader selection
else if (prefKey.equals("glsl_shader_pref"))
{
final DirectoryFragment shaderBrowser = DirectoryFragment.newInstance(R.string.glsl_shader_select);
File shaderDir = new File(getActivity().getApplicationInfo().dataDir, "shaders_glsl");
if (shaderDir.exists())
shaderBrowser.setStartDirectory(shaderDir.getAbsolutePath());
shaderBrowser.addAllowedExts(".glsl");
shaderBrowser.setPathSettingKey("video_shader");
shaderBrowser.show(getFragmentManager(), "shaderBrowser");
}
return true;
}
}

View File

@ -1,28 +1,43 @@
package com.retroarch.browser.preferences.fragments.util;
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
package com.retroarch.browser.preferences.fragments.util;
import com.retroarch.R;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.Preference;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.support.v4.app.ListFragment;
import android.support.v4.app.Fragment;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.ViewGroup;
import android.widget.ListView;
public class PreferenceListFragment extends ListFragment
public abstract class PreferenceListFragment extends Fragment implements PreferenceManagerCompat.OnPreferenceTreeClickListener
{
private static final String PREFERENCES_TAG = "android:preferences";
private static final String PREFERENCES_TAG = "android:preferences";
private PreferenceManager mPreferenceManager;
private ListView mList;
private boolean mHavePrefs;
@ -34,7 +49,7 @@ public class PreferenceListFragment extends ListFragment
private static final int FIRST_REQUEST_CODE = 100;
private static final int MSG_BIND_PREFERENCES = 1;
private final Handler mHandler = new Handler()
private Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
@ -48,35 +63,42 @@ public class PreferenceListFragment extends ListFragment
}
};
private final Runnable mRequestFocus = new Runnable()
final private Runnable mRequestFocus = new Runnable()
{
@Override
public void run()
{
mList.focusableViewAvailable(mList);
}
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle b)
/**
* Interface that PreferenceFragment's containing activity should
* implement to be able to process preference items that wish to
* switch to a new fragment.
*/
public interface OnPreferenceStartFragmentCallback
{
View view = inflater.inflate(R.layout.preference_list_content, container, false);
view.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
return view;
/**
* Called when the user has clicked on a Preference that has
* a fragment class name associated with it. The implementation
* to should instantiate and switch to an instance of the given
* fragment.
*/
boolean onPreferenceStartFragment(PreferenceListFragment caller, Preference pref);
}
@Override
public void onDestroyView()
public void onCreate(Bundle paramBundle)
{
super.onDestroyView();
super.onCreate(paramBundle);
mPreferenceManager = PreferenceManagerCompat.newInstance(getActivity(), FIRST_REQUEST_CODE);
PreferenceManagerCompat.setFragment(mPreferenceManager, this);
}
// Kill the list
mList = null;
// Remove callbacks and messages.
mHandler.removeCallbacks(mRequestFocus);
mHandler.removeMessages(MSG_BIND_PREFERENCES);
@Override
public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle)
{
return paramLayoutInflater.inflate(R.layout.preference_list_fragment, paramViewGroup, false);
}
@Override
@ -84,12 +106,10 @@ public class PreferenceListFragment extends ListFragment
{
super.onActivityCreated(savedInstanceState);
if (mHavePrefs)
{
bindPreferences();
if (mHavePrefs) {
bindPreferences();
}
// Done initializing.
mInitDone = true;
if (savedInstanceState != null)
@ -107,47 +127,34 @@ public class PreferenceListFragment extends ListFragment
}
@Override
public void onCreate(Bundle savedInstanceState)
public void onStart()
{
super.onCreate(savedInstanceState);
mPreferenceManager = onCreatePreferenceManager();
postBindPreferences();
super.onStart();
PreferenceManagerCompat.setOnPreferenceTreeClickListener(mPreferenceManager, this);
}
@Override
public void onStop()
{
super.onStop();
PreferenceManagerCompat.dispatchActivityStop(mPreferenceManager);
PreferenceManagerCompat.setOnPreferenceTreeClickListener(mPreferenceManager, null);
}
try
{
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");
m.setAccessible(true);
m.invoke(mPreferenceManager);
}
catch(Exception e)
{
e.printStackTrace();
}
@Override
public void onDestroyView()
{
mList = null;
mHandler.removeCallbacks(mRequestFocus);
mHandler.removeMessages(MSG_BIND_PREFERENCES);
super.onDestroyView();
}
@Override
public void onDestroy()
{
super.onDestroy();
try
{
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");
m.setAccessible(true);
m.invoke(mPreferenceManager);
}
catch(Exception e)
{
e.printStackTrace();
}
PreferenceManagerCompat.dispatchActivityDestroy(mPreferenceManager);
}
@Override
@ -169,69 +176,12 @@ public class PreferenceListFragment extends ListFragment
{
super.onActivityResult(requestCode, resultCode, data);
try
{
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);
m.setAccessible(true);
m.invoke(mPreferenceManager, requestCode, resultCode, data);
}
catch(Exception e)
{
e.printStackTrace();
}
PreferenceManagerCompat.dispatchActivityResult(mPreferenceManager, requestCode, resultCode, data);
}
/**
* Posts a message to bind the preferences to the list view.
* <p>
* Binding late is preferred as any custom preference types created in
* {@link #onCreate(Bundle)} are able to have their views recycled.
*/
private void postBindPreferences()
{
if (mHandler.hasMessages(MSG_BIND_PREFERENCES))
{
return;
}
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}
private void bindPreferences()
{
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null)
{
preferenceScreen.bind(getListView());
}
}
/**
* Creates the {@link PreferenceManager}.
*
* @return The {@link PreferenceManager} used by this fragment.
*/
private PreferenceManager onCreatePreferenceManager()
{
try
{
Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);
c.setAccessible(true);
PreferenceManager preferenceManager = c.newInstance(getActivity(), FIRST_REQUEST_CODE);
return preferenceManager;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
/**
* Gets the {@link PreferenceManager} used by this fragment.
*
* @return The {@link PreferenceManager} used by this fragment.
* Returns the {@link PreferenceManager} used by this fragment.
* @return The {@link PreferenceManager}.
*/
public PreferenceManager getPreferenceManager()
{
@ -240,90 +190,75 @@ public class PreferenceListFragment extends ListFragment
/**
* Sets the root of the preference hierarchy that this fragment is showing.
*
*
* @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
*/
public void setPreferenceScreen(PreferenceScreen preferenceScreen)
{
try
if (PreferenceManagerCompat.setPreferences(mPreferenceManager, preferenceScreen) && preferenceScreen != null)
{
Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);
m.setAccessible(true);
boolean result = (Boolean) m.invoke(mPreferenceManager, preferenceScreen);
if (result && preferenceScreen != null)
mHavePrefs = true;
if (mInitDone)
{
mHavePrefs = true;
if (mInitDone)
{
postBindPreferences();
}
postBindPreferences();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* Gets the root of the preference hierarchy that this fragment is showing.
*
*
* @return The {@link PreferenceScreen} that is the root of the preference
* hierarchy.
*/
public PreferenceScreen getPreferenceScreen()
{
try
{
Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");
m.setAccessible(true);
return (PreferenceScreen) m.invoke(mPreferenceManager);
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
return PreferenceManagerCompat.getPreferenceScreen(mPreferenceManager);
}
/**
* Adds preferences from activities that match the given {@link Intent}.
*
*
* @param intent The {@link Intent} to query activities.
*/
public void addPreferencesFromIntent(Intent intent)
{
throw new UnsupportedOperationException("addPreferencesFromIntent not implemented yet.");
requirePreferenceManager();
setPreferenceScreen(PreferenceManagerCompat.inflateFromIntent(mPreferenceManager, intent, getPreferenceScreen()));
}
/**
* Inflates the given XML resource and adds the preference hierarchy to the current
* preference hierarchy.
*
*
* @param preferencesResId The XML resource ID to inflate.
*/
public void addPreferencesFromResource(int preferencesResId)
{
try
requirePreferenceManager();
setPreferenceScreen(PreferenceManagerCompat.inflateFromResource(mPreferenceManager, getActivity(),
preferencesResId, getPreferenceScreen()));
}
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)
{
//if (preference.getFragment() != null &&
if (getActivity() instanceof OnPreferenceStartFragmentCallback)
{
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
m.setAccessible(true);
PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(mPreferenceManager, getActivity(), preferencesResId, getPreferenceScreen());
setPreferenceScreen(prefScreen);
}
catch(Exception e)
{
e.printStackTrace();
return ((OnPreferenceStartFragmentCallback)getActivity()).onPreferenceStartFragment(
this, preference);
}
return false;
}
/**
* Finds a {@link Preference} based on its key.
*
* @param key The key of the preference to retrieve.
*
* @return The {@link Preference} with the key, or null.
*
* @see PreferenceGroup#findPreference(CharSequence)
*/
public Preference findPreference(CharSequence key)
@ -336,6 +271,29 @@ public class PreferenceListFragment extends ListFragment
return mPreferenceManager.findPreference(key);
}
private void requirePreferenceManager()
{
if (mPreferenceManager == null)
{
throw new RuntimeException("This should be called after super.onCreate.");
}
}
private void postBindPreferences()
{
if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}
private void bindPreferences()
{
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null)
{
preferenceScreen.bind(getListView());
}
}
public ListView getListView()
{
ensureList();
@ -349,24 +307,45 @@ public class PreferenceListFragment extends ListFragment
return;
}
final View root = getView();
View root = getView();
if (root == null)
{
throw new IllegalStateException("Content view not yet created");
}
final View rawListView = root.findViewById(android.R.id.list);
View rawListView = root.findViewById(android.R.id.list);
if (!(rawListView instanceof ListView))
{
throw new RuntimeException("Content has view with id attribute 'android.R.id.list' that is not a ListView class");
throw new RuntimeException(
"Content has view with id attribute 'android.R.id.list' that is not a ListView class");
}
mList = (ListView)rawListView;
if (mList == null)
{
throw new RuntimeException("Your content must have a ListView whose id attribute is 'android.R.id.list'");
throw new RuntimeException(
"Your content must have a ListView whose id attribute is 'android.R.id.list'");
}
mList.setOnKeyListener(mListOnKeyListener);
mHandler.post(mRequestFocus);
}
private OnKeyListener mListOnKeyListener = new OnKeyListener()
{
@Override
public boolean onKey(View v, int keyCode, KeyEvent event)
{
Object selectedItem = mList.getSelectedItem();
if (selectedItem instanceof Preference)
{
@SuppressWarnings("unused")
View selectedView = mList.getSelectedView();
//return ((Preference)selectedItem).onKey(
// selectedView, keyCode, event);
return false;
}
return false;
}
};
}

View File

@ -0,0 +1,275 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.retroarch.browser.preferences.fragments.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.util.Log;
class PreferenceManagerCompat
{
private static final String TAG = PreferenceManagerCompat.class.getSimpleName();
/**
* Interface definition for a callback to be invoked when a
* {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is
* clicked.
*/
interface OnPreferenceTreeClickListener
{
/**
* Called when a preference in the tree rooted at this
* {@link PreferenceScreen} has been clicked.
*
* @param preferenceScreen The {@link PreferenceScreen} that the
* preference is located in.
* @param preference The preference that was clicked.
* @return Whether the click was handled.
*/
boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference);
}
static PreferenceManager newInstance(Activity activity, int firstRequestCode)
{
try
{
Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);
c.setAccessible(true);
return c.newInstance(activity, firstRequestCode);
}
catch (Exception e)
{
Log.w(TAG, "Couldn't call constructor PreferenceManager by reflection", e);
}
return null;
}
/**
* Sets the owning preference fragment
*/
static void setFragment(PreferenceManager manager, PreferenceListFragment fragment)
{
// stub
}
/**
* Sets the callback to be invoked when a {@link Preference} in the
* hierarchy rooted at this {@link PreferenceManager} is clicked.
*
* @param listener The callback to be invoked.
*/
static void setOnPreferenceTreeClickListener(PreferenceManager manager, final OnPreferenceTreeClickListener listener)
{
try
{
Field onPreferenceTreeClickListener = PreferenceManager.class.getDeclaredField("mOnPreferenceTreeClickListener");
onPreferenceTreeClickListener.setAccessible(true);
if (listener != null)
{
Object proxy = Proxy.newProxyInstance(onPreferenceTreeClickListener.getType().getClassLoader(), new Class[] { onPreferenceTreeClickListener.getType() }, new InvocationHandler()
{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
{
if (method.getName().equals("onPreferenceTreeClick"))
{
return Boolean.valueOf(listener.onPreferenceTreeClick((PreferenceScreen) args[0], (Preference) args[1]));
}
else
{
return null;
}
}
});
onPreferenceTreeClickListener.set(manager, proxy);
}
else
{
onPreferenceTreeClickListener.set(manager, null);
}
}
catch (Exception e)
{
Log.w(TAG, "Couldn't set PreferenceManager.mOnPreferenceTreeClickListener by reflection", e);
}
}
/**
* Inflates a preference hierarchy from the preference hierarchies of
* {@link Activity Activities} that match the given {@link Intent}. An
* {@link Activity} defines its preference hierarchy with meta-data using
* the {@link #METADATA_KEY_PREFERENCES} key.
* <p>
* If a preference hierarchy is given, the new preference hierarchies will
* be merged in.
*
* @param queryIntent The intent to match activities.
* @param rootPreferences Optional existing hierarchy to merge the new
* hierarchies into.
* @return The root hierarchy (if one was not provided, the new hierarchy's
* root).
*/
static PreferenceScreen inflateFromIntent(PreferenceManager manager, Intent intent, PreferenceScreen screen)
{
try
{
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class);
m.setAccessible(true);
PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(manager, intent, screen);
return prefScreen;
}
catch (Exception e)
{
Log.w(TAG, "Couldn't call PreferenceManager.inflateFromIntent by reflection", e);
}
return null;
}
/**
* Inflates a preference hierarchy from XML. If a preference hierarchy is
* given, the new preference hierarchies will be merged in.
*
* @param context The context of the resource.
* @param resId The resource ID of the XML to inflate.
* @param rootPreferences Optional existing hierarchy to merge the new
* hierarchies into.
* @return The root hierarchy (if one was not provided, the new hierarchy's
* root).
* @hide
*/
static PreferenceScreen inflateFromResource(PreferenceManager manager, Activity activity, int resId, PreferenceScreen screen)
{
try
{
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
m.setAccessible(true);
PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(manager, activity, resId, screen);
return prefScreen;
}
catch (Exception e)
{
Log.w(TAG, "Couldn't call PreferenceManager.inflateFromResource by reflection", e);
}
return null;
}
/**
* Returns the root of the preference hierarchy managed by this class.
*
* @return The {@link PreferenceScreen} object that is at the root of the hierarchy.
*/
static PreferenceScreen getPreferenceScreen(PreferenceManager manager)
{
try
{
Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");
m.setAccessible(true);
return (PreferenceScreen) m.invoke(manager);
}
catch (Exception e)
{
Log.w(TAG, "Couldn't call PreferenceManager.getPreferenceScreen by reflection", e);
}
return null;
}
/**
* Called by the {@link PreferenceManager} to dispatch a subactivity result.
*/
static void dispatchActivityResult(PreferenceManager manager, int requestCode, int resultCode, Intent data)
{
try
{
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);
m.setAccessible(true);
m.invoke(manager, requestCode, resultCode, data);
}
catch (Exception e)
{
Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityResult by reflection", e);
}
}
/**
* Called by the {@link PreferenceManager} to dispatch the activity stop
* event.
*/
static void dispatchActivityStop(PreferenceManager manager)
{
try
{
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");
m.setAccessible(true);
m.invoke(manager);
}
catch (Exception e)
{
Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityStop by reflection", e);
}
}
/**
* Called by the {@link PreferenceManager} to dispatch the activity destroy
* event.
*/
static void dispatchActivityDestroy(PreferenceManager manager)
{
try
{
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");
m.setAccessible(true);
m.invoke(manager);
}
catch (Exception e)
{
Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityDestroy by reflection", e);
}
}
/**
* Sets the root of the preference hierarchy.
*
* @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
* @return Whether the {@link PreferenceScreen} given is different than the previous.
*/
static boolean setPreferences(PreferenceManager manager, PreferenceScreen screen)
{
try
{
Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);
m.setAccessible(true);
return ((Boolean) m.invoke(manager, screen));
}
catch (Exception e)
{
Log.w(TAG, "Couldn't call PreferenceManager.setPreferences by reflection", e);
}
return false;
}
}