paulscode.android.mupen64plusae.persistent.GlobalPrefs.java Source code

Java tutorial

Introduction

Here is the source code for paulscode.android.mupen64plusae.persistent.GlobalPrefs.java

Source

/**
 * Mupen64PlusAE, an N64 emulator for the Android platform
 *
 * Copyright (C) 2013 Paul Lamb
 *
 * This file is part of Mupen64PlusAE.
 *
 * Mupen64PlusAE is free software: you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Mupen64PlusAE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with Mupen64PlusAE. If
 * not, see <http://www.gnu.org/licenses/>.
 *
 * Authors: littleguy77
 */
package paulscode.android.mupen64plusae.persistent;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.WordUtils;
import org.mupen64plusae.v3.alpha.R;

import paulscode.android.mupen64plusae.ActivityHelper;
import paulscode.android.mupen64plusae.input.map.PlayerMap;
import paulscode.android.mupen64plusae.jni.NativeConstants;
import paulscode.android.mupen64plusae.persistent.AppData.HardwareInfo;
import paulscode.android.mupen64plusae.profile.ControllerProfile;
import paulscode.android.mupen64plusae.util.Plugin;
import paulscode.android.mupen64plusae.util.SafeMethods;
import android.app.Activity;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.support.v7.preference.PreferenceManager;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.KeyEvent;

/**
 * A convenience class for quickly, safely, and consistently retrieving typed user preferences.
 * <p>
 * <b>Developers:</b> After creating a preference in /res/xml/preferences.xml, you are encouraged to
 * provide convenient access to it by expanding this class. Although this adds an extra step to
 * development, it simplifies code maintenance later since all maintenance can be consolidated to a
 * single file. For example, if you change the name of a key, you only need to update one line in
 * this class:
 *
 * <pre>
 * {@code
 * myPreference = mPreferences.getString( "myOldKey", "myFallbackValue" );
 *            --> mPreferences.getString( "myNewKey", "myFallbackValue" );
 * }
 * </pre>
 *
 * Without this class, you would need to search through the entire code base for every call to
 * getString( "myOldKey", ... ) and update each one. This class also ensures that the same fallback
 * value will be used everywhere. A third advantage is that you can easily provide frequently-used
 * "derived" preferences, as in
 *
 * <pre>
 * {@code
 * isMyPreferenceValid = ( myPreference != null ) && ( myPreference.field != someBadValue );
 * }
 * </pre>
 *
 * Finally, the cost of looking up a preference value is made up front in this class's constructor,
 * rather than at the point of use. This could improve application performance if the value is used
 * often, such as the frame refresh loop of a game.
 */
public class GlobalPrefs {
    /** The parent directory containing all user-writable data files. */
    public final String userDataDir;

    /** The subdirectory containing gallery data cache. */
    public final String galleryCacheDir;

    /** The subdirectory containing cover art files. */
    public final String coverArtDir;

    /** The subdirectory containing unzipped ROM files. */
    public final String unzippedRomsDir;

    /** The subdirectory containing custom profiles. */
    public final String profilesDir;

    /** The subdirectory containing crash logs. */
    public final String crashLogDir;

    /** The subdirectory returned from the core's ConfigGetUserDataPath() method. */
    public final String coreUserDataDir;

    /** The subdirectory returned from the core's ConfigGetUserCachePath() method. */
    public final String coreUserCacheDir;

    /** The subdirectory where hi-res textures must be unzipped. */
    public final String hiResTextureDir;

    /** Directory where texture cache htc files are stored */
    public final String textureCacheDir;

    /** The directory containing all custom touchscreen skin folders. */
    public final String touchscreenCustomSkinsDir;

    /** Legacy auto save directory */
    public final String legacyAutoSaves;

    /** Legacy slot save directory */
    public final String legacySlotSaves;

    /** The path of the rom info cache for the gallery. */
    public final String romInfoCache_cfg;

    /** The path of the custom controller profiles file. */
    public final String controllerProfiles_cfg;

    /** The path of the custom touchscreen profiles file. */
    public final String touchscreenProfiles_cfg;

    /** The path of the custom emulation profiles file. */
    public final String emulationProfiles_cfg;

    /** The controller profiles config */
    private ConfigFile mControllerProfilesConfig = null;

