diff options
Diffstat (limited to 'Source/Android/app/src/main/java')
9 files changed, 208 insertions, 9 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/DolphinApplication.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/DolphinApplication.java index 22ee55cb70..3fd6e2192b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/DolphinApplication.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/DolphinApplication.java @@ -1,17 +1,28 @@ package org.dolphinemu.dolphinemu; import android.app.Application; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; import org.dolphinemu.dolphinemu.services.DirectoryInitializationService; import org.dolphinemu.dolphinemu.utils.PermissionsHandler; +import org.dolphinemu.dolphinemu.utils.VolleyUtil; public class DolphinApplication extends Application { + public static final String FIRST_OPEN = "FIRST_OPEN"; @Override public void onCreate() { super.onCreate(); + // Passed at emulation start to trigger first open event. + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + SharedPreferences.Editor sPrefsEditor = preferences.edit(); + sPrefsEditor.putBoolean(FIRST_OPEN, true); + sPrefsEditor.apply(); + + VolleyUtil.init(getApplicationContext()); System.loadLibrary("main"); if (PermissionsHandler.hasWriteAccess(getApplicationContext())) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index c986857e75..922c041a7b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -322,7 +322,7 @@ public final class NativeLibrary /** * Begins emulation. */ - public static native void Run(String path); + public static native void Run(String path, boolean firstOpen); /** * Begins emulation from the specified savestate. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java index 5d960a3b9f..599559030a 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java @@ -27,13 +27,15 @@ public class Settings public static final String SECTION_BINDINGS = "Android"; + public static final String SECTION_ANALYTICS = "Analytics"; + private String gameId; private static final Map<String, List<String>> configFileSectionsMap = new HashMap<>(); static { - configFileSectionsMap.put(SettingsFile.FILE_NAME_DOLPHIN, Arrays.asList(SECTION_INI_CORE, SECTION_INI_INTERFACE, SECTION_BINDINGS)); + configFileSectionsMap.put(SettingsFile.FILE_NAME_DOLPHIN, Arrays.asList(SECTION_INI_CORE, SECTION_INI_INTERFACE, SECTION_BINDINGS, SECTION_ANALYTICS)); configFileSectionsMap.put(SettingsFile.FILE_NAME_GFX, Arrays.asList(SECTION_GFX_SETTINGS, SECTION_GFX_ENHANCEMENTS, SECTION_GFX_HACKS, SECTION_STEREOSCOPY)); configFileSectionsMap.put(SettingsFile.FILE_NAME_WIIMOTE, Arrays.asList(SECTION_WIIMOTE + 1, SECTION_WIIMOTE + 2, SECTION_WIIMOTE + 3, SECTION_WIIMOTE + 4)); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java index fbdaf8ad92..98d62ccfd1 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java @@ -210,14 +210,17 @@ public final class SettingsFragmentPresenter Setting overclock = null; Setting speedLimit = null; Setting audioStretch = null; + Setting analytics = null; SettingSection coreSection = mSettings.getSection(Settings.SECTION_INI_CORE); + SettingSection analyticsSection = mSettings.getSection(Settings.SECTION_ANALYTICS); cpuCore = coreSection.getSetting(SettingsFile.KEY_CPU_CORE); dualCore = coreSection.getSetting(SettingsFile.KEY_DUAL_CORE); overclockEnable = coreSection.getSetting(SettingsFile.KEY_OVERCLOCK_ENABLE); overclock = coreSection.getSetting(SettingsFile.KEY_OVERCLOCK_PERCENT); speedLimit = coreSection.getSetting(SettingsFile.KEY_SPEED_LIMIT); audioStretch = coreSection.getSetting(SettingsFile.KEY_AUDIO_STRETCH); + analytics = analyticsSection.getSetting(SettingsFile.KEY_ANALYTICS_ENABLED); // TODO: Having different emuCoresEntries/emuCoresValues for each architecture is annoying. // The proper solution would be to have one emuCoresEntries and one emuCoresValues @@ -246,6 +249,7 @@ public final class SettingsFragmentPresenter sl.add(new SliderSetting(SettingsFile.KEY_OVERCLOCK_PERCENT, Settings.SECTION_INI_CORE, R.string.overclock_title, R.string.overclock_title_description, 400, "%", 100, overclock)); sl.add(new SliderSetting(SettingsFile.KEY_SPEED_LIMIT, Settings.SECTION_INI_CORE, R.string.speed_limit, 0, 200, "%", 100, speedLimit)); sl.add(new CheckBoxSetting(SettingsFile.KEY_AUDIO_STRETCH, Settings.SECTION_INI_CORE, R.string.audio_stretch, R.string.audio_stretch_description, false, audioStretch)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_ANALYTICS_ENABLED, Settings.SECTION_ANALYTICS, R.string.analytics, 0, false, analytics)); } private void addInterfaceSettings(ArrayList<SettingsItem> sl) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java index 2260b413f7..b68c879716 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java @@ -50,6 +50,9 @@ public final class SettingsFile public static final String KEY_SLOT_A_DEVICE = "SlotA"; public static final String KEY_SLOT_B_DEVICE = "SlotB"; + public static final String KEY_ANALYTICS_ENABLED = "Enabled"; + public static final String KEY_ANALYTICS_PERMISSION_ASKED = "PermissionAsked"; + public static final String KEY_USE_PANIC_HANDLERS = "UsePanicHandlers"; public static final String KEY_OSD_MESSAGES = "OnScreenDisplayMessages"; @@ -294,12 +297,14 @@ public final class SettingsFile catch (FileNotFoundException e) { Log.error("[SettingsFile] File not found: " + ini.getAbsolutePath() + e.getMessage()); - view.onSettingsFileNotFound(); + if (view != null) + view.onSettingsFileNotFound(); } catch (IOException e) { Log.error("[SettingsFile] Error reading from: " + ini.getAbsolutePath()+ e.getMessage()); - view.onSettingsFileNotFound(); + if (view != null) + view.onSettingsFileNotFound(); } finally { @@ -384,12 +389,14 @@ public final class SettingsFile catch (FileNotFoundException e) { Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage()); - view.showToastMessage("Error saving " + fileName + ".ini: " + e.getMessage()); + if (view != null) + view.showToastMessage("Error saving " + fileName + ".ini: " + e.getMessage()); } catch (UnsupportedEncodingException e) { Log.error("[SettingsFile] Bad encoding; please file a bug report: " + fileName + ".ini: " + e.getMessage()); - view.showToastMessage("Error saving " + fileName + ".ini: " + e.getMessage()); + if (view != null) + view.showToastMessage("Error saving " + fileName + ".ini: " + e.getMessage()); } finally { @@ -489,6 +496,23 @@ public final class SettingsFile sections.put(Settings.SECTION_INI_CORE, coreSection); } + public static void firstAnalyticsAdd(boolean enabled) + { + HashMap<String, SettingSection> dolphinSections = readFile(SettingsFile.FILE_NAME_DOLPHIN, null); + SettingSection analyticsSection = dolphinSections.get(Settings.SECTION_ANALYTICS); + + Setting analyticsEnabled = new StringSetting(KEY_ANALYTICS_ENABLED, Settings.SECTION_ANALYTICS, enabled ? "True" : "False"); + Setting analyticsFirstAsk = new StringSetting(KEY_ANALYTICS_PERMISSION_ASKED, Settings.SECTION_ANALYTICS, "True"); + + analyticsSection.putSetting(analyticsFirstAsk); + analyticsSection.putSetting(analyticsEnabled); + + dolphinSections.put(Settings.SECTION_ANALYTICS, analyticsSection); + + TreeMap<String, SettingSection> saveSection = new TreeMap<>(dolphinSections); + saveFile(SettingsFile.FILE_NAME_DOLPHIN, saveSection, null); + } + /** * For a line of text, determines what type of data is being represented, and returns * a Setting object containing this data. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index c7e13a9999..15e5980acc 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -16,6 +16,7 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.Toast; +import org.dolphinemu.dolphinemu.DolphinApplication; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.EmulationActivity; @@ -84,7 +85,12 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); String gamePath = getArguments().getString(KEY_GAMEPATH); - mEmulationState = new EmulationState(gamePath, getTemporaryStateFilePath()); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + boolean firstOpen = preferences.getBoolean(DolphinApplication.FIRST_OPEN, true); + SharedPreferences.Editor sPrefsEditor = preferences.edit(); + sPrefsEditor.putBoolean(DolphinApplication.FIRST_OPEN, false); + sPrefsEditor.apply(); + mEmulationState = new EmulationState(gamePath, getTemporaryStateFilePath(), firstOpen); } /** @@ -264,10 +270,12 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C private Surface mSurface; private boolean mRunWhenSurfaceIsValid; private boolean loadPreviousTemporaryState; + private boolean firstOpen; private final String temporaryStatePath; - EmulationState(String gamePath, String temporaryStatePath) + EmulationState(String gamePath, String temporaryStatePath, boolean firstOpen) { + this.firstOpen = firstOpen; mGamePath = gamePath; this.temporaryStatePath = temporaryStatePath; // Starting state is stopped. @@ -411,7 +419,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C else { Log.debug("[EmulationFragment] Starting emulation thread."); - NativeLibrary.Run(mGamePath); + NativeLibrary.Run(mGamePath, firstOpen); } }, "NativeEmulation"); mEmulationThread.start(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Analytics.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Analytics.java new file mode 100644 index 0000000000..158e7c2055 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Analytics.java @@ -0,0 +1,125 @@ +package org.dolphinemu.dolphinemu.utils; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.os.Build; +import android.preference.PreferenceManager; +import android.support.v4.content.LocalBroadcastManager; + +import com.android.volley.Request; +import com.android.volley.toolbox.StringRequest; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.features.settings.model.Settings; +import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; +import org.dolphinemu.dolphinemu.services.DirectoryInitializationService; + +public class Analytics +{ + private static DirectoryStateReceiver directoryStateReceiver; + + private static final String analyticsAsked = Settings.SECTION_ANALYTICS + "_" + SettingsFile.KEY_ANALYTICS_PERMISSION_ASKED; + private static final String analyticsEnabled = Settings.SECTION_ANALYTICS + "_" + SettingsFile.KEY_ANALYTICS_ENABLED; + + private static final String DEVICE_MANUFACTURER = "DEVICE_MANUFACTURER"; + private static final String DEVICE_OS = "DEVICE_OS"; + private static final String DEVICE_MODEL = "DEVICE_MODEL"; + private static final String DEVICE_TYPE = "DEVICE_TYPE"; + + private static String deviceType; + + public static void checkAnalyticsInit(Context context) + { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + if (!preferences.getBoolean(analyticsAsked, false)) + { + if (!DirectoryInitializationService.areDolphinDirectoriesReady()) + { + // Wait for directories to get initialized + IntentFilter statusIntentFilter = new IntentFilter( + DirectoryInitializationService.BROADCAST_ACTION); + + directoryStateReceiver = new DirectoryStateReceiver(directoryInitializationState -> + { + if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) + { + LocalBroadcastManager.getInstance(context).unregisterReceiver(directoryStateReceiver); + directoryStateReceiver = null; + showMessage(context, preferences); + } + }); + // Registers the DirectoryStateReceiver and its intent filters + LocalBroadcastManager.getInstance(context).registerReceiver( + directoryStateReceiver, + statusIntentFilter); + } + else + { + showMessage(context, preferences); + } + } + // Get device type now since we have a context + deviceType = TvUtil.isLeanback(context) ? "android-tv" : "android-mobile"; + } + + private static void showMessage(Context context, SharedPreferences preferences) + { + // We asked, set to true regardless of answer + SharedPreferences.Editor sPrefsEditor = preferences.edit(); + sPrefsEditor.putBoolean(analyticsAsked, true); + sPrefsEditor.apply(); + + new AlertDialog.Builder(context) + .setTitle(context.getString(R.string.analytics)) + .setMessage(context.getString(R.string.analytics_desc)) + .setPositiveButton(R.string.yes, (dialogInterface, i) -> + { + sPrefsEditor.putBoolean(analyticsEnabled, true); + sPrefsEditor.apply(); + SettingsFile.firstAnalyticsAdd(true); + }) + .setNegativeButton(R.string.no, (dialogInterface, i) -> + { + sPrefsEditor.putBoolean(analyticsEnabled, false); + sPrefsEditor.apply(); + SettingsFile.firstAnalyticsAdd(false); + }) + .create() + .show(); + } + + public static void sendReport(String endpoint, byte[] data) + { + StringRequest request = new StringRequest(Request.Method.POST, endpoint, + null, error -> Log.debug("Send Report Failure code: " + + error.networkResponse.statusCode)) + { + @Override + public byte[] getBody() + { + return data; + } + }; + + VolleyUtil.getQueue().add(request); + } + + public static String getValue(String key) + { + switch (key) + { + case DEVICE_MODEL: + return Build.MODEL; + case DEVICE_MANUFACTURER: + return Build.MANUFACTURER; + case DEVICE_OS: + return String.valueOf(Build.VERSION.SDK_INT); + case DEVICE_TYPE: + return deviceType; + default: + return ""; + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java index 1be60cd21f..232de7f347 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java @@ -14,6 +14,9 @@ public final class StartupHandler // Ask the user to grant write permission if it's not already granted PermissionsHandler.checkWritePermission(parent); + // Ask the user if he wants to enable analytics if we haven't yet. + Analytics.checkAnalyticsInit(parent); + String start_file = ""; Bundle extras = parent.getIntent().getExtras(); if (extras != null) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/VolleyUtil.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/VolleyUtil.java new file mode 100644 index 0000000000..1e523bb45f --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/VolleyUtil.java @@ -0,0 +1,22 @@ +package org.dolphinemu.dolphinemu.utils; + +import android.content.Context; + +import com.android.volley.RequestQueue; +import com.android.volley.toolbox.Volley; + +public class VolleyUtil +{ + private static RequestQueue queue; + + public static void init(Context context) + { + if (queue == null) + queue = Volley.newRequestQueue(context); + } + + public static RequestQueue getQueue() + { + return queue; + } +} |
