mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-24 14:24:54 +00:00
IOS/USB: Add a warning about RECORD_AUDIO permission
This commit is contained in:
parent
2dd01bae6e
commit
c7c96ff1f2
8 changed files with 107 additions and 12 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.hardware.usb.UsbManager;
|
||||
|
@ -15,13 +16,15 @@ import org.dolphinemu.dolphinemu.utils.VolleyUtil;
|
|||
public class DolphinApplication extends Application
|
||||
{
|
||||
private static DolphinApplication application;
|
||||
private static ActivityTracker sActivityTracker;
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
super.onCreate();
|
||||
application = this;
|
||||
registerActivityLifecycleCallbacks(new ActivityTracker());
|
||||
sActivityTracker = new ActivityTracker();
|
||||
registerActivityLifecycleCallbacks(sActivityTracker);
|
||||
VolleyUtil.init(getApplicationContext());
|
||||
System.loadLibrary("main");
|
||||
|
||||
|
@ -36,4 +39,9 @@ public class DolphinApplication extends Application
|
|||
{
|
||||
return application.getApplicationContext();
|
||||
}
|
||||
|
||||
public static Activity getAppActivity()
|
||||
{
|
||||
return sActivityTracker.getCurrentActivity();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.widget.CompoundButton
|
||||
import org.dolphinemu.dolphinemu.databinding.ListItemSettingSwitchBinding
|
||||
|
@ -63,13 +60,9 @@ class SwitchSettingViewHolder(
|
|||
}
|
||||
|
||||
if (setting.setting === BooleanSetting.MAIN_EMULATE_WII_SPEAK && isChecked) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||
itemView.context.checkSelfPermission(Manifest.permission.RECORD_AUDIO)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
val settingsActivity = itemView.context as Activity
|
||||
settingsActivity.requestPermissions(
|
||||
arrayOf(Manifest.permission.RECORD_AUDIO),
|
||||
PermissionsHandler.REQUEST_CODE_RECORD_AUDIO)
|
||||
if (!PermissionsHandler.hasRecordAudioPermission(itemView.context)) {
|
||||
val settingsActivity = itemView.context as Activity
|
||||
PermissionsHandler.requestRecordAudioPermission(settingsActivity)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,15 @@ class ActivityTracker : ActivityLifecycleCallbacks {
|
|||
private val resumedActivities = HashSet<Activity>()
|
||||
private var backgroundExecutionAllowed = false
|
||||
private var firstStart = true
|
||||
var currentActivity : Activity? = null
|
||||
private set
|
||||
|
||||
private fun isMainActivity(activity: Activity): Boolean {
|
||||
return activity is MainView
|
||||
}
|
||||
|
||||
override fun onActivityCreated(activity: Activity, bundle: Bundle?) {
|
||||
currentActivity = activity
|
||||
if (isMainActivity(activity)) {
|
||||
firstStart = bundle == null
|
||||
}
|
||||
|
@ -51,7 +54,11 @@ class ActivityTracker : ActivityLifecycleCallbacks {
|
|||
|
||||
override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {}
|
||||
|
||||
override fun onActivityDestroyed(activity: Activity) {}
|
||||
override fun onActivityDestroyed(activity: Activity) {
|
||||
if (currentActivity === activity) {
|
||||
currentActivity = null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
package org.dolphinemu.dolphinemu.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
@ -11,6 +12,11 @@ import androidx.core.content.ContextCompat;
|
|||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||
import static android.Manifest.permission.RECORD_AUDIO;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.DolphinApplication;
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
|
||||
public class PermissionsHandler
|
||||
{
|
||||
|
@ -53,4 +59,32 @@ public class PermissionsHandler
|
|||
{
|
||||
return sWritePermissionDenied;
|
||||
}
|
||||
|
||||
public static boolean hasRecordAudioPermission(Context context)
|
||||
{
|
||||
if (context == null)
|
||||
context = DolphinApplication.getAppContext();
|
||||
int hasRecordPermission = ContextCompat.checkSelfPermission(context, RECORD_AUDIO);
|
||||
return hasRecordPermission == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
public static void requestRecordAudioPermission(Activity activity)
|
||||
{
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||
return;
|
||||
|
||||
if (activity == null)
|
||||
{
|
||||
// Calling from C++ code
|
||||
activity = DolphinApplication.getAppActivity();
|
||||
// Since the emulation (and cubeb) has already started, enabling the microphone permission
|
||||
// now might require restarting the game to be effective. Warn the user about it.
|
||||
NativeLibrary.displayAlertMsg(
|
||||
activity.getString(R.string.wii_speak_permission_warning),
|
||||
activity.getString(R.string.wii_speak_permission_warning_description),
|
||||
false, true, false);
|
||||
}
|
||||
|
||||
activity.requestPermissions(new String[]{RECORD_AUDIO}, REQUEST_CODE_RECORD_AUDIO);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -943,4 +943,6 @@ It can efficiently compress both junk data and encrypted Wii data.
|
|||
|
||||
<string name="emulate_wii_speak">Wii Speak</string>
|
||||
<string name="disconnect_wii_speak">Mute Wii Speak</string>
|
||||
<string name="wii_speak_permission_warning">Missing Microphone Permission</string>
|
||||
<string name="wii_speak_permission_warning_description">Wii Speak emulation requires microphone permission. You might need to restart the game for the permission to be effective.</string>
|
||||
</resources>
|
||||
|
|
|
@ -116,6 +116,10 @@ static jmethodID s_core_device_control_constructor;
|
|||
static jclass s_input_detector_class;
|
||||
static jfieldID s_input_detector_pointer;
|
||||
|
||||
static jclass s_permission_handler_class;
|
||||
static jmethodID s_permission_handler_has_record_audio_permission;
|
||||
static jmethodID s_permission_handler_request_record_audio_permission;
|
||||
|
||||
static jmethodID s_runnable_run;
|
||||
|
||||
namespace IDCache
|
||||
|
@ -538,6 +542,21 @@ jfieldID GetInputDetectorPointer()
|
|||
return s_input_detector_pointer;
|
||||
}
|
||||
|
||||
jclass GetPermissionHandlerClass()
|
||||
{
|
||||
return s_permission_handler_class;
|
||||
}
|
||||
|
||||
jmethodID GetPermissionHandlerHasRecordAudioPermission()
|
||||
{
|
||||
return s_permission_handler_has_record_audio_permission;
|
||||
}
|
||||
|
||||
jmethodID GetPermissionHandlerRequestRecordAudioPermission()
|
||||
{
|
||||
return s_permission_handler_request_record_audio_permission;
|
||||
}
|
||||
|
||||
jmethodID GetRunnableRun()
|
||||
{
|
||||
return s_runnable_run;
|
||||
|
@ -765,6 +784,16 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||
s_input_detector_pointer = env->GetFieldID(input_detector_class, "pointer", "J");
|
||||
env->DeleteLocalRef(input_detector_class);
|
||||
|
||||
const jclass permission_handler_class =
|
||||
env->FindClass("org/dolphinemu/dolphinemu/utils/PermissionsHandler");
|
||||
s_permission_handler_class =
|
||||
reinterpret_cast<jclass>(env->NewGlobalRef(permission_handler_class));
|
||||
s_permission_handler_has_record_audio_permission = env->GetStaticMethodID(
|
||||
permission_handler_class, "hasRecordAudioPermission", "(Landroid/content/Context;)Z");
|
||||
s_permission_handler_request_record_audio_permission = env->GetStaticMethodID(
|
||||
permission_handler_class, "requestRecordAudioPermission", "(Landroid/app/Activity;)V");
|
||||
env->DeleteLocalRef(permission_handler_class);
|
||||
|
||||
const jclass runnable_class = env->FindClass("java/lang/Runnable");
|
||||
s_runnable_run = env->GetMethodID(runnable_class, "run", "()V");
|
||||
env->DeleteLocalRef(runnable_class);
|
||||
|
@ -804,5 +833,6 @@ JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
|
|||
env->DeleteGlobalRef(s_core_device_class);
|
||||
env->DeleteGlobalRef(s_core_device_control_class);
|
||||
env->DeleteGlobalRef(s_input_detector_class);
|
||||
env->DeleteGlobalRef(s_permission_handler_class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,10 @@ jmethodID GetCoreDeviceControlConstructor();
|
|||
jclass GetInputDetectorClass();
|
||||
jfieldID GetInputDetectorPointer();
|
||||
|
||||
jclass GetPermissionHandlerClass();
|
||||
jmethodID GetPermissionHandlerHasRecordAudioPermission();
|
||||
jmethodID GetPermissionHandlerRequestRecordAudioPermission();
|
||||
|
||||
jmethodID GetRunnableRun();
|
||||
|
||||
} // namespace IDCache
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
#include <Objbase.h>
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "jni/AndroidCommon/IDCache.h"
|
||||
#endif
|
||||
|
||||
namespace IOS::HLE::USB
|
||||
{
|
||||
Microphone::Microphone(const WiiSpeakState& sampler) : m_sampler(sampler)
|
||||
|
@ -118,6 +122,19 @@ void Microphone::StreamStart()
|
|||
Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); });
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
JNIEnv* env = IDCache::GetEnvForThread();
|
||||
if (jboolean result = env->CallStaticBooleanMethod(
|
||||
IDCache::GetPermissionHandlerClass(),
|
||||
IDCache::GetPermissionHandlerHasRecordAudioPermission(), nullptr);
|
||||
result == JNI_FALSE)
|
||||
{
|
||||
env->CallStaticVoidMethod(IDCache::GetPermissionHandlerClass(),
|
||||
IDCache::GetPermissionHandlerRequestRecordAudioPermission(),
|
||||
nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
cubeb_stream_params params{};
|
||||
params.format = CUBEB_SAMPLE_S16LE;
|
||||
params.rate = SAMPLING_RATE;
|
||||
|
|
Loading…
Add table
Reference in a new issue