    /** The touchscreen profiles config */
    private ConfigFile mTouchscreenProfilesConfig = null;

    /** The emulation profiles config */
    private ConfigFile mEmulationProfilesConfig = null;

    /** The path of the user's custom cheat files. */
    public final String customCheats_txt;

    /** The selected audio plug-in. */
    public final Plugin audioPlugin;

    /** True if the touchscreen feedback is enabled. */
    public final boolean isTouchscreenFeedbackEnabled;

    /** The touchscreen transparency value. */
    public final int touchscreenTransparency;

    /** Factor applied to the final calculated visible touchmap scale. */
    public final float touchscreenScale;

    /** The method used for auto holding buttons. */
    public final int touchscreenAutoHold;

    /** True if a single peripheral device can control multiple players concurrently. */
    public final boolean isControllerShared;

    /** The set of key codes that are not allowed to be mapped. **/
    public final List<Integer> unmappableKeyCodes;

    /** True if the recently played section of the gallery should be shown. */
    public final boolean isRecentShown;

    /** True if the full ROM rip info should be shown. */
    public final boolean isFullNameShown;

    /** The screen orientation for the game activity. */
    public final int displayOrientation;

    /** The vertical screen position. */
    public final int displayPosition;

    /** The action bar transparency value. */
    public final int displayActionBarTransparency;

    /** True if the FPS indicator is displayed. */
    public final boolean isFpsEnabled;

    /** True if immersive mode should be used (KitKat only). */
    public final boolean isImmersiveModeEnabled;

    /** True if framelimiter is used. */
    public final boolean isFramelimiterEnabled;

    /** True if Android polygon offset hack is enabled. **/
    public final boolean isPolygonOffsetHackEnabled;

    /** The manually-overridden hardware type, used for flicker reduction. */
    public final int videoHardwareType;

    /** The polygon offset to use. */
    public final float videoPolygonOffset;

    /** True if the left and right audio channels are swapped. */
    public final boolean audioSwapChannels;

    /** Size of secondary buffer in output samples. This is SDL's hardware buffer, which directly affects latency. */
    public final int audioSDLSecondaryBufferSize;

    /** Size of secondary buffer in output samples. This is SLES's hardware buffer, which directly affects latency. */
    public final int audioSLESSecondaryBufferSize;

    /** Number of SLES secondary buffers. */
    public final int audioSLESSecondaryBufferNbr;

    /** Number of SLES sampling rate. */
    public final int audioSLESSamplingRate;

    /** True if big-screen navigation mode is enabled. */
    public final boolean isBigScreenMode;

    /** Maximum number of auto saves */
    public final int maxAutoSaves;

    /** The input profile for Player 1. */
    public final ControllerProfile controllerProfile1;

    /** The input profile for Player 2. */
    public final ControllerProfile controllerProfile2;

    /** The input profile for Player 3. */
    public final ControllerProfile controllerProfile3;

    /** The input profile for Player 4. */
    public final ControllerProfile controllerProfile4;

    /** The player map for multi-player gaming. */
    public final PlayerMap playerMap;

    // Shared preferences keys and key templates
    private static final String KEY_EMULATION_PROFILE_DEFAULT = "emulationProfileDefault";
    private static final String KEY_TOUCHSCREEN_PROFILE_DEFAULT = "touchscreenProfileDefault";
    private static final String KEY_CONTROLLER_PROFILE_DEFAULT = "controllerProfileDefault";
    private static final String KEYTEMPLATE_PAK_TYPE = "inputPakType%1$d";
    private static final String KEY_PLAYER_MAP_REMINDER = "playerMapReminder";
    private static final String KEY_LOCALE_OVERRIDE = "localeOverride";
    // ... add more as needed

    // Shared preferences default values
    public static final String DEFAULT_EMULATION_PROFILE_DEFAULT = "Glide64-Fast";
    public static final String DEFAULT_TOUCHSCREEN_PROFILE_DEFAULT = AppData.IS_OUYA_HARDWARE ? "" : "Analog";
    public static final String DEFAULT_CONTROLLER_PROFILE_DEFAULT = AppData.IS_OUYA_HARDWARE ? "OUYA" : "";
    public static final int DEFAULT_PAK_TYPE = NativeConstants.PAK_TYPE_MEMORY;
    public static final boolean DEFAULT_PLAYER_MAP_REMINDER = true;
    public static final String DEFAULT_LOCALE_OVERRIDE = "";
    // ... add more as needed

