Merge pull request #10811 from 8bitDream/pip_mute
android: Add a PiP interface to mute / unmute
This commit is contained in:
		| @@ -286,7 +286,7 @@ object NativeLibrary { | ||||
|     /** | ||||
|      * Unpauses emulation from a paused state. | ||||
|      */ | ||||
|     external fun unPauseEmulation() | ||||
|     external fun unpauseEmulation() | ||||
|  | ||||
|     /** | ||||
|      * Pauses emulation. | ||||
| @@ -313,6 +313,21 @@ object NativeLibrary { | ||||
|      */ | ||||
|     external fun isPaused(): Boolean | ||||
|  | ||||
|     /** | ||||
|      * Mutes emulation sound | ||||
|      */ | ||||
|     external fun muteAudio(): Boolean | ||||
|  | ||||
|     /** | ||||
|      * Unmutes emulation sound | ||||
|      */ | ||||
|     external fun unmuteAudio(): Boolean | ||||
|  | ||||
|     /** | ||||
|      * Returns true if emulation audio is muted. | ||||
|      */ | ||||
|     external fun isMuted(): Boolean | ||||
|  | ||||
|     /** | ||||
|      * Returns the performance stats for the current game | ||||
|      */ | ||||
|   | ||||
| @@ -65,6 +65,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | ||||
|  | ||||
|     private val actionPause = "ACTION_EMULATOR_PAUSE" | ||||
|     private val actionPlay = "ACTION_EMULATOR_PLAY" | ||||
|     private val actionMute = "ACTION_EMULATOR_MUTE" | ||||
|     private val actionUnmute = "ACTION_EMULATOR_UNMUTE" | ||||
|  | ||||
|     private val settingsViewModel: SettingsViewModel by viewModels() | ||||
|  | ||||
| @@ -320,6 +322,41 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | ||||
|             pictureInPictureActions.add(pauseRemoteAction) | ||||
|         } | ||||
|  | ||||
|         if (NativeLibrary.isMuted()) { | ||||
|             val unmuteIcon = Icon.createWithResource( | ||||
|                 this@EmulationActivity, | ||||
|                 R.drawable.ic_pip_unmute | ||||
|             ) | ||||
|             val unmutePendingIntent = PendingIntent.getBroadcast( | ||||
|                 this@EmulationActivity, | ||||
|                 R.drawable.ic_pip_unmute, | ||||
|                 Intent(actionUnmute), | ||||
|                 pendingFlags | ||||
|             ) | ||||
|             val unmuteRemoteAction = RemoteAction( | ||||
|                 unmuteIcon, | ||||
|                 getString(R.string.unmute), | ||||
|                 getString(R.string.unmute), | ||||
|                 unmutePendingIntent | ||||
|             ) | ||||
|             pictureInPictureActions.add(unmuteRemoteAction) | ||||
|         } else { | ||||
|             val muteIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_mute) | ||||
|             val mutePendingIntent = PendingIntent.getBroadcast( | ||||
|                 this@EmulationActivity, | ||||
|                 R.drawable.ic_pip_mute, | ||||
|                 Intent(actionMute), | ||||
|                 pendingFlags | ||||
|             ) | ||||
|             val muteRemoteAction = RemoteAction( | ||||
|                 muteIcon, | ||||
|                 getString(R.string.mute), | ||||
|                 getString(R.string.mute), | ||||
|                 mutePendingIntent | ||||
|             ) | ||||
|             pictureInPictureActions.add(muteRemoteAction) | ||||
|         } | ||||
|  | ||||
|         return this.apply { setActions(pictureInPictureActions) } | ||||
|     } | ||||
|  | ||||
| @@ -337,10 +374,15 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | ||||
|     private var pictureInPictureReceiver = object : BroadcastReceiver() { | ||||
|         override fun onReceive(context: Context?, intent: Intent) { | ||||
|             if (intent.action == actionPlay) { | ||||
|                 if (NativeLibrary.isPaused()) NativeLibrary.unPauseEmulation() | ||||
|                 if (NativeLibrary.isPaused()) NativeLibrary.unpauseEmulation() | ||||
|             } else if (intent.action == actionPause) { | ||||
|                 if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation() | ||||
|             } | ||||
|             if (intent.action == actionUnmute) { | ||||
|                 if (NativeLibrary.isMuted()) NativeLibrary.unmuteAudio() | ||||
|             } else if (intent.action == actionMute) { | ||||
|                 if (!NativeLibrary.isMuted()) NativeLibrary.muteAudio() | ||||
|             } | ||||
|             buildPictureInPictureParams() | ||||
|         } | ||||
|     } | ||||
| @@ -354,6 +396,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | ||||
|             IntentFilter().apply { | ||||
|                 addAction(actionPause) | ||||
|                 addAction(actionPlay) | ||||
|                 addAction(actionMute) | ||||
|                 addAction(actionUnmute) | ||||
|             }.also { | ||||
|                 registerReceiver(pictureInPictureReceiver, it) | ||||
|             } | ||||
| @@ -362,6 +406,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | ||||
|                 unregisterReceiver(pictureInPictureReceiver) | ||||
|             } catch (ignored: Exception) { | ||||
|             } | ||||
|             // Always resume audio, since there is no UI button | ||||
|             if (NativeLibrary.isMuted()) NativeLibrary.unmuteAudio() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -714,7 +714,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | ||||
|                 State.PAUSED -> { | ||||
|                     Log.debug("[EmulationFragment] Resuming emulation.") | ||||
|                     NativeLibrary.surfaceChanged(surface) | ||||
|                     NativeLibrary.unPauseEmulation() | ||||
|                     NativeLibrary.unpauseEmulation() | ||||
|                 } | ||||
|  | ||||
|                 else -> Log.debug("[EmulationFragment] Bug, run called while already running.") | ||||
|   | ||||
| @@ -14,7 +14,6 @@ add_library(yuzu-android SHARED | ||||
|     id_cache.cpp | ||||
|     id_cache.h | ||||
|     native.cpp | ||||
|     native.h | ||||
| ) | ||||
|  | ||||
| set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
| #include <android/api-level.h> | ||||
| #include <android/native_window_jni.h> | ||||
| #include <core/loader/nro.h> | ||||
| #include <jni.h> | ||||
|  | ||||
| #include "common/detached_tasks.h" | ||||
| #include "common/dynamic_library.h" | ||||
| @@ -527,35 +528,32 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { | ||||
|  | ||||
| extern "C" { | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, | ||||
|                                                           [[maybe_unused]] jclass clazz, | ||||
|                                                           jobject surf) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jclass clazz, jobject surf) { | ||||
|     EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf)); | ||||
|     EmulationSession::GetInstance().SurfaceChanged(); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, | ||||
|                                                             [[maybe_unused]] jclass clazz) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jclass clazz) { | ||||
|     ANativeWindow_release(EmulationSession::GetInstance().NativeWindow()); | ||||
|     EmulationSession::GetInstance().SetNativeWindow(nullptr); | ||||
|     EmulationSession::GetInstance().SurfaceChanged(); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, | ||||
|                                                            [[maybe_unused]] jclass clazz, | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jclass clazz, | ||||
|                                                            jstring j_directory) { | ||||
|     Common::FS::SetAppDirectory(GetJString(env, j_directory)); | ||||
| } | ||||
|  | ||||
| int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, | ||||
|                                                             [[maybe_unused]] jclass clazz, | ||||
| int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jclass clazz, | ||||
|                                                             jstring j_file) { | ||||
|     return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file)); | ||||
| } | ||||
|  | ||||
| void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver( | ||||
|     JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir, | ||||
|     jstring custom_driver_name, jstring file_redirect_dir) { | ||||
| void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* env, jclass clazz, | ||||
|                                                                        jstring hook_lib_dir, | ||||
|                                                                        jstring custom_driver_dir, | ||||
|                                                                        jstring custom_driver_name, | ||||
|                                                                        jstring file_redirect_dir) { | ||||
|     EmulationSession::GetInstance().InitializeGpuDriver( | ||||
|         GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir), | ||||
|         GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir)); | ||||
| @@ -572,7 +570,7 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver( | ||||
| } | ||||
|  | ||||
| jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading( | ||||
|     [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject instance) { | ||||
|     JNIEnv* env, [[maybe_unused]] jobject instance) { | ||||
| #ifdef ARCHITECTURE_arm64 | ||||
|     // If the KGSL device exists custom drivers can be loaded using adrenotools | ||||
|     return SupportsCustomDriver(); | ||||
| @@ -581,49 +579,52 @@ jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDri | ||||
| #endif | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, | ||||
|                                                           [[maybe_unused]] jclass clazz) { | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, jclass clazz) { | ||||
|     Core::Crypto::KeyManager::Instance().ReloadKeys(); | ||||
|     return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded()); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_unPauseEmulation([[maybe_unused]] JNIEnv* env, | ||||
|                                                             [[maybe_unused]] jclass clazz) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_unpauseEmulation(JNIEnv* env, jclass clazz) { | ||||
|     EmulationSession::GetInstance().UnPauseEmulation(); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation([[maybe_unused]] JNIEnv* env, | ||||
|                                                           [[maybe_unused]] jclass clazz) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation(JNIEnv* env, jclass clazz) { | ||||
|     EmulationSession::GetInstance().PauseEmulation(); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation([[maybe_unused]] JNIEnv* env, | ||||
|                                                          [[maybe_unused]] jclass clazz) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation(JNIEnv* env, jclass clazz) { | ||||
|     EmulationSession::GetInstance().HaltEmulation(); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata([[maybe_unused]] JNIEnv* env, | ||||
|                                                             [[maybe_unused]] jclass clazz) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata(JNIEnv* env, jclass clazz) { | ||||
|     EmulationSession::GetInstance().ResetRomMetadata(); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning([[maybe_unused]] JNIEnv* env, | ||||
|                                                          [[maybe_unused]] jclass clazz) { | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning(JNIEnv* env, jclass clazz) { | ||||
|     return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning()); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused([[maybe_unused]] JNIEnv* env, | ||||
|                                                         [[maybe_unused]] jclass clazz) { | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass clazz) { | ||||
|     return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused()); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly([[maybe_unused]] JNIEnv* env, | ||||
|                                                               [[maybe_unused]] jclass clazz) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_muteAduio(JNIEnv* env, jclass clazz) { | ||||
|     Settings::values.audio_muted = true; | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_unmuteAudio(JNIEnv* env, jclass clazz) { | ||||
|     Settings::values.audio_muted = false; | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isMuted(JNIEnv* env, jclass clazz) { | ||||
|     return static_cast<jboolean>(Settings::values.audio_muted.GetValue()); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly(JNIEnv* env, jclass clazz) { | ||||
|     return EmulationSession::GetInstance().IsHandheldOnly(); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType([[maybe_unused]] JNIEnv* env, | ||||
|                                                              [[maybe_unused]] jclass clazz, | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType(JNIEnv* env, jclass clazz, | ||||
|                                                              jint j_device, jint j_type) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().SetDeviceType(j_device, j_type); | ||||
| @@ -631,8 +632,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType([[maybe_unused]] JN | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent([[maybe_unused]] JNIEnv* env, | ||||
|                                                                      [[maybe_unused]] jclass clazz, | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent(JNIEnv* env, jclass clazz, | ||||
|                                                                      jint j_device) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); | ||||
| @@ -640,15 +640,14 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent([[maybe_unu | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent( | ||||
|     [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device) { | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(JNIEnv* env, jclass clazz, | ||||
|                                                                         jint j_device) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device); | ||||
|     } | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unused]] JNIEnv* env, | ||||
|                                                                     [[maybe_unused]] jclass clazz, | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz, | ||||
|                                                                     [[maybe_unused]] jint j_device, | ||||
|                                                                     jint j_button, jint action) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
| @@ -660,8 +659,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unus | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_unused]] JNIEnv* env, | ||||
|                                                                       [[maybe_unused]] jclass clazz, | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent(JNIEnv* env, jclass clazz, | ||||
|                                                                       jint j_device, jint stick_id, | ||||
|                                                                       jfloat x, jfloat y) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
| @@ -671,9 +669,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_un | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent( | ||||
|     [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device, | ||||
|     jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x, | ||||
|     jfloat accel_y, jfloat accel_z) { | ||||
|     JNIEnv* env, jclass clazz, jint j_device, jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, | ||||
|     jfloat gyro_z, jfloat accel_x, jfloat accel_y, jfloat accel_z) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().Window().OnGamepadMotionEvent( | ||||
|             j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); | ||||
| @@ -681,8 +678,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent( | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag([[maybe_unused]] JNIEnv* env, | ||||
|                                                             [[maybe_unused]] jclass clazz, | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag(JNIEnv* env, jclass clazz, | ||||
|                                                             jbyteArray j_data) { | ||||
|     jboolean isCopy{false}; | ||||
|     std::span<u8> data(reinterpret_cast<u8*>(env->GetByteArrayElements(j_data, &isCopy)), | ||||
| @@ -694,39 +690,34 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag([[maybe_unused]] JNI | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag([[maybe_unused]] JNIEnv* env, | ||||
|                                                               [[maybe_unused]] jclass clazz) { | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag(JNIEnv* env, jclass clazz) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().Window().OnRemoveNfcTag(); | ||||
|     } | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env, | ||||
|                                                           [[maybe_unused]] jclass clazz, jint id, | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed(JNIEnv* env, jclass clazz, jint id, | ||||
|                                                           jfloat x, jfloat y) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env, | ||||
|                                                         [[maybe_unused]] jclass clazz, jint id, | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, jclass clazz, jint id, | ||||
|                                                         jfloat x, jfloat y) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased([[maybe_unused]] JNIEnv* env, | ||||
|                                                            [[maybe_unused]] jclass clazz, jint id) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass clazz, jint id) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().Window().OnTouchReleased(id); | ||||
|     } | ||||
| } | ||||
|  | ||||
| jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon([[maybe_unused]] JNIEnv* env, | ||||
|                                                          [[maybe_unused]] jclass clazz, | ||||
| jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz, | ||||
|                                                          [[maybe_unused]] jstring j_filename) { | ||||
|     auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename)); | ||||
|     jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size())); | ||||
| @@ -735,67 +726,58 @@ jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon([[maybe_unused]] JNIEnv | ||||
|     return icon; | ||||
| } | ||||
|  | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle([[maybe_unused]] JNIEnv* env, | ||||
|                                                        [[maybe_unused]] jclass clazz, | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz, | ||||
|                                                        [[maybe_unused]] jstring j_filename) { | ||||
|     auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename)); | ||||
|     return env->NewStringUTF(title.c_str()); | ||||
| } | ||||
|  | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription([[maybe_unused]] JNIEnv* env, | ||||
|                                                              [[maybe_unused]] jclass clazz, | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription(JNIEnv* env, jclass clazz, | ||||
|                                                              jstring j_filename) { | ||||
|     return j_filename; | ||||
| } | ||||
|  | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId([[maybe_unused]] JNIEnv* env, | ||||
|                                                         [[maybe_unused]] jclass clazz, | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId(JNIEnv* env, jclass clazz, | ||||
|                                                         jstring j_filename) { | ||||
|     return j_filename; | ||||
| } | ||||
|  | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions([[maybe_unused]] JNIEnv* env, | ||||
|                                                          [[maybe_unused]] jclass clazz, | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz, | ||||
|                                                          [[maybe_unused]] jstring j_filename) { | ||||
|     return env->NewStringUTF(""); | ||||
| } | ||||
|  | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv* env, | ||||
|                                                          [[maybe_unused]] jclass clazz, | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz, | ||||
|                                                          [[maybe_unused]] jstring j_filename) { | ||||
|     return env->NewStringUTF(""); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew([[maybe_unused]] JNIEnv* env, | ||||
|                                                           [[maybe_unused]] jclass clazz, | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz, | ||||
|                                                           [[maybe_unused]] jstring j_filename) { | ||||
|     return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename)); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation | ||||
|     [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) { | ||||
|     [[maybe_unused]] (JNIEnv* env, jclass clazz) { | ||||
|     // Create the default config.ini. | ||||
|     Config{}; | ||||
|     // Initialize the emulated system. | ||||
|     EmulationSession::GetInstance().System().Initialize(); | ||||
| } | ||||
|  | ||||
| jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore([[maybe_unused]] JNIEnv* env, | ||||
|                                                           [[maybe_unused]] jclass clazz) { | ||||
| jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { | ||||
|     return {}; | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( | ||||
|     [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file, | ||||
|     JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_file, | ||||
|     [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNIEnv* env, | ||||
|                                                           [[maybe_unused]] jclass clazz) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) { | ||||
|     Config{}; | ||||
| } | ||||
|  | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting([[maybe_unused]] JNIEnv* env, | ||||
|                                                              [[maybe_unused]] jclass clazz, | ||||
| jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting(JNIEnv* env, jclass clazz, | ||||
|                                                              jstring j_game_id, jstring j_section, | ||||
|                                                              jstring j_key) { | ||||
|     std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | ||||
| @@ -809,8 +791,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting([[maybe_unused]] JN | ||||
|     return env->NewStringUTF(""); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting([[maybe_unused]] JNIEnv* env, | ||||
|                                                           [[maybe_unused]] jclass clazz, | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting(JNIEnv* env, jclass clazz, | ||||
|                                                           jstring j_game_id, jstring j_section, | ||||
|                                                           jstring j_key, jstring j_value) { | ||||
|     std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | ||||
| @@ -824,16 +805,14 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting([[maybe_unused]] JNIEn | ||||
|     env->ReleaseStringUTFChars(j_value, value.data()); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni([[maybe_unused]] JNIEnv* env, | ||||
|                                                        [[maybe_unused]] jclass clazz, | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz, | ||||
|                                                        jstring j_game_id) { | ||||
|     std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | ||||
|  | ||||
|     env->ReleaseStringUTFChars(j_game_id, game_id.data()); | ||||
| } | ||||
|  | ||||
| jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]] JNIEnv* env, | ||||
|                                                                 [[maybe_unused]] jclass clazz) { | ||||
| jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) { | ||||
|     jdoubleArray j_stats = env->NewDoubleArray(4); | ||||
|  | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
| @@ -849,11 +828,11 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]] | ||||
|     return j_stats; | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory( | ||||
|     [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {} | ||||
| void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(JNIEnv* env, | ||||
|                                                                            jclass clazz, | ||||
|                                                                            jstring j_path) {} | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env, | ||||
|                                                                     [[maybe_unused]] jclass clazz, | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2(JNIEnv* env, jclass clazz, | ||||
|                                                                     jstring j_path) { | ||||
|     const std::string path = GetJString(env, j_path); | ||||
|  | ||||
| @@ -864,8 +843,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unus | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo([[maybe_unused]] JNIEnv* env, | ||||
|                                                          [[maybe_unused]] jclass clazz) { | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo(JNIEnv* env, jclass clazz) { | ||||
|     LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc); | ||||
|     LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level()); | ||||
| } | ||||
|   | ||||
| @@ -1,165 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <jni.h> | ||||
|  | ||||
| // Function calls from the Java side | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_UnPauseEmulation(JNIEnv* env, | ||||
|                                                                               jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_PauseEmulation(JNIEnv* env, | ||||
|                                                                             jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_StopEmulation(JNIEnv* env, | ||||
|                                                                            jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ResetRomMetadata(JNIEnv* env, | ||||
|                                                                               jclass clazz); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_IsRunning(JNIEnv* env, | ||||
|                                                                            jclass clazz); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly(JNIEnv* env, | ||||
|                                                                                 jclass clazz); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType(JNIEnv* env, | ||||
|                                                                                jclass clazz, | ||||
|                                                                                jstring j_device, | ||||
|                                                                                jstring j_type); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent( | ||||
|     JNIEnv* env, jclass clazz, jstring j_device); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent( | ||||
|     JNIEnv* env, jclass clazz, jstring j_device); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadEvent( | ||||
|     JNIEnv* env, jclass clazz, jstring j_device, jint j_button, jint action); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMoveEvent( | ||||
|     JNIEnv* env, jclass clazz, jstring j_device, jint axis, jfloat x, jfloat y); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadAxisEvent( | ||||
|     JNIEnv* env, jclass clazz, jstring j_device, jint axis_id, jfloat axis_val); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag(JNIEnv* env, | ||||
|                                                                               jclass clazz, | ||||
|                                                                               jbyteArray j_data); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag(JNIEnv* env, | ||||
|                                                                                 jclass clazz); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchEvent(JNIEnv* env, | ||||
|                                                                               jclass clazz, | ||||
|                                                                               jfloat x, jfloat y, | ||||
|                                                                               jboolean pressed); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, jclass clazz, | ||||
|                                                                           jfloat x, jfloat y); | ||||
|  | ||||
| JNIEXPORT jbyteArray JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetIcon(JNIEnv* env, | ||||
|                                                                            jclass clazz, | ||||
|                                                                            jstring j_file); | ||||
|  | ||||
| JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetTitle(JNIEnv* env, jclass clazz, | ||||
|                                                                          jstring j_filename); | ||||
|  | ||||
| JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetDescription(JNIEnv* env, | ||||
|                                                                                jclass clazz, | ||||
|                                                                                jstring j_filename); | ||||
|  | ||||
| JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGameId(JNIEnv* env, jclass clazz, | ||||
|                                                                           jstring j_filename); | ||||
|  | ||||
| JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetRegions(JNIEnv* env, | ||||
|                                                                            jclass clazz, | ||||
|                                                                            jstring j_filename); | ||||
|  | ||||
| JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetCompany(JNIEnv* env, | ||||
|                                                                            jclass clazz, | ||||
|                                                                            jstring j_filename); | ||||
|  | ||||
| JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGitRevision(JNIEnv* env, | ||||
|                                                                                jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetAppDirectory(JNIEnv* env, | ||||
|                                                                              jclass clazz, | ||||
|                                                                              jstring j_directory); | ||||
|  | ||||
| JNIEXPORT void JNICALL | ||||
| Java_org_yuzu_yuzu_1emu_NativeLibrary_Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeGpuDriver( | ||||
|     JNIEnv* env, jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir, | ||||
|     jstring custom_driver_name, jstring file_redirect_dir); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env, | ||||
|                                                                             jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_SetSysDirectory( | ||||
|     JNIEnv* env, jclass clazz, jstring path_); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetSysDirectory(JNIEnv* env, | ||||
|                                                                              jclass clazz, | ||||
|                                                                              jstring path); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeEmulation(JNIEnv* env, | ||||
|                                                                                  jclass clazz); | ||||
|  | ||||
| JNIEXPORT jint JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_DefaultCPUCore(JNIEnv* env, | ||||
|                                                                             jclass clazz); | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetProfiling(JNIEnv* env, jclass clazz, | ||||
|                                                                           jboolean enable); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_WriteProfileResults(JNIEnv* env, | ||||
|                                                                                  jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_NotifyOrientationChange( | ||||
|     JNIEnv* env, jclass clazz, jint layout_option, jint rotation); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2( | ||||
|     JNIEnv* env, jclass clazz, jstring j_path); | ||||
|  | ||||
| JNIEXPORT void JNICALL | ||||
| Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z( | ||||
|     JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env, | ||||
|                                                                             jclass clazz, | ||||
|                                                                             jobject surf); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, | ||||
|                                                                               jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitGameIni(JNIEnv* env, jclass clazz, | ||||
|                                                                          jstring j_game_id); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadSettings(JNIEnv* env, | ||||
|                                                                             jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SetUserSetting( | ||||
|     JNIEnv* env, jclass clazz, jstring j_game_id, jstring j_section, jstring j_key, | ||||
|     jstring j_value); | ||||
|  | ||||
| JNIEXPORT jstring JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetUserSetting( | ||||
|     JNIEnv* env, jclass clazz, jstring game_id, jstring section, jstring key); | ||||
|  | ||||
| JNIEXPORT jdoubleArray JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_GetPerfStats(JNIEnv* env, | ||||
|                                                                                   jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_LogDeviceInfo(JNIEnv* env, | ||||
|                                                                            jclass clazz); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardText( | ||||
|     JNIEnv* env, jclass clazz, jstring j_text); | ||||
|  | ||||
| JNIEXPORT void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardInput( | ||||
|     JNIEnv* env, jclass clazz, jint j_key_code); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										9
									
								
								src/android/app/src/main/res/drawable/ic_pip_mute.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/android/app/src/main/res/drawable/ic_pip_mute.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="@android:color/white" | ||||
|         android:pathData="M7,9v6h4l5,5V4l-5,5H7z" /> | ||||
| </vector> | ||||
							
								
								
									
										9
									
								
								src/android/app/src/main/res/drawable/ic_pip_unmute.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/android/app/src/main/res/drawable/ic_pip_unmute.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="@android:color/white" | ||||
|         android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z" /> | ||||
| </vector> | ||||
| @@ -399,6 +399,8 @@ | ||||
|     <string name="picture_in_picture_description">Minimize window when placed in the background</string> | ||||
|     <string name="pause">Pause</string> | ||||
|     <string name="play">Play</string> | ||||
|     <string name="mute">Mute</string> | ||||
|     <string name="unmute">Unmute</string> | ||||
|  | ||||
|     <!-- Licenses screen strings --> | ||||
|     <string name="licenses">Licenses</string> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user