    private final SharedPreferences mPreferences;
    private final Locale mLocale;
    private final String mLocaleCode;
    private final String[] mLocaleNames;
    private final String[] mLocaleCodes;

    //Pak Type
    public enum PakType {
        NONE(NativeConstants.PAK_TYPE_NONE, R.string.menuItem_pak_empty), MEMORY(NativeConstants.PAK_TYPE_MEMORY,
                R.string.menuItem_pak_mem), RAMBLE(NativeConstants.PAK_TYPE_RUMBLE, R.string.menuItem_pak_rumble);

        private final int mNativeValue;
        private final int mResourceStringName;

        PakType(int nativeValue, int resourceStringName) {
            mNativeValue = nativeValue;
            mResourceStringName = resourceStringName;
        }

        public int getNativeValue() {
            return mNativeValue;
        }

        public static PakType getPakTypeFromNativeValue(int nativeValue) {
            switch (nativeValue) {
            case NativeConstants.PAK_TYPE_NONE:
                return NONE;
            case NativeConstants.PAK_TYPE_MEMORY:
                return MEMORY;
            case NativeConstants.PAK_TYPE_RUMBLE:
                return RAMBLE;
            default:
                return NONE;

            }
        }

        public int getResourceString() {
            return mResourceStringName;
        }
    }

    /**
     * Instantiates a new user preferences wrapper.
     *
     * @param context
     *            The application context.
     */
    public GlobalPrefs(Context context, AppData appData) {
        mPreferences = PreferenceManager.getDefaultSharedPreferences(context);

        // Locale
        mLocaleCode = mPreferences.getString(KEY_LOCALE_OVERRIDE, DEFAULT_LOCALE_OVERRIDE);
        mLocale = TextUtils.isEmpty(mLocaleCode) ? Locale.getDefault() : createLocale(mLocaleCode);
        final Locale[] availableLocales = Locale.getAvailableLocales();
        String[] values = context.getResources().getStringArray(R.array.localeOverride_values);
        String[] entries = new String[values.length];
        for (int i = values.length - 1; i > 0; i--) {
            final Locale locale = createLocale(values[i]);

            // Get intersection of languages (available on device) and (translated for Mupen)
            if (ArrayUtils.contains(availableLocales, locale)) {
                // Get the name of the language, as written natively
                entries[i] = WordUtils.capitalize(locale.getDisplayName(locale));
            } else {
                // Remove the item from the list
                entries = (String[]) ArrayUtils.remove(entries, i);
                values = (String[]) ArrayUtils.remove(values, i);
            }
        }
        entries[0] = context.getString(R.string.localeOverride_entrySystemDefault);
        mLocaleNames = entries;
        mLocaleCodes = values;

        // Files
        userDataDir = mPreferences.getString("pathGameSaves", "");
        galleryCacheDir = userDataDir + "/GalleryCache";
        coverArtDir = galleryCacheDir + "/CoverArt";
        unzippedRomsDir = galleryCacheDir + "/UnzippedRoms";
        profilesDir = userDataDir + "/Profiles";
        crashLogDir = userDataDir + "/CrashLogs";
        coreUserDataDir = userDataDir + "/CoreConfig/UserData";
        coreUserCacheDir = userDataDir + "/CoreConfig/UserCache";
        hiResTextureDir = coreUserDataDir + "/mupen64plus/hires_texture/"; // MUST match what rice assumes natively
        textureCacheDir = coreUserCacheDir + "/mupen64plus/cache";
        romInfoCache_cfg = galleryCacheDir + "/romInfoCache.cfg";
        controllerProfiles_cfg = profilesDir + "/controller.cfg";
        touchscreenProfiles_cfg = profilesDir + "/touchscreen.cfg";
        emulationProfiles_cfg = profilesDir + "/emulation.cfg";
        customCheats_txt = profilesDir + "/customCheats.txt";
        touchscreenCustomSkinsDir = userDataDir + "/CustomSkins";
        legacyAutoSaves = userDataDir + "/AutoSaves";
        legacySlotSaves = userDataDir + "/SlotSaves";

        // Plug-ins
        audioPlugin = new Plugin(mPreferences, appData.libsDir, "audioPlugin");

        // Library prefs
        isRecentShown = mPreferences.getBoolean("showRecentlyPlayed", true);
        isFullNameShown = mPreferences.getBoolean("showFullNames", true);

        // Touchscreen prefs
        isTouchscreenFeedbackEnabled = mPreferences.getBoolean("touchscreenFeedback", false);
        touchscreenScale = (mPreferences.getInt("touchscreenScale", 100)) / 100.0f;
        touchscreenTransparency = (255 * mPreferences.getInt("touchscreenTransparency", 100)) / 100;
        touchscreenAutoHold = getSafeInt(mPreferences, "touchscreenAutoHold", 0);

        // Video prefs
        displayOrientation = getSafeInt(mPreferences, "displayOrientation", 0);
        displayPosition = getSafeInt(mPreferences, "displayPosition", Gravity.CENTER_VERTICAL);
        final int transparencyPercent = mPreferences.getInt("displayActionBarTransparency", 50);
        displayActionBarTransparency = (255 * transparencyPercent) / 100;
        isFpsEnabled = mPreferences.getBoolean("displayFps", false);
        final int selectedHardwareType = getSafeInt(mPreferences, "videoHardwareType", -1);
        isPolygonOffsetHackEnabled = selectedHardwareType > -2;
        videoHardwareType = selectedHardwareType < 0 ? appData.hardwareInfo.hardwareType : selectedHardwareType;
        switch (videoHardwareType) {
        case HardwareInfo.HARDWARE_TYPE_OMAP:
            videoPolygonOffset = 0.2f;
            break;
        case HardwareInfo.HARDWARE_TYPE_OMAP_2:
            videoPolygonOffset = -1.5f;
            break;
        case HardwareInfo.HARDWARE_TYPE_QUALCOMM:
            videoPolygonOffset = -0.2f;
            break;
        case HardwareInfo.HARDWARE_TYPE_IMAP:
            videoPolygonOffset = -0.001f;
            break;
        case HardwareInfo.HARDWARE_TYPE_TEGRA:
            videoPolygonOffset = -2.0f;
            break;
        case HardwareInfo.HARDWARE_TYPE_UNKNOWN:
            videoPolygonOffset = -1.5f;
            break;
        default:
            videoPolygonOffset = SafeMethods.toFloat(mPreferences.getString("videoPolygonOffset", "-1.5"), -1.5f);
            break;
        }
        isImmersiveModeEnabled = mPreferences.getBoolean("displayImmersiveMode", false);

        // Audio prefs
        audioSwapChannels = mPreferences.getBoolean("audioSwapChannels", false);
        audioSDLSecondaryBufferSize = getSafeInt(mPreferences, "audioSDLBufferSize", 2048);
        audioSLESSecondaryBufferSize = getSafeInt(mPreferences, "audioSLESBufferSize2", 256);
        audioSLESSecondaryBufferNbr = getSafeInt(mPreferences, "audioSLESBufferNbr2", 20);
        audioSLESSamplingRate = getSafeInt(mPreferences, "audioSLESSamplingRate", 0);

        if (audioPlugin.enabled)
            isFramelimiterEnabled = !mPreferences.getBoolean("audioSynchronize", true);
        else
            isFramelimiterEnabled = !mPreferences.getString("audioPlugin", "").equals("nospeedlimit");

        // User interface modes
        final String navMode = mPreferences.getString("navigationMode", "auto");
        if (navMode.equals("bigscreen"))
            isBigScreenMode = true;
        else if (navMode.equals("standard"))
            isBigScreenMode = false;
        else
            isBigScreenMode = AppData.IS_OUYA_HARDWARE || appData.isAndroidTv; // TODO: Add other systems as they enter market

        // Peripheral share mode
        isControllerShared = mPreferences.getBoolean("inputShareController", false);

        maxAutoSaves = mPreferences.getInt("gameAutoSaves", 5);

        // Determine the key codes that should not be mapped to controls
        final boolean volKeysMappable = mPreferences.getBoolean("inputVolumeMappable", false);
        final List<Integer> unmappables = new ArrayList<>();
        unmappables.add(KeyEvent.KEYCODE_MENU);

        // Back key is needed to show/hide the action bar in HC+
        unmappables.add(KeyEvent.KEYCODE_BACK);

        if (!volKeysMappable) {
            unmappables.add(KeyEvent.KEYCODE_VOLUME_UP);
            unmappables.add(KeyEvent.KEYCODE_VOLUME_DOWN);
            unmappables.add(KeyEvent.KEYCODE_VOLUME_MUTE);
        }
        unmappableKeyCodes = Collections.unmodifiableList(unmappables);

        // Controller profiles
        controllerProfile1 = loadControllerProfile(mPreferences, GamePrefs.CONTROLLER_PROFILE1,
                getControllerProfileDefault(1), GetControllerProfilesConfig(),
                appData.GetControllerProfilesConfig());
        controllerProfile2 = loadControllerProfile(mPreferences, GamePrefs.CONTROLLER_PROFILE2,
                getControllerProfileDefault(2), GetControllerProfilesConfig(),
                appData.GetControllerProfilesConfig());
        controllerProfile3 = loadControllerProfile(mPreferences, GamePrefs.CONTROLLER_PROFILE3,
                getControllerProfileDefault(3), GetControllerProfilesConfig(),
                appData.GetControllerProfilesConfig());
        controllerProfile4 = loadControllerProfile(mPreferences, GamePrefs.CONTROLLER_PROFILE4,
                getControllerProfileDefault(4), GetControllerProfilesConfig(),
                appData.GetControllerProfilesConfig());

        // Player map
        playerMap = new PlayerMap(mPreferences.getString(GamePrefs.PLAYER_MAP, ""));

        // Determine whether controller deconfliction is needed
        int numControllers = 0;
        numControllers += controllerProfile1 != null ? 1 : 0;
        numControllers += controllerProfile2 != null ? 1 : 0;
        numControllers += controllerProfile3 != null ? 1 : 0;
        numControllers += controllerProfile4 != null ? 1 : 0;

        playerMap.setEnabled(numControllers > 1 && !isControllerShared);
    }

    public void enforceLocale(Activity activity) {
        final Configuration config = activity.getBaseContext().getResources().getConfiguration();
        if (!mLocale.equals(config.locale)) {
            config.locale = mLocale;
            activity.getBaseContext().getResources().updateConfiguration(config, null);
        }
    }

    public void changeLocale(final Activity activity) {
        // Get the index of the current locale
        final int currentIndex = ArrayUtils.indexOf(mLocaleCodes, mLocaleCode);

        // Populate and show the language menu
        final Builder builder = new Builder(activity);
        builder.setTitle(R.string.menuItem_localeOverride);
        builder.setSingleChoiceItems(mLocaleNames, currentIndex, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                if (which >= 0 && which != currentIndex) {
                    mPreferences.edit().putString(KEY_LOCALE_OVERRIDE, mLocaleCodes[which]).apply();
                    ActivityHelper.restartActivity(activity);
                }
            }
        });
        builder.create().show();
    }

    public String getEmulationProfileDefault() {
        return getString(KEY_EMULATION_PROFILE_DEFAULT, DEFAULT_EMULATION_PROFILE_DEFAULT);
    }

    public String getTouchscreenProfileDefault() {
        return getString(KEY_TOUCHSCREEN_PROFILE_DEFAULT, DEFAULT_TOUCHSCREEN_PROFILE_DEFAULT);
    }

    public String getControllerProfileDefault(int player) {
        switch (player) {
        case 2:
            return getString(GamePrefs.CONTROLLER_PROFILE2, DEFAULT_CONTROLLER_PROFILE_DEFAULT);
        case 3:
            return getString(GamePrefs.CONTROLLER_PROFILE3, DEFAULT_CONTROLLER_PROFILE_DEFAULT);
        case 4:
            return getString(GamePrefs.CONTROLLER_PROFILE4, DEFAULT_CONTROLLER_PROFILE_DEFAULT);
        default:
            break;
        }

        return getString(GamePrefs.CONTROLLER_PROFILE1,
                getString(KEY_CONTROLLER_PROFILE_DEFAULT, DEFAULT_CONTROLLER_PROFILE_DEFAULT));
    }

    public PakType getPakType(int player) {
        return PakType.getPakTypeFromNativeValue(getInt(KEYTEMPLATE_PAK_TYPE, player, DEFAULT_PAK_TYPE));
    }

    public boolean getPlayerMapReminder() {
        return getBoolean(KEY_PLAYER_MAP_REMINDER, DEFAULT_PLAYER_MAP_REMINDER);
    }

    public void putEmulationProfileDefault(String value) {
        putString(KEY_EMULATION_PROFILE_DEFAULT, value);
    }

    public void putTouchscreenProfileDefault(String value) {
        putString(KEY_TOUCHSCREEN_PROFILE_DEFAULT, value);
    }

    public void putControllerProfileDefault(String value) {
        putString(GamePrefs.CONTROLLER_PROFILE1, value);
    }

    public void putPakType(int player, PakType pakType) {
        putInt(KEYTEMPLATE_PAK_TYPE, player, pakType.getNativeValue());
    }

    public void putPlayerMapReminder(boolean value) {
        putBoolean(KEY_PLAYER_MAP_REMINDER, value);
    }

    public boolean getBoolean(String key, boolean defaultValue) {
        return mPreferences.getBoolean(key, defaultValue);
    }

    public int getInt(String keyTemplate, int index, int defaultValue) {
        final String key = String.format(Locale.US, keyTemplate, index);
        return mPreferences.getInt(key, defaultValue);
    }

    public String getString(String key, String defaultValue) {
        return mPreferences.getString(key, defaultValue);
    }

    private void putBoolean(String key, boolean value) {
        mPreferences.edit().putBoolean(key, value).apply();
    }

    private void putInt(String keyTemplate, int index, int value) {
        final String key = String.format(Locale.US, keyTemplate, index);
        mPreferences.edit().putInt(key, value).apply();
    }

    private void putString(String key, String value) {
        mPreferences.edit().putString(key, value).apply();
    }

    private Locale createLocale(String code) {
        final String[] codes = code.split("_");
        switch (codes.length) {
        case 1: // Language code provided
            return new Locale(codes[0]);
        case 2: // Language and country code provided
            return new Locale(codes[0], codes[1]);
        case 3: // Language, country, and variant code provided
            return new Locale(codes[0], codes[1], codes[2]);
        default: // Invalid input
            return null;
        }
    }

    /**
     * Gets the selected value of a ListPreference, as an integer.
     *
     * @param preferences  The object containing the ListPreference.
     * @param key          The key of the ListPreference.
     * @param defaultValue The value to use if parsing fails.
     *
     * @return The value of the selected entry, as an integer.
     */
    private static int getSafeInt(SharedPreferences preferences, String key, int defaultValue) {
        try {
            return Integer.parseInt(preferences.getString(key, String.valueOf(defaultValue)));
        } catch (final NumberFormatException ex) {
            return defaultValue;
        }
    }

    public ConfigFile GetEmulationProfilesConfig() {
        if (mEmulationProfilesConfig == null) {
            mEmulationProfilesConfig = new ConfigFile(emulationProfiles_cfg);
        }

        return mEmulationProfilesConfig;
    }

    public ConfigFile GetTouchscreenProfilesConfig() {
        if (mTouchscreenProfilesConfig == null) {
            mTouchscreenProfilesConfig = new ConfigFile(touchscreenProfiles_cfg);
        }

        return mTouchscreenProfilesConfig;
    }

    public ConfigFile GetControllerProfilesConfig() {
        if (mControllerProfilesConfig == null) {
            mControllerProfilesConfig = new ConfigFile(controllerProfiles_cfg);
        }

        return mControllerProfilesConfig;
    }

    private static ControllerProfile loadControllerProfile(SharedPreferences prefs, String key, String defaultName,
            ConfigFile custom, ConfigFile builtin) {
        final String name = prefs.getString(key, defaultName);

        if (custom.keySet().contains(name))
            return new ControllerProfile(false, custom.get(name));
        else if (builtin.keySet().contains(name))
            return new ControllerProfile(true, builtin.get(name));
        else if (custom.keySet().contains(defaultName))
            return new ControllerProfile(false, custom.get(defaultName));
        else if (builtin.keySet().contains(defaultName))
            return new ControllerProfile(true, builtin.get(defaultName));
        else
            return null;
    }